blob: 3b0db516c27ccf788686f96d8bd4f76254099172 [file] [log] [blame]
David Andersonee84d742019-01-07 18:10:29 -08001//
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
David Andersonb3aff182019-01-11 14:37:51 -080019#include <string.h>
David Andersonee84d742019-01-07 18:10:29 -080020#include <unistd.h>
21
David Andersonb3aff182019-01-11 14:37:51 -080022#include <string>
23
David Andersonee84d742019-01-07 18:10:29 -080024#include <android-base/file.h>
David Andersonb3aff182019-01-11 14:37:51 -080025#include <android-base/parseint.h>
Howard Chenee5c2b12019-11-08 11:57:47 +080026#include <android-base/strings.h>
David Anderson15d8b4c2019-02-01 16:30:31 -080027#include <android-base/unique_fd.h>
David Andersonee84d742019-01-07 18:10:29 -080028
29#include "file_paths.h"
David Andersonb3aff182019-01-11 14:37:51 -080030#include "libgsi_private.h"
David Andersonee84d742019-01-07 18:10:29 -080031
32namespace android {
33namespace gsi {
34
David Andersonb3aff182019-01-11 14:37:51 -080035using namespace std::literals;
Howard Chenee5c2b12019-11-08 11:57:47 +080036using android::base::ReadFileToString;
37using android::base::Split;
David Anderson15d8b4c2019-02-01 16:30:31 -080038using android::base::unique_fd;
David Andersonb3aff182019-01-11 14:37:51 -080039
David Andersonee84d742019-01-07 18:10:29 -080040bool IsGsiRunning() {
41 return !access(kGsiBootedIndicatorFile, F_OK);
42}
43
44bool IsGsiInstalled() {
David Anderson9bdf8632019-07-01 14:49:11 -070045 return !access(kDsuInstallStatusFile, F_OK);
David Andersonee84d742019-01-07 18:10:29 -080046}
47
David Anderson15d8b4c2019-02-01 16:30:31 -080048static bool WriteAndSyncFile(const std::string& data, const std::string& file) {
49 unique_fd fd(open(file.c_str(), O_WRONLY | O_NOFOLLOW | O_CLOEXEC));
50 if (fd < 0) {
51 return false;
52 }
53 if (!android::base::WriteFully(fd, data.c_str(), data.size())) {
54 return false;
55 }
56 return fsync(fd) == 0;
57}
58
Howard Chenee5c2b12019-11-08 11:57:47 +080059std::string GetDsuSlot(const std::string& install_dir) {
60 return android::base::Basename(install_dir);
61}
62
Howard Chend5229bf2019-09-15 23:16:06 +080063bool CanBootIntoGsi(std::string* error) {
64 // Always delete this as a safety precaution, so we can return to the
65 // original system image. If we're confident GSI will boot, this will
66 // get re-created by MarkSystemAsGsi.
67 android::base::RemoveFileIfExists(kGsiBootedIndicatorFile);
68
David Andersonc053b3b2019-01-08 18:22:07 -080069 if (!IsGsiInstalled()) {
David Andersonee84d742019-01-07 18:10:29 -080070 *error = "not detected";
71 return false;
72 }
David Andersonb3aff182019-01-11 14:37:51 -080073
74 std::string boot_key;
75 if (!GetInstallStatus(&boot_key)) {
76 *error = "error ("s + strerror(errno) + ")";
77 return false;
78 }
79
80 // Give up if we've failed to boot kMaxBootAttempts times.
81 int attempts;
82 if (GetBootAttempts(boot_key, &attempts)) {
David Anderson782b3232019-01-17 14:18:20 -080083 if (attempts + 1 > kMaxBootAttempts) {
David Andersonb3aff182019-01-11 14:37:51 -080084 *error = "exceeded max boot attempts";
85 return false;
86 }
David Anderson782b3232019-01-17 14:18:20 -080087
88 std::string new_key;
David Anderson9bdf8632019-07-01 14:49:11 -070089 if (!access(kDsuOneShotBootFile, F_OK)) {
David Anderson782b3232019-01-17 14:18:20 -080090 // Mark the GSI as disabled. This only affects the next boot, not
David Anderson564a04c2019-02-27 13:33:44 -080091 // the current boot. Note that we leave the one_shot status behind.
92 // This is so IGsiService can still return GSI_STATE_SINGLE_BOOT
93 // while the GSI is running.
David Anderson782b3232019-01-17 14:18:20 -080094 new_key = kInstallStatusDisabled;
95 } else {
96 new_key = std::to_string(attempts + 1);
97 }
David Anderson9bdf8632019-07-01 14:49:11 -070098 if (!WriteAndSyncFile(new_key, kDsuInstallStatusFile)) {
David Andersonb3aff182019-01-11 14:37:51 -080099 *error = "error ("s + strerror(errno) + ")";
100 return false;
101 }
102 return true;
103 }
104
David Andersone7a8ade2019-03-13 19:21:22 -0700105 if (boot_key != kInstallStatusOk) {
106 *error = "not enabled";
107 return false;
108 }
109 return true;
David Andersonee84d742019-01-07 18:10:29 -0800110}
111
David Andersonee84d742019-01-07 18:10:29 -0800112bool UninstallGsi() {
David Anderson9bdf8632019-07-01 14:49:11 -0700113 return android::base::WriteStringToFile(kInstallStatusWipe, kDsuInstallStatusFile);
David Andersona141ba82019-01-14 19:09:27 -0800114}
115
116bool DisableGsi() {
David Anderson9bdf8632019-07-01 14:49:11 -0700117 return android::base::WriteStringToFile(kInstallStatusDisabled, kDsuInstallStatusFile);
David Andersonee84d742019-01-07 18:10:29 -0800118}
119
120bool MarkSystemAsGsi() {
121 return android::base::WriteStringToFile("1", kGsiBootedIndicatorFile);
122}
123
David Andersonb3aff182019-01-11 14:37:51 -0800124bool GetInstallStatus(std::string* status) {
David Anderson9bdf8632019-07-01 14:49:11 -0700125 return android::base::ReadFileToString(kDsuInstallStatusFile, status);
David Andersonb3aff182019-01-11 14:37:51 -0800126}
127
128bool GetBootAttempts(const std::string& boot_key, int* attempts) {
129 return android::base::ParseInt(boot_key, attempts);
130}
131
David Andersonee84d742019-01-07 18:10:29 -0800132} // namespace gsi
133} // namespace android