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