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