diff options
author | Yo Chiang <yochiang@google.com> | 2020-10-21 21:49:20 +0800 |
---|---|---|
committer | Yo Chiang <yochiang@google.com> | 2020-10-22 07:12:15 +0000 |
commit | c443f4fe9222330405a2f22fb372fabc85afe46f (patch) | |
tree | efc0f923c915bfdac79b2bbd929c2d220adab5fe | |
parent | bb1950da878cc077d206603ec240221c06ee1d54 (diff) | |
download | gsid-c443f4fe9222330405a2f22fb372fabc85afe46f.tar.gz |
Add "create-partition" debugging API to gsi_tool
`gsi_tool create-partition [-p <name>] [-s <size>] [--readwrite]`
is a debugging API used to create DSU partitions. Readwritable
partitions such as userdata and scratch should be created with the
"--readwrite" flag.
This is like `gsi_tool install` but `create-partition` is more primitive
and does less things (doesn't auto-create userdata, doesn't auto-reboot.)
This is a debugging API so don't depend on its behavior and don't expect
it to be stable.
Bug: 165925766
Test: adb shell gsi_tool create-partition --readwrite \
--partition scratch --size $((200 * 1024 * 1024))
Change-Id: I9ce463220534ba46c948ea48e9c52bdc0ff762b1
-rw-r--r-- | gsi_tool.cpp | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/gsi_tool.cpp b/gsi_tool.cpp index 8839246..56d6de1 100644 --- a/gsi_tool.cpp +++ b/gsi_tool.cpp @@ -50,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); @@ -60,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}, @@ -322,6 +324,128 @@ 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->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; |