From c443f4fe9222330405a2f22fb372fabc85afe46f Mon Sep 17 00:00:00 2001 From: Yo Chiang Date: Wed, 21 Oct 2020 21:49:20 +0800 Subject: Add "create-partition" debugging API to gsi_tool `gsi_tool create-partition [-p ] [-s ] [--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 --- gsi_tool.cpp | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) 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, char**)>; static int Disable(sp gsid, int argc, char** argv); static int Enable(sp gsid, int argc, char** argv); static int Install(sp gsid, int argc, char** argv); +static int CreatePartition(sp gsid, int argc, char** argv); static int Wipe(sp gsid, int argc, char** argv); static int WipeData(sp gsid, int argc, char** argv); static int Status(sp gsid, int argc, char** argv); @@ -60,6 +61,7 @@ static const std::map 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 gsid, int argc, char** argv) { return 0; } +// Experimental API +static int CreatePartition(sp 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 gsid, int argc, char** /* argv */) { if (argc > 1) { std::cerr << "Unrecognized arguments to wipe." << std::endl; -- cgit v1.2.3