diff options
-rw-r--r-- | aidl/android/gsi/IGsiService.aidl | 20 | ||||
-rw-r--r-- | gsi_service.cpp | 93 | ||||
-rw-r--r-- | gsi_service.h | 15 | ||||
-rw-r--r-- | gsi_tool.cpp | 31 |
4 files changed, 90 insertions, 69 deletions
diff --git a/aidl/android/gsi/IGsiService.aidl b/aidl/android/gsi/IGsiService.aidl index e144161..57028fb 100644 --- a/aidl/android/gsi/IGsiService.aidl +++ b/aidl/android/gsi/IGsiService.aidl @@ -26,6 +26,18 @@ interface IGsiService { const int STATUS_WORKING = 1; const int STATUS_COMPLETE = 2; + /* Install succeeded. */ + const int INSTALL_OK = 0; + /* Install failed with a generic system error. */ + const int INSTALL_ERROR_GENERIC = 1; + /* Install failed because there was no free space. */ + const int INSTALL_ERROR_NO_SPACE = 2; + /** + * Install failed because the file system was too fragmented or did not + * have enough additional free space. + */ + const int INSTALL_ERROR_FILE_SYSTEM_CLUTTERED = 3; + /** * Begins a GSI installation. * @@ -40,9 +52,9 @@ interface IGsiService { * @param gsiSize The size of the on-disk GSI image. * @param userdataSize The desired size of the userdata partition. * @param wipeUserdata True to wipe destination userdata. - * @return true on success, false otherwise. + * @return 0 on success, an error code on failure. */ - boolean startGsiInstall(long gsiSize, long userdataSize, boolean wipeUserdata); + int startGsiInstall(long gsiSize, long userdataSize, boolean wipeUserdata); /** * Write bytes from a stream to the on-disk GSI. @@ -71,9 +83,9 @@ interface IGsiService { * Complete a GSI installation and mark it as bootable. The caller is * responsible for rebooting the device as soon as possible. * - * @return true on success, false otherwise. + * @return INSTALL_* error code. */ - boolean setGsiBootable(); + int setGsiBootable(); /** * Cancel an in-progress GSI install. diff --git a/gsi_service.cpp b/gsi_service.cpp index cb9f184..9b74c44 100644 --- a/gsi_service.cpp +++ b/gsi_service.cpp @@ -74,7 +74,7 @@ GsiService::~GsiService() { } binder::Status GsiService::startGsiInstall(int64_t gsiSize, int64_t userdataSize, bool wipeUserdata, - bool* _aidl_return) { + int* _aidl_return) { std::lock_guard<std::mutex> guard(main_lock_); // Make sure any interrupted installations are cleaned up. @@ -83,14 +83,13 @@ binder::Status GsiService::startGsiInstall(int64_t gsiSize, int64_t userdataSize // Only rm userdata_gsi if one didn't already exist. wipe_userdata_on_failure_ = wipeUserdata || access(kUserdataFile, F_OK); - if (!StartInstall(gsiSize, userdataSize, wipeUserdata)) { + int status = StartInstall(gsiSize, userdataSize, wipeUserdata); + if (status != INSTALL_OK) { // Perform local cleanup and delete any lingering files. PostInstallCleanup(); RemoveGsiFiles(wipe_userdata_on_failure_); - *_aidl_return = false; - } else { - *_aidl_return = true; } + *_aidl_return = status; // Clear the progress indicator. UpdateProgress(STATUS_NO_OPERATION, 0); @@ -139,11 +138,11 @@ binder::Status GsiService::commitGsiChunkFromMemory(const std::vector<uint8_t>& return binder::Status::ok(); } -binder::Status GsiService::setGsiBootable(bool* _aidl_return) { +binder::Status GsiService::setGsiBootable(int* _aidl_return) { std::lock_guard<std::mutex> guard(main_lock_); if (installing_) { - *_aidl_return = SetGsiBootable(); + *_aidl_return = SetGsiBootable() ? INSTALL_OK : INSTALL_ERROR_GENERIC; } else { *_aidl_return = ReenableGsi(); } @@ -255,13 +254,19 @@ void GsiService::PostInstallCleanup() { installing_ = false; } -bool GsiService::StartInstall(int64_t gsi_size, int64_t userdata_size, bool wipe_userdata) { +int GsiService::StartInstall(int64_t gsi_size, int64_t userdata_size, bool wipe_userdata) { gsi_size_ = gsi_size; userdata_size_ = userdata_size; wipe_userdata_ = wipe_userdata; - if (!PerformSanityChecks() || !PreallocateFiles() || !FormatUserdata()) { - return false; + if (int status = PerformSanityChecks()) { + return status; + } + if (int status = PreallocateFiles()) { + return status; + } + if (!FormatUserdata()) { + return INSTALL_ERROR_GENERIC; } // Map system_gsi so we can write to it. @@ -269,38 +274,38 @@ bool GsiService::StartInstall(int64_t gsi_size, int64_t userdata_size, bool wipe if (!CreateLogicalPartition(kUserdataDevice, *metadata_.get(), "system_gsi", true, kDmTimeout, &block_device)) { LOG(ERROR) << "Error creating device-mapper node for system_gsi"; - return false; + return INSTALL_ERROR_GENERIC; } static const int kOpenFlags = O_RDWR | O_NOFOLLOW | O_CLOEXEC; system_fd_.reset(open(block_device.c_str(), kOpenFlags)); if (system_fd_ < 0) { PLOG(ERROR) << "could not open " << block_device; - return false; + return INSTALL_ERROR_GENERIC; } installing_ = true; - return true; + return INSTALL_OK; } -bool GsiService::PerformSanityChecks() { +int GsiService::PerformSanityChecks() { if (gsi_size_ < 0) { LOG(ERROR) << "image size " << gsi_size_ << " is negative"; - return false; + return INSTALL_ERROR_GENERIC; } if (android::gsi::IsGsiRunning()) { LOG(ERROR) << "cannot install gsi inside a live gsi"; - return false; + return INSTALL_ERROR_GENERIC; } if (!EnsureFolderExists(kGsiDataFolder) || !EnsureFolderExists(kGsiMetadataFolder)) { - return false; + return INSTALL_ERROR_GENERIC; } struct statvfs sb; if (statvfs(kGsiDataFolder, &sb)) { PLOG(ERROR) << "failed to read file system stats"; - return false; + return INSTALL_ERROR_GENERIC; } // This is the same as android::vold::GetFreebytes() but we also @@ -309,7 +314,7 @@ bool GsiService::PerformSanityChecks() { uint64_t fs_size = sb.f_blocks * sb.f_frsize; if (free_space <= (gsi_size_ + userdata_size_)) { LOG(ERROR) << "not enough free space (only" << free_space << " bytes available)"; - return false; + return INSTALL_ERROR_NO_SPACE; } // We are asking for 40% of the /data to be empty. // TODO: may be not hard code it like this @@ -317,12 +322,12 @@ bool GsiService::PerformSanityChecks() { if (free_space_percent < kMinimumFreeSpaceThreshold) { LOG(ERROR) << "free space " << static_cast<uint64_t>(free_space_percent) << "% is below the minimum threshold of " << kMinimumFreeSpaceThreshold << "%"; - return false; + return INSTALL_ERROR_FILE_SYSTEM_CLUTTERED; } - return true; + return INSTALL_OK; } -bool GsiService::PreallocateFiles() { +int GsiService::PreallocateFiles() { if (wipe_userdata_) { android::base::RemoveFileIfExists(kUserdataFile); } @@ -331,6 +336,7 @@ bool GsiService::PreallocateFiles() { // TODO: trigger GC from fiemap writer. // Create fallocated files. + int error; FiemapUniquePtr userdata_image; if (wipe_userdata_ || access(kUserdataFile, F_OK)) { if (!userdata_size_) { @@ -338,18 +344,18 @@ bool GsiService::PreallocateFiles() { } StartAsyncOperation("create userdata", userdata_size_); - userdata_image = CreateFiemapWriter(kUserdataFile, userdata_size_); + userdata_image = CreateFiemapWriter(kUserdataFile, userdata_size_, &error); if (!userdata_image) { LOG(ERROR) << "Could not create userdata image: " << kUserdataFile; - return false; + return error; } // Signal that we need to reformat userdata. wipe_userdata_ = true; } else { - userdata_image = CreateFiemapWriter(kUserdataFile, 0); + userdata_image = CreateFiemapWriter(kUserdataFile, 0, &error); if (!userdata_image) { LOG(ERROR) << "Could not open userdata image: " << kUserdataFile; - return false; + return error; } if (userdata_size_ && userdata_image->size() < userdata_size_) { // :TODO: need to fallocate more blocks and resizefs. @@ -358,16 +364,16 @@ bool GsiService::PreallocateFiles() { } StartAsyncOperation("create system", gsi_size_); - auto system_image = CreateFiemapWriter(kSystemFile, gsi_size_); + auto system_image = CreateFiemapWriter(kSystemFile, gsi_size_, &error); if (!system_image) { - return false; + return error; } UpdateProgress(STATUS_COMPLETE, gsi_size_); // Save the extent information in liblp. metadata_ = CreateMetadata(userdata_image.get(), system_image.get()); if (!metadata_) { - return false; + return INSTALL_ERROR_GENERIC; } system_image->Flush(); @@ -377,11 +383,11 @@ bool GsiService::PreallocateFiles() { gsi_bytes_written_ = 0; userdata_block_size_ = userdata_image->block_size(); system_block_size_ = system_image->block_size(); - return true; + return INSTALL_OK; } fiemap_writer::FiemapUniquePtr GsiService::CreateFiemapWriter(const std::string& path, - uint64_t size) { + uint64_t size, int* error) { bool create = (size != 0); std::function<bool(uint64_t, uint64_t)> progress; @@ -396,12 +402,14 @@ fiemap_writer::FiemapUniquePtr GsiService::CreateFiemapWriter(const std::string& auto file = FiemapWriter::Open(path, size, create, std::move(progress)); if (!file) { LOG(ERROR) << "failed to create " << path; + *error = INSTALL_ERROR_GENERIC; return nullptr; } uint64_t extents = file->extents().size(); if (extents > kMaximumExtents) { LOG(ERROR) << "file " << path << " has too many extents: " << extents; + *error = INSTALL_ERROR_FILE_SYSTEM_CLUTTERED; return nullptr; } return file; @@ -489,41 +497,42 @@ bool GsiService::SetGsiBootable() { return true; } -bool GsiService::ReenableGsi() { +int GsiService::ReenableGsi() { if (!android::gsi::IsGsiInstalled()) { LOG(ERROR) << "no gsi installed - cannot re-enable"; - return false; + return INSTALL_ERROR_GENERIC; } std::string boot_key; if (!GetInstallStatus(&boot_key)) { PLOG(ERROR) << "read " << kGsiInstallStatusFile; - return false; + return INSTALL_ERROR_GENERIC; } if (boot_key != kInstallStatusDisabled) { LOG(ERROR) << "GSI is not currently disabled"; - return false; + return INSTALL_ERROR_GENERIC; } - auto userdata_image = CreateFiemapWriter(kUserdataFile, 0); + int error; + auto userdata_image = CreateFiemapWriter(kUserdataFile, 0, &error); if (!userdata_image) { LOG(ERROR) << "could not find userdata image"; - return false; + return error; } - auto system_image = CreateFiemapWriter(kSystemFile, 0); + auto system_image = CreateFiemapWriter(kSystemFile, 0, &error); if (!system_image) { LOG(ERROR) << "could not find system image"; - return false; + return error; } auto metadata = CreateMetadata(userdata_image.get(), system_image.get()); if (!metadata) { - return false; + return INSTALL_ERROR_GENERIC; } if (!CreateMetadataFile(*metadata.get()) || !CreateInstallStatusFile()) { - return false; + return INSTALL_ERROR_GENERIC; } - return true; + return INSTALL_OK; } bool GsiService::RemoveGsiFiles(bool wipeUserdata) { diff --git a/gsi_service.h b/gsi_service.h index 8fb8188..a69f72d 100644 --- a/gsi_service.h +++ b/gsi_service.h @@ -38,14 +38,14 @@ class GsiService : public BinderService<GsiService>, public BnGsiService { ~GsiService() override; binder::Status startGsiInstall(int64_t gsiSize, int64_t userdataSize, bool wipeUserdata, - bool* _aidl_return) override; + int* _aidl_return) override; binder::Status commitGsiChunkFromStream(const ::android::os::ParcelFileDescriptor& stream, int64_t bytes, bool* _aidl_return) override; binder::Status getInstallProgress(::android::gsi::GsiProgress* _aidl_return) override; binder::Status commitGsiChunkFromMemory(const ::std::vector<uint8_t>& bytes, bool* _aidl_return) override; binder::Status cancelGsiInstall(bool* _aidl_return) override; - binder::Status setGsiBootable(bool* _aidl_return) override; + binder::Status setGsiBootable(int* _aidl_return) override; binder::Status removeGsiInstall(bool* _aidl_return) override; binder::Status disableGsiInstall(bool* _aidl_return) override; binder::Status isGsiRunning(bool* _aidl_return) override; @@ -61,14 +61,14 @@ class GsiService : public BinderService<GsiService>, public BnGsiService { using LpMetadata = android::fs_mgr::LpMetadata; using MetadataBuilder = android::fs_mgr::MetadataBuilder; - bool StartInstall(int64_t gsi_size, int64_t userdata_size, bool wipe_userdata); - bool PerformSanityChecks(); - bool PreallocateFiles(); + int StartInstall(int64_t gsi_size, int64_t userdata_size, bool wipe_userdata); + int PerformSanityChecks(); + int PreallocateFiles(); bool FormatUserdata(); bool CommitGsiChunk(int stream_fd, int64_t bytes); bool CommitGsiChunk(const void* data, size_t bytes); bool SetGsiBootable(); - bool ReenableGsi(); + int ReenableGsi(); bool DisableGsiInstall(); bool EnsureFolderExists(const std::string& path); bool AddPartitionFiemap(android::fs_mgr::MetadataBuilder* builder, @@ -76,7 +76,8 @@ class GsiService : public BinderService<GsiService>, public BnGsiService { android::fiemap_writer::FiemapWriter* writer); std::unique_ptr<LpMetadata> CreateMetadata(android::fiemap_writer::FiemapWriter* userdata, android::fiemap_writer::FiemapWriter* system); - fiemap_writer::FiemapUniquePtr CreateFiemapWriter(const std::string& path, uint64_t size); + fiemap_writer::FiemapUniquePtr CreateFiemapWriter(const std::string& path, uint64_t size, + int* error); bool CreateInstallStatusFile(); bool CreateMetadataFile(const android::fs_mgr::LpMetadata& metadata); void PostInstallCleanup(); diff --git a/gsi_tool.cpp b/gsi_tool.cpp index 008ae28..2d232c3 100644 --- a/gsi_tool.cpp +++ b/gsi_tool.cpp @@ -224,37 +224,36 @@ static int Install(sp<IGsiService> gsid, int argc, char** argv) { android::base::unique_fd input(dup(1)); if (input < 0) { - std::cout << "Error duplicating descriptor: " << strerror(errno); + std::cout << "Error duplicating descriptor: " << strerror(errno) << std::endl; return EX_SOFTWARE; } // Note: the progress bar needs to be re-started in between each call. ProgressBar progress(gsid); - - bool ok = false; progress.Display(); - gsid->startGsiInstall(gsi_size, userdata_size, wipe_userdata, &ok); - if (!ok) { - std::cout << "Could not start live image install"; + + int error; + auto status = gsid->startGsiInstall(gsi_size, userdata_size, wipe_userdata, &error); + if (!status.isOk() || error != IGsiService::INSTALL_OK) { + std::cout << "Could not start live image install, error code " << error << std::endl; return EX_SOFTWARE; } android::os::ParcelFileDescriptor stream(std::move(input)); - ok = false; + bool ok = false; progress.Display(); gsid->commitGsiChunkFromStream(stream, gsi_size, &ok); if (!ok) { - std::cout << "Could not commit live image data"; + std::cout << "Could not commit live image data" << std::endl; return EX_SOFTWARE; } progress.Finish(); - ok = false; - gsid->setGsiBootable(&ok); - if (!ok) { - std::cout << "Could not make live image bootable"; + status = gsid->setGsiBootable(&error); + if (!status.isOk() || error != IGsiService::INSTALL_OK) { + std::cout << "Could not make live image bootable, error code " << error << std::endl; return EX_SOFTWARE; } return 0; @@ -295,10 +294,10 @@ static int Enable(sp<IGsiService> gsid, int argc, char** /* argv */) { return EX_SOFTWARE; } - bool ok = false; - gsid->setGsiBootable(&ok); - if (!ok) { - std::cout << "Error re-enabling GSI" << std::endl; + int error; + auto status = gsid->setGsiBootable(&error); + if (!status.isOk() || error != IGsiService::INSTALL_OK) { + std::cout << "Error re-enabling GSI, error code " << error << std::endl; return EX_SOFTWARE; } std::cout << "Live image install successfully enabled." << std::endl; |