Merge "Adding a constant for /metadata/gsi/dsu/avb/."
diff --git a/Android.bp b/Android.bp
index e46c16a..1667ffb 100644
--- a/Android.bp
+++ b/Android.bp
@@ -95,6 +95,7 @@
     ],
     static_libs: [
         "gsi_aidl_interface-cpp",
+        "libavb",
         "libcutils",
         "libdm",
         "libext4_utils",
@@ -122,10 +123,11 @@
 filegroup {
     name: "gsiservice_aidl",
     srcs: [
+        "aidl/android/gsi/AvbPublicKey.aidl",
         "aidl/android/gsi/GsiProgress.aidl",
-        "aidl/android/gsi/IImageService.aidl",
         "aidl/android/gsi/IGsid.aidl",
         "aidl/android/gsi/IGsiService.aidl",
+        "aidl/android/gsi/IImageService.aidl",
         "aidl/android/gsi/IProgressCallback.aidl",
         "aidl/android/gsi/MappedImage.aidl",
     ],
diff --git a/aidl/android/gsi/AvbPublicKey.aidl b/aidl/android/gsi/AvbPublicKey.aidl
new file mode 100644
index 0000000..519ec80
--- /dev/null
+++ b/aidl/android/gsi/AvbPublicKey.aidl
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+package android.gsi;
+
+/** {@hide} */
+parcelable AvbPublicKey {
+    /* Raw data bytes. */
+    byte[] bytes;
+    /* SHA-1 digest of the key. */
+    byte[] sha1;
+}
diff --git a/aidl/android/gsi/IGsiService.aidl b/aidl/android/gsi/IGsiService.aidl
index cd48c63..65050fe 100644
--- a/aidl/android/gsi/IGsiService.aidl
+++ b/aidl/android/gsi/IGsiService.aidl
@@ -16,6 +16,7 @@
 
 package android.gsi;
 
+import android.gsi.AvbPublicKey;
 import android.gsi.GsiProgress;
 import android.gsi.IImageService;
 import android.os.ParcelFileDescriptor;
@@ -188,4 +189,20 @@
      * for dumpstate.
      */
     @utf8InCpp String dumpDeviceMapperDevices();
+
+    /**
+     * Retrieve AVB public key from the current mapped partition.
+     * This works only while partition device is mapped and the end-of-partition
+     * AVB footer has been written.
+     * A call to createPartition() does the following things:
+     * 1. Close the previous partition installer, thus unmap the partition.
+     * 2. Open a new partition installer.
+     * 3. Create and map the new partition.
+     *
+     * In other words, getAvbPublicKey() works between two createPartition() calls.
+     *
+     * @param dst           Output the AVB public key.
+     * @return              0 on success, an error code on failure.
+     */
+    int getAvbPublicKey(out AvbPublicKey dst);
 }
diff --git a/aidl/android/gsi/IImageService.aidl b/aidl/android/gsi/IImageService.aidl
index 5d9002f..c8c5a9d 100644
--- a/aidl/android/gsi/IImageService.aidl
+++ b/aidl/android/gsi/IImageService.aidl
@@ -16,6 +16,7 @@
 
 package android.gsi;
 
+import android.gsi.AvbPublicKey;
 import android.gsi.MappedImage;
 import android.gsi.IProgressCallback;
 
@@ -26,6 +27,11 @@
     const int CREATE_IMAGE_READONLY = 0x1;
     const int CREATE_IMAGE_ZERO_FILL = 0x2;
 
+    /* Successfully returned */
+    const int IMAGE_OK = 0;
+    /* Generic error code */
+    const int IMAGE_ERROR = 1;
+
     /**
      * Create an image that can be mapped as a block device.
      *
@@ -87,6 +93,18 @@
     boolean isImageMapped(@utf8InCpp String name);
 
     /**
+     * Retrieve AVB public key from an image.
+     * If the image is already mapped then it works the same as
+     * IGsiService::getAvbPublicKey(). Otherwise this will attempt to
+     * map / unmap the partition image upon enter / return.
+     *
+     * @param name          Image name as passed to createBackingImage().
+     * @param dst           Output of the AVB public key.
+     * @return              0 on success, an error code on failure.
+     */
+    int getAvbPublicKey(@utf8InCpp String name, out AvbPublicKey dst);
+
+    /**
      * Get all installed backing image names
      *
      * @return list of installed backing image names
diff --git a/gsi_service.cpp b/gsi_service.cpp
index 9b74502..3705c5b 100644
--- a/gsi_service.cpp
+++ b/gsi_service.cpp
@@ -25,6 +25,7 @@
 #include <sys/vfs.h>
 #include <unistd.h>
 
+#include <array>
 #include <chrono>
 #include <string>
 #include <vector>
@@ -38,8 +39,10 @@
 #include <android/gsi/IGsiService.h>
 #include <ext4_utils/ext4_utils.h>
 #include <fs_mgr.h>
+#include <libavb/libavb.h>
 #include <libdm/dm.h>
 #include <libfiemap/image_manager.h>
+#include <openssl/sha.h>
 #include <private/android_filesystem_config.h>
 
 #include "file_paths.h"
@@ -52,6 +55,7 @@
 using namespace android::fs_mgr;
 using namespace android::fiemap;
 using android::base::ReadFileToString;
+using android::base::ReadFullyAtOffset;
 using android::base::RemoveFileIfExists;
 using android::base::StringPrintf;
 using android::base::unique_fd;
@@ -66,6 +70,8 @@
 // Default userdata image size.
 static constexpr int64_t kDefaultUserdataSize = int64_t(2) * 1024 * 1024 * 1024;
 
+static bool GetAvbPublicKeyFromFd(int fd, AvbPublicKey* dst);
+
 void Gsid::Register() {
     auto ret = android::BinderService<Gsid>::publish();
     if (ret != android::OK) {
@@ -195,6 +201,7 @@
     }
     installer_ = std::make_unique<PartitionInstaller>(this, install_dir_, name,
                                                       GetDsuSlot(install_dir_), size, readOnly);
+    progress_ = {};
     int status = installer_->StartInstall();
     if (status != INSTALL_OK) {
         installer_ = nullptr;
@@ -241,6 +248,9 @@
     ENFORCE_SYSTEM;
     std::lock_guard<std::mutex> guard(progress_lock_);
 
+    if (installer_ == nullptr) {
+        progress_ = {};
+    }
     *_aidl_return = progress_;
     return binder::Status::ok();
 }
@@ -316,6 +326,7 @@
         // Can't remove gsi files while running.
         *_aidl_return = UninstallGsi();
     } else {
+        installer_ = {};
         *_aidl_return = RemoveGsiFiles(install_dir);
     }
     return binder::Status::ok();
@@ -440,6 +451,24 @@
     return binder::Status::ok();
 }
 
+binder::Status GsiService::getAvbPublicKey(AvbPublicKey* dst, int32_t* _aidl_return) {
+    ENFORCE_SYSTEM;
+    std::lock_guard<std::mutex> guard(parent_->lock());
+
+    if (!installer_) {
+        *_aidl_return = INSTALL_ERROR_GENERIC;
+        return binder::Status::ok();
+    }
+    int fd = installer_->GetPartitionFd();
+    if (!GetAvbPublicKeyFromFd(fd, dst)) {
+        LOG(ERROR) << "Failed to extract AVB public key";
+        *_aidl_return = INSTALL_ERROR_GENERIC;
+        return binder::Status::ok();
+    }
+    *_aidl_return = INSTALL_OK;
+    return binder::Status::ok();
+}
+
 bool GsiService::CreateInstallStatusFile() {
     if (!android::base::WriteStringToFile("0", kDsuInstallStatusFile)) {
         PLOG(ERROR) << "write " << kDsuInstallStatusFile;
@@ -482,6 +511,8 @@
     binder::Status unmapImageDevice(const std::string& name) override;
     binder::Status backingImageExists(const std::string& name, bool* _aidl_return) override;
     binder::Status isImageMapped(const std::string& name, bool* _aidl_return) override;
+    binder::Status getAvbPublicKey(const std::string& name, AvbPublicKey* dst,
+                                   int32_t* _aidl_return) override;
     binder::Status zeroFillNewImage(const std::string& name, int64_t bytes) override;
     binder::Status removeAllImages() override;
     binder::Status removeDisabledImages() override;
@@ -582,6 +613,46 @@
     return binder::Status::ok();
 }
 
+binder::Status ImageService::getAvbPublicKey(const std::string& name, AvbPublicKey* dst,
+                                             int32_t* _aidl_return) {
+    if (!CheckUid()) return UidSecurityError();
+
+    std::lock_guard<std::mutex> guard(parent_->lock());
+
+    std::string device_path;
+    std::unique_ptr<MappedDevice> mapped_device;
+    if (!impl_->IsImageMapped(name)) {
+        mapped_device = MappedDevice::Open(impl_.get(), 10s, name);
+        if (!mapped_device) {
+            PLOG(ERROR) << "Fail to map image: " << name;
+            *_aidl_return = IMAGE_ERROR;
+            return binder::Status::ok();
+        }
+        device_path = mapped_device->path();
+    } else {
+        if (!impl_->GetMappedImageDevice(name, &device_path)) {
+            PLOG(ERROR) << "GetMappedImageDevice() failed";
+            *_aidl_return = IMAGE_ERROR;
+            return binder::Status::ok();
+        }
+    }
+    android::base::unique_fd fd(open(device_path.c_str(), O_RDONLY | O_CLOEXEC));
+    if (!fd.ok()) {
+        PLOG(ERROR) << "Fail to open mapped device: " << device_path;
+        *_aidl_return = IMAGE_ERROR;
+        return binder::Status::ok();
+    }
+    bool ok = GetAvbPublicKeyFromFd(fd.get(), dst);
+    fd = {};
+    if (!ok) {
+        LOG(ERROR) << "Failed to extract AVB public key";
+        *_aidl_return = IMAGE_ERROR;
+        return binder::Status::ok();
+    }
+    *_aidl_return = IMAGE_OK;
+    return binder::Status::ok();
+}
+
 binder::Status ImageService::zeroFillNewImage(const std::string& name, int64_t bytes) {
     if (!CheckUid()) return UidSecurityError();
 
@@ -647,11 +718,11 @@
     }
     std::string metadata_dir, data_dir;
     if (!android::base::Realpath(in_metadata_dir, &metadata_dir)) {
-        PLOG(ERROR) << "realpath failed: " << metadata_dir;
+        PLOG(ERROR) << "realpath failed for metadata: " << in_metadata_dir;
         return BinderError("Invalid path");
     }
     if (!android::base::Realpath(in_data_dir, &data_dir)) {
-        PLOG(ERROR) << "realpath failed: " << data_dir;
+        PLOG(ERROR) << "realpath failed for data: " << in_data_dir;
         return BinderError("Invalid path");
     }
     if (!android::base::StartsWith(metadata_dir, kImageMetadataPrefix) ||
@@ -934,5 +1005,47 @@
     }
 }
 
+static bool GetAvbPublicKeyFromFd(int fd, AvbPublicKey* dst) {
+    // Read the AVB footer from EOF.
+    int64_t total_size = get_block_device_size(fd);
+    int64_t footer_offset = total_size - AVB_FOOTER_SIZE;
+    std::array<uint8_t, AVB_FOOTER_SIZE> footer_bytes;
+    if (!ReadFullyAtOffset(fd, footer_bytes.data(), AVB_FOOTER_SIZE, footer_offset)) {
+        PLOG(ERROR) << "cannot read AVB footer";
+        return false;
+    }
+    // Validate the AVB footer data and byte swap to native byte order.
+    AvbFooter footer;
+    if (!avb_footer_validate_and_byteswap((const AvbFooter*)footer_bytes.data(), &footer)) {
+        LOG(ERROR) << "invalid AVB footer";
+        return false;
+    }
+    // Read the VBMeta image.
+    std::vector<uint8_t> vbmeta_bytes(footer.vbmeta_size);
+    if (!ReadFullyAtOffset(fd, vbmeta_bytes.data(), vbmeta_bytes.size(), footer.vbmeta_offset)) {
+        PLOG(ERROR) << "cannot read VBMeta image";
+        return false;
+    }
+    // Validate the VBMeta image and retrieve AVB public key.
+    // After a successful call to avb_vbmeta_image_verify(), public_key_data
+    // will point to the serialized AVB public key, in the same format generated
+    // by the `avbtool extract_public_key` command.
+    const uint8_t* public_key_data;
+    size_t public_key_size;
+    AvbVBMetaVerifyResult result = avb_vbmeta_image_verify(vbmeta_bytes.data(), vbmeta_bytes.size(),
+                                                           &public_key_data, &public_key_size);
+    if (result != AVB_VBMETA_VERIFY_RESULT_OK) {
+        LOG(ERROR) << "invalid VBMeta image: " << avb_vbmeta_verify_result_to_string(result);
+        return false;
+    }
+    if (public_key_data != nullptr) {
+        dst->bytes.resize(public_key_size);
+        memcpy(dst->bytes.data(), public_key_data, public_key_size);
+        dst->sha1.resize(SHA_DIGEST_LENGTH);
+        SHA1(public_key_data, public_key_size, dst->sha1.data());
+    }
+    return true;
+}
+
 }  // namespace gsi
 }  // namespace android
diff --git a/gsi_service.h b/gsi_service.h
index b828899..a853e2b 100644
--- a/gsi_service.h
+++ b/gsi_service.h
@@ -82,6 +82,7 @@
     binder::Status openImageService(const std::string& prefix,
                                     android::sp<IImageService>* _aidl_return) override;
     binder::Status dumpDeviceMapperDevices(std::string* _aidl_return) override;
+    binder::Status getAvbPublicKey(AvbPublicKey* dst, int32_t* _aidl_return) override;
 
     // This is in GsiService, rather than GsiInstaller, since we need to access
     // it outside of the main lock which protects the unique_ptr.
diff --git a/gsi_tool.cpp b/gsi_tool.cpp
index 9abb1ff..a38bf20 100644
--- a/gsi_tool.cpp
+++ b/gsi_tool.cpp
@@ -31,6 +31,7 @@
 #include <android-base/logging.h>
 #include <android-base/parseint.h>
 #include <android-base/properties.h>
+#include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <android/gsi/IGsiService.h>
@@ -45,6 +46,7 @@
 
 using android::sp;
 using android::base::Split;
+using android::base::StringPrintf;
 using CommandCallback = std::function<int(sp<IGsiService>, int, char**)>;
 
 static int Disable(sp<IGsiService> gsid, int argc, char** argv);
@@ -438,6 +440,18 @@
         }
         for (auto&& image : images) {
             std::cout << "installed: " << image << std::endl;
+            AvbPublicKey public_key;
+            int err = 0;
+            status = image_service->getAvbPublicKey(image, &public_key, &err);
+            std::cout << "AVB public key (sha1): ";
+            if (!public_key.bytes.empty()) {
+                for (auto b : public_key.sha1) {
+                    std::cout << StringPrintf("%02x", b & 255);
+                }
+                std::cout << std::endl;
+            } else {
+                std::cout << "[NONE]" << std::endl;
+            }
         }
     }
     return 0;
diff --git a/partition_installer.cpp b/partition_installer.cpp
index ff2cc59..2ac313f 100644
--- a/partition_installer.cpp
+++ b/partition_installer.cpp
@@ -257,6 +257,10 @@
     return true;
 }
 
+int PartitionInstaller::GetPartitionFd() {
+    return system_device_->fd();
+}
+
 bool PartitionInstaller::MapAshmem(int fd, size_t size) {
     ashmem_size_ = size;
     ashmem_data_ = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
diff --git a/partition_installer.h b/partition_installer.h
index 830c034..1503648 100644
--- a/partition_installer.h
+++ b/partition_installer.h
@@ -48,6 +48,7 @@
     bool CommitGsiChunk(const void* data, size_t bytes);
     bool MapAshmem(int fd, size_t size);
     bool CommitGsiChunk(size_t bytes);
+    int GetPartitionFd();
 
     static int WipeWritable(const std::string& active_dsu, const std::string& install_dir,
                             const std::string& name);