• 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 "gsi_service.h"
18 
19 #include <errno.h>
20 #include <linux/fs.h>
21 #include <sys/ioctl.h>
22 #include <sys/stat.h>
23 #include <sys/statvfs.h>
24 #include <sys/types.h>
25 #include <sys/vfs.h>
26 #include <unistd.h>
27 
28 #include <chrono>
29 #include <string>
30 #include <vector>
31 
32 #include <android-base/file.h>
33 #include <android-base/logging.h>
34 #include <android-base/stringprintf.h>
35 #include <android-base/strings.h>
36 #include <android/gsi/IGsiService.h>
37 #include <ext4_utils/ext4_utils.h>
38 #include <fs_mgr.h>
39 #include <fs_mgr_dm_linear.h>
40 #include <fstab/fstab.h>
41 #include <libdm/dm.h>
42 #include <libfiemap_writer/fiemap_writer.h>
43 #include <logwrap/logwrap.h>
44 #include <private/android_filesystem_config.h>
45 
46 #include "file_paths.h"
47 #include "libgsi_private.h"
48 
49 namespace android {
50 namespace gsi {
51 
52 using namespace std::literals;
53 using namespace android::dm;
54 using namespace android::fs_mgr;
55 using namespace android::fiemap_writer;
56 using android::base::StringPrintf;
57 using android::base::unique_fd;
58 
59 static constexpr char kUserdataDevice[] = "/dev/block/by-name/userdata";
60 
61 // The default size of userdata.img for GSI.
62 // We are looking for /data to have atleast 40% free space
63 static constexpr uint32_t kMinimumFreeSpaceThreshold = 40;
64 // We determine the fragmentation by making sure the files
65 // we create don't have more than 16 extents.
66 static constexpr uint32_t kMaximumExtents = 512;
67 // Default userdata image size.
68 static constexpr int64_t kDefaultUserdataSize = int64_t(8) * 1024 * 1024 * 1024;
69 static constexpr std::chrono::milliseconds kDmTimeout = 5000ms;
70 
Register()71 void GsiService::Register() {
72     auto ret = android::BinderService<GsiService>::publish();
73     if (ret != android::OK) {
74         LOG(FATAL) << "Could not register gsi service: " << ret;
75     }
76 }
77 
GsiService()78 GsiService::GsiService() {
79     progress_ = {};
80 }
81 
~GsiService()82 GsiService::~GsiService() {
83     PostInstallCleanup();
84 }
85 
86 #define ENFORCE_SYSTEM                          \
87     do {                                        \
88         binder::Status status = CheckUid();     \
89         if (!status.isOk()) return status;      \
90     } while (0)
91 
92 #define ENFORCE_SYSTEM_OR_SHELL                                         \
93     do {                                                                \
94         binder::Status status = CheckUid(AccessLevel::SystemOrShell);   \
95         if (!status.isOk()) return status;                              \
96     } while (0)
97 
startGsiInstall(int64_t gsiSize,int64_t userdataSize,bool wipeUserdata,int * _aidl_return)98 binder::Status GsiService::startGsiInstall(int64_t gsiSize, int64_t userdataSize, bool wipeUserdata,
99                                            int* _aidl_return) {
100     GsiInstallParams params;
101     params.gsiSize = gsiSize;
102     params.userdataSize = userdataSize;
103     params.wipeUserdata = wipeUserdata;
104     return beginGsiInstall(params, _aidl_return);
105 }
106 
beginGsiInstall(const GsiInstallParams & given_params,int * _aidl_return)107 binder::Status GsiService::beginGsiInstall(const GsiInstallParams& given_params, int* _aidl_return) {
108     ENFORCE_SYSTEM;
109     std::lock_guard<std::mutex> guard(main_lock_);
110 
111     // Make sure any interrupted installations are cleaned up.
112     PostInstallCleanup();
113 
114     // Do some precursor validation on the arguments before diving into the
115     // install process.
116     GsiInstallParams params = given_params;
117     if (int status = ValidateInstallParams(&params)) {
118         *_aidl_return = status;
119         return binder::Status::ok();
120     }
121 
122     int status = StartInstall(params);
123     if (status != INSTALL_OK) {
124         // Perform local cleanup and delete any lingering files.
125         PostInstallCleanup();
126         RemoveGsiFiles(params.installDir, wipe_userdata_on_failure_);
127     }
128     *_aidl_return = status;
129 
130     // Clear the progress indicator.
131     UpdateProgress(STATUS_NO_OPERATION, 0);
132     return binder::Status::ok();
133 }
134 
commitGsiChunkFromStream(const android::os::ParcelFileDescriptor & stream,int64_t bytes,bool * _aidl_return)135 binder::Status GsiService::commitGsiChunkFromStream(const android::os::ParcelFileDescriptor& stream,
136                                                     int64_t bytes, bool* _aidl_return) {
137     ENFORCE_SYSTEM;
138     std::lock_guard<std::mutex> guard(main_lock_);
139 
140     *_aidl_return = CommitGsiChunk(stream.get(), bytes);
141 
142     // Clear the progress indicator.
143     UpdateProgress(STATUS_NO_OPERATION, 0);
144     return binder::Status::ok();
145 }
146 
StartAsyncOperation(const std::string & step,int64_t total_bytes)147 void GsiService::StartAsyncOperation(const std::string& step, int64_t total_bytes) {
148     std::lock_guard<std::mutex> guard(progress_lock_);
149 
150     progress_.step = step;
151     progress_.status = STATUS_WORKING;
152     progress_.bytes_processed = 0;
153     progress_.total_bytes = total_bytes;
154 }
155 
UpdateProgress(int status,int64_t bytes_processed)156 void GsiService::UpdateProgress(int status, int64_t bytes_processed) {
157     std::lock_guard<std::mutex> guard(progress_lock_);
158 
159     progress_.status = status;
160     if (status == STATUS_COMPLETE) {
161         progress_.bytes_processed = progress_.total_bytes;
162     } else {
163         progress_.bytes_processed = bytes_processed;
164     }
165 }
166 
getInstallProgress(::android::gsi::GsiProgress * _aidl_return)167 binder::Status GsiService::getInstallProgress(::android::gsi::GsiProgress* _aidl_return) {
168     ENFORCE_SYSTEM;
169     std::lock_guard<std::mutex> guard(progress_lock_);
170 
171     *_aidl_return = progress_;
172     return binder::Status::ok();
173 }
174 
commitGsiChunkFromMemory(const std::vector<uint8_t> & bytes,bool * _aidl_return)175 binder::Status GsiService::commitGsiChunkFromMemory(const std::vector<uint8_t>& bytes,
176                                                     bool* _aidl_return) {
177     ENFORCE_SYSTEM;
178     std::lock_guard<std::mutex> guard(main_lock_);
179 
180     *_aidl_return = CommitGsiChunk(bytes.data(), bytes.size());
181     return binder::Status::ok();
182 }
183 
setGsiBootable(bool one_shot,int * _aidl_return)184 binder::Status GsiService::setGsiBootable(bool one_shot, int* _aidl_return) {
185     std::lock_guard<std::mutex> guard(main_lock_);
186 
187     if (installing_) {
188         ENFORCE_SYSTEM;
189         int error = SetGsiBootable(one_shot);
190         PostInstallCleanup();
191         if (error) {
192             RemoveGsiFiles(install_dir_, wipe_userdata_on_failure_);
193             *_aidl_return = error;
194         } else {
195             *_aidl_return = INSTALL_OK;
196         }
197     } else {
198         ENFORCE_SYSTEM_OR_SHELL;
199         *_aidl_return = ReenableGsi(one_shot);
200         PostInstallCleanup();
201     }
202 
203     return binder::Status::ok();
204 }
205 
isGsiEnabled(bool * _aidl_return)206 binder::Status GsiService::isGsiEnabled(bool* _aidl_return) {
207     ENFORCE_SYSTEM_OR_SHELL;
208     std::lock_guard<std::mutex> guard(main_lock_);
209     std::string boot_key;
210     if (!GetInstallStatus(&boot_key)) {
211         *_aidl_return = false;
212     } else {
213         *_aidl_return = (boot_key == kInstallStatusOk);
214     }
215     return binder::Status::ok();
216 }
217 
removeGsiInstall(bool * _aidl_return)218 binder::Status GsiService::removeGsiInstall(bool* _aidl_return) {
219     ENFORCE_SYSTEM_OR_SHELL;
220     std::lock_guard<std::mutex> guard(main_lock_);
221 
222     // Just in case an install was left hanging.
223     std::string install_dir;
224     if (installing_) {
225         install_dir = install_dir_;
226         PostInstallCleanup();
227     } else {
228         install_dir = GetInstalledImageDir();
229     }
230 
231     if (IsGsiRunning()) {
232         // Can't remove gsi files while running.
233         *_aidl_return = UninstallGsi();
234     } else {
235         *_aidl_return = RemoveGsiFiles(install_dir, true /* wipeUserdata */);
236     }
237     return binder::Status::ok();
238 }
239 
disableGsiInstall(bool * _aidl_return)240 binder::Status GsiService::disableGsiInstall(bool* _aidl_return) {
241     ENFORCE_SYSTEM_OR_SHELL;
242     std::lock_guard<std::mutex> guard(main_lock_);
243 
244     *_aidl_return = DisableGsiInstall();
245     return binder::Status::ok();
246 }
247 
isGsiRunning(bool * _aidl_return)248 binder::Status GsiService::isGsiRunning(bool* _aidl_return) {
249     ENFORCE_SYSTEM_OR_SHELL;
250     std::lock_guard<std::mutex> guard(main_lock_);
251 
252     *_aidl_return = IsGsiRunning();
253     return binder::Status::ok();
254 }
255 
isGsiInstalled(bool * _aidl_return)256 binder::Status GsiService::isGsiInstalled(bool* _aidl_return) {
257     ENFORCE_SYSTEM_OR_SHELL;
258     std::lock_guard<std::mutex> guard(main_lock_);
259 
260     *_aidl_return = IsGsiInstalled();
261     return binder::Status::ok();
262 }
263 
isGsiInstallInProgress(bool * _aidl_return)264 binder::Status GsiService::isGsiInstallInProgress(bool* _aidl_return) {
265     ENFORCE_SYSTEM_OR_SHELL;
266     std::lock_guard<std::mutex> guard(main_lock_);
267 
268     *_aidl_return = installing_;
269     return binder::Status::ok();
270 }
271 
cancelGsiInstall(bool * _aidl_return)272 binder::Status GsiService::cancelGsiInstall(bool* _aidl_return) {
273     ENFORCE_SYSTEM;
274     should_abort_ = true;
275     std::lock_guard<std::mutex> guard(main_lock_);
276 
277     should_abort_ = false;
278     if (installing_) {
279         PostInstallCleanup();
280         RemoveGsiFiles(install_dir_, wipe_userdata_on_failure_);
281     }
282 
283     *_aidl_return = true;
284     return binder::Status::ok();
285 }
286 
getGsiBootStatus(int * _aidl_return)287 binder::Status GsiService::getGsiBootStatus(int* _aidl_return) {
288     ENFORCE_SYSTEM_OR_SHELL;
289     std::lock_guard<std::mutex> guard(main_lock_);
290 
291     if (!IsGsiInstalled()) {
292         *_aidl_return = BOOT_STATUS_NOT_INSTALLED;
293         return binder::Status::ok();
294     }
295 
296     std::string boot_key;
297     if (!GetInstallStatus(&boot_key)) {
298         PLOG(ERROR) << "read " << kGsiInstallStatusFile;
299         *_aidl_return = BOOT_STATUS_NOT_INSTALLED;
300         return binder::Status::ok();
301     }
302 
303     bool single_boot = !access(kGsiOneShotBootFile, F_OK);
304 
305     if (boot_key == kInstallStatusWipe) {
306         // This overrides all other statuses.
307         *_aidl_return = BOOT_STATUS_WILL_WIPE;
308     } else if (boot_key == kInstallStatusDisabled) {
309         // A single-boot GSI will have a "disabled" status, because it's
310         // disabled immediately upon reading the one_shot_boot file. However,
311         // we still want to return SINGLE_BOOT, because it makes the
312         // transition clearer to the user.
313         if (single_boot) {
314             *_aidl_return = BOOT_STATUS_SINGLE_BOOT;
315         } else {
316             *_aidl_return = BOOT_STATUS_DISABLED;
317         }
318     } else if (single_boot) {
319         *_aidl_return = BOOT_STATUS_SINGLE_BOOT;
320     } else {
321         *_aidl_return = BOOT_STATUS_ENABLED;
322     }
323     return binder::Status::ok();
324 }
325 
getUserdataImageSize(int64_t * _aidl_return)326 binder::Status GsiService::getUserdataImageSize(int64_t* _aidl_return) {
327     ENFORCE_SYSTEM;
328     std::lock_guard<std::mutex> guard(main_lock_);
329 
330     *_aidl_return = -1;
331 
332     if (installing_) {
333         // Size has already been computed.
334         *_aidl_return = userdata_size_;
335     } else if (IsGsiRunning()) {
336         // :TODO: libdm
337         unique_fd fd(open(kUserdataDevice, O_RDONLY | O_NOFOLLOW | O_CLOEXEC));
338         if (fd < 0) {
339             PLOG(ERROR) << "open " << kUserdataDevice;
340             return binder::Status::ok();
341         }
342 
343         int64_t size;
344         if (ioctl(fd, BLKGETSIZE64, &size)) {
345             PLOG(ERROR) << "BLKGETSIZE64 " << kUserdataDevice;
346             return binder::Status::ok();
347         }
348         *_aidl_return = size;
349     } else {
350         // Stat the size of the userdata file.
351         auto userdata_gsi = GetInstalledImagePath("userdata_gsi");
352         struct stat s;
353         if (stat(userdata_gsi.c_str(), &s)) {
354             if (errno != ENOENT) {
355                 PLOG(ERROR) << "open " << userdata_gsi;
356                 return binder::Status::ok();
357             }
358             *_aidl_return = 0;
359         } else {
360             *_aidl_return = s.st_size;
361         }
362     }
363     return binder::Status::ok();
364 }
365 
getInstalledGsiImageDir(std::string * _aidl_return)366 binder::Status GsiService::getInstalledGsiImageDir(std::string* _aidl_return) {
367     ENFORCE_SYSTEM;
368     std::lock_guard<std::mutex> guard(main_lock_);
369 
370     if (IsGsiInstalled()) {
371         *_aidl_return = GetInstalledImageDir();
372     }
373     return binder::Status::ok();
374 }
375 
wipeGsiUserdata(int * _aidl_return)376 binder::Status GsiService::wipeGsiUserdata(int* _aidl_return) {
377     ENFORCE_SYSTEM_OR_SHELL;
378     std::lock_guard<std::mutex> guard(main_lock_);
379 
380     if (IsGsiRunning() || !IsGsiInstalled()) {
381         *_aidl_return = IGsiService::INSTALL_ERROR_GENERIC;
382         return binder::Status::ok();
383     }
384 
385     *_aidl_return = WipeUserdata();
386 
387     return binder::Status::ok();
388 }
389 
CheckUid(AccessLevel level)390 binder::Status GsiService::CheckUid(AccessLevel level) {
391     std::vector<uid_t> allowed_uids{AID_ROOT, AID_SYSTEM};
392     if (level == AccessLevel::SystemOrShell) {
393         allowed_uids.push_back(AID_SHELL);
394     }
395 
396     uid_t uid = IPCThreadState::self()->getCallingUid();
397     for (const auto& allowed_uid : allowed_uids) {
398         if (allowed_uid == uid) {
399             return binder::Status::ok();
400         }
401     }
402 
403     auto message = StringPrintf("UID %d is not allowed", uid);
404     return binder::Status::fromExceptionCode(binder::Status::EX_SECURITY,
405                                              String8(message.c_str()));
406 }
407 
PostInstallCleanup()408 void GsiService::PostInstallCleanup() {
409     // This must be closed before unmapping partitions.
410     system_writer_ = nullptr;
411 
412     const auto& dm = DeviceMapper::Instance();
413     if (dm.GetState("userdata_gsi") != DmDeviceState::INVALID) {
414         DestroyLogicalPartition("userdata_gsi", kDmTimeout);
415     }
416     if (dm.GetState("system_gsi") != DmDeviceState::INVALID) {
417         DestroyLogicalPartition("system_gsi", kDmTimeout);
418     }
419 
420     installing_ = false;
421     partitions_ .clear();
422 }
423 
IsExternalStoragePath(const std::string & path)424 static bool IsExternalStoragePath(const std::string& path) {
425     if (!android::base::StartsWith(path, "/mnt/media_rw/")) {
426         return false;
427     }
428     unique_fd fd(open(path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
429     if (fd < 0) {
430         PLOG(ERROR) << "open failed: " << path;
431         return false;
432     }
433     struct statfs info;
434     if (fstatfs(fd, &info)) {
435         PLOG(ERROR) << "statfs failed: " << path;
436         return false;
437     }
438     LOG(ERROR) << "fs type: " << info.f_type;
439     return info.f_type == MSDOS_SUPER_MAGIC;
440 }
441 
ValidateInstallParams(GsiInstallParams * params)442 int GsiService::ValidateInstallParams(GsiInstallParams* params) {
443     // If no install path was specified, use the default path. We also allow
444     // specifying the top-level folder, and then we choose the correct location
445     // underneath.
446     if (params->installDir.empty() || params->installDir == "/data/gsi") {
447         params->installDir = kDefaultGsiImageFolder;
448     }
449 
450     // Normalize the path and add a trailing slash.
451     std::string origInstallDir = params->installDir;
452     if (!android::base::Realpath(origInstallDir, &params->installDir)) {
453         PLOG(ERROR) << "realpath failed: " << origInstallDir;
454         return INSTALL_ERROR_GENERIC;
455     }
456     // Ensure the path ends in / for consistency. Even though GetImagePath()
457     // does this already, we want it to appear this way in install_dir.
458     if (!android::base::EndsWith(params->installDir, "/")) {
459         params->installDir += "/";
460     }
461 
462     // Currently, we can only install to /data/gsi/ or external storage.
463     if (IsExternalStoragePath(params->installDir)) {
464         Fstab fstab;
465         if (!ReadDefaultFstab(&fstab)) {
466             LOG(ERROR) << "cannot read default fstab";
467             return INSTALL_ERROR_GENERIC;
468         }
469         FstabEntry* system = GetEntryForMountPoint(&fstab, "/system");
470         if (!system) {
471             LOG(ERROR) << "cannot find /system fstab entry";
472             return INSTALL_ERROR_GENERIC;
473         }
474         if (fs_mgr_verity_is_check_at_most_once(*system)) {
475             LOG(ERROR) << "cannot install GSIs to external media if verity uses check_at_most_once";
476             return INSTALL_ERROR_GENERIC;
477         }
478     } else if (params->installDir != kDefaultGsiImageFolder) {
479         LOG(ERROR) << "cannot install GSI to " << params->installDir;
480         return INSTALL_ERROR_GENERIC;
481     }
482 
483     if (params->gsiSize % LP_SECTOR_SIZE) {
484         LOG(ERROR) << "GSI size " << params->gsiSize << " is not a multiple of " << LP_SECTOR_SIZE;
485         return INSTALL_ERROR_GENERIC;
486     }
487     if (params->userdataSize % LP_SECTOR_SIZE) {
488         LOG(ERROR) << "userdata size " << params->userdataSize << " is not a multiple of "
489                    << LP_SECTOR_SIZE;
490         return INSTALL_ERROR_GENERIC;
491     }
492     return INSTALL_OK;
493 }
494 
StartInstall(const GsiInstallParams & params)495 int GsiService::StartInstall(const GsiInstallParams& params) {
496     installing_ = true;
497     userdata_block_size_ = 0;
498     system_block_size_ = 0;
499     gsi_size_ = params.gsiSize;
500     userdata_size_ = (params.userdataSize) ? params.userdataSize : kDefaultUserdataSize;
501     wipe_userdata_ = params.wipeUserdata;
502     can_use_devicemapper_ = false;
503     gsi_bytes_written_ = 0;
504     install_dir_ = params.installDir;
505 
506     userdata_gsi_path_ = GetImagePath(install_dir_, "userdata_gsi");
507     system_gsi_path_ = GetImagePath(install_dir_, "system_gsi");
508 
509     // Only rm userdata_gsi if one didn't already exist.
510     wipe_userdata_on_failure_ = wipe_userdata_ || access(userdata_gsi_path_.c_str(), F_OK);
511 
512     if (int status = PerformSanityChecks()) {
513         return status;
514     }
515     if (int status = PreallocateFiles()) {
516         return status;
517     }
518     if (int status = DetermineReadWriteMethod()) {
519         return status;
520     }
521     if (!FormatUserdata()) {
522         return INSTALL_ERROR_GENERIC;
523     }
524 
525     // Map system_gsi so we can write to it.
526     system_writer_ = OpenPartition("system_gsi");
527     if (!system_writer_) {
528         return INSTALL_ERROR_GENERIC;
529     }
530     return INSTALL_OK;
531 }
532 
DetermineReadWriteMethod()533 int GsiService::DetermineReadWriteMethod() {
534     // If there is a device-mapper node wrapping the block device, then we're
535     // able to create another node around it; the dm layer does not carry the
536     // exclusion lock down the stack when a mount occurs.
537     //
538     // If there is no intermediate device-mapper node, then partitions cannot be
539     // opened writable due to sepolicy and exclusivity of having a mounted
540     // filesystem. This should only happen on devices with no encryption, or
541     // devices with FBE and no metadata encryption. For these cases it suffices
542     // to perform normal file writes to /data/gsi (which is unencrypted).
543     std::string block_device;
544     if (!FiemapWriter::GetBlockDeviceForFile(system_gsi_path_.c_str(), &block_device,
545                                              &can_use_devicemapper_)) {
546         return INSTALL_ERROR_GENERIC;
547     }
548     if (install_dir_ != kDefaultGsiImageFolder && can_use_devicemapper_) {
549         // Never use device-mapper on external media. We don't support adopted
550         // storage yet, and accidentally using device-mapper could be dangerous
551         // as we hardcode the userdata device as backing storage.
552         LOG(ERROR) << "unexpected device-mapper node used to mount external media";
553         return INSTALL_ERROR_GENERIC;
554     }
555     return INSTALL_OK;
556 }
557 
GetImagePath(const std::string & image_dir,const std::string & name)558 std::string GsiService::GetImagePath(const std::string& image_dir, const std::string& name) {
559     std::string dir = image_dir;
560     if (!android::base::EndsWith(dir, "/")) {
561         dir += "/";
562     }
563     return dir + name + ".img";
564 }
565 
GetInstalledImageDir()566 std::string GsiService::GetInstalledImageDir() {
567     // If there's no install left, just return /data/gsi since that's where
568     // installs go by default.
569     std::string dir;
570     if (android::base::ReadFileToString(kGsiInstallDirFile, &dir)) {
571         return dir;
572     }
573     return kDefaultGsiImageFolder;
574 }
575 
GetInstalledImagePath(const std::string & name)576 std::string GsiService::GetInstalledImagePath(const std::string& name) {
577     return GetImagePath(GetInstalledImageDir(), name);
578 }
579 
PerformSanityChecks()580 int GsiService::PerformSanityChecks() {
581     if (gsi_size_ < 0) {
582         LOG(ERROR) << "image size " << gsi_size_ << " is negative";
583         return INSTALL_ERROR_GENERIC;
584     }
585     if (android::gsi::IsGsiRunning()) {
586         LOG(ERROR) << "cannot install gsi inside a live gsi";
587         return INSTALL_ERROR_GENERIC;
588     }
589 
590     struct statvfs sb;
591     if (statvfs(install_dir_.c_str(), &sb)) {
592         PLOG(ERROR) << "failed to read file system stats";
593         return INSTALL_ERROR_GENERIC;
594     }
595 
596     // This is the same as android::vold::GetFreebytes() but we also
597     // need the total file system size so we open code it here.
598     uint64_t free_space = 1ULL * sb.f_bavail * sb.f_frsize;
599     uint64_t fs_size = sb.f_blocks * sb.f_frsize;
600     if (free_space <= (gsi_size_ + userdata_size_)) {
601         LOG(ERROR) << "not enough free space (only " << free_space << " bytes available)";
602         return INSTALL_ERROR_NO_SPACE;
603     }
604     // We are asking for 40% of the /data to be empty.
605     // TODO: may be not hard code it like this
606     double free_space_percent = ((1.0 * free_space) / fs_size) * 100;
607     if (free_space_percent < kMinimumFreeSpaceThreshold) {
608         LOG(ERROR) << "free space " << static_cast<uint64_t>(free_space_percent)
609                    << "% is below the minimum threshold of " << kMinimumFreeSpaceThreshold << "%";
610         return INSTALL_ERROR_FILE_SYSTEM_CLUTTERED;
611     }
612     return INSTALL_OK;
613 }
614 
PreallocateFiles()615 int GsiService::PreallocateFiles() {
616     if (wipe_userdata_) {
617         SplitFiemap::RemoveSplitFiles(userdata_gsi_path_);
618     }
619     SplitFiemap::RemoveSplitFiles(system_gsi_path_);
620 
621     // TODO: trigger GC from fiemap writer.
622 
623     // Create fallocated files.
624     if (int status = PreallocateUserdata()) {
625         return status;
626     }
627     if (int status = PreallocateSystem()) {
628         return status;
629     }
630 
631     // Save the extent information in liblp.
632     metadata_ = CreateMetadata();
633     if (!metadata_) {
634         return INSTALL_ERROR_GENERIC;
635     }
636 
637     UpdateProgress(STATUS_COMPLETE, 0);
638     return INSTALL_OK;
639 }
640 
PreallocateUserdata()641 int GsiService::PreallocateUserdata() {
642     int error;
643     std::unique_ptr<SplitFiemap> userdata_image;
644     if (wipe_userdata_ || access(userdata_gsi_path_.c_str(), F_OK)) {
645         StartAsyncOperation("create userdata", userdata_size_);
646         userdata_image = CreateFiemapWriter(userdata_gsi_path_, userdata_size_, &error);
647         if (!userdata_image) {
648             LOG(ERROR) << "Could not create userdata image: " << userdata_gsi_path_;
649             return error;
650         }
651         // Signal that we need to reformat userdata.
652         wipe_userdata_ = true;
653     } else {
654         userdata_image = CreateFiemapWriter(userdata_gsi_path_, 0, &error);
655         if (!userdata_image) {
656             LOG(ERROR) << "Could not open userdata image: " << userdata_gsi_path_;
657             return error;
658         }
659         if (userdata_size_ && userdata_image->size() < userdata_size_) {
660             // :TODO: need to fallocate more blocks and resizefs.
661         }
662         userdata_size_ = userdata_image->size();
663     }
664 
665     userdata_block_size_ = userdata_image->block_size();
666 
667     Image image = {
668             .writer = std::move(userdata_image),
669             .actual_size = userdata_size_,
670     };
671     partitions_.emplace(std::make_pair("userdata_gsi", std::move(image)));
672     return INSTALL_OK;
673 }
674 
PreallocateSystem()675 int GsiService::PreallocateSystem() {
676     StartAsyncOperation("create system", gsi_size_);
677 
678     int error;
679     auto system_image = CreateFiemapWriter(system_gsi_path_, gsi_size_, &error);
680     if (!system_image) {
681         return error;
682     }
683 
684     system_block_size_ = system_image->block_size();
685 
686     Image image = {
687             .writer = std::move(system_image),
688             .actual_size = gsi_size_,
689     };
690     partitions_.emplace(std::make_pair("system_gsi", std::move(image)));
691     return INSTALL_OK;
692 }
693 
CreateFiemapWriter(const std::string & path,uint64_t size,int * error)694 std::unique_ptr<SplitFiemap> GsiService::CreateFiemapWriter(const std::string& path,
695                                                             uint64_t size, int* error) {
696     bool create = (size != 0);
697 
698     std::function<bool(uint64_t, uint64_t)> progress;
699     if (create) {
700         // TODO: allow cancelling inside cancelGsiInstall.
701         progress = [this](uint64_t bytes, uint64_t /* total */) -> bool {
702             UpdateProgress(STATUS_WORKING, bytes);
703             if (should_abort_) return false;
704             return true;
705         };
706     }
707 
708     std::unique_ptr<SplitFiemap> file;
709     if (!size) {
710         file = SplitFiemap::Open(path);
711     } else {
712         file = SplitFiemap::Create(path, size, 0, std::move(progress));
713     }
714     if (!file) {
715         LOG(ERROR) << "failed to create or open " << path;
716         *error = INSTALL_ERROR_GENERIC;
717         return nullptr;
718     }
719 
720     uint64_t extents = file->extents().size();
721     if (extents > kMaximumExtents) {
722         LOG(ERROR) << "file " << path << " has too many extents: " << extents;
723         *error = INSTALL_ERROR_FILE_SYSTEM_CLUTTERED;
724         return nullptr;
725     }
726     return file;
727 }
728 
729 // Write data through an fd.
730 class FdWriter final : public GsiService::WriteHelper {
731   public:
FdWriter(const std::string & path,unique_fd && fd)732     FdWriter(const std::string& path, unique_fd&& fd) : path_(path), fd_(std::move(fd)) {}
733 
Write(const void * data,uint64_t bytes)734     bool Write(const void* data, uint64_t bytes) override {
735         return android::base::WriteFully(fd_, data, bytes);
736     }
Flush()737     bool Flush() override {
738         if (fsync(fd_)) {
739             PLOG(ERROR) << "fsync failed: " << path_;
740             return false;
741         }
742         return true;
743     }
Size()744     uint64_t Size() override { return get_block_device_size(fd_); }
745 
746   private:
747     std::string path_;
748     unique_fd fd_;
749 };
750 
751 // Write data through a SplitFiemap.
752 class SplitFiemapWriter final : public GsiService::WriteHelper {
753   public:
SplitFiemapWriter(SplitFiemap * writer)754     explicit SplitFiemapWriter(SplitFiemap* writer) : writer_(writer) {}
755 
Write(const void * data,uint64_t bytes)756     bool Write(const void* data, uint64_t bytes) override {
757         return writer_->Write(data, bytes);
758     }
Flush()759     bool Flush() override {
760         return writer_->Flush();
761     }
Size()762     uint64_t Size() override { return writer_->size(); }
763 
764   private:
765     SplitFiemap* writer_;
766 };
767 
OpenPartition(const std::string & name)768 std::unique_ptr<GsiService::WriteHelper> GsiService::OpenPartition(const std::string& name) {
769     if (can_use_devicemapper_) {
770         std::string path;
771         if (!CreateLogicalPartition(kUserdataDevice, *metadata_.get(), name, true, kDmTimeout,
772                                     &path)) {
773             LOG(ERROR) << "Error creating device-mapper node for " << name;
774             return {};
775         }
776 
777         static const int kOpenFlags = O_RDWR | O_NOFOLLOW | O_CLOEXEC;
778         unique_fd fd(open(path.c_str(), kOpenFlags));
779         if (fd < 0) {
780             PLOG(ERROR) << "could not open " << path;
781         }
782         return std::make_unique<FdWriter>(GetImagePath(install_dir_, name), std::move(fd));
783     }
784 
785     auto iter = partitions_.find(name);
786     if (iter == partitions_.end()) {
787         LOG(ERROR) << "could not find partition " << name;
788         return {};
789     }
790     return std::make_unique<SplitFiemapWriter>(iter->second.writer.get());
791 }
792 
CommitGsiChunk(int stream_fd,int64_t bytes)793 bool GsiService::CommitGsiChunk(int stream_fd, int64_t bytes) {
794     StartAsyncOperation("write gsi", gsi_size_);
795 
796     if (bytes < 0) {
797         LOG(ERROR) << "chunk size " << bytes << " is negative";
798         return false;
799     }
800 
801     auto buffer = std::make_unique<char[]>(system_block_size_);
802 
803     int progress = -1;
804     uint64_t remaining = bytes;
805     while (remaining) {
806         // :TODO: check file pin status!
807         size_t max_to_read = std::min(system_block_size_, remaining);
808         ssize_t rv = TEMP_FAILURE_RETRY(read(stream_fd, buffer.get(), max_to_read));
809         if (rv < 0) {
810             PLOG(ERROR) << "read gsi chunk";
811             return false;
812         }
813         if (rv == 0) {
814             LOG(ERROR) << "no bytes left in stream";
815             return false;
816         }
817         if (!CommitGsiChunk(buffer.get(), rv)) {
818             return false;
819         }
820         CHECK(static_cast<uint64_t>(rv) <= remaining);
821         remaining -= rv;
822 
823         // Only update the progress when the % (or permille, in this case)
824         // significantly changes.
825         int new_progress = ((gsi_size_ - remaining) * 1000) / gsi_size_;
826         if (new_progress != progress) {
827             UpdateProgress(STATUS_WORKING, gsi_size_ - remaining);
828         }
829     }
830 
831     UpdateProgress(STATUS_COMPLETE, gsi_size_);
832     return true;
833 }
834 
CommitGsiChunk(const void * data,size_t bytes)835 bool GsiService::CommitGsiChunk(const void* data, size_t bytes) {
836     if (!installing_) {
837         LOG(ERROR) << "no gsi installation in progress";
838         return false;
839     }
840     if (static_cast<uint64_t>(bytes) > gsi_size_ - gsi_bytes_written_) {
841         // We cannot write past the end of the image file.
842         LOG(ERROR) << "chunk size " << bytes << " exceeds remaining image size (" << gsi_size_
843                    << " expected, " << gsi_bytes_written_ << " written)";
844         return false;
845     }
846 
847     if (!system_writer_->Write(data, bytes)) {
848         PLOG(ERROR) << "write failed";
849         return false;
850     }
851     gsi_bytes_written_ += bytes;
852     return true;
853 }
854 
SetGsiBootable(bool one_shot)855 int GsiService::SetGsiBootable(bool one_shot) {
856     if (gsi_bytes_written_ != gsi_size_) {
857         // We cannot boot if the image is incomplete.
858         LOG(ERROR) << "image incomplete; expected " << gsi_size_ << " bytes, waiting for "
859                    << (gsi_size_ - gsi_bytes_written_) << " bytes";
860         return INSTALL_ERROR_GENERIC;
861     }
862 
863     if (!system_writer_->Flush()) {
864         return INSTALL_ERROR_GENERIC;
865     }
866 
867     // If files moved (are no longer pinned), the metadata file will be invalid.
868     for (const auto& [name, image] : partitions_) {
869         if (!image.writer->HasPinnedExtents()) {
870             LOG(ERROR) << name << " no longer has pinned extents";
871             return INSTALL_ERROR_GENERIC;
872         }
873     }
874 
875     // Remember the installation directory.
876     if (!android::base::WriteStringToFile(install_dir_, kGsiInstallDirFile)) {
877         PLOG(ERROR) << "write failed: " << kGsiInstallDirFile;
878         return INSTALL_ERROR_GENERIC;
879     }
880 
881     // Note: create the install status file last, since this is the actual boot
882     // indicator.
883     if (!CreateMetadataFile() || !SetBootMode(one_shot) || !CreateInstallStatusFile()) {
884         return INSTALL_ERROR_GENERIC;
885     }
886     return INSTALL_OK;
887 }
888 
ReenableGsi(bool one_shot)889 int GsiService::ReenableGsi(bool one_shot) {
890     if (!android::gsi::IsGsiInstalled()) {
891         LOG(ERROR) << "no gsi installed - cannot re-enable";
892         return INSTALL_ERROR_GENERIC;
893     }
894 
895     std::string boot_key;
896     if (!GetInstallStatus(&boot_key)) {
897         PLOG(ERROR) << "read " << kGsiInstallStatusFile;
898         return INSTALL_ERROR_GENERIC;
899     }
900     if (boot_key != kInstallStatusDisabled) {
901         LOG(ERROR) << "GSI is not currently disabled";
902         return INSTALL_ERROR_GENERIC;
903     }
904 
905     if (IsGsiRunning()) {
906         if (!SetBootMode(one_shot) || !CreateInstallStatusFile()) {
907             return INSTALL_ERROR_GENERIC;
908         }
909         return INSTALL_OK;
910     }
911     // Note: this metadata is only used to recover the original partition sizes.
912     // We do not trust the extent information, which will get rebuilt later.
913     auto old_metadata = ReadFromImageFile(kGsiLpMetadataFile);
914     if (!old_metadata) {
915         LOG(ERROR) << "GSI install is incomplete";
916         return INSTALL_ERROR_GENERIC;
917     }
918 
919     // Set up enough installer state so that we can use various helper
920     // methods.
921     //
922     // TODO(dvander) Extract all of the installer state into a separate
923     // class so this is more manageable.
924     install_dir_ = GetInstalledImageDir();
925     system_gsi_path_ = GetImagePath(install_dir_, "system_gsi");
926     if (int error = DetermineReadWriteMethod()) {
927         return error;
928     }
929 
930     // Recover parition information.
931     Image userdata_image;
932     if (int error = GetExistingImage(*old_metadata.get(), "userdata_gsi", &userdata_image)) {
933         return error;
934     }
935     partitions_.emplace(std::make_pair("userdata_gsi", std::move(userdata_image)));
936 
937     Image system_image;
938     if (int error = GetExistingImage(*old_metadata.get(), "system_gsi", &system_image)) {
939         return error;
940     }
941     partitions_.emplace(std::make_pair("system_gsi", std::move(system_image)));
942 
943     metadata_ = CreateMetadata();
944     if (!metadata_) {
945         return INSTALL_ERROR_GENERIC;
946     }
947     if (!CreateMetadataFile() || !SetBootMode(one_shot) || !CreateInstallStatusFile()) {
948         return INSTALL_ERROR_GENERIC;
949     }
950     return INSTALL_OK;
951 }
952 
WipeUserdata()953 int GsiService::WipeUserdata() {
954     // Note: this metadata is only used to recover the original partition sizes.
955     // We do not trust the extent information, which will get rebuilt later.
956     auto old_metadata = ReadFromImageFile(kGsiLpMetadataFile);
957     if (!old_metadata) {
958         LOG(ERROR) << "GSI install is incomplete";
959         return INSTALL_ERROR_GENERIC;
960     }
961 
962     install_dir_ = GetInstalledImageDir();
963     system_gsi_path_ = GetImagePath(install_dir_, "system_gsi");
964     if (int error = DetermineReadWriteMethod()) {
965         return error;
966     }
967 
968     // Recover parition information.
969     Image userdata_image;
970     if (int error = GetExistingImage(*old_metadata.get(), "userdata_gsi", &userdata_image)) {
971         return error;
972     }
973     partitions_.emplace(std::make_pair("userdata_gsi", std::move(userdata_image)));
974 
975     metadata_ = CreateMetadata();
976     if (!metadata_) {
977         return INSTALL_ERROR_GENERIC;
978     }
979 
980     auto writer = OpenPartition("userdata_gsi");
981     if (!writer) {
982         return IGsiService::INSTALL_ERROR_GENERIC;
983     }
984 
985     // Wipe the first 1MiB of the device, ensuring both the first block and
986     // the superblock are destroyed.
987     static constexpr uint64_t kEraseSize = 1024 * 1024;
988 
989     std::string zeroes(4096, 0);
990     uint64_t erase_size = std::min(kEraseSize, writer->Size());
991     for (uint64_t i = 0; i < erase_size; i += zeroes.size()) {
992         if (!writer->Write(zeroes.data(), zeroes.size())) {
993             PLOG(ERROR) << "write userdata_gsi";
994             return IGsiService::INSTALL_ERROR_GENERIC;
995         }
996     }
997     return INSTALL_OK;
998 }
999 
GetPartitionSize(const LpMetadata & metadata,const LpMetadataPartition & partition)1000 static uint64_t GetPartitionSize(const LpMetadata& metadata, const LpMetadataPartition& partition) {
1001     uint64_t total = 0;
1002     for (size_t i = 0; i < partition.num_extents; i++) {
1003         const auto& extent = metadata.extents[partition.first_extent_index + i];
1004         if (extent.target_type != LP_TARGET_TYPE_LINEAR) {
1005             LOG(ERROR) << "non-linear extent detected";
1006             return 0;
1007         }
1008         total += extent.num_sectors * LP_SECTOR_SIZE;
1009     }
1010     return total;
1011 }
1012 
GetPartitionSize(const LpMetadata & metadata,const std::string & name)1013 static uint64_t GetPartitionSize(const LpMetadata& metadata, const std::string& name) {
1014     for (const auto& partition : metadata.partitions) {
1015         if (GetPartitionName(partition) == name) {
1016             return GetPartitionSize(metadata, partition);
1017         }
1018     }
1019     return 0;
1020 }
1021 
GetExistingImage(const LpMetadata & metadata,const std::string & name,Image * image)1022 int GsiService::GetExistingImage(const LpMetadata& metadata, const std::string& name,
1023                                  Image* image) {
1024     int error;
1025     std::string path = GetInstalledImagePath(name);
1026     auto writer = CreateFiemapWriter(path.c_str(), 0, &error);
1027     if (!writer) {
1028         return error;
1029     }
1030 
1031     // Even after recovering the FIEMAP, we also need to know the exact intended
1032     // size of the image, since FiemapWriter may have extended the final block.
1033     uint64_t actual_size = GetPartitionSize(metadata, name);
1034     if (!actual_size) {
1035         LOG(ERROR) << "Could not determine the pre-existing size of " << name;
1036         return INSTALL_ERROR_GENERIC;
1037     }
1038     image->writer = std::move(writer);
1039     image->actual_size = actual_size;
1040     return INSTALL_OK;
1041 }
1042 
RemoveGsiFiles(const std::string & install_dir,bool wipeUserdata)1043 bool GsiService::RemoveGsiFiles(const std::string& install_dir, bool wipeUserdata) {
1044     bool ok = true;
1045     std::string message;
1046     if (!SplitFiemap::RemoveSplitFiles(GetImagePath(install_dir, "system_gsi"), &message)) {
1047         LOG(ERROR) << message;
1048         ok = false;
1049     }
1050     if (wipeUserdata &&
1051         !SplitFiemap::RemoveSplitFiles(GetImagePath(install_dir, "userdata_gsi"), &message)) {
1052         LOG(ERROR) << message;
1053         ok = false;
1054     }
1055 
1056     std::vector<std::string> files{
1057             kGsiInstallStatusFile,
1058             kGsiLpMetadataFile,
1059             kGsiOneShotBootFile,
1060             kGsiInstallDirFile,
1061     };
1062     for (const auto& file : files) {
1063         if (!android::base::RemoveFileIfExists(file, &message)) {
1064             LOG(ERROR) << message;
1065             ok = false;
1066         }
1067     }
1068     return ok;
1069 }
1070 
DisableGsiInstall()1071 bool GsiService::DisableGsiInstall() {
1072     if (!android::gsi::IsGsiInstalled()) {
1073         LOG(ERROR) << "cannot disable gsi install - no install detected";
1074         return false;
1075     }
1076     if (installing_) {
1077         LOG(ERROR) << "cannot disable gsi during GSI installation";
1078         return false;
1079     }
1080     if (!DisableGsi()) {
1081         PLOG(ERROR) << "could not write gsi status";
1082         return false;
1083     }
1084     return true;
1085 }
1086 
CreateMetadata()1087 std::unique_ptr<LpMetadata> GsiService::CreateMetadata() {
1088     std::string data_device_path;
1089     if (install_dir_ == kDefaultGsiImageFolder && !access(kUserdataDevice, F_OK)) {
1090         data_device_path = kUserdataDevice;
1091     } else {
1092         auto writer = partitions_["system_gsi"].writer.get();
1093         data_device_path = writer->bdev_path();
1094     }
1095     auto data_device_name = android::base::Basename(data_device_path);
1096 
1097     PartitionOpener opener;
1098     BlockDeviceInfo data_device_info;
1099     if (!opener.GetInfo(data_device_path, &data_device_info)) {
1100         LOG(ERROR) << "Error reading userdata partition";
1101         return nullptr;
1102     }
1103 
1104     std::vector<BlockDeviceInfo> block_devices = {data_device_info};
1105     auto builder = MetadataBuilder::New(block_devices, data_device_name, 128 * 1024, 1);
1106     if (!builder) {
1107         LOG(ERROR) << "Error creating metadata builder";
1108         return nullptr;
1109     }
1110     builder->IgnoreSlotSuffixing();
1111 
1112     for (const auto& [name, image] : partitions_) {
1113         uint32_t flags = LP_PARTITION_ATTR_NONE;
1114         if (name == "system_gsi") {
1115             flags |= LP_PARTITION_ATTR_READONLY;
1116         }
1117         Partition* partition = builder->AddPartition(name, flags);
1118         if (!partition) {
1119             LOG(ERROR) << "Error adding " << name << " to partition table";
1120             return nullptr;
1121         }
1122         if (!AddPartitionFiemap(builder.get(), partition, image, data_device_name)) {
1123             return nullptr;
1124         }
1125     }
1126 
1127     auto metadata = builder->Export();
1128     if (!metadata) {
1129         LOG(ERROR) << "Error exporting partition table";
1130         return nullptr;
1131     }
1132     return metadata;
1133 }
1134 
CreateMetadataFile()1135 bool GsiService::CreateMetadataFile() {
1136     if (!WriteToImageFile(kGsiLpMetadataFile, *metadata_.get())) {
1137         LOG(ERROR) << "Error writing GSI partition table image";
1138         return false;
1139     }
1140     return true;
1141 }
1142 
FormatUserdata()1143 bool GsiService::FormatUserdata() {
1144     auto writer = OpenPartition("userdata_gsi");
1145     if (!writer) {
1146         return false;
1147     }
1148 
1149     // libcutils checks the first 4K, no matter the block size.
1150     std::string zeroes(4096, 0);
1151     if (!writer->Write(zeroes.data(), zeroes.size())) {
1152         PLOG(ERROR) << "write userdata_gsi";
1153         return false;
1154     }
1155     return true;
1156 }
1157 
AddPartitionFiemap(MetadataBuilder * builder,Partition * partition,const Image & image,const std::string & block_device)1158 bool GsiService::AddPartitionFiemap(MetadataBuilder* builder, Partition* partition,
1159                                     const Image& image, const std::string& block_device) {
1160     uint64_t sectors_needed = image.actual_size / LP_SECTOR_SIZE;
1161     for (const auto& extent : image.writer->extents()) {
1162         // :TODO: block size check for length, not sector size
1163         if (extent.fe_length % LP_SECTOR_SIZE != 0) {
1164             LOG(ERROR) << "Extent is not sector-aligned: " << extent.fe_length;
1165             return false;
1166         }
1167         if (extent.fe_physical % LP_SECTOR_SIZE != 0) {
1168             LOG(ERROR) << "Extent physical sector is not sector-aligned: " << extent.fe_physical;
1169             return false;
1170         }
1171 
1172         uint64_t num_sectors =
1173                 std::min(static_cast<uint64_t>(extent.fe_length / LP_SECTOR_SIZE), sectors_needed);
1174         if (!num_sectors || !sectors_needed) {
1175             // This should never happen, but we include it just in case. It would
1176             // indicate that the last filesystem block had multiple extents.
1177             LOG(WARNING) << "FiemapWriter allocated extra blocks";
1178             break;
1179         }
1180 
1181         uint64_t physical_sector = extent.fe_physical / LP_SECTOR_SIZE;
1182         if (!builder->AddLinearExtent(partition, block_device, num_sectors, physical_sector)) {
1183             LOG(ERROR) << "Could not add extent to lp metadata";
1184             return false;
1185         }
1186 
1187         sectors_needed -= num_sectors;
1188     }
1189     return true;
1190 }
1191 
SetBootMode(bool one_shot)1192 bool GsiService::SetBootMode(bool one_shot) {
1193     if (one_shot) {
1194         if (!android::base::WriteStringToFile("1", kGsiOneShotBootFile)) {
1195             PLOG(ERROR) << "write " << kGsiOneShotBootFile;
1196             return false;
1197         }
1198     } else if (!access(kGsiOneShotBootFile, F_OK)) {
1199         std::string error;
1200         if (!android::base::RemoveFileIfExists(kGsiOneShotBootFile, &error)) {
1201             LOG(ERROR) << error;
1202             return false;
1203         }
1204     }
1205     return true;
1206 }
1207 
CreateInstallStatusFile()1208 bool GsiService::CreateInstallStatusFile() {
1209     if (!android::base::WriteStringToFile("0", kGsiInstallStatusFile)) {
1210         PLOG(ERROR) << "write " << kGsiInstallStatusFile;
1211         return false;
1212     }
1213     return true;
1214 }
1215 
RunStartupTasks()1216 void GsiService::RunStartupTasks() {
1217     if (!IsGsiInstalled()) {
1218         return;
1219     }
1220 
1221     std::string boot_key;
1222     if (!GetInstallStatus(&boot_key)) {
1223         PLOG(ERROR) << "read " << kGsiInstallStatusFile;
1224         return;
1225     }
1226 
1227     if (!IsGsiRunning()) {
1228         // Check if a wipe was requested from fastboot or adb-in-gsi.
1229         if (boot_key == kInstallStatusWipe) {
1230             RemoveGsiFiles(GetInstalledImageDir(), true /* wipeUserdata */);
1231         }
1232     } else {
1233         // NB: When single-boot is enabled, init will write "disabled" into the
1234         // install_status file, which will cause GetBootAttempts to return
1235         // false. Thus, we won't write "ok" here.
1236         int ignore;
1237         if (GetBootAttempts(boot_key, &ignore)) {
1238             // Mark the GSI as having successfully booted.
1239             if (!android::base::WriteStringToFile(kInstallStatusOk, kGsiInstallStatusFile)) {
1240                 PLOG(ERROR) << "write " << kGsiInstallStatusFile;
1241             }
1242         }
1243     }
1244 }
1245 
1246 }  // namespace gsi
1247 }  // namespace android
1248