Introduce libgsi, gsi_tool.
libgsi is a very small library to communicate critical gsi knowledge to
init and fs_mgr, to avoid hardcoding path names and constants.
gsi_tool is a shell wrapper to talk to gsid through binder.
gsid (currently in vold, will be moved shortly) is the daemon to manage
gsi installs.
Bug: 121210348
Test: N/A
Change-Id: I7942af56cb8e6ed69d28189bcf8d9806aa5e3e45
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..55773a2
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,11 @@
+BasedOnStyle: Google
+AccessModifierOffset: -2
+AllowShortFunctionsOnASingleLine: Inline
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+IndentWidth: 4
+ContinuationIndentWidth: 8
+PointerAlignment: Left
+TabWidth: 4
+UseTab: Never
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..6a1d992
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,51 @@
+//
+// Copyright (C) 2018 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.
+//
+
+cc_binary {
+ name: "gsi_tool",
+ shared_libs: [
+ "libbinder",
+ "libbase",
+ "liblog",
+ "libservices",
+ "libutils",
+ ],
+ static_libs: [
+ "libvold_binder",
+ ],
+ srcs: [
+ "gsi_tool.cpp",
+ ],
+}
+
+cc_library {
+ name: "libgsi",
+ recovery_available: true,
+ srcs: [
+ "libgsi.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ ],
+ export_include_dirs: ["include"],
+}
+
+cc_library_headers {
+ name: "libgsi_headers",
+ recovery_available: true,
+ vendor_available: true,
+ export_include_dirs: ["include"],
+}
diff --git a/file_paths.h b/file_paths.h
new file mode 100644
index 0000000..585461c
--- /dev/null
+++ b/file_paths.h
@@ -0,0 +1,26 @@
+//
+// 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
+
+namespace android {
+namespace gsi {
+
+static constexpr char kGsiBootableFile[] = "/metadata/vold/gsi/bootable";
+static constexpr char kGsiMetadata[] = "/metadata/vold/gsi/lp_metadata";
+
+} // namespace gsi
+} // namespace android
diff --git a/gsi_tool.cpp b/gsi_tool.cpp
new file mode 100644
index 0000000..5fbf569
--- /dev/null
+++ b/gsi_tool.cpp
@@ -0,0 +1,148 @@
+//
+// 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.
+//
+
+#include <getopt.h>
+#include <stdio.h>
+#include <sysexits.h>
+
+#include <functional>
+#include <iostream>
+#include <map>
+#include <string>
+
+#include <android-base/parseint.h>
+#include <android-base/unique_fd.h>
+#include <android/os/IVold.h>
+#include <binder/IServiceManager.h>
+
+using android::sp;
+using android::os::IVold;
+using CommandCallback = std::function<int(sp<IVold>, int, char**)>;
+
+static int Install(sp<IVold> vold, int argc, char** argv);
+static int Wipe(sp<IVold> vold, int argc, char** argv);
+
+static const std::map<std::string, CommandCallback> kCommandMap = {
+ {"install", Install},
+ {"wipe", Wipe},
+};
+
+static sp<IVold> getService() {
+ auto sm = android::defaultServiceManager();
+ auto name = android::String16("vold");
+ android::sp<android::IBinder> res = sm->checkService(name);
+ if (!res) {
+ return nullptr;
+ }
+ return android::interface_cast<android::os::IVold>(res);
+}
+
+static int Install([[maybe_unused]] sp<IVold> vold, int argc, char** argv) {
+ struct option options[] = {
+ {"gsi-size", required_argument, nullptr, 's'},
+ {"userdata-size", required_argument, nullptr, 'u'},
+ {nullptr, 0, nullptr, 0},
+ };
+
+ int64_t gsi_size = 0;
+ int64_t userdata_size = static_cast<int64_t>(1024 * 1024 * 1024) * 8;
+
+ int rv, index;
+ while ((rv = getopt_long_only(argc, argv, "", options, &index)) != -1) {
+ switch (rv) {
+ case 's':
+ if (!android::base::ParseInt(optarg, &gsi_size) || gsi_size <= 0) {
+ std::cout << "Could not parse image size: " << optarg << std::endl;
+ return EX_USAGE;
+ }
+ break;
+ case 'u':
+ if (!android::base::ParseInt(optarg, &userdata_size) || userdata_size <= 0) {
+ std::cout << "Could not parse image size: " << optarg << std::endl;
+ return EX_USAGE;
+ }
+ break;
+ }
+ }
+
+ if (gsi_size <= 0) {
+ std::cout << "Must specify --gsi-size." << std::endl;
+ return EX_USAGE;
+ }
+
+ android::base::unique_fd input(dup(1));
+ if (input < 0) {
+ std::cout << "Error duplicating descriptor: " << strerror(errno);
+ return EX_SOFTWARE;
+ }
+
+ auto status = vold->startGsiInstall(gsi_size, userdata_size);
+ if (!status.isOk()) {
+ std::cout << "Could not start live image install: " << status.exceptionMessage().string()
+ << std::endl;
+ return EX_SOFTWARE;
+ }
+
+ status = vold->commitGsiChunk(input, gsi_size);
+ if (!status.isOk()) {
+ std::cout << "Could not commit live image data: " << status.exceptionMessage().string()
+ << std::endl;
+ return EX_SOFTWARE;
+ }
+
+ status = vold->setGsiBootable();
+ if (!status.isOk()) {
+ std::cout << "Could not make live image bootable: " << status.exceptionMessage().string()
+ << std::endl;
+ return EX_SOFTWARE;
+ }
+ return 0;
+}
+
+static int Wipe(sp<IVold> vold, int argc, char** /* argv */) {
+ if (argc > 1) {
+ std::cout << "Unrecognized arguments to wipe." << std::endl;
+ return EX_USAGE;
+ }
+ auto status = vold->removeGsiInstall();
+ if (!status.isOk()) {
+ std::cout << status.exceptionMessage().string() << std::endl;
+ return EX_SOFTWARE;
+ }
+ std::cout << "Live image install successfully removed." << std::endl;
+ return 0;
+}
+
+int main(int argc, char** argv) {
+ auto vold = getService();
+ if (!vold) {
+ std::cout << "Could not connect to the vold service." << std::endl;
+ return EX_NOPERM;
+ }
+
+ if (1 >= argc) {
+ std::cout << "Expected command." << std::endl;
+ return EX_USAGE;
+ }
+
+ std::string command = argv[1];
+ auto iter = kCommandMap.find(command);
+ if (iter == kCommandMap.end()) {
+ std::cout << "Unrecognized command: " << command << std::endl;
+ return EX_USAGE;
+ }
+ return iter->second(vold, argc - 1, argv + 1);
+}
diff --git a/include/libgsi/libgsi.h b/include/libgsi/libgsi.h
new file mode 100644
index 0000000..e025c87
--- /dev/null
+++ b/include/libgsi/libgsi.h
@@ -0,0 +1,48 @@
+//
+// 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 {
+
+static constexpr char kGsiBootedIndicatorFile[] = "/metadata/vold/gsi/booted";
+
+// Returns true if the currently running system image is a live GSI.
+bool IsGsiRunning();
+
+// Return true if a GSI is installed (but not necessarily running).
+bool IsGsiInstalled();
+
+// Set the GSI as no longer bootable. This effectively removes the GSI. If no
+// GSI was bootable, false is returned.
+bool UninstallGsi();
+
+// Returns true if init should attempt to boot into a live GSI image, false
+// otherwise. If true, then the path to the liblp metadata file is set. If
+// false, an error message is set instead.
+//
+// This is only called by first-stage init.
+bool CanBootIntoGsi(std::string* metadata_file, std::string* error);
+
+// Called by first-stage init to indicate that we're about to boot into a
+// GSI.
+bool MarkSystemAsGsi();
+
+} // namespace gsi
+} // namespace android
diff --git a/libgsi.cpp b/libgsi.cpp
new file mode 100644
index 0000000..4291389
--- /dev/null
+++ b/libgsi.cpp
@@ -0,0 +1,68 @@
+//
+// 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.
+//
+
+#include "libgsi/libgsi.h"
+
+#include <unistd.h>
+
+#include <android-base/file.h>
+
+#include "file_paths.h"
+
+namespace android {
+namespace gsi {
+
+bool IsGsiRunning() {
+ return !access(kGsiBootedIndicatorFile, F_OK);
+}
+
+bool IsGsiInstalled() {
+ return !access(kGsiBootableFile, R_OK);
+}
+
+static bool CanBootIntoGsi(std::string* error) {
+ if (IsGsiInstalled()) {
+ *error = "not detected";
+ return false;
+ }
+ // :TODO: boot attempts
+ return true;
+}
+
+bool CanBootIntoGsi(std::string* metadata_file, std::string* error) {
+ if (!CanBootIntoGsi(error)) {
+ android::base::RemoveFileIfExists(kGsiBootedIndicatorFile);
+ android::base::RemoveFileIfExists(kGsiBootableFile);
+ return false;
+ }
+
+ *metadata_file = kGsiMetadata;
+ return true;
+}
+
+bool UninstallGsi() {
+ if (!android::base::RemoveFileIfExists(kGsiBootableFile)) {
+ return false;
+ }
+ return true;
+}
+
+bool MarkSystemAsGsi() {
+ return android::base::WriteStringToFile("1", kGsiBootedIndicatorFile);
+}
+
+} // namespace gsi
+} // namespace android