Loading fuse_sideload/fuse_provider.cpp +6 −1 Original line number Diff line number Diff line Loading @@ -49,6 +49,11 @@ FuseFileDataProvider::FuseFileDataProvider(const std::string& path, uint32_t blo fuse_block_size_ = block_size; } std::unique_ptr<FuseDataProvider> FuseFileDataProvider::CreateFromFile(const std::string& path, uint32_t block_size) { return std::make_unique<FuseFileDataProvider>(path, block_size); } bool FuseFileDataProvider::ReadBlockAlignedData(uint8_t* buffer, uint32_t fetch_size, uint32_t start_block) const { uint64_t offset = static_cast<uint64_t>(start_block) * fuse_block_size_; Loading Loading @@ -127,7 +132,7 @@ bool FuseBlockDataProvider::ReadBlockAlignedData(uint8_t* buffer, uint32_t fetch return true; } std::unique_ptr<FuseBlockDataProvider> FuseBlockDataProvider::CreateFromBlockMap( std::unique_ptr<FuseDataProvider> FuseBlockDataProvider::CreateFromBlockMap( const std::string& block_map_path, uint32_t fuse_block_size) { auto block_map = BlockMapData::ParseBlockMapFile(block_map_path); if (!block_map) { Loading fuse_sideload/include/fuse_provider.h +14 −3 Original line number Diff line number Diff line Loading @@ -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: Loading @@ -60,10 +62,13 @@ class FuseFileDataProvider : public FuseDataProvider { public: FuseFileDataProvider(const std::string& path, uint32_t block_size); static std::unique_ptr<FuseDataProvider> 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; } Loading @@ -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<FuseBlockDataProvider> CreateFromBlockMap( const std::string& block_map_path, uint32_t fuse_block_size); static std::unique_ptr<FuseDataProvider> 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: Loading install/Android.bp +1 −1 Original line number Diff line number Diff line Loading @@ -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", Loading install/fuse_sdcard_install.cpp→install/fuse_install.cpp +47 −24 Original line number Diff line number Diff line Loading @@ -14,7 +14,7 @@ * limitations under the License. */ #include "install/fuse_sdcard_install.h" #include "install/fuse_install.h" #include <dirent.h> #include <signal.h> Loading @@ -27,6 +27,7 @@ #include <algorithm> #include <functional> #include <memory> #include <string> #include <vector> #include <android-base/logging.h> Loading Loading @@ -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); } } Loading Loading @@ -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<FuseFileDataProvider>(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; } 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", 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; umount2(SDCARD_ROOT, MNT_DETACH); } 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; return run_fuse_sideload(std::move(file_data_reader)) == 0; } 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); } Loading Loading @@ -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; } install/include/install/fuse_sdcard_install.h→install/include/install/fuse_install.h +8 −1 Original line number Diff line number Diff line Loading @@ -16,8 +16,15 @@ #pragma once #include <string_view> #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); Loading
fuse_sideload/fuse_provider.cpp +6 −1 Original line number Diff line number Diff line Loading @@ -49,6 +49,11 @@ FuseFileDataProvider::FuseFileDataProvider(const std::string& path, uint32_t blo fuse_block_size_ = block_size; } std::unique_ptr<FuseDataProvider> FuseFileDataProvider::CreateFromFile(const std::string& path, uint32_t block_size) { return std::make_unique<FuseFileDataProvider>(path, block_size); } bool FuseFileDataProvider::ReadBlockAlignedData(uint8_t* buffer, uint32_t fetch_size, uint32_t start_block) const { uint64_t offset = static_cast<uint64_t>(start_block) * fuse_block_size_; Loading Loading @@ -127,7 +132,7 @@ bool FuseBlockDataProvider::ReadBlockAlignedData(uint8_t* buffer, uint32_t fetch return true; } std::unique_ptr<FuseBlockDataProvider> FuseBlockDataProvider::CreateFromBlockMap( std::unique_ptr<FuseDataProvider> FuseBlockDataProvider::CreateFromBlockMap( const std::string& block_map_path, uint32_t fuse_block_size) { auto block_map = BlockMapData::ParseBlockMapFile(block_map_path); if (!block_map) { Loading
fuse_sideload/include/fuse_provider.h +14 −3 Original line number Diff line number Diff line Loading @@ -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: Loading @@ -60,10 +62,13 @@ class FuseFileDataProvider : public FuseDataProvider { public: FuseFileDataProvider(const std::string& path, uint32_t block_size); static std::unique_ptr<FuseDataProvider> 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; } Loading @@ -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<FuseBlockDataProvider> CreateFromBlockMap( const std::string& block_map_path, uint32_t fuse_block_size); static std::unique_ptr<FuseDataProvider> 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: Loading
install/Android.bp +1 −1 Original line number Diff line number Diff line Loading @@ -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", Loading
install/fuse_sdcard_install.cpp→install/fuse_install.cpp +47 −24 Original line number Diff line number Diff line Loading @@ -14,7 +14,7 @@ * limitations under the License. */ #include "install/fuse_sdcard_install.h" #include "install/fuse_install.h" #include <dirent.h> #include <signal.h> Loading @@ -27,6 +27,7 @@ #include <algorithm> #include <functional> #include <memory> #include <string> #include <vector> #include <android-base/logging.h> Loading Loading @@ -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); } } Loading Loading @@ -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<FuseFileDataProvider>(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; } 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", 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; umount2(SDCARD_ROOT, MNT_DETACH); } 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; return run_fuse_sideload(std::move(file_data_reader)) == 0; } 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); } Loading Loading @@ -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; }
install/include/install/fuse_sdcard_install.h→install/include/install/fuse_install.h +8 −1 Original line number Diff line number Diff line Loading @@ -16,8 +16,15 @@ #pragma once #include <string_view> #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);