summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--aidl/android/gsi/IGsiService.aidl20
-rw-r--r--gsi_service.cpp93
-rw-r--r--gsi_service.h15
-rw-r--r--gsi_tool.cpp31
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;