diff options
| author | android-build-team Robot <android-build-team-robot@google.com> | 2019-06-22 23:18:13 +0000 |
|---|---|---|
| committer | android-build-team Robot <android-build-team-robot@google.com> | 2019-06-22 23:18:13 +0000 |
| commit | a42c64f8fc52a3c6d536a1d32d8683f9c7f080ca (patch) | |
| tree | 6ed1cb9f7b39f29374eaaa25ec64700ea97b8567 | |
| parent | f3854cc752c907668fec79aac9373347f21856e5 (diff) | |
| parent | 8c9388a1188ef98b9f36d5e8b6dbd462ad08f6e1 (diff) | |
| download | platform_system_gsid-android10-tests-release.tar.gz platform_system_gsid-android10-tests-release.tar.bz2 platform_system_gsid-android10-tests-release.zip | |
Snap for 5681426 from 8c9388a1188ef98b9f36d5e8b6dbd462ad08f6e1 to qt-releaseandroid-vts-10.0_r5android-vts-10.0_r4android-vts-10.0_r3android-vts-10.0_r2android-vts-10.0_r1android-cts-10.0_r5android-cts-10.0_r4android-cts-10.0_r3android-cts-10.0_r2android-cts-10.0_r1android-10.0.0_r6android-10.0.0_r5android-10.0.0_r46android-10.0.0_r4android-10.0.0_r3android-10.0.0_r2android-10.0.0_r17android-10.0.0_r11android-10.0.0_r10android-10.0.0_r1android10-tests-releaseandroid10-security-releaseandroid10-s3-releaseandroid10-s2-releaseandroid10-s1-releaseandroid10-release
Change-Id: Icb6c28c84955a1f109dc2d4e536f0b3681fbc733
| -rw-r--r-- | Android.bp | 1 | ||||
| -rw-r--r-- | aidl/android/gsi/IGsiService.aidl | 9 | ||||
| -rw-r--r-- | gsi_service.cpp | 64 | ||||
| -rw-r--r-- | gsi_service.h | 3 | ||||
| -rw-r--r-- | gsi_tool.cpp | 40 |
5 files changed, 117 insertions, 0 deletions
@@ -68,6 +68,7 @@ cc_binary { "gsi_aidl_interface-cpp", "libbase", "libbinder", + "libext4_utils", "libfs_mgr", "libgsi", "liblog", diff --git a/aidl/android/gsi/IGsiService.aidl b/aidl/android/gsi/IGsiService.aidl index 8a0201d..4ffdf62 100644 --- a/aidl/android/gsi/IGsiService.aidl +++ b/aidl/android/gsi/IGsiService.aidl @@ -172,4 +172,13 @@ interface IGsiService { * @return 0 on success, an error code on failure. */ int beginGsiInstall(in GsiInstallParams params); + + /** + * Wipe the userdata of an existing GSI install. This will not work if the + * GSI is currently running. The userdata image will not be removed, but the + * first block will be zeroed ensuring that the next GSI boot formats /data. + * + * @return 0 on success, an error code on failure. + */ + int wipeGsiUserdata(); } diff --git a/gsi_service.cpp b/gsi_service.cpp index 615f77e..3efec40 100644 --- a/gsi_service.cpp +++ b/gsi_service.cpp @@ -34,6 +34,7 @@ #include <android-base/stringprintf.h> #include <android-base/strings.h> #include <android/gsi/IGsiService.h> +#include <ext4_utils/ext4_utils.h> #include <fs_mgr.h> #include <fs_mgr_dm_linear.h> #include <fstab/fstab.h> @@ -372,6 +373,20 @@ binder::Status GsiService::getInstalledGsiImageDir(std::string* _aidl_return) { return binder::Status::ok(); } +binder::Status GsiService::wipeGsiUserdata(int* _aidl_return) { + ENFORCE_SYSTEM_OR_SHELL; + std::lock_guard<std::mutex> guard(main_lock_); + + if (IsGsiRunning() || !IsGsiInstalled()) { + *_aidl_return = IGsiService::INSTALL_ERROR_GENERIC; + return binder::Status::ok(); + } + + *_aidl_return = WipeUserdata(); + + return binder::Status::ok(); +} + binder::Status GsiService::CheckUid(AccessLevel level) { std::vector<uid_t> allowed_uids{AID_ROOT, AID_SYSTEM}; if (level == AccessLevel::SystemOrShell) { @@ -726,6 +741,7 @@ class FdWriter final : public GsiService::WriteHelper { } return true; } + uint64_t Size() override { return get_block_device_size(fd_); } private: std::string path_; @@ -743,6 +759,7 @@ class SplitFiemapWriter final : public GsiService::WriteHelper { bool Flush() override { return writer_->Flush(); } + uint64_t Size() override { return writer_->size(); } private: SplitFiemap* writer_; @@ -933,6 +950,53 @@ int GsiService::ReenableGsi(bool one_shot) { return INSTALL_OK; } +int GsiService::WipeUserdata() { + // Note: this metadata is only used to recover the original partition sizes. + // We do not trust the extent information, which will get rebuilt later. + auto old_metadata = ReadFromImageFile(kGsiLpMetadataFile); + if (!old_metadata) { + LOG(ERROR) << "GSI install is incomplete"; + return INSTALL_ERROR_GENERIC; + } + + install_dir_ = GetInstalledImageDir(); + system_gsi_path_ = GetImagePath(install_dir_, "system_gsi"); + if (int error = DetermineReadWriteMethod()) { + return error; + } + + // Recover parition information. + Image userdata_image; + if (int error = GetExistingImage(*old_metadata.get(), "userdata_gsi", &userdata_image)) { + return error; + } + partitions_.emplace(std::make_pair("userdata_gsi", std::move(userdata_image))); + + metadata_ = CreateMetadata(); + if (!metadata_) { + return INSTALL_ERROR_GENERIC; + } + + auto writer = OpenPartition("userdata_gsi"); + if (!writer) { + return IGsiService::INSTALL_ERROR_GENERIC; + } + + // Wipe the first 1MiB of the device, ensuring both the first block and + // the superblock are destroyed. + static constexpr uint64_t kEraseSize = 1024 * 1024; + + std::string zeroes(4096, 0); + uint64_t erase_size = std::min(kEraseSize, writer->Size()); + for (uint64_t i = 0; i < erase_size; i += zeroes.size()) { + if (!writer->Write(zeroes.data(), zeroes.size())) { + PLOG(ERROR) << "write userdata_gsi"; + return IGsiService::INSTALL_ERROR_GENERIC; + } + } + return INSTALL_OK; +} + static uint64_t GetPartitionSize(const LpMetadata& metadata, const LpMetadataPartition& partition) { uint64_t total = 0; for (size_t i = 0; i < partition.num_extents; i++) { diff --git a/gsi_service.h b/gsi_service.h index 8ec69a3..30b5782 100644 --- a/gsi_service.h +++ b/gsi_service.h @@ -58,6 +58,7 @@ class GsiService : public BinderService<GsiService>, public BnGsiService { binder::Status getUserdataImageSize(int64_t* _aidl_return) override; binder::Status getGsiBootStatus(int* _aidl_return) override; binder::Status getInstalledGsiImageDir(std::string* _aidl_return) override; + binder::Status wipeGsiUserdata(int* _aidl_return) override; static char const* getServiceName() { return kGsiServiceName; } @@ -70,6 +71,7 @@ class GsiService : public BinderService<GsiService>, public BnGsiService { virtual ~WriteHelper() {}; virtual bool Write(const void* data, uint64_t bytes) = 0; virtual bool Flush() = 0; + virtual uint64_t Size() = 0; WriteHelper() = default; WriteHelper(const WriteHelper&) = delete; @@ -100,6 +102,7 @@ class GsiService : public BinderService<GsiService>, public BnGsiService { bool CommitGsiChunk(const void* data, size_t bytes); int SetGsiBootable(bool one_shot); int ReenableGsi(bool one_shot); + int WipeUserdata(); bool DisableGsiInstall(); bool AddPartitionFiemap(android::fs_mgr::MetadataBuilder* builder, android::fs_mgr::Partition* partition, const Image& image, diff --git a/gsi_tool.cpp b/gsi_tool.cpp index a9a6920..ee6094b 100644 --- a/gsi_tool.cpp +++ b/gsi_tool.cpp @@ -45,6 +45,7 @@ static int Disable(sp<IGsiService> gsid, int argc, char** argv); static int Enable(sp<IGsiService> gsid, int argc, char** argv); static int Install(sp<IGsiService> gsid, int argc, char** argv); static int Wipe(sp<IGsiService> gsid, int argc, char** argv); +static int WipeData(sp<IGsiService> gsid, int argc, char** argv); static int Status(sp<IGsiService> gsid, int argc, char** argv); static int Cancel(sp<IGsiService> gsid, int argc, char** argv); @@ -53,6 +54,7 @@ static const std::map<std::string, CommandCallback> kCommandMap = { {"enable", Enable}, {"install", Install}, {"wipe", Wipe}, + {"wipe-data", WipeData}, {"status", Status}, {"cancel", Cancel}, }; @@ -330,6 +332,43 @@ static int Wipe(sp<IGsiService> gsid, int argc, char** /* argv */) { return 0; } +static int WipeData(sp<IGsiService> gsid, int argc, char** /* argv */) { + if (argc > 1) { + std::cerr << "Unrecognized arguments to wipe-data.\n"; + return EX_USAGE; + } + + bool running; + auto status = gsid->isGsiRunning(&running); + if (!status.isOk()) { + std::cerr << "error: " << status.exceptionMessage().string() << std::endl; + return EX_SOFTWARE; + } + if (running) { + std::cerr << "Cannot wipe GSI userdata while running a GSI.\n"; + return EX_USAGE; + } + + bool installed; + status = gsid->isGsiInstalled(&installed); + if (!status.isOk()) { + std::cerr << "error: " << status.exceptionMessage().string() << std::endl; + return EX_SOFTWARE; + } + if (!installed) { + std::cerr << "No GSI is installed.\n"; + return EX_USAGE; + } + + int error; + status = gsid->wipeGsiUserdata(&error); + if (!status.isOk() || error) { + std::cerr << "Could not wipe GSI userdata: " << ErrorMessage(status, error) << "\n"; + return EX_SOFTWARE; + } + return 0; +} + static int Status(sp<IGsiService> gsid, int argc, char** /* argv */) { if (argc > 1) { std::cerr << "Unrecognized arguments to status." << std::endl; @@ -459,6 +498,7 @@ static int usage(int /* argc */, char* argv[]) { " --userdata-size (the latter defaults to 8GiB)\n" " --wipe (remove old gsi userdata first)\n" " wipe Completely remove a GSI and its associated data\n" + " wipe-data Ensure the GSI's userdata will be formatted\n" " cancel Cancel the installation\n" " status Show status\n", argv[0], argv[0]); |
