gsi_tool.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. //
  2. // Copyright (C) 2019 The Android Open Source Project
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. //
  16. #include <getopt.h>
  17. #include <stdio.h>
  18. #include <sysexits.h>
  19. #include <chrono>
  20. #include <condition_variable>
  21. #include <functional>
  22. #include <iostream>
  23. #include <map>
  24. #include <mutex>
  25. #include <string>
  26. #include <thread>
  27. #include <android-base/parseint.h>
  28. #include <android-base/properties.h>
  29. #include <android-base/unique_fd.h>
  30. #include <android/gsi/IGsiService.h>
  31. #include <binder/IServiceManager.h>
  32. #include <cutils/android_reboot.h>
  33. #include <libgsi/libgsi.h>
  34. using namespace android::gsi;
  35. using namespace std::chrono_literals;
  36. using android::sp;
  37. using CommandCallback = std::function<int(sp<IGsiService>, int, char**)>;
  38. static int Disable(sp<IGsiService> gsid, int argc, char** argv);
  39. static int Enable(sp<IGsiService> gsid, int argc, char** argv);
  40. static int Install(sp<IGsiService> gsid, int argc, char** argv);
  41. static int Wipe(sp<IGsiService> gsid, int argc, char** argv);
  42. static int WipeData(sp<IGsiService> gsid, int argc, char** argv);
  43. static int Status(sp<IGsiService> gsid, int argc, char** argv);
  44. static int Cancel(sp<IGsiService> gsid, int argc, char** argv);
  45. static const std::map<std::string, CommandCallback> kCommandMap = {
  46. {"disable", Disable},
  47. {"enable", Enable},
  48. {"install", Install},
  49. {"wipe", Wipe},
  50. {"wipe-data", WipeData},
  51. {"status", Status},
  52. {"cancel", Cancel},
  53. };
  54. static sp<IGsiService> GetGsiService() {
  55. if (android::base::GetProperty("init.svc.gsid", "") != "running") {
  56. if (!android::base::SetProperty("ctl.start", "gsid") ||
  57. !android::base::WaitForProperty("init.svc.gsid", "running", 5s)) {
  58. std::cerr << "Unable to start gsid\n";
  59. return nullptr;
  60. }
  61. }
  62. static const int kSleepTimeMs = 50;
  63. static const int kTotalWaitTimeMs = 3000;
  64. for (int i = 0; i < kTotalWaitTimeMs / kSleepTimeMs; i++) {
  65. auto sm = android::defaultServiceManager();
  66. auto name = android::String16(kGsiServiceName);
  67. android::sp<android::IBinder> res = sm->checkService(name);
  68. if (res) {
  69. return android::interface_cast<IGsiService>(res);
  70. }
  71. usleep(kSleepTimeMs * 1000);
  72. }
  73. return nullptr;
  74. }
  75. static std::string ErrorMessage(const android::binder::Status& status, int error_code = IGsiService::INSTALL_ERROR_GENERIC) {
  76. if (!status.isOk()) {
  77. return status.exceptionMessage().string();
  78. }
  79. return "error code " + std::to_string(error_code);
  80. }
  81. class ProgressBar {
  82. public:
  83. explicit ProgressBar(sp<IGsiService> gsid) : gsid_(gsid) {}
  84. ~ProgressBar() { Stop(); }
  85. void Display() {
  86. Finish();
  87. done_ = false;
  88. last_update_ = {};
  89. worker_ = std::make_unique<std::thread>([this]() { Worker(); });
  90. }
  91. void Stop() {
  92. if (!worker_) {
  93. return;
  94. }
  95. SignalDone();
  96. worker_->join();
  97. worker_ = nullptr;
  98. }
  99. void Finish() {
  100. if (!worker_) {
  101. return;
  102. }
  103. Stop();
  104. FinishLastBar();
  105. }
  106. private:
  107. void Worker() {
  108. std::unique_lock<std::mutex> lock(mutex_);
  109. while (!done_) {
  110. if (!UpdateProgress()) {
  111. return;
  112. }
  113. cv_.wait_for(lock, 500ms, [this] { return done_; });
  114. }
  115. }
  116. bool UpdateProgress() {
  117. GsiProgress latest;
  118. auto status = gsid_->getInstallProgress(&latest);
  119. if (!status.isOk()) {
  120. std::cout << std::endl;
  121. return false;
  122. }
  123. if (latest.status == IGsiService::STATUS_NO_OPERATION) {
  124. return true;
  125. }
  126. if (last_update_.step != latest.step) {
  127. FinishLastBar();
  128. }
  129. Display(latest);
  130. return true;
  131. }
  132. void FinishLastBar() {
  133. // If no bar was in progress, don't do anything.
  134. if (last_update_.total_bytes == 0) {
  135. return;
  136. }
  137. // Ensure we finish the display at 100%.
  138. last_update_.bytes_processed = last_update_.total_bytes;
  139. Display(last_update_);
  140. std::cout << std::endl;
  141. }
  142. void Display(const GsiProgress& progress) {
  143. if (progress.total_bytes == 0) {
  144. return;
  145. }
  146. static constexpr int kColumns = 80;
  147. static constexpr char kRedColor[] = "\x1b[31m";
  148. static constexpr char kGreenColor[] = "\x1b[32m";
  149. static constexpr char kResetColor[] = "\x1b[0m";
  150. int percentage = (progress.bytes_processed * 100) / progress.total_bytes;
  151. int64_t bytes_per_col = progress.total_bytes / kColumns;
  152. uint32_t fill_count = progress.bytes_processed / bytes_per_col;
  153. uint32_t dash_count = kColumns - fill_count;
  154. std::string fills = std::string(fill_count, '=');
  155. std::string dashes = std::string(dash_count, '-');
  156. // Give the end of the bar some flare.
  157. if (!fills.empty() && !dashes.empty()) {
  158. fills[fills.size() - 1] = '>';
  159. }
  160. fprintf(stdout, "\r%-15s%6d%% ", progress.step.c_str(), percentage);
  161. fprintf(stdout, "%s[%s%s%s", kGreenColor, fills.c_str(), kRedColor, dashes.c_str());
  162. fprintf(stdout, "%s]%s", kGreenColor, kResetColor);
  163. fflush(stdout);
  164. last_update_ = progress;
  165. }
  166. void SignalDone() {
  167. std::lock_guard<std::mutex> guard(mutex_);
  168. done_ = true;
  169. cv_.notify_all();
  170. }
  171. private:
  172. sp<IGsiService> gsid_;
  173. std::unique_ptr<std::thread> worker_;
  174. std::condition_variable cv_;
  175. std::mutex mutex_;
  176. GsiProgress last_update_;
  177. bool done_ = false;
  178. };
  179. static int Install(sp<IGsiService> gsid, int argc, char** argv) {
  180. struct option options[] = {
  181. {"install-dir", required_argument, nullptr, 'i'},
  182. {"gsi-size", required_argument, nullptr, 's'},
  183. {"no-reboot", no_argument, nullptr, 'n'},
  184. {"userdata-size", required_argument, nullptr, 'u'},
  185. {"wipe", no_argument, nullptr, 'w'},
  186. {nullptr, 0, nullptr, 0},
  187. };
  188. GsiInstallParams params;
  189. params.gsiSize = 0;
  190. params.userdataSize = 0;
  191. params.wipeUserdata = false;
  192. bool reboot = true;
  193. if (getuid() != 0) {
  194. std::cerr << "must be root to install a GSI" << std::endl;
  195. return EX_NOPERM;
  196. }
  197. int rv, index;
  198. while ((rv = getopt_long_only(argc, argv, "", options, &index)) != -1) {
  199. switch (rv) {
  200. case 's':
  201. if (!android::base::ParseInt(optarg, &params.gsiSize) || params.gsiSize <= 0) {
  202. std::cerr << "Could not parse image size: " << optarg << std::endl;
  203. return EX_USAGE;
  204. }
  205. break;
  206. case 'u':
  207. if (!android::base::ParseInt(optarg, &params.userdataSize) ||
  208. params.userdataSize < 0) {
  209. std::cerr << "Could not parse image size: " << optarg << std::endl;
  210. return EX_USAGE;
  211. }
  212. break;
  213. case 'i':
  214. params.installDir = optarg;
  215. break;
  216. case 'w':
  217. params.wipeUserdata = true;
  218. break;
  219. case 'n':
  220. reboot = false;
  221. break;
  222. }
  223. }
  224. if (params.gsiSize <= 0) {
  225. std::cerr << "Must specify --gsi-size." << std::endl;
  226. return EX_USAGE;
  227. }
  228. bool running_gsi = false;
  229. gsid->isGsiRunning(&running_gsi);
  230. if (running_gsi) {
  231. std::cerr << "Cannot install a GSI within a live GSI." << std::endl;
  232. std::cerr << "Use gsi_tool disable or wipe and reboot first." << std::endl;
  233. return EX_SOFTWARE;
  234. }
  235. android::base::unique_fd input(dup(1));
  236. if (input < 0) {
  237. std::cerr << "Error duplicating descriptor: " << strerror(errno) << std::endl;
  238. return EX_SOFTWARE;
  239. }
  240. // Note: the progress bar needs to be re-started in between each call.
  241. ProgressBar progress(gsid);
  242. progress.Display();
  243. int error;
  244. auto status = gsid->beginGsiInstall(params, &error);
  245. if (!status.isOk() || error != IGsiService::INSTALL_OK) {
  246. std::cerr << "Could not start live image install: " << ErrorMessage(status, error) << "\n";
  247. return EX_SOFTWARE;
  248. }
  249. android::os::ParcelFileDescriptor stream(std::move(input));
  250. bool ok = false;
  251. progress.Display();
  252. status = gsid->commitGsiChunkFromStream(stream, params.gsiSize, &ok);
  253. if (!ok) {
  254. std::cerr << "Could not commit live image data: " << ErrorMessage(status) << "\n";
  255. return EX_SOFTWARE;
  256. }
  257. progress.Finish();
  258. status = gsid->setGsiBootable(true, &error);
  259. if (!status.isOk() || error != IGsiService::INSTALL_OK) {
  260. std::cerr << "Could not make live image bootable: " << ErrorMessage(status, error) << "\n";
  261. return EX_SOFTWARE;
  262. }
  263. if (reboot) {
  264. if (!android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,adb")) {
  265. std::cerr << "Failed to reboot automatically" << std::endl;
  266. return EX_SOFTWARE;
  267. }
  268. } else {
  269. std::cout << "Please reboot to use the GSI." << std::endl;
  270. }
  271. return 0;
  272. }
  273. static int Wipe(sp<IGsiService> gsid, int argc, char** /* argv */) {
  274. if (argc > 1) {
  275. std::cerr << "Unrecognized arguments to wipe." << std::endl;
  276. return EX_USAGE;
  277. }
  278. bool ok;
  279. auto status = gsid->removeGsiInstall(&ok);
  280. if (!status.isOk() || !ok) {
  281. std::cerr << "Could not remove GSI install: " << ErrorMessage(status) << "\n";
  282. return EX_SOFTWARE;
  283. }
  284. bool running = false;
  285. if (gsid->isGsiRunning(&running).isOk() && running) {
  286. std::cout << "Live image install will be removed next reboot." << std::endl;
  287. } else {
  288. std::cout << "Live image install successfully removed." << std::endl;
  289. }
  290. return 0;
  291. }
  292. static int WipeData(sp<IGsiService> gsid, int argc, char** /* argv */) {
  293. if (argc > 1) {
  294. std::cerr << "Unrecognized arguments to wipe-data.\n";
  295. return EX_USAGE;
  296. }
  297. bool running;
  298. auto status = gsid->isGsiRunning(&running);
  299. if (!status.isOk()) {
  300. std::cerr << "error: " << status.exceptionMessage().string() << std::endl;
  301. return EX_SOFTWARE;
  302. }
  303. if (running) {
  304. std::cerr << "Cannot wipe GSI userdata while running a GSI.\n";
  305. return EX_USAGE;
  306. }
  307. bool installed;
  308. status = gsid->isGsiInstalled(&installed);
  309. if (!status.isOk()) {
  310. std::cerr << "error: " << status.exceptionMessage().string() << std::endl;
  311. return EX_SOFTWARE;
  312. }
  313. if (!installed) {
  314. std::cerr << "No GSI is installed.\n";
  315. return EX_USAGE;
  316. }
  317. int error;
  318. status = gsid->wipeGsiUserdata(&error);
  319. if (!status.isOk() || error) {
  320. std::cerr << "Could not wipe GSI userdata: " << ErrorMessage(status, error) << "\n";
  321. return EX_SOFTWARE;
  322. }
  323. return 0;
  324. }
  325. static int Status(sp<IGsiService> gsid, int argc, char** /* argv */) {
  326. if (argc > 1) {
  327. std::cerr << "Unrecognized arguments to status." << std::endl;
  328. return EX_USAGE;
  329. }
  330. bool running;
  331. auto status = gsid->isGsiRunning(&running);
  332. if (!status.isOk()) {
  333. std::cerr << "error: " << status.exceptionMessage().string() << std::endl;
  334. return EX_SOFTWARE;
  335. } else if (running) {
  336. std::cout << "running" << std::endl;
  337. }
  338. bool installed;
  339. status = gsid->isGsiInstalled(&installed);
  340. if (!status.isOk()) {
  341. std::cerr << "error: " << status.exceptionMessage().string() << std::endl;
  342. return EX_SOFTWARE;
  343. } else if (installed) {
  344. std::cout << "installed" << std::endl;
  345. }
  346. bool enabled;
  347. status = gsid->isGsiEnabled(&enabled);
  348. if (!status.isOk()) {
  349. std::cerr << status.exceptionMessage().string() << std::endl;
  350. return EX_SOFTWARE;
  351. } else if (running || installed) {
  352. std::cout << (enabled ? "enabled" : "disabled") << std::endl;
  353. } else {
  354. std::cout << "normal" << std::endl;
  355. }
  356. return 0;
  357. }
  358. static int Cancel(sp<IGsiService> gsid, int /* argc */, char** /* argv */) {
  359. bool cancelled = false;
  360. auto status = gsid->cancelGsiInstall(&cancelled);
  361. if (!status.isOk()) {
  362. std::cerr << status.exceptionMessage().string() << std::endl;
  363. return EX_SOFTWARE;
  364. }
  365. if (!cancelled) {
  366. std::cout << "Fail to cancel the installation." << std::endl;
  367. return EX_SOFTWARE;
  368. }
  369. return 0;
  370. }
  371. static int Enable(sp<IGsiService> gsid, int argc, char** argv) {
  372. bool one_shot = false;
  373. struct option options[] = {
  374. {"single-boot", no_argument, nullptr, 's'},
  375. {nullptr, 0, nullptr, 0},
  376. };
  377. int rv, index;
  378. while ((rv = getopt_long_only(argc, argv, "", options, &index)) != -1) {
  379. switch (rv) {
  380. case 's':
  381. one_shot = true;
  382. break;
  383. default:
  384. std::cerr << "Unrecognized argument to enable\n";
  385. return EX_USAGE;
  386. }
  387. }
  388. bool installed = false;
  389. gsid->isGsiInstalled(&installed);
  390. if (!installed) {
  391. std::cerr << "Could not find GSI install to re-enable" << std::endl;
  392. return EX_SOFTWARE;
  393. }
  394. bool installing = false;
  395. gsid->isGsiInstallInProgress(&installing);
  396. if (installing) {
  397. std::cerr << "Cannot enable or disable while an installation is in progress." << std::endl;
  398. return EX_SOFTWARE;
  399. }
  400. int error;
  401. auto status = gsid->setGsiBootable(one_shot, &error);
  402. if (!status.isOk() || error != IGsiService::INSTALL_OK) {
  403. std::cerr << "Error re-enabling GSI: " << ErrorMessage(status, error) << "\n";
  404. return EX_SOFTWARE;
  405. }
  406. std::cout << "Live image install successfully enabled." << std::endl;
  407. return 0;
  408. }
  409. static int Disable(sp<IGsiService> gsid, int argc, char** /* argv */) {
  410. if (argc > 1) {
  411. std::cerr << "Unrecognized arguments to disable." << std::endl;
  412. return EX_USAGE;
  413. }
  414. bool installing = false;
  415. gsid->isGsiInstallInProgress(&installing);
  416. if (installing) {
  417. std::cerr << "Cannot enable or disable while an installation is in progress." << std::endl;
  418. return EX_SOFTWARE;
  419. }
  420. bool ok = false;
  421. gsid->disableGsiInstall(&ok);
  422. if (!ok) {
  423. std::cerr << "Error disabling GSI" << std::endl;
  424. return EX_SOFTWARE;
  425. }
  426. std::cout << "Live image install successfully disabled." << std::endl;
  427. return 0;
  428. }
  429. static int usage(int /* argc */, char* argv[]) {
  430. fprintf(stderr,
  431. "%s - command-line tool for installing GSI images.\n"
  432. "\n"
  433. "Usage:\n"
  434. " %s <disable|install|wipe|status> [options]\n"
  435. "\n"
  436. " disable Disable the currently installed GSI.\n"
  437. " enable [-s, --single-boot]\n"
  438. " Enable a previously disabled GSI.\n"
  439. " install Install a new GSI. Specify the image size with\n"
  440. " --gsi-size and the desired userdata size with\n"
  441. " --userdata-size (the latter defaults to 8GiB)\n"
  442. " --wipe (remove old gsi userdata first)\n"
  443. " wipe Completely remove a GSI and its associated data\n"
  444. " wipe-data Ensure the GSI's userdata will be formatted\n"
  445. " cancel Cancel the installation\n"
  446. " status Show status\n",
  447. argv[0], argv[0]);
  448. return EX_USAGE;
  449. }
  450. int main(int argc, char** argv) {
  451. auto gsid = GetGsiService();
  452. if (!gsid) {
  453. std::cerr << "Could not connect to the gsid service." << std::endl;
  454. return EX_NOPERM;
  455. }
  456. if (1 >= argc) {
  457. std::cerr << "Expected command." << std::endl;
  458. return EX_USAGE;
  459. }
  460. std::string command = argv[1];
  461. auto iter = kCommandMap.find(command);
  462. if (iter == kCommandMap.end()) {
  463. std::cerr << "Unrecognized command: " << command << std::endl;
  464. return usage(argc, argv);
  465. }
  466. int rc = iter->second(gsid, argc - 1, argv + 1);
  467. return rc;
  468. }