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