summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp1
-rw-r--r--daemon.cpp12
-rw-r--r--file_paths.h7
-rw-r--r--gsi_service.cpp54
-rw-r--r--gsi_service.h4
-rw-r--r--gsid.rc3
-rw-r--r--include/libgsi/libgsi.h2
-rw-r--r--libgsi.cpp45
-rw-r--r--libgsi_private.h31
9 files changed, 143 insertions, 16 deletions
diff --git a/Android.bp b/Android.bp
index 62bca52..a44f391 100644
--- a/Android.bp
+++ b/Android.bp
@@ -69,6 +69,7 @@ cc_binary {
"libbinder",
"libgsi",
"libfs_mgr",
+ "libgsi",
"liblog",
"liblp",
"libutils",
diff --git a/daemon.cpp b/daemon.cpp
index 5f8576e..0ea1cb5 100644
--- a/daemon.cpp
+++ b/daemon.cpp
@@ -16,16 +16,26 @@
#include "gsi_service.h"
+#include <getopt.h>
+
+#include <string>
+
#include <android-base/logging.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
using android::ProcessState;
using android::sp;
+using namespace std::literals;
-int main(int /* argc */, char** argv) {
+int main(int argc, char** argv) {
android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));
+ if (argc > 1 && argv[1] == "run-startup-tasks"s) {
+ android::gsi::GsiService::RunStartupTasks();
+ exit(0);
+ }
+
android::gsi::GsiService::Register();
{
sp<ProcessState> ps(ProcessState::self());
diff --git a/file_paths.h b/file_paths.h
index 078540f..b305db3 100644
--- a/file_paths.h
+++ b/file_paths.h
@@ -26,8 +26,13 @@ static constexpr char kSystemFile[] = "/data/unencrypted/gsi/system_gsi.img";
static constexpr char kGsiMetadataFolder[] = "/metadata/gsi";
static constexpr char kGsiLpMetadataFile[] = "/metadata/gsi/lp_metadata";
-static constexpr char kGsiBootableFile[] = "/metadata/gsi/bootable";
static constexpr char kGsiMetadata[] = "/metadata/gsi/lp_metadata";
+// This file can contain the following values:
+// [int] - boot attempt counter, starting from 0
+// "ok" - boot was marked successful
+// "disabled" - boot into GSI no longer allowed
+static constexpr char kGsiInstallStatusFile[] = "/metadata/gsi/install_status";
+
} // namespace gsi
} // namespace android
diff --git a/gsi_service.cpp b/gsi_service.cpp
index d30ba07..95d5255 100644
--- a/gsi_service.cpp
+++ b/gsi_service.cpp
@@ -33,7 +33,9 @@
#include <fs_mgr_dm_linear.h>
#include <libfiemap_writer/fiemap_writer.h>
#include <logwrap/logwrap.h>
+
#include "file_paths.h"
+#include "libgsi_private.h"
namespace android {
namespace gsi {
@@ -317,7 +319,7 @@ bool GsiService::SetGsiBootable() {
return false;
}
- if (!CreateMetadataFile() || !CreateBootableFile()) {
+ if (!CreateMetadataFile() || !CreateInstallStatusFile()) {
return false;
}
@@ -325,11 +327,11 @@ bool GsiService::SetGsiBootable() {
return true;
}
-bool GsiService::RemoveGsiInstall() {
+static bool RemoveGsiFiles() {
const std::vector<std::string> files{
kUserdataFile,
kSystemFile,
- kGsiBootableFile,
+ kGsiInstallStatusFile,
kGsiLpMetadataFile,
};
bool ok = true;
@@ -340,6 +342,17 @@ bool GsiService::RemoveGsiInstall() {
ok = false;
}
}
+ return ok;
+}
+
+bool GsiService::RemoveGsiInstall() {
+ bool ok = false;
+ if (IsGsiRunning()) {
+ // Can't remove gsi files while running.
+ ok = UninstallGsi();
+ } else {
+ ok = RemoveGsiFiles();
+ }
installing_ = false;
return ok;
}
@@ -414,11 +427,9 @@ bool GsiService::AddPartitionFiemap(MetadataBuilder* builder, Partition* partiti
return true;
}
-bool GsiService::CreateBootableFile() {
- android::base::unique_fd fd(
- open(kGsiBootableFile, O_WRONLY | O_CLOEXEC | O_NOFOLLOW | O_CREAT, 0755));
- if (fd < 0) {
- LOG(ERROR) << "open: " << strerror(errno) << ": " << kGsiBootableFile;
+bool GsiService::CreateInstallStatusFile() {
+ if (!android::base::WriteStringToFile("0", kGsiInstallStatusFile)) {
+ PLOG(ERROR) << "write " << kGsiInstallStatusFile;
return false;
}
return true;
@@ -433,5 +444,32 @@ bool GsiService::EnsureFolderExists(const std::string& path) {
return false;
}
+void GsiService::RunStartupTasks() {
+ if (!IsGsiInstalled()) {
+ return;
+ }
+
+ std::string boot_key;
+ if (!GetInstallStatus(&boot_key)) {
+ PLOG(ERROR) << "read " << kGsiInstallStatusFile;
+ return;
+ }
+
+ if (!IsGsiRunning()) {
+ // Check if a wipe was requested from fastboot or adb-in-gsi.
+ if (boot_key == kInstallStatusWipe) {
+ RemoveGsiFiles();
+ }
+ } else {
+ int ignore;
+ if (GetBootAttempts(boot_key, &ignore)) {
+ // Mark the GSI as having successfully booted.
+ if (!android::base::WriteStringToFile(kInstallStatusOk, kGsiInstallStatusFile)) {
+ PLOG(ERROR) << "write " << kGsiInstallStatusFile;
+ }
+ }
+ }
+}
+
} // namespace gsi
} // namespace android
diff --git a/gsi_service.h b/gsi_service.h
index 1b20fd6..7f5d49b 100644
--- a/gsi_service.h
+++ b/gsi_service.h
@@ -48,6 +48,8 @@ class GsiService : public BinderService<GsiService>, public BnGsiService {
static char const* getServiceName() { return kGsiServiceName; }
+ static void RunStartupTasks();
+
private:
using LpMetadata = android::fs_mgr::LpMetadata;
using MetadataBuilder = android::fs_mgr::MetadataBuilder;
@@ -66,7 +68,7 @@ class GsiService : public BinderService<GsiService>, public BnGsiService {
android::fiemap_writer::FiemapWriter* writer);
std::unique_ptr<MetadataBuilder> CreateMetadataBuilder();
fiemap_writer::FiemapUniquePtr CreateFiemapWriter(const std::string& path, uint64_t size);
- bool CreateBootableFile();
+ bool CreateInstallStatusFile();
bool CreateMetadataFile();
void PostInstallCleanup();
diff --git a/gsid.rc b/gsid.rc
index cf99ec1..81ff606 100644
--- a/gsid.rc
+++ b/gsid.rc
@@ -3,3 +3,6 @@ service gsid /system/bin/gsid
disabled
user root
group root
+
+on boot
+ exec - gsid gsid -- /system/bin/gsid run-startup-tasks
diff --git a/include/libgsi/libgsi.h b/include/libgsi/libgsi.h
index 705636c..ba5dd71 100644
--- a/include/libgsi/libgsi.h
+++ b/include/libgsi/libgsi.h
@@ -25,6 +25,8 @@ static constexpr char kGsiServiceName[] = "gsiservice";
static constexpr char kGsiBootedIndicatorFile[] = "/metadata/gsi/booted";
+static constexpr int kMaxBootAttempts = 3;
+
// Returns true if the currently running system image is a live GSI.
bool IsGsiRunning();
diff --git a/libgsi.cpp b/libgsi.cpp
index 135fe04..7be4251 100644
--- a/libgsi.cpp
+++ b/libgsi.cpp
@@ -16,21 +16,28 @@
#include "libgsi/libgsi.h"
+#include <string.h>
#include <unistd.h>
+#include <string>
+
#include <android-base/file.h>
+#include <android-base/parseint.h>
#include "file_paths.h"
+#include "libgsi_private.h"
namespace android {
namespace gsi {
+using namespace std::literals;
+
bool IsGsiRunning() {
return !access(kGsiBootedIndicatorFile, F_OK);
}
bool IsGsiInstalled() {
- return !access(kGsiBootableFile, F_OK);
+ return !access(kGsiInstallStatusFile, F_OK);
}
static bool CanBootIntoGsi(std::string* error) {
@@ -38,8 +45,29 @@ static bool CanBootIntoGsi(std::string* error) {
*error = "not detected";
return false;
}
- // :TODO: boot attempts
- return true;
+
+ std::string boot_key;
+ if (!GetInstallStatus(&boot_key)) {
+ *error = "error ("s + strerror(errno) + ")";
+ return false;
+ }
+
+ // Give up if we've failed to boot kMaxBootAttempts times.
+ int attempts;
+ if (GetBootAttempts(boot_key, &attempts)) {
+ if (attempts + 1 >= kMaxBootAttempts) {
+ *error = "exceeded max boot attempts";
+ return false;
+ }
+ std::string new_key = std::to_string(attempts + 1);
+ if (!android::base::WriteStringToFile(new_key, kGsiInstallStatusFile)) {
+ *error = "error ("s + strerror(errno) + ")";
+ return false;
+ }
+ return true;
+ }
+
+ return boot_key == kInstallStatusOk;
}
bool CanBootIntoGsi(std::string* metadata_file, std::string* error) {
@@ -49,7 +77,6 @@ bool CanBootIntoGsi(std::string* metadata_file, std::string* error) {
android::base::RemoveFileIfExists(kGsiBootedIndicatorFile);
if (!CanBootIntoGsi(error)) {
- android::base::RemoveFileIfExists(kGsiBootableFile);
return false;
}
@@ -58,7 +85,7 @@ bool CanBootIntoGsi(std::string* metadata_file, std::string* error) {
}
bool UninstallGsi() {
- if (!android::base::RemoveFileIfExists(kGsiBootableFile)) {
+ if (!android::base::WriteStringToFile(kInstallStatusWipe, kGsiInstallStatusFile)) {
return false;
}
return true;
@@ -68,5 +95,13 @@ bool MarkSystemAsGsi() {
return android::base::WriteStringToFile("1", kGsiBootedIndicatorFile);
}
+bool GetInstallStatus(std::string* status) {
+ return android::base::ReadFileToString(kGsiInstallStatusFile, status);
+}
+
+bool GetBootAttempts(const std::string& boot_key, int* attempts) {
+ return android::base::ParseInt(boot_key, attempts);
+}
+
} // namespace gsi
} // namespace android
diff --git a/libgsi_private.h b/libgsi_private.h
new file mode 100644
index 0000000..54e4ab2
--- /dev/null
+++ b/libgsi_private.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+
+namespace android {
+namespace gsi {
+
+bool GetInstallStatus(std::string* status);
+bool GetBootAttempts(const std::string& boot_key, int* attempts);
+
+static constexpr char kInstallStatusOk[] = "ok";
+static constexpr char kInstallStatusWipe[] = "wipe";
+
+} // namespace gsi
+} // namespace android