Introduce a library to contain gsid's image creation logic.

README.md contains a full explanation. GsiInstaller's logic will be
removed in a follow-up CL.

Bug: 134536978
Test: libgsi_image_test gtest
Change-Id: I76f273e06bd8633c6c16e3f3c76ade28e59efe6f
diff --git a/gsi_service.cpp b/gsi_service.cpp
index 3d04fe1..3ee2e12 100644
--- a/gsi_service.cpp
+++ b/gsi_service.cpp
@@ -32,8 +32,10 @@
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <android/gsi/BnImageManager.h>
 #include <android/gsi/IGsiService.h>
 #include <fs_mgr.h>
+#include <libfiemap/image_manager.h>
 #include <private/android_filesystem_config.h>
 
 #include "file_paths.h"
@@ -86,7 +88,7 @@
 binder::Status GsiService::beginGsiInstall(const GsiInstallParams& given_params,
                                            int* _aidl_return) {
     ENFORCE_SYSTEM;
-    std::lock_guard<std::mutex> guard(main_lock_);
+    std::lock_guard<std::mutex> guard(lock_);
 
     // Make sure any interrupted installations are cleaned up.
     installer_ = nullptr;
@@ -111,7 +113,7 @@
 binder::Status GsiService::commitGsiChunkFromStream(const android::os::ParcelFileDescriptor& stream,
                                                     int64_t bytes, bool* _aidl_return) {
     ENFORCE_SYSTEM;
-    std::lock_guard<std::mutex> guard(main_lock_);
+    std::lock_guard<std::mutex> guard(lock_);
 
     if (!installer_) {
         *_aidl_return = false;
@@ -153,7 +155,7 @@
 binder::Status GsiService::commitGsiChunkFromMemory(const std::vector<uint8_t>& bytes,
                                                     bool* _aidl_return) {
     ENFORCE_SYSTEM;
-    std::lock_guard<std::mutex> guard(main_lock_);
+    std::lock_guard<std::mutex> guard(lock_);
 
     if (!installer_) {
         *_aidl_return = false;
@@ -165,7 +167,7 @@
 }
 
 binder::Status GsiService::setGsiBootable(bool one_shot, int* _aidl_return) {
-    std::lock_guard<std::mutex> guard(main_lock_);
+    std::lock_guard<std::mutex> guard(lock_);
 
     if (installer_) {
         ENFORCE_SYSTEM;
@@ -185,7 +187,7 @@
 
 binder::Status GsiService::isGsiEnabled(bool* _aidl_return) {
     ENFORCE_SYSTEM_OR_SHELL;
-    std::lock_guard<std::mutex> guard(main_lock_);
+    std::lock_guard<std::mutex> guard(lock_);
     std::string boot_key;
     if (!GetInstallStatus(&boot_key)) {
         *_aidl_return = false;
@@ -197,7 +199,7 @@
 
 binder::Status GsiService::removeGsiInstall(bool* _aidl_return) {
     ENFORCE_SYSTEM_OR_SHELL;
-    std::lock_guard<std::mutex> guard(main_lock_);
+    std::lock_guard<std::mutex> guard(lock_);
 
     // Just in case an install was left hanging.
     std::string install_dir;
@@ -218,7 +220,7 @@
 
 binder::Status GsiService::disableGsiInstall(bool* _aidl_return) {
     ENFORCE_SYSTEM_OR_SHELL;
-    std::lock_guard<std::mutex> guard(main_lock_);
+    std::lock_guard<std::mutex> guard(lock_);
 
     *_aidl_return = DisableGsiInstall();
     return binder::Status::ok();
@@ -226,7 +228,7 @@
 
 binder::Status GsiService::isGsiRunning(bool* _aidl_return) {
     ENFORCE_SYSTEM_OR_SHELL;
-    std::lock_guard<std::mutex> guard(main_lock_);
+    std::lock_guard<std::mutex> guard(lock_);
 
     *_aidl_return = IsGsiRunning();
     return binder::Status::ok();
@@ -234,7 +236,7 @@
 
 binder::Status GsiService::isGsiInstalled(bool* _aidl_return) {
     ENFORCE_SYSTEM_OR_SHELL;
-    std::lock_guard<std::mutex> guard(main_lock_);
+    std::lock_guard<std::mutex> guard(lock_);
 
     *_aidl_return = IsGsiInstalled();
     return binder::Status::ok();
@@ -242,7 +244,7 @@
 
 binder::Status GsiService::isGsiInstallInProgress(bool* _aidl_return) {
     ENFORCE_SYSTEM_OR_SHELL;
-    std::lock_guard<std::mutex> guard(main_lock_);
+    std::lock_guard<std::mutex> guard(lock_);
 
     *_aidl_return = !!installer_;
     return binder::Status::ok();
@@ -251,7 +253,7 @@
 binder::Status GsiService::cancelGsiInstall(bool* _aidl_return) {
     ENFORCE_SYSTEM;
     should_abort_ = true;
-    std::lock_guard<std::mutex> guard(main_lock_);
+    std::lock_guard<std::mutex> guard(lock_);
 
     should_abort_ = false;
     installer_ = nullptr;
@@ -262,7 +264,7 @@
 
 binder::Status GsiService::getGsiBootStatus(int* _aidl_return) {
     ENFORCE_SYSTEM_OR_SHELL;
-    std::lock_guard<std::mutex> guard(main_lock_);
+    std::lock_guard<std::mutex> guard(lock_);
 
     if (!IsGsiInstalled()) {
         *_aidl_return = BOOT_STATUS_NOT_INSTALLED;
@@ -301,7 +303,7 @@
 
 binder::Status GsiService::getUserdataImageSize(int64_t* _aidl_return) {
     ENFORCE_SYSTEM;
-    std::lock_guard<std::mutex> guard(main_lock_);
+    std::lock_guard<std::mutex> guard(lock_);
 
     *_aidl_return = -1;
 
@@ -341,7 +343,7 @@
 
 binder::Status GsiService::getInstalledGsiImageDir(std::string* _aidl_return) {
     ENFORCE_SYSTEM;
-    std::lock_guard<std::mutex> guard(main_lock_);
+    std::lock_guard<std::mutex> guard(lock_);
 
     if (IsGsiInstalled()) {
         *_aidl_return = GetInstalledImageDir();
@@ -351,7 +353,7 @@
 
 binder::Status GsiService::wipeGsiUserdata(int* _aidl_return) {
     ENFORCE_SYSTEM_OR_SHELL;
-    std::lock_guard<std::mutex> guard(main_lock_);
+    std::lock_guard<std::mutex> guard(lock_);
 
     if (IsGsiRunning() || !IsGsiInstalled()) {
         *_aidl_return = IGsiService::INSTALL_ERROR_GENERIC;
@@ -364,6 +366,124 @@
     return binder::Status::ok();
 }
 
+static binder::Status BinderError(const std::string& message) {
+    return binder::Status::fromExceptionCode(binder::Status::EX_SERVICE_SPECIFIC,
+                                             String8(message.c_str()));
+}
+
+static binder::Status UidSecurityError() {
+    uid_t uid = IPCThreadState::self()->getCallingUid();
+    auto message = StringPrintf("UID %d is not allowed", uid);
+    return binder::Status::fromExceptionCode(binder::Status::EX_SECURITY, String8(message.c_str()));
+}
+
+class ImageManagerService : public BinderService<ImageManagerService>, public BnImageManager {
+  public:
+    ImageManagerService(GsiService* parent, std::unique_ptr<ImageManager>&& impl, uid_t uid);
+    binder::Status createBackingImage(const std::string& name, int64_t size,
+                                      bool readonly) override;
+    binder::Status deleteBackingImage(const std::string& name) override;
+    binder::Status mapImageDevice(const std::string& name, int32_t timeout_ms,
+                                  MappedImage* mapping) override;
+    binder::Status unmapImageDevice(const std::string& name) override;
+
+  private:
+    bool CheckUid();
+
+    android::sp<GsiService> parent_;
+    std::unique_ptr<ImageManager> impl_;
+    uid_t uid_;
+};
+
+ImageManagerService::ImageManagerService(GsiService* parent, std::unique_ptr<ImageManager>&& impl,
+                                         uid_t uid)
+    : parent_(parent), impl_(std::move(impl)), uid_(uid) {}
+
+binder::Status ImageManagerService::createBackingImage(const std::string& name, int64_t size,
+                                                       bool readonly) {
+    if (!CheckUid()) return UidSecurityError();
+
+    std::lock_guard<std::mutex> guard(*parent_->lock());
+
+    if (!impl_->CreateBackingImage(name, size, readonly, nullptr)) {
+        return BinderError("Failed to create");
+    }
+    return binder::Status::ok();
+}
+
+binder::Status ImageManagerService::deleteBackingImage(const std::string& name) {
+    if (!CheckUid()) return UidSecurityError();
+
+    std::lock_guard<std::mutex> guard(*parent_->lock());
+
+    if (!impl_->DeleteBackingImage(name)) {
+        return BinderError("Failed to delete");
+    }
+    return binder::Status::ok();
+}
+
+binder::Status ImageManagerService::mapImageDevice(const std::string& name, int32_t timeout_ms,
+                                                   MappedImage* mapping) {
+    if (!CheckUid()) return UidSecurityError();
+
+    std::lock_guard<std::mutex> guard(*parent_->lock());
+
+    if (!impl_->MapImageDevice(name, std::chrono::milliseconds(timeout_ms), &mapping->path)) {
+        return BinderError("Failed to map");
+    }
+    return binder::Status::ok();
+}
+
+binder::Status ImageManagerService::unmapImageDevice(const std::string& name) {
+    if (!CheckUid()) return UidSecurityError();
+
+    std::lock_guard<std::mutex> guard(*parent_->lock());
+
+    if (!impl_->UnmapImageDevice(name)) {
+        return BinderError("Failed to unmap");
+    }
+    return binder::Status::ok();
+}
+
+bool ImageManagerService::CheckUid() {
+    return uid_ == IPCThreadState::self()->getCallingUid();
+}
+
+binder::Status GsiService::openImageManager(const std::string& prefix,
+                                            android::sp<IImageManager>* _aidl_return) {
+    static constexpr char kImageMetadataPrefix[] = "/metadata/gsi/";
+    static constexpr char kImageDataPrefix[] = "/data/gsi/";
+
+    auto metadata_dir = kImageMetadataPrefix + prefix;
+    auto data_dir = kImageDataPrefix + prefix;
+
+    if (!android::base::Realpath(metadata_dir, &metadata_dir)) {
+        LOG(ERROR) << "realpath failed: " << metadata_dir;
+        return BinderError("Invalid path");
+    }
+    if (!android::base::Realpath(data_dir, &data_dir)) {
+        LOG(ERROR) << "realpath failed: " << data_dir;
+        return BinderError("Invalid path");
+    }
+    if (!android::base::StartsWith(metadata_dir, kImageMetadataPrefix) ||
+        !android::base::StartsWith(data_dir, kImageDataPrefix)) {
+        return BinderError("Invalid path");
+    }
+
+    uid_t uid = IPCThreadState::self()->getCallingUid();
+    if (uid != AID_ROOT) {
+        return UidSecurityError();
+    }
+
+    auto impl = ImageManager::Open(metadata_dir, data_dir);
+    if (!impl) {
+        return BinderError("Unknown error");
+    }
+
+    *_aidl_return = new ImageManagerService(this, std::move(impl), uid);
+    return binder::Status::ok();
+}
+
 binder::Status GsiService::CheckUid(AccessLevel level) {
     std::vector<uid_t> allowed_uids{AID_ROOT, AID_SYSTEM};
     if (level == AccessLevel::SystemOrShell) {
@@ -376,9 +496,7 @@
             return binder::Status::ok();
         }
     }
-
-    auto message = StringPrintf("UID %d is not allowed", uid);
-    return binder::Status::fromExceptionCode(binder::Status::EX_SECURITY, String8(message.c_str()));
+    return UidSecurityError();
 }
 
 static bool IsExternalStoragePath(const std::string& path) {