diff options
Diffstat (limited to 'gsi_tool.cpp')
-rw-r--r-- | gsi_tool.cpp | 148 |
1 files changed, 145 insertions, 3 deletions
diff --git a/gsi_tool.cpp b/gsi_tool.cpp index 4c246cc..a6a79a5 100644 --- a/gsi_tool.cpp +++ b/gsi_tool.cpp @@ -35,7 +35,6 @@ #include <android-base/strings.h> #include <android-base/unique_fd.h> #include <android/gsi/IGsiService.h> -#include <binder/IServiceManager.h> #include <cutils/android_reboot.h> #include <libgsi/libgsi.h> #include <libgsi/libgsid.h> @@ -51,6 +50,7 @@ using CommandCallback = std::function<int(sp<IGsiService>, int, char**)>; 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 CreatePartition(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); @@ -61,6 +61,7 @@ static const std::map<std::string, CommandCallback> kCommandMap = { {"disable", Disable}, {"enable", Enable}, {"install", Install}, + {"create-partition", CreatePartition}, {"wipe", Wipe}, {"wipe-data", WipeData}, {"status", Status}, @@ -256,7 +257,7 @@ static int Install(sp<IGsiService> gsid, int argc, char** argv) { return EX_SOFTWARE; } - android::base::unique_fd input(dup(1)); + android::base::unique_fd input(dup(STDIN_FILENO)); if (input < 0) { std::cerr << "Error duplicating descriptor: " << strerror(errno) << std::endl; return EX_SOFTWARE; @@ -277,6 +278,12 @@ static int Install(sp<IGsiService> gsid, int argc, char** argv) { << "\n"; return EX_SOFTWARE; } + status = gsid->closePartition(&error); + if (!status.isOk() || error != IGsiService::INSTALL_OK) { + std::cerr << "Could not closePartition(userdata): " << ErrorMessage(status, error) + << std::endl; + return EX_SOFTWARE; + } } status = gsid->createPartition(partition, gsiSize, true, &error); @@ -294,6 +301,13 @@ static int Install(sp<IGsiService> gsid, int argc, char** argv) { return EX_SOFTWARE; } + status = gsid->closePartition(&error); + if (!status.isOk() || error != IGsiService::INSTALL_OK) { + std::cerr << "Could not closePartition(" << partition + << "): " << ErrorMessage(status, error) << std::endl; + return EX_SOFTWARE; + } + status = gsid->closeInstall(&error); if (!status.isOk() || error != IGsiService::INSTALL_OK) { std::cerr << "Could not close DSU installation: " << ErrorMessage(status, error) << "\n"; @@ -323,6 +337,134 @@ static int Install(sp<IGsiService> gsid, int argc, char** argv) { return 0; } +// Experimental API +static int CreatePartition(sp<IGsiService> gsid, int argc, char** argv) { + std::string installDir; + std::string partitionName; + bool readOnly = true; + int64_t partitionSize = 0; + + struct option options[] = { + {"install-dir", required_argument, nullptr, 'i'}, + {"partition-name", required_argument, nullptr, 'p'}, + {"readwrite", no_argument, nullptr, 'r'}, + {"size", required_argument, nullptr, 's'}, + {nullptr, 0, nullptr, 0}, + }; + + int rv = 0; + while ((rv = getopt_long_only(argc, argv, "", options, nullptr)) != -1) { + switch (rv) { + case 'i': + installDir = optarg; + break; + case 'p': + partitionName = optarg; + break; + case 'r': + readOnly = false; + break; + case 's': + if (!android::base::ParseInt(optarg, &partitionSize)) { + std::cerr << "Could not parse partition size: " << optarg << std::endl; + return EX_USAGE; + } + break; + default: + return EX_USAGE; + } + } + + if (getuid() != 0) { + std::cerr << "must be root to install a DSU" << std::endl; + return EX_NOPERM; + } + + bool gsiRunning = false; + auto status = gsid->isGsiRunning(&gsiRunning); + if (!status.isOk()) { + std::cerr << "Could not get DSU running status: " << ErrorMessage(status) << std::endl; + return EX_SOFTWARE; + } + if (gsiRunning) { + std::cerr << "Could not install DSU within an active DSU." << std::endl; + return EX_SOFTWARE; + } + + if (partitionSize <= 0) { + std::cerr << "Partition size must be greater than zero: " << partitionSize << std::endl; + return EX_USAGE; + } + + // Note: the progress bar needs to be re-started in between each call. + ProgressBar progress(gsid); + progress.Display(); + + int error; + status = gsid->openInstall(installDir, &error); + if (!status.isOk() || error != IGsiService::INSTALL_OK) { + std::cerr << "Could not open DSU installation: " << ErrorMessage(status, error) + << std::endl; + return EX_SOFTWARE; + } + + status = gsid->createPartition(partitionName, partitionSize, readOnly, &error); + if (!status.isOk() || error != IGsiService::INSTALL_OK) { + std::cerr << "Could not create DSU partition: " << ErrorMessage(status, error) << std::endl; + return EX_SOFTWARE; + } + + if (readOnly) { + android::base::unique_fd input(dup(STDIN_FILENO)); + if (input < 0) { + std::cerr << "Error duplicating descriptor: " << strerror(errno) << std::endl; + return EX_SOFTWARE; + } + android::os::ParcelFileDescriptor stream(std::move(input)); + + bool ok = false; + status = gsid->commitGsiChunkFromStream(stream, partitionSize, &ok); + if (!ok) { + std::cerr << "Could not commit data from stdin: " << ErrorMessage(status) << std::endl; + return EX_SOFTWARE; + } + } + + status = gsid->closePartition(&error); + if (!status.isOk() || error != IGsiService::INSTALL_OK) { + std::cerr << "Could not close DSU partition:" << ErrorMessage(status, error) << std::endl; + return EX_SOFTWARE; + } + + status = gsid->closeInstall(&error); + if (!status.isOk() || error != IGsiService::INSTALL_OK) { + std::cerr << "Could not close DSU installation: " << ErrorMessage(status, error) + << std::endl; + return EX_SOFTWARE; + } + + progress.Finish(); + + std::string dsuSlot; + status = gsid->getActiveDsuSlot(&dsuSlot); + if (!status.isOk()) { + std::cerr << "Could not get the active DSU slot: " << ErrorMessage(status) << std::endl; + return EX_SOFTWARE; + } + + // Immediately enable DSU after a partition is installed to ensure the installation status file + // is created. + status = gsid->enableGsi(/* one_shot = */ true, dsuSlot, &error); + if (!status.isOk() || error != IGsiService::INSTALL_OK) { + std::cerr << "Could not make DSU bootable: " << ErrorMessage(status, error) << std::endl; + return EX_SOFTWARE; + } + + std::cout << "Enabled DSU slot: " << dsuSlot << std::endl; + std::cout << "Please reboot to use the DSU." << std::endl; + return 0; +} + static int Wipe(sp<IGsiService> gsid, int argc, char** /* argv */) { if (argc > 1) { std::cerr << "Unrecognized arguments to wipe." << std::endl; @@ -570,7 +712,7 @@ static int usage(int /* argc */, char* argv[]) { } int main(int argc, char** argv) { - android::base::InitLogging(argv, android::base::StdioLogger, android::base::DefaultAborter); + android::base::InitLogging(argv, android::base::StderrLogger, android::base::DefaultAborter); android::sp<IGsiService> service = GetGsiService(); if (!service) { |