Merge "Build adbd apex with different linkages"
diff --git a/apexd/Android.bp b/apexd/Android.bp
index 66b546f..5c6abc4 100644
--- a/apexd/Android.bp
+++ b/apexd/Android.bp
@@ -378,6 +378,7 @@
     ":gen_corrupt_superblock_apex",
     ":gen_corrupt_apex",
     ":gen_capex_without_apex",
+    ":gen_key_mismatch_with_original_capex",
     ":com.android.apex.cts.shim.v1_prebuilt",
     ":com.android.apex.cts.shim.v2_prebuilt",
     ":com.android.apex.cts.shim.v2_wrong_sha_prebuilt",
diff --git a/apexd/apex_file.cpp b/apexd/apex_file.cpp
index 6169ad5..d65d426 100644
--- a/apexd/apex_file.cpp
+++ b/apexd/apex_file.cpp
@@ -39,6 +39,7 @@
 using android::base::borrowed_fd;
 using android::base::Error;
 using android::base::ReadFullyAtOffset;
+using android::base::RemoveFileIfExists;
 using android::base::Result;
 using android::base::unique_fd;
 
@@ -426,13 +427,33 @@
     return ErrnoError() << "Failed to open decompression destination "
                         << GetPath();
   }
+
+  // Prepare a guard that deletes the extracted file if anything goes wrong
+  auto decompressed_guard = android::base::make_scope_guard(
+      [&dest_path] { RemoveFileIfExists(dest_path); });
+
+  // Extract the original_apex to dest_path
   ret = ExtractEntryToFile(handle, &entry, dest_fd.get());
   if (ret < 0) {
     return Error() << "Could not decompress to file " << dest_path
                    << ErrorCodeString(ret);
   }
 
+  // Post decompression verification
+  auto decompressed_apex = ApexFile::Open(dest_path);
+  if (!decompressed_apex.ok()) {
+    return Error() << "Could not open decompressed APEX: "
+                   << decompressed_apex.error();
+  }
+  if (GetBundledPublicKey() != decompressed_apex->GetBundledPublicKey()) {
+    return Error()
+           << "Public key of compressed APEX is different than original APEX";
+  }
+
+  // Verification complete. Accept the decompressed file
+  decompressed_guard.Disable();
   LOG(VERBOSE) << "Decompressed " << src_path << " to " << dest_path;
+
   return {};
 }
 
diff --git a/apexd/apex_file_test.cpp b/apexd/apex_file_test.cpp
index 98f5a1b..39d664d 100644
--- a/apexd/apex_file_test.cpp
+++ b/apexd/apex_file_test.cpp
@@ -30,6 +30,7 @@
 #include "apexd_utils.h"
 
 using android::base::GetExecutableDirectory;
+using android::base::RemoveFileIfExists;
 using android::base::Result;
 
 static const std::string kTestDataDir = GetExecutableDirectory() + "/";
@@ -267,6 +268,31 @@
               ::testing::HasSubstr("Cannot decompress an uncompressed APEX"));
 }
 
+TEST(ApexFileTest, DecompressFailIfPublicKeyNotSameAsOriginal) {
+  const std::string compressed_file_path =
+      kTestDataDir +
+      "com.android.apex.compressed_key_mismatch_with_original.capex";
+  Result<ApexFile> compressed_apex_file = ApexFile::Open(compressed_file_path);
+  ASSERT_RESULT_OK(compressed_apex_file);
+
+  TemporaryFile decompression_file;
+  RemoveFileIfExists(decompression_file.path);
+
+  // Compressed APEX should fail to decompress if public key is different than
+  // original APEX
+  auto result = compressed_apex_file->Decompress(decompression_file.path);
+  ASSERT_FALSE(result.ok());
+  ASSERT_THAT(
+      result.error().message(),
+      ::testing::HasSubstr(
+          "Public key of compressed APEX is different than original APEX"));
+
+  // The decompressed_file should not exist
+  auto exist = PathExists(decompression_file.path);
+  ASSERT_RESULT_OK(exist);
+  ASSERT_FALSE(*exist);
+}
+
 }  // namespace
 }  // namespace apex
 }  // namespace android
diff --git a/apexd/apexd.cpp b/apexd/apexd.cpp
index 0c53cf9..e3733d8 100644
--- a/apexd/apexd.cpp
+++ b/apexd/apexd.cpp
@@ -119,6 +119,7 @@
 
 static constexpr size_t kLoopDeviceSetupAttempts = 3u;
 
+// Please DO NOT add new modules to this list without contacting mainline-modularization@ first.
 static const std::vector<std::string> kBootstrapApexes = ([]() {
   std::vector<std::string> ret = {
       "com.android.art",
diff --git a/apexd/apexd_testdata/Android.bp b/apexd/apexd_testdata/Android.bp
index e8e4808..302c13e 100644
--- a/apexd/apexd_testdata/Android.bp
+++ b/apexd/apexd_testdata/Android.bp
@@ -80,6 +80,17 @@
        "--output=$(genDir)/com.android.apex.compressed_different_key.capex"
 }
 
+genrule {
+  // Generates a capex which has a different public key than original_apex
+  name: "gen_key_mismatch_with_original_capex",
+  out: ["com.android.apex.compressed_key_mismatch_with_original.capex"],
+  srcs: [":com.android.apex.compressed.v1"],
+  tools: ["soong_zip"],
+  cmd: "unzip -q $(in) -d $(genDir) && " + // unzip input
+       "echo 'different-key' >> $(genDir)/apex_pubkey && " + // modify the public key
+       "$(location soong_zip) -d -C $(genDir) -D $(genDir) -L 9 " +// repack the compressed APEX
+       "-o $(genDir)/com.android.apex.compressed_key_mismatch_with_original.capex",
+}
 
 apex {
     name: "com.android.apex.compressed.v1_original",