blob: b342cc54b3d81f4de2880cd0e559922d3eda32a6 [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
Howard Chenee5c2b12019-11-08 11:57:47 +080040bool GetActiveDsu(std::string* active_dsu) {
41 return android::base::ReadFileToString(kDsuActiveFile, active_dsu);
42}
43
David Andersonee84d742019-01-07 18:10:29 -080044bool IsGsiRunning() {
45 return !access(kGsiBootedIndicatorFile, F_OK);
46}
47
48bool IsGsiInstalled() {
David Anderson9bdf8632019-07-01 14:49:11 -070049 return !access(kDsuInstallStatusFile, F_OK);
David Andersonee84d742019-01-07 18:10:29 -080050}
51
David Anderson15d8b4c2019-02-01 16:30:31 -080052static 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
Howard Chenee5c2b12019-11-08 11:57:47 +080063std::string GetDsuSlot(const std::string& install_dir) {
64 return android::base::Basename(install_dir);
65}
66
Howard Chend5229bf2019-09-15 23:16:06 +080067bool 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
David Andersonc053b3b2019-01-08 18:22:07 -080073 if (!IsGsiInstalled()) {
David Andersonee84d742019-01-07 18:10:29 -080074 *error = "not detected";
75 return false;
76 }
David Andersonb3aff182019-01-11 14:37:51 -080077
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)) {
David Anderson782b3232019-01-17 14:18:20 -080087 if (attempts + 1 > kMaxBootAttempts) {
David Andersonb3aff182019-01-11 14:37:51 -080088 *error = "exceeded max boot attempts";
89 return false;
90 }
David Anderson782b3232019-01-17 14:18:20 -080091
92 std::string new_key;
David Anderson9bdf8632019-07-01 14:49:11 -070093 if (!access(kDsuOneShotBootFile, F_OK)) {
David Anderson782b3232019-01-17 14:18:20 -080094 // Mark the GSI as disabled. This only affects the next boot, not
David Anderson564a04c2019-02-27 13:33:44 -080095 // 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.
David Anderson782b3232019-01-17 14:18:20 -080098 new_key = kInstallStatusDisabled;
99 } else {
100 new_key = std::to_string(attempts + 1);
101 }
David Anderson9bdf8632019-07-01 14:49:11 -0700102 if (!WriteAndSyncFile(new_key, kDsuInstallStatusFile)) {
David Andersonb3aff182019-01-11 14:37:51 -0800103 *error = "error ("s + strerror(errno) + ")";
104 return false;
105 }
106 return true;
107 }
108
David Andersone7a8ade2019-03-13 19:21:22 -0700109 if (boot_key != kInstallStatusOk) {
110 *error = "not enabled";
111 return false;
112 }
113 return true;
David Andersonee84d742019-01-07 18:10:29 -0800114}
115
David Andersonee84d742019-01-07 18:10:29 -0800116bool UninstallGsi() {
David Anderson9bdf8632019-07-01 14:49:11 -0700117 return android::base::WriteStringToFile(kInstallStatusWipe, kDsuInstallStatusFile);
David Andersona141ba82019-01-14 19:09:27 -0800118}
119
120bool DisableGsi() {
David Anderson9bdf8632019-07-01 14:49:11 -0700121 return android::base::WriteStringToFile(kInstallStatusDisabled, kDsuInstallStatusFile);
David Andersonee84d742019-01-07 18:10:29 -0800122}
123
124bool MarkSystemAsGsi() {
125 return android::base::WriteStringToFile("1", kGsiBootedIndicatorFile);
126}
127
David Andersonb3aff182019-01-11 14:37:51 -0800128bool GetInstallStatus(std::string* status) {
David Anderson9bdf8632019-07-01 14:49:11 -0700129 return android::base::ReadFileToString(kDsuInstallStatusFile, status);
David Andersonb3aff182019-01-11 14:37:51 -0800130}
131
132bool GetBootAttempts(const std::string& boot_key, int* attempts) {
133 return android::base::ParseInt(boot_key, attempts);
134}
135
David Andersonee84d742019-01-07 18:10:29 -0800136} // namespace gsi
137} // namespace android