• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 #include <getopt.h>
18 #include <stdio.h>
19 #include <sysexits.h>
20 #include <unistd.h>
21 
22 #include <algorithm>
23 #include <chrono>
24 #include <condition_variable>
25 #include <functional>
26 #include <iostream>
27 #include <map>
28 #include <mutex>
29 #include <string>
30 #include <thread>
31 
32 #include <android-base/logging.h>
33 #include <android-base/parseint.h>
34 #include <android-base/properties.h>
35 #include <android-base/stringprintf.h>
36 #include <android-base/strings.h>
37 #include <android-base/unique_fd.h>
38 #include <android/gsi/IGsiService.h>
39 #include <binder/ProcessState.h>
40 #include <cutils/android_reboot.h>
41 #include <libgsi/libgsi.h>
42 #include <libgsi/libgsid.h>
43 
44 using namespace android::gsi;
45 using namespace std::chrono_literals;
46 
47 using android::sp;
48 using android::base::Split;
49 using android::base::StringPrintf;
50 using CommandCallback = std::function<int(sp<IGsiService>, int, char**)>;
51 
52 static int Disable(sp<IGsiService> gsid, int argc, char** argv);
53 static int Enable(sp<IGsiService> gsid, int argc, char** argv);
54 static int Install(sp<IGsiService> gsid, int argc, char** argv);
55 static int CreatePartition(sp<IGsiService> gsid, int argc, char** argv);
56 static int Wipe(sp<IGsiService> gsid, int argc, char** argv);
57 static int WipeData(sp<IGsiService> gsid, int argc, char** argv);
58 static int Status(sp<IGsiService> gsid, int argc, char** argv);
59 static int Cancel(sp<IGsiService> gsid, int argc, char** argv);
60 
61 static const std::map<std::string, CommandCallback> kCommandMap = {
62         // clang-format off
63         {"disable", Disable},
64         {"enable", Enable},
65         {"install", Install},
66         {"create-partition", CreatePartition},
67         {"wipe", Wipe},
68         {"wipe-data", WipeData},
69         {"status", Status},
70         {"cancel", Cancel},
71         // clang-format on
72 };
73 
74 // Commands not allowed for locked DSU
75 static const std::vector<std::string> kEnforceNonLockedDsu = {
76         // clang-format off
77         "disable",
78         "enable",
79         "wipe",
80         // clang-format on
81 };
82 
ErrorMessage(const android::binder::Status & status,int error_code=IGsiService::INSTALL_ERROR_GENERIC)83 static std::string ErrorMessage(const android::binder::Status& status,
84                                 int error_code = IGsiService::INSTALL_ERROR_GENERIC) {
85     if (!status.isOk()) {
86         return status.exceptionMessage().c_str();
87     }
88     return "error code " + std::to_string(error_code);
89 }
90 
IsRoot()91 static inline bool IsRoot() {
92     return getuid() == 0;
93 }
94 
EnforceNonLockedDsu(sp<IGsiService> gsid)95 static int EnforceNonLockedDsu(sp<IGsiService> gsid) {
96     bool running;
97     auto status = gsid->isGsiRunning(&running);
98     if (!status.isOk()) {
99         std::cerr << "Could not get DSU running status: " << ErrorMessage(status) << std::endl;
100         return EX_SOFTWARE;
101     }
102     if (!running) {
103         return 0;
104     }
105     std::string dsuSlot = {};
106     status = gsid->getActiveDsuSlot(&dsuSlot);
107     if (!status.isOk()) {
108         std::cerr << "Could not get the active DSU slot: " << ErrorMessage(status) << std::endl;
109         return EX_SOFTWARE;
110     }
111     if (android::base::EndsWith(dsuSlot, ".lock") && !IsRoot()) {
112         std::cerr << "Must be root to access a locked DSU" << std::endl;
113         return EX_NOPERM;
114     }
115     return 0;
116 }
117 
118 class ProgressBar {
119   public:
ProgressBar(sp<IGsiService> gsid)120     explicit ProgressBar(sp<IGsiService> gsid) : gsid_(gsid) {}
121 
~ProgressBar()122     ~ProgressBar() { Stop(); }
123 
Display()124     void Display() {
125         Finish();
126         done_ = false;
127         last_update_ = {};
128         worker_ = std::make_unique<std::thread>([this]() { Worker(); });
129     }
130 
Stop()131     void Stop() {
132         if (!worker_) {
133             return;
134         }
135         SignalDone();
136         worker_->join();
137         worker_ = nullptr;
138     }
139 
Finish()140     void Finish() {
141         if (!worker_) {
142             return;
143         }
144         Stop();
145         FinishLastBar();
146     }
147 
148   private:
Worker()149     void Worker() {
150         std::unique_lock<std::mutex> lock(mutex_);
151         while (!done_) {
152             if (!UpdateProgress()) {
153                 return;
154             }
155             cv_.wait_for(lock, 500ms, [this] { return done_; });
156         }
157     }
158 
UpdateProgress()159     bool UpdateProgress() {
160         GsiProgress latest;
161         auto status = gsid_->getInstallProgress(&latest);
162         if (!status.isOk()) {
163             std::cout << std::endl;
164             return false;
165         }
166         if (latest.status == IGsiService::STATUS_NO_OPERATION) {
167             return true;
168         }
169         if (last_update_.step != latest.step) {
170             FinishLastBar();
171         }
172         Display(latest);
173         return true;
174     }
175 
FinishLastBar()176     void FinishLastBar() {
177         // If no bar was in progress, don't do anything.
178         if (last_update_.total_bytes == 0) {
179             return;
180         }
181         // Ensure we finish the display at 100%.
182         last_update_.bytes_processed = last_update_.total_bytes;
183         Display(last_update_);
184         std::cout << std::endl;
185     }
186 
Display(const GsiProgress & progress)187     void Display(const GsiProgress& progress) {
188         if (progress.total_bytes == 0) {
189             return;
190         }
191 
192         static constexpr int kColumns = 80;
193         static constexpr char kRedColor[] = "\x1b[31m";
194         static constexpr char kGreenColor[] = "\x1b[32m";
195         static constexpr char kResetColor[] = "\x1b[0m";
196 
197         int percentage = (progress.bytes_processed * 100) / progress.total_bytes;
198         int64_t bytes_per_col = progress.total_bytes / kColumns;
199         uint32_t fill_count = progress.bytes_processed / bytes_per_col;
200         uint32_t dash_count = kColumns - fill_count;
201         std::string fills = std::string(fill_count, '=');
202         std::string dashes = std::string(dash_count, '-');
203 
204         // Give the end of the bar some flare.
205         if (!fills.empty() && !dashes.empty()) {
206             fills[fills.size() - 1] = '>';
207         }
208 
209         fprintf(stdout, "\r%-15s%6d%% ", progress.step.c_str(), percentage);
210         fprintf(stdout, "%s[%s%s%s", kGreenColor, fills.c_str(), kRedColor, dashes.c_str());
211         fprintf(stdout, "%s]%s", kGreenColor, kResetColor);
212         fflush(stdout);
213 
214         last_update_ = progress;
215     }
216 
SignalDone()217     void SignalDone() {
218         std::lock_guard<std::mutex> guard(mutex_);
219         done_ = true;
220         cv_.notify_all();
221     }
222 
223   private:
224     sp<IGsiService> gsid_;
225     std::unique_ptr<std::thread> worker_;
226     std::condition_variable cv_;
227     std::mutex mutex_;
228     GsiProgress last_update_;
229     bool done_ = false;
230 };
231 
Install(sp<IGsiService> gsid,int argc,char ** argv)232 static int Install(sp<IGsiService> gsid, int argc, char** argv) {
233     constexpr const char* kDefaultPartition = "system";
234     struct option options[] = {
235             {"install-dir", required_argument, nullptr, 'i'},
236             {"gsi-size", required_argument, nullptr, 's'},
237             {"no-reboot", no_argument, nullptr, 'n'},
238             {"userdata-size", required_argument, nullptr, 'u'},
239             {"partition-name", required_argument, nullptr, 'p'},
240             {nullptr, 0, nullptr, 0},
241     };
242 
243     int64_t gsiSize = 0;
244     int64_t userdataSize = 0;
245     bool reboot = true;
246     std::string installDir = "";
247     std::string partition = kDefaultPartition;
248     if (!IsRoot()) {
249         std::cerr << "must be root to install a GSI" << std::endl;
250         return EX_NOPERM;
251     }
252 
253     int rv, index;
254     while ((rv = getopt_long_only(argc, argv, "", options, &index)) != -1) {
255         switch (rv) {
256             case 'p':
257                 partition = optarg;
258                 break;
259             case 's':
260                 if (!android::base::ParseInt(optarg, &gsiSize) || gsiSize <= 0) {
261                     std::cerr << "Could not parse image size: " << optarg << std::endl;
262                     return EX_USAGE;
263                 }
264                 break;
265             case 'u':
266                 if (!android::base::ParseInt(optarg, &userdataSize) || userdataSize < 0) {
267                     std::cerr << "Could not parse image size: " << optarg << std::endl;
268                     return EX_USAGE;
269                 }
270                 break;
271             case 'i':
272                 installDir = optarg;
273                 break;
274             case 'n':
275                 reboot = false;
276                 break;
277         }
278     }
279 
280     if (gsiSize <= 0) {
281         std::cerr << "Must specify --gsi-size." << std::endl;
282         return EX_USAGE;
283     }
284 
285     bool running_gsi = false;
286     gsid->isGsiRunning(&running_gsi);
287     if (running_gsi) {
288         std::cerr << "Cannot install a GSI within a live GSI." << std::endl;
289         std::cerr << "Use gsi_tool disable or wipe and reboot first." << std::endl;
290         return EX_SOFTWARE;
291     }
292 
293     android::base::unique_fd input(dup(STDIN_FILENO));
294     if (input < 0) {
295         std::cerr << "Error duplicating descriptor: " << strerror(errno) << std::endl;
296         return EX_SOFTWARE;
297     }
298     // Note: the progress bar needs to be re-started in between each call.
299     ProgressBar progress(gsid);
300     progress.Display();
301     int error;
302     auto status = gsid->openInstall(installDir, &error);
303     if (!status.isOk() || error != IGsiService::INSTALL_OK) {
304         std::cerr << "Could not open DSU installation: " << ErrorMessage(status, error) << "\n";
305         return EX_SOFTWARE;
306     }
307     if (partition == kDefaultPartition) {
308         auto status = gsid->createPartition("userdata", userdataSize, false, &error);
309         if (!status.isOk() || error != IGsiService::INSTALL_OK) {
310             std::cerr << "Could not start live image install: " << ErrorMessage(status, error)
311                       << "\n";
312             return EX_SOFTWARE;
313         }
314         status = gsid->closePartition(&error);
315         if (!status.isOk() || error != IGsiService::INSTALL_OK) {
316             std::cerr << "Could not closePartition(userdata): " << ErrorMessage(status, error)
317                       << std::endl;
318             return EX_SOFTWARE;
319         }
320     }
321 
322     status = gsid->createPartition(partition, gsiSize, true, &error);
323     if (!status.isOk() || error != IGsiService::INSTALL_OK) {
324         std::cerr << "Could not start live image install: " << ErrorMessage(status, error) << "\n";
325         return EX_SOFTWARE;
326     }
327     android::os::ParcelFileDescriptor stream(std::move(input));
328 
329     bool ok = false;
330     progress.Display();
331     status = gsid->commitGsiChunkFromStream(stream, gsiSize, &ok);
332     if (!ok) {
333         std::cerr << "Could not commit live image data: " << ErrorMessage(status) << "\n";
334         return EX_SOFTWARE;
335     }
336 
337     status = gsid->closePartition(&error);
338     if (!status.isOk() || error != IGsiService::INSTALL_OK) {
339         std::cerr << "Could not closePartition(" << partition
340                   << "): " << ErrorMessage(status, error) << std::endl;
341         return EX_SOFTWARE;
342     }
343 
344     status = gsid->closeInstall(&error);
345     if (!status.isOk() || error != IGsiService::INSTALL_OK) {
346         std::cerr << "Could not close DSU installation: " << ErrorMessage(status, error) << "\n";
347         return EX_SOFTWARE;
348     }
349     progress.Finish();
350     std::string dsuSlot;
351     status = gsid->getActiveDsuSlot(&dsuSlot);
352     if (!status.isOk()) {
353         std::cerr << "Could not get the active DSU slot: " << ErrorMessage(status) << "\n";
354         return EX_SOFTWARE;
355     }
356     status = gsid->enableGsi(true, dsuSlot, &error);
357     if (!status.isOk() || error != IGsiService::INSTALL_OK) {
358         std::cerr << "Could not make live image bootable: " << ErrorMessage(status, error) << "\n";
359         return EX_SOFTWARE;
360     }
361 
362     if (reboot) {
363         if (!android::base::SetProperty(ANDROID_RB_PROPERTY, "reboot,adb")) {
364             std::cerr << "Failed to reboot automatically" << std::endl;
365             return EX_SOFTWARE;
366         }
367     } else {
368         std::cout << "Please reboot to use the GSI." << std::endl;
369     }
370     return 0;
371 }
372 
373 // Experimental API
CreatePartition(sp<IGsiService> gsid,int argc,char ** argv)374 static int CreatePartition(sp<IGsiService> gsid, int argc, char** argv) {
375     std::string installDir;
376     std::string partitionName;
377     bool readOnly = true;
378     int64_t partitionSize = 0;
379 
380     struct option options[] = {
381             {"install-dir", required_argument, nullptr, 'i'},
382             {"partition-name", required_argument, nullptr, 'p'},
383             {"readwrite", no_argument, nullptr, 'r'},
384             {"size", required_argument, nullptr, 's'},
385             {nullptr, 0, nullptr, 0},
386     };
387 
388     int rv = 0;
389     while ((rv = getopt_long_only(argc, argv, "", options, nullptr)) != -1) {
390         switch (rv) {
391             case 'i':
392                 installDir = optarg;
393                 break;
394             case 'p':
395                 partitionName = optarg;
396                 break;
397             case 'r':
398                 readOnly = false;
399                 break;
400             case 's':
401                 if (!android::base::ParseInt(optarg, &partitionSize)) {
402                     std::cerr << "Could not parse partition size: " << optarg << std::endl;
403                     return EX_USAGE;
404                 }
405                 break;
406             default:
407                 return EX_USAGE;
408         }
409     }
410 
411     if (!IsRoot()) {
412         std::cerr << "must be root to install a DSU" << std::endl;
413         return EX_NOPERM;
414     }
415 
416     bool gsiRunning = false;
417     auto status = gsid->isGsiRunning(&gsiRunning);
418     if (!status.isOk()) {
419         std::cerr << "Could not get DSU running status: " << ErrorMessage(status) << std::endl;
420         return EX_SOFTWARE;
421     }
422     if (gsiRunning) {
423         std::cerr << "Could not install DSU within an active DSU." << std::endl;
424         return EX_SOFTWARE;
425     }
426 
427     if (partitionSize <= 0) {
428         std::cerr << "Partition size must be greater than zero: " << partitionSize << std::endl;
429         return EX_USAGE;
430     }
431 
432     // Note: the progress bar needs to be re-started in between each call.
433     ProgressBar progress(gsid);
434     progress.Display();
435 
436     int error;
437     status = gsid->openInstall(installDir, &error);
438     if (!status.isOk() || error != IGsiService::INSTALL_OK) {
439         std::cerr << "Could not open DSU installation: " << ErrorMessage(status, error)
440                   << std::endl;
441         return EX_SOFTWARE;
442     }
443 
444     status = gsid->createPartition(partitionName, partitionSize, readOnly, &error);
445     if (!status.isOk() || error != IGsiService::INSTALL_OK) {
446         std::cerr << "Could not create DSU partition: " << ErrorMessage(status, error) << std::endl;
447         return EX_SOFTWARE;
448     }
449 
450     if (readOnly) {
451         android::base::unique_fd input(dup(STDIN_FILENO));
452         if (input < 0) {
453             std::cerr << "Error duplicating descriptor: " << strerror(errno) << std::endl;
454             return EX_SOFTWARE;
455         }
456         android::os::ParcelFileDescriptor stream(std::move(input));
457 
458         bool ok = false;
459         status = gsid->commitGsiChunkFromStream(stream, partitionSize, &ok);
460         if (!ok) {
461             std::cerr << "Could not commit data from stdin: " << ErrorMessage(status) << std::endl;
462             return EX_SOFTWARE;
463         }
464     }
465 
466     status = gsid->closePartition(&error);
467     if (!status.isOk() || error != IGsiService::INSTALL_OK) {
468         std::cerr << "Could not close DSU partition:" << ErrorMessage(status, error) << std::endl;
469         return EX_SOFTWARE;
470     }
471 
472     status = gsid->closeInstall(&error);
473     if (!status.isOk() || error != IGsiService::INSTALL_OK) {
474         std::cerr << "Could not close DSU installation: " << ErrorMessage(status, error)
475                   << std::endl;
476         return EX_SOFTWARE;
477     }
478 
479     progress.Finish();
480 
481     std::string dsuSlot;
482     status = gsid->getActiveDsuSlot(&dsuSlot);
483     if (!status.isOk()) {
484         std::cerr << "Could not get the active DSU slot: " << ErrorMessage(status) << std::endl;
485         return EX_SOFTWARE;
486     }
487 
488     // Immediately enable DSU after a partition is installed to ensure the installation status file
489     // is created.
490     status = gsid->enableGsi(/* one_shot = */ true, dsuSlot, &error);
491     if (!status.isOk() || error != IGsiService::INSTALL_OK) {
492         std::cerr << "Could not make DSU bootable: " << ErrorMessage(status, error) << std::endl;
493         return EX_SOFTWARE;
494     }
495 
496     std::cout << "Enabled DSU slot: " << dsuSlot << std::endl;
497     std::cout << "Please reboot to use the DSU." << std::endl;
498     return 0;
499 }
500 
Wipe(sp<IGsiService> gsid,int argc,char **)501 static int Wipe(sp<IGsiService> gsid, int argc, char** /* argv */) {
502     if (argc > 1) {
503         std::cerr << "Unrecognized arguments to wipe." << std::endl;
504         return EX_USAGE;
505     }
506     bool ok;
507     auto status = gsid->removeGsi(&ok);
508     if (!status.isOk() || !ok) {
509         std::cerr << "Could not remove GSI install: " << ErrorMessage(status) << "\n";
510         return EX_SOFTWARE;
511     }
512 
513     bool running = false;
514     if (gsid->isGsiRunning(&running).isOk() && running) {
515         std::cout << "Live image install will be removed next reboot." << std::endl;
516     } else {
517         std::cout << "Live image install successfully removed." << std::endl;
518     }
519     return 0;
520 }
521 
WipeData(sp<IGsiService> gsid,int argc,char **)522 static int WipeData(sp<IGsiService> gsid, int argc, char** /* argv */) {
523     if (argc > 1) {
524         std::cerr << "Unrecognized arguments to wipe-data.\n";
525         return EX_USAGE;
526     }
527 
528     bool running;
529     auto status = gsid->isGsiRunning(&running);
530     if (!status.isOk()) {
531         std::cerr << "error: " << status.exceptionMessage().c_str() << std::endl;
532         return EX_SOFTWARE;
533     }
534     if (running) {
535         std::cerr << "Cannot wipe GSI userdata while running a GSI.\n";
536         return EX_USAGE;
537     }
538 
539     bool installed;
540     status = gsid->isGsiInstalled(&installed);
541     if (!status.isOk()) {
542         std::cerr << "error: " << status.exceptionMessage().c_str() << std::endl;
543         return EX_SOFTWARE;
544     }
545     if (!installed) {
546         std::cerr << "No GSI is installed.\n";
547         return EX_USAGE;
548     }
549 
550     int error;
551     status = gsid->zeroPartition("userdata" + std::string(kDsuPostfix), &error);
552     if (!status.isOk() || error) {
553         std::cerr << "Could not wipe GSI userdata: " << ErrorMessage(status, error) << "\n";
554         return EX_SOFTWARE;
555     }
556     return 0;
557 }
558 
Status(sp<IGsiService> gsid,int argc,char **)559 static int Status(sp<IGsiService> gsid, int argc, char** /* argv */) {
560     if (argc > 1) {
561         std::cerr << "Unrecognized arguments to status." << std::endl;
562         return EX_USAGE;
563     }
564     bool running;
565     auto status = gsid->isGsiRunning(&running);
566     if (!status.isOk()) {
567         std::cerr << "error: " << status.exceptionMessage().c_str() << std::endl;
568         return EX_SOFTWARE;
569     } else if (running) {
570         std::cout << "running" << std::endl;
571     }
572     bool installed;
573     status = gsid->isGsiInstalled(&installed);
574     if (!status.isOk()) {
575         std::cerr << "error: " << status.exceptionMessage().c_str() << std::endl;
576         return EX_SOFTWARE;
577     } else if (installed) {
578         std::cout << "installed" << std::endl;
579     }
580     bool enabled;
581     status = gsid->isGsiEnabled(&enabled);
582     if (!status.isOk()) {
583         std::cerr << status.exceptionMessage().c_str() << std::endl;
584         return EX_SOFTWARE;
585     } else if (running || installed) {
586         std::cout << (enabled ? "enabled" : "disabled") << std::endl;
587     } else {
588         std::cout << "normal" << std::endl;
589     }
590     if (!IsRoot()) {
591         return 0;
592     }
593 
594     std::vector<std::string> dsu_slots;
595     status = gsid->getInstalledDsuSlots(&dsu_slots);
596     if (!status.isOk()) {
597         std::cerr << status.exceptionMessage().c_str() << std::endl;
598         return EX_SOFTWARE;
599     }
600     int n = 0;
601     for (auto&& dsu_slot : dsu_slots) {
602         std::cout << "[" << n++ << "] " << dsu_slot << std::endl;
603         sp<IImageService> image_service = nullptr;
604         status = gsid->openImageService("dsu/" + dsu_slot + "/", &image_service);
605         if (!status.isOk()) {
606             if (running) {
607                 // openImageService through binder (gsid) could fail if running,
608                 // because we can't stat the "outside" userdata.
609                 continue;
610             }
611             std::cerr << "error: " << status.exceptionMessage().c_str() << std::endl;
612             return EX_SOFTWARE;
613         }
614         std::vector<std::string> images;
615         status = image_service->getAllBackingImages(&images);
616         if (!status.isOk()) {
617             std::cerr << "error: " << status.exceptionMessage().c_str() << std::endl;
618             return EX_SOFTWARE;
619         }
620         for (auto&& image : images) {
621             std::cout << "installed: " << image << std::endl;
622             AvbPublicKey public_key;
623             int err = 0;
624             status = image_service->getAvbPublicKey(image, &public_key, &err);
625             std::cout << "AVB public key (sha1): ";
626             if (!public_key.bytes.empty()) {
627                 for (auto b : public_key.sha1) {
628                     std::cout << StringPrintf("%02x", b & 255);
629                 }
630                 std::cout << std::endl;
631             } else {
632                 std::cout << "[NONE]" << std::endl;
633             }
634         }
635     }
636     return 0;
637 }
638 
Cancel(sp<IGsiService> gsid,int,char **)639 static int Cancel(sp<IGsiService> gsid, int /* argc */, char** /* argv */) {
640     bool cancelled = false;
641     auto status = gsid->cancelGsiInstall(&cancelled);
642     if (!status.isOk()) {
643         std::cerr << status.exceptionMessage().c_str() << std::endl;
644         return EX_SOFTWARE;
645     }
646     if (!cancelled) {
647         std::cout << "Fail to cancel the installation." << std::endl;
648         return EX_SOFTWARE;
649     }
650     return 0;
651 }
652 
Enable(sp<IGsiService> gsid,int argc,char ** argv)653 static int Enable(sp<IGsiService> gsid, int argc, char** argv) {
654     bool one_shot = false;
655     std::string dsuSlot = {};
656     struct option options[] = {
657             {"single-boot", no_argument, nullptr, 's'},
658             {"dsuslot", required_argument, nullptr, 'd'},
659             {nullptr, 0, nullptr, 0},
660     };
661     int rv, index;
662     while ((rv = getopt_long_only(argc, argv, "", options, &index)) != -1) {
663         switch (rv) {
664             case 's':
665                 one_shot = true;
666                 break;
667             case 'd':
668                 dsuSlot = optarg;
669                 break;
670             default:
671                 std::cerr << "Unrecognized argument to enable\n";
672                 return EX_USAGE;
673         }
674     }
675 
676     bool installed = false;
677     gsid->isGsiInstalled(&installed);
678     if (!installed) {
679         std::cerr << "Could not find GSI install to re-enable" << std::endl;
680         return EX_SOFTWARE;
681     }
682 
683     bool installing = false;
684     gsid->isGsiInstallInProgress(&installing);
685     if (installing) {
686         std::cerr << "Cannot enable or disable while an installation is in progress." << std::endl;
687         return EX_SOFTWARE;
688     }
689     if (dsuSlot.empty()) {
690         auto status = gsid->getActiveDsuSlot(&dsuSlot);
691         if (!status.isOk()) {
692             std::cerr << "Could not get the active DSU slot: " << ErrorMessage(status) << "\n";
693             return EX_SOFTWARE;
694         }
695     }
696     int error;
697     auto status = gsid->enableGsi(one_shot, dsuSlot, &error);
698     if (!status.isOk() || error != IGsiService::INSTALL_OK) {
699         std::cerr << "Error re-enabling GSI: " << ErrorMessage(status, error) << "\n";
700         return EX_SOFTWARE;
701     }
702     std::cout << "Live image install successfully enabled." << std::endl;
703     return 0;
704 }
705 
Disable(sp<IGsiService> gsid,int argc,char **)706 static int Disable(sp<IGsiService> gsid, int argc, char** /* argv */) {
707     if (argc > 1) {
708         std::cerr << "Unrecognized arguments to disable." << std::endl;
709         return EX_USAGE;
710     }
711     bool installing = false;
712     gsid->isGsiInstallInProgress(&installing);
713     if (installing) {
714         std::cerr << "Cannot enable or disable while an installation is in progress." << std::endl;
715         return EX_SOFTWARE;
716     }
717 
718     bool ok = false;
719     gsid->disableGsi(&ok);
720     if (!ok) {
721         std::cerr << "Error disabling GSI" << std::endl;
722         return EX_SOFTWARE;
723     }
724     std::cout << "Live image install successfully disabled." << std::endl;
725     return 0;
726 }
727 
usage(int,char * argv[])728 static int usage(int /* argc */, char* argv[]) {
729     fprintf(stderr,
730             "%s - command-line tool for installing GSI images.\n"
731             "\n"
732             "Usage:\n"
733             "  %s <disable|install|wipe|status> [options]\n"
734             "\n"
735             "  disable      Disable the currently installed GSI.\n"
736             "  enable       [-s, --single-boot]\n"
737             "               [-d, --dsuslot slotname]\n"
738             "               Enable a previously disabled GSI.\n"
739             "  install      Install a new GSI. Specify the image size with\n"
740             "               --gsi-size and the desired userdata size with\n"
741             "               --userdata-size (the latter defaults to 8GiB)\n"
742             "               --wipe (remove old gsi userdata first)\n"
743             "  wipe         Completely remove a GSI and its associated data\n"
744             "  wipe-data    Ensure the GSI's userdata will be formatted\n"
745             "  cancel       Cancel the installation\n"
746             "  status       Show status\n",
747             argv[0], argv[0]);
748     return EX_USAGE;
749 }
750 
main(int argc,char ** argv)751 int main(int argc, char** argv) {
752     android::base::InitLogging(argv, android::base::StderrLogger, android::base::DefaultAborter);
753 
754     // Start a threadpool to service waitForService() callbacks.
755     android::ProcessState::self()->startThreadPool();
756     android::sp<IGsiService> service = GetGsiService();
757     if (!service) {
758         return EX_SOFTWARE;
759     }
760 
761     if (1 >= argc) {
762         std::cerr << "Expected command." << std::endl;
763         return EX_USAGE;
764     }
765 
766     std::string command = argv[1];
767 
768     int rc;
769     const auto& vec = kEnforceNonLockedDsu;
770     if (std::find(vec.begin(), vec.end(), command) != vec.end() &&
771         (rc = EnforceNonLockedDsu(service)) != 0) {
772         return rc;
773     }
774 
775     auto iter = kCommandMap.find(command);
776     if (iter == kCommandMap.end()) {
777         std::cerr << "Unrecognized command: " << command << std::endl;
778         return usage(argc, argv);
779     }
780 
781     rc = iter->second(service, argc - 1, argv + 1);
782     return rc;
783 }
784