diff --git a/fuse_sideload/fuse_provider.cpp b/fuse_sideload/fuse_provider.cpp index 5ee6e247..8fa1b5c2 100644 --- a/fuse_sideload/fuse_provider.cpp +++ b/fuse_sideload/fuse_provider.cpp @@ -49,6 +49,11 @@ FuseFileDataProvider::FuseFileDataProvider(const std::string& path, uint32_t blo fuse_block_size_ = block_size; } +std::unique_ptr FuseFileDataProvider::CreateFromFile(const std::string& path, + uint32_t block_size) { + return std::make_unique(path, block_size); +} + bool FuseFileDataProvider::ReadBlockAlignedData(uint8_t* buffer, uint32_t fetch_size, uint32_t start_block) const { uint64_t offset = static_cast(start_block) * fuse_block_size_; @@ -127,7 +132,7 @@ bool FuseBlockDataProvider::ReadBlockAlignedData(uint8_t* buffer, uint32_t fetch return true; } -std::unique_ptr FuseBlockDataProvider::CreateFromBlockMap( +std::unique_ptr FuseBlockDataProvider::CreateFromBlockMap( const std::string& block_map_path, uint32_t fuse_block_size) { auto block_map = BlockMapData::ParseBlockMapFile(block_map_path); if (!block_map) { diff --git a/fuse_sideload/include/fuse_provider.h b/fuse_sideload/include/fuse_provider.h index 8d4ea407..3cdaef33 100644 --- a/fuse_sideload/include/fuse_provider.h +++ b/fuse_sideload/include/fuse_provider.h @@ -44,6 +44,8 @@ class FuseDataProvider { virtual bool ReadBlockAlignedData(uint8_t* buffer, uint32_t fetch_size, uint32_t start_block) const = 0; + virtual bool Valid() const = 0; + virtual void Close() {} protected: @@ -60,10 +62,13 @@ class FuseFileDataProvider : public FuseDataProvider { public: FuseFileDataProvider(const std::string& path, uint32_t block_size); + static std::unique_ptr CreateFromFile(const std::string& path, + uint32_t block_size); + bool ReadBlockAlignedData(uint8_t* buffer, uint32_t fetch_size, uint32_t start_block) const override; - bool Valid() const { + bool Valid() const override { return fd_ != -1; } @@ -78,14 +83,20 @@ class FuseFileDataProvider : public FuseDataProvider { class FuseBlockDataProvider : public FuseDataProvider { public: // Constructs the fuse provider from the block map. - static std::unique_ptr CreateFromBlockMap( - const std::string& block_map_path, uint32_t fuse_block_size); + static std::unique_ptr CreateFromBlockMap(const std::string& block_map_path, + uint32_t fuse_block_size); RangeSet ranges() const { return ranges_; } + bool ReadBlockAlignedData(uint8_t* buffer, uint32_t fetch_size, uint32_t start_block) const override; + + bool Valid() const override { + return fd_ != -1; + } + void Close() override; private: diff --git a/install/Android.bp b/install/Android.bp index 4696e501..89cc3f23 100644 --- a/install/Android.bp +++ b/install/Android.bp @@ -61,7 +61,7 @@ cc_library_static { srcs: [ "adb_install.cpp", "asn1_decoder.cpp", - "fuse_sdcard_install.cpp", + "fuse_install.cpp", "install.cpp", "package.cpp", "verifier.cpp", diff --git a/install/fuse_sdcard_install.cpp b/install/fuse_install.cpp similarity index 81% rename from install/fuse_sdcard_install.cpp rename to install/fuse_install.cpp index 9fdb2f34..ffde4a34 100644 --- a/install/fuse_sdcard_install.cpp +++ b/install/fuse_install.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "install/fuse_sdcard_install.h" +#include "install/fuse_install.h" #include #include @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -74,7 +75,8 @@ static std::string BrowseDirectory(const std::string& path, Device* device, Reco // Skip "." and ".." entries. if (name == "." || name == "..") continue; dirs.push_back(name + "/"); - } else if (de->d_type == DT_REG && android::base::EndsWithIgnoreCase(name, ".zip")) { + } else if (de->d_type == DT_REG && (android::base::EndsWithIgnoreCase(name, ".zip") || + android::base::EndsWithIgnoreCase(name, ".map"))) { entries.push_back(name); } } @@ -119,42 +121,37 @@ static std::string BrowseDirectory(const std::string& path, Device* device, Reco // Unreachable. } -static bool StartSdcardFuse(const std::string& path) { - auto file_data_reader = std::make_unique(path, 65536); +static bool StartInstallPackageFuse(std::string_view path) { + if (path.empty()) { + return false; + } + + constexpr auto FUSE_BLOCK_SIZE = 65536; + bool is_block_map = android::base::ConsumePrefix(&path, "@"); + auto file_data_reader = + is_block_map ? FuseBlockDataProvider::CreateFromBlockMap(std::string(path), FUSE_BLOCK_SIZE) + : FuseFileDataProvider::CreateFromFile(std::string(path), FUSE_BLOCK_SIZE); if (!file_data_reader->Valid()) { return false; } - // The installation process expects to find the sdcard unmounted. Unmount it with MNT_DETACH so - // that our open file continues to work but new references see it as unmounted. - umount2("/sdcard", MNT_DETACH); + if (android::base::StartsWith(path, SDCARD_ROOT)) { + // The installation process expects to find the sdcard unmounted. Unmount it with MNT_DETACH so + // that our open file continues to work but new references see it as unmounted. + umount2(SDCARD_ROOT, MNT_DETACH); + } return run_fuse_sideload(std::move(file_data_reader)) == 0; } -InstallResult ApplyFromSdcard(Device* device, RecoveryUI* ui) { - if (ensure_path_mounted(SDCARD_ROOT) != 0) { - LOG(ERROR) << "\n-- Couldn't mount " << SDCARD_ROOT << ".\n"; - return INSTALL_ERROR; - } - - std::string path = BrowseDirectory(SDCARD_ROOT, device, ui); - if (path.empty()) { - LOG(ERROR) << "\n-- No package file selected.\n"; - ensure_path_unmounted(SDCARD_ROOT); - return INSTALL_ERROR; - } - - ui->Print("\n-- Install %s ...\n", path.c_str()); - SetSdcardUpdateBootloaderMessage(); - +InstallResult InstallWithFuseFromPath(std::string_view path, RecoveryUI* ui) { // We used to use fuse in a thread as opposed to a process. Since accessing // through fuse involves going from kernel to userspace to kernel, it leads // to deadlock when a page fault occurs. (Bug: 26313124) pid_t child; if ((child = fork()) == 0) { - bool status = StartSdcardFuse(path); + bool status = StartInstallPackageFuse(path); _exit(status ? EXIT_SUCCESS : EXIT_FAILURE); } @@ -203,6 +200,32 @@ InstallResult ApplyFromSdcard(Device* device, RecoveryUI* ui) { LOG(ERROR) << "Error exit from the fuse process: " << WEXITSTATUS(status); } + return result; +} + +InstallResult ApplyFromSdcard(Device* device) { + auto ui = device->GetUI(); + if (ensure_path_mounted(SDCARD_ROOT) != 0) { + LOG(ERROR) << "\n-- Couldn't mount " << SDCARD_ROOT << ".\n"; + return INSTALL_ERROR; + } + + std::string path = BrowseDirectory(SDCARD_ROOT, device, ui); + if (path.empty()) { + LOG(ERROR) << "\n-- No package file selected.\n"; + ensure_path_unmounted(SDCARD_ROOT); + return INSTALL_ERROR; + } + + // Hint the install function to read from a block map file. + if (android::base::EndsWithIgnoreCase(path, ".map")) { + path = "@" + path; + } + + ui->Print("\n-- Install %s ...\n", path.c_str()); + SetSdcardUpdateBootloaderMessage(); + + auto result = InstallWithFuseFromPath(path, ui); ensure_path_unmounted(SDCARD_ROOT); return result; } diff --git a/install/include/install/fuse_sdcard_install.h b/install/include/install/fuse_install.h similarity index 62% rename from install/include/install/fuse_sdcard_install.h rename to install/include/install/fuse_install.h index e5bb01f0..63b116ae 100644 --- a/install/include/install/fuse_sdcard_install.h +++ b/install/include/install/fuse_install.h @@ -16,8 +16,15 @@ #pragma once +#include + #include "install/install.h" #include "recovery_ui/device.h" #include "recovery_ui/ui.h" -InstallResult ApplyFromSdcard(Device* device, RecoveryUI* ui); +// Starts FUSE with the package from |path| as the data source. And installs the package from +// |FUSE_SIDELOAD_HOST_PATHNAME|. The |path| can point to the location of a package zip file or a +// block map file with the prefix '@'; e.g. /sdcard/package.zip, @/cache/recovery/block.map. +InstallResult InstallWithFuseFromPath(std::string_view path, RecoveryUI* ui); + +InstallResult ApplyFromSdcard(Device* device); diff --git a/minadbd/fuse_adb_provider.h b/minadbd/fuse_adb_provider.h index c5561e57..43c07d28 100644 --- a/minadbd/fuse_adb_provider.h +++ b/minadbd/fuse_adb_provider.h @@ -29,6 +29,10 @@ class FuseAdbDataProvider : public FuseDataProvider { bool ReadBlockAlignedData(uint8_t* buffer, uint32_t fetch_size, uint32_t start_block) const override; + bool Valid() const override { + return fd_ != -1; + } + private: // The underlying source to read data from (i.e. the one that talks to the host). int fd_; diff --git a/recovery.cpp b/recovery.cpp index db66ea7e..b18a8e74 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -49,7 +49,7 @@ #include "common.h" #include "fsck_unshare_blocks.h" #include "install/adb_install.h" -#include "install/fuse_sdcard_install.h" +#include "install/fuse_install.h" #include "install/install.h" #include "install/package.h" #include "install/wipe_data.h" @@ -408,7 +408,7 @@ static Device::BuiltinAction PromptAndWait(Device* device, InstallResult status) status = ApplyFromAdb(device, false /* rescue_mode */, &reboot_action); } else { adb = false; - status = ApplyFromSdcard(device, ui); + status = ApplyFromSdcard(device); } ui->Print("\nInstall from %s completed with status %d.\n", adb ? "ADB" : "SD card", status); diff --git a/tests/unit/fuse_provider_test.cpp b/tests/unit/fuse_provider_test.cpp index c5995dd7..37f99f92 100644 --- a/tests/unit/fuse_provider_test.cpp +++ b/tests/unit/fuse_provider_test.cpp @@ -44,7 +44,8 @@ TEST(FuseBlockMapTest, CreateFromBlockMap_smoke) { ASSERT_TRUE(block_map_data); ASSERT_EQ(10000, block_map_data->file_size()); ASSERT_EQ(4096, block_map_data->fuse_block_size()); - ASSERT_EQ(RangeSet({ { 10, 11 }, { 20, 21 }, { 22, 23 } }), block_map_data->ranges()); + ASSERT_EQ(RangeSet({ { 10, 11 }, { 20, 21 }, { 22, 23 } }), + static_cast(block_map_data.get())->ranges()); } TEST(FuseBlockMapTest, ReadBlockAlignedData_smoke) { diff --git a/tests/unit/fuse_sideload_test.cpp b/tests/unit/fuse_sideload_test.cpp index 6add99f4..ea895038 100644 --- a/tests/unit/fuse_sideload_test.cpp +++ b/tests/unit/fuse_sideload_test.cpp @@ -40,6 +40,10 @@ class FuseTestDataProvider : public FuseDataProvider { bool ReadBlockAlignedData(uint8_t*, uint32_t, uint32_t) const override { return true; } + + bool Valid() const override { + return true; + } }; TEST(SideloadTest, run_fuse_sideload_wrong_parameters) {