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 "libgsi/libgsi.h" 18 19 #include <string.h> 20 #include <unistd.h> 21 22 #include <string> 23 24 #include <android-base/file.h> 25 #include <android-base/parseint.h> 26 #include <android-base/strings.h> 27 #include <android-base/unique_fd.h> 28 29 #include "file_paths.h" 30 #include "libgsi_private.h" 31 32 namespace android { 33 namespace gsi { 34 35 using namespace std::literals; 36 using android::base::ReadFileToString; 37 using android::base::Split; 38 using android::base::unique_fd; 39 40 bool GetActiveDsu(std::string* active_dsu) { 41 return android::base::ReadFileToString(kDsuActiveFile, active_dsu); 42 } 43 44 bool IsGsiRunning() { 45 return !access(kGsiBootedIndicatorFile, F_OK); 46 } 47 48 bool IsGsiInstalled() { 49 return !access(kDsuInstallStatusFile, F_OK); 50 } 51 52 static bool WriteAndSyncFile(const std::string& data, const std::string& file) { 53 unique_fd fd(open(file.c_str(), O_WRONLY | O_NOFOLLOW | O_CLOEXEC)); 54 if (fd < 0) { 55 return false; 56 } 57 if (!android::base::WriteFully(fd, data.c_str(), data.size())) { 58 return false; 59 } 60 return fsync(fd) == 0; 61 } 62 63 std::string GetDsuSlot(const std::string& install_dir) { 64 return android::base::Basename(install_dir); 65 } 66 67 bool CanBootIntoGsi(std::string* error) { 68 // Always delete this as a safety precaution, so we can return to the 69 // original system image. If we're confident GSI will boot, this will 70 // get re-created by MarkSystemAsGsi. 71 android::base::RemoveFileIfExists(kGsiBootedIndicatorFile); 72 73 if (!IsGsiInstalled()) { 74 *error = "not detected"; 75 return false; 76 } 77 78 std::string boot_key; 79 if (!GetInstallStatus(&boot_key)) { 80 *error = "error ("s + strerror(errno) + ")"; 81 return false; 82 } 83 84 // Give up if we've failed to boot kMaxBootAttempts times. 85 int attempts; 86 if (GetBootAttempts(boot_key, &attempts)) { 87 if (attempts + 1 > kMaxBootAttempts) { 88 *error = "exceeded max boot attempts"; 89 return false; 90 } 91 92 std::string new_key; 93 if (!access(kDsuOneShotBootFile, F_OK)) { 94 // Mark the GSI as disabled. This only affects the next boot, not 95 // the current boot. Note that we leave the one_shot status behind. 96 // This is so IGsiService can still return GSI_STATE_SINGLE_BOOT 97 // while the GSI is running. 98 new_key = kInstallStatusDisabled; 99 } else { 100 new_key = std::to_string(attempts + 1); 101 } 102 if (!WriteAndSyncFile(new_key, kDsuInstallStatusFile)) { 103 *error = "error ("s + strerror(errno) + ")"; 104 return false; 105 } 106 return true; 107 } 108 109 if (boot_key != kInstallStatusOk) { 110 *error = "not enabled"; 111 return false; 112 } 113 return true; 114 } 115 116 bool UninstallGsi() { 117 return android::base::WriteStringToFile(kInstallStatusWipe, kDsuInstallStatusFile); 118 } 119 120 bool DisableGsi() { 121 return android::base::WriteStringToFile(kInstallStatusDisabled, kDsuInstallStatusFile); 122 } 123 124 bool MarkSystemAsGsi() { 125 return android::base::WriteStringToFile("1", kGsiBootedIndicatorFile); 126 } 127 128 bool GetInstallStatus(std::string* status) { 129 return android::base::ReadFileToString(kDsuInstallStatusFile, status); 130 } 131 132 bool GetBootAttempts(const std::string& boot_key, int* attempts) { 133 return android::base::ParseInt(boot_key, attempts); 134 } 135 136 } // namespace gsi 137 } // namespace android 138