diff options
Diffstat (limited to '')
-rw-r--r-- | Android.bp | 2 | ||||
-rw-r--r-- | install/include/install/install.h | 4 | ||||
-rw-r--r-- | install/install.cpp | 47 | ||||
-rw-r--r-- | recovery.cpp | 25 | ||||
-rw-r--r-- | tests/Android.bp | 1 | ||||
-rw-r--r-- | tests/component/install_test.cpp | 28 |
6 files changed, 106 insertions, 1 deletions
diff --git a/Android.bp b/Android.bp index f92078256..f367e5e7d 100644 --- a/Android.bp +++ b/Android.bp @@ -69,6 +69,7 @@ cc_defaults { ], static_libs: [ + "libc++fs", "libinstall", "librecovery_fastboot", "libminui", @@ -94,6 +95,7 @@ cc_library_static { ], shared_libs: [ + "libfusesideload", "librecovery_ui", ], } diff --git a/install/include/install/install.h b/install/include/install/install.h index c0a8f1f4c..ed0f6c7da 100644 --- a/install/include/install/install.h +++ b/install/include/install/install.h @@ -69,3 +69,7 @@ bool verify_package_compatibility(ZipArchiveHandle package_zip); // Mandatory checks: ota-type, pre-device and serial number(if presents) // AB OTA specific checks: pre-build version, fingerprint, timestamp. int CheckPackageMetadata(const std::map<std::string, std::string>& metadata, OtaType ota_type); + +// Ensures the path to the update package is mounted. Also set the |should_use_fuse| to true if the +// package stays on a removable media. +bool SetupPackageMount(const std::string& package_path, bool* should_use_fuse); diff --git a/install/install.cpp b/install/install.cpp index e2d470096..9203ef0e5 100644 --- a/install/install.cpp +++ b/install/install.cpp @@ -30,6 +30,7 @@ #include <atomic> #include <chrono> #include <condition_variable> +#include <filesystem> #include <functional> #include <limits> #include <mutex> @@ -736,3 +737,49 @@ bool verify_package(Package* package, RecoveryUI* ui) { } return true; } + +bool SetupPackageMount(const std::string& package_path, bool* should_use_fuse) { + CHECK(should_use_fuse != nullptr); + + if (package_path.empty()) { + return false; + } + + *should_use_fuse = true; + if (package_path[0] == '@') { + auto block_map_path = package_path.substr(1); + if (ensure_path_mounted(block_map_path) != 0) { + LOG(ERROR) << "Failed to mount " << block_map_path; + return false; + } + // uncrypt only produces block map only if the package stays on /data. + *should_use_fuse = false; + return true; + } + + // Package is not a block map file. + if (ensure_path_mounted(package_path) != 0) { + LOG(ERROR) << "Failed to mount " << package_path; + return false; + } + + // Reject the package if the input path doesn't equal the canonicalized path. + // e.g. /cache/../sdcard/update_package. + std::error_code ec; + auto canonical_path = std::filesystem::canonical(package_path, ec); + if (ec) { + LOG(ERROR) << "Failed to get canonical of " << package_path << ", " << ec.message(); + return false; + } + if (canonical_path.string() != package_path) { + LOG(ERROR) << "Installation aborts. The canonical path " << canonical_path.string() + << " doesn't equal the original path " << package_path; + return false; + } + + constexpr const char* CACHE_ROOT = "/cache"; + if (android::base::StartsWith(package_path, CACHE_ROOT)) { + *should_use_fuse = false; + } + return true; +} diff --git a/recovery.cpp b/recovery.cpp index 5fc673ec2..e51687a7e 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -50,6 +50,7 @@ #include "common.h" #include "fsck_unshare_blocks.h" +#include "fuse_sideload.h" #include "install/adb_install.h" #include "install/fuse_sdcard_install.h" #include "install/install.h" @@ -881,7 +882,29 @@ Device::BuiltinAction start_recovery(Device* device, const std::vector<std::stri set_retry_bootloader_message(retry_count + 1, args); } - status = install_package(update_package, should_wipe_cache, true, retry_count, ui); + bool should_use_fuse = false; + if (!SetupPackageMount(update_package, &should_use_fuse)) { + LOG(INFO) << "Failed to set up the package access, skipping installation"; + status = INSTALL_ERROR; + } else if (should_use_fuse) { + LOG(INFO) << "Installing package " << update_package << " with fuse"; + auto file_data_reader = std::make_unique<FuseFileDataProvider>(update_package, 65536); + status = run_fuse_sideload(std::move(file_data_reader)); + } else if (auto memory_package = Package::CreateMemoryPackage( + update_package, + std::bind(&RecoveryUI::SetProgress, ui, std::placeholders::_1)); + memory_package != nullptr) { + status = install_package(update_package, should_wipe_cache, true, retry_count, ui); + } else { + // We may fail to memory map the package on 32 bit builds for packages with 2GiB+ size. + // In such cases, we will try to install the package with fuse. This is not the default + // installation method because it introduces a layer of indirection from the kernel space. + LOG(WARNING) << "Failed to memory map package " << update_package + << "; falling back to install with fuse"; + auto file_data_reader = std::make_unique<FuseFileDataProvider>(update_package, 65536); + status = run_fuse_sideload(std::move(file_data_reader)); + } + if (status != INSTALL_SUCCESS) { ui->Print("Installation aborted.\n"); diff --git a/tests/Android.bp b/tests/Android.bp index 09ef716d6..a0d82d5fd 100644 --- a/tests/Android.bp +++ b/tests/Android.bp @@ -99,6 +99,7 @@ librecovery_static_libs = [ "liblp", "libvndksupport", "libtinyxml2", + "libc++fs", ] cc_test { diff --git a/tests/component/install_test.cpp b/tests/component/install_test.cpp index 385132939..c1f0ca812 100644 --- a/tests/component/install_test.cpp +++ b/tests/component/install_test.cpp @@ -34,6 +34,7 @@ #include "install/install.h" #include "otautil/paths.h" +#include "otautil/roots.h" #include "private/setup_commands.h" static void BuildZipArchive(const std::map<std::string, std::string>& file_map, int fd, @@ -595,3 +596,30 @@ TEST(InstallTest, CheckPackageMetadata_ab_post_timestamp) { "\n"); test_check_package_metadata(metadata, OtaType::AB, 0); } + +TEST(InstallTest, SetupPackageMount_package_path) { + load_volume_table(); + bool install_with_fuse; + + // Setup should fail if the input path doesn't exist. + ASSERT_FALSE(SetupPackageMount("/does_not_exist", &install_with_fuse)); + + // Package should be installed with fuse if it's not in /cache. + TemporaryDir temp_dir; + TemporaryFile update_package(temp_dir.path); + ASSERT_TRUE(SetupPackageMount(update_package.path, &install_with_fuse)); + ASSERT_TRUE(install_with_fuse); + + // Setup should fail if the input path isn't canonicalized. + std::string uncanonical_package_path = android::base::Join( + std::vector<std::string>{ + temp_dir.path, + "..", + android::base::Basename(temp_dir.path), + android::base::Basename(update_package.path), + }, + '/'); + + ASSERT_EQ(0, access(uncanonical_package_path.c_str(), R_OK)); + ASSERT_FALSE(SetupPackageMount(uncanonical_package_path, &install_with_fuse)); +} |