recovery: Allow bypassing signature verification on non-release builds

For non-release (userdebug, eng) builds, when signature verification
fails, ask the user whether they wish to install anyway.

Change-Id: I950ad455e6f698cabe348f0482eb64287cc88a08
diff --git a/install/adb_install.cpp b/install/adb_install.cpp
index 84711d3..ad4be38 100644
--- a/install/adb_install.cpp
+++ b/install/adb_install.cpp
@@ -90,7 +90,11 @@
 
 // Installs the package from FUSE. Returns the installation result and whether it should continue
 // waiting for new commands.
-static auto AdbInstallPackageHandler(RecoveryUI* ui, int* result) {
+static auto AdbInstallPackageHandler(
+    Device* device, int* result,
+    const std::function<bool(Device*)>& ask_to_continue_unverified_fn) {
+  RecoveryUI* ui = device->GetUI();
+
   // How long (in seconds) we wait for the package path to be ready. It doesn't need to be too long
   // because the minadbd service has already issued an install command. FUSE_SIDELOAD_HOST_PATHNAME
   // will start to exist once the host connects and starts serving a package. Poll for its
@@ -111,7 +115,13 @@
       }
     }
     ui->CancelWaitKey();
-    *result = install_package(FUSE_SIDELOAD_HOST_PATHNAME, false, false, 0, ui);
+
+    *result = install_package(FUSE_SIDELOAD_HOST_PATHNAME, false, false, 0, true /* verify */, ui);
+    if (*result == INSTALL_UNVERIFIED && ask_to_continue_unverified_fn &&
+        ask_to_continue_unverified_fn(device)) {
+      *result =
+          install_package(FUSE_SIDELOAD_HOST_PATHNAME, false, false, 0, false /* verify */, ui);
+    }
     break;
   }
 
@@ -347,7 +357,8 @@
   signal(SIGPIPE, SIG_DFL);
 }
 
-int ApplyFromAdb(Device* device, bool rescue_mode, Device::BuiltinAction* reboot_action) {
+int ApplyFromAdb(Device* device, bool rescue_mode, Device::BuiltinAction* reboot_action,
+                 const std::function<bool(Device*)>& ask_to_continue_unverified_fn) {
   // Save the usb state to restore after the sideload operation.
   std::string usb_state = android::base::GetProperty("sys.usb.state", "none");
   // Clean up state and stop adbd.
@@ -356,11 +367,10 @@
     return INSTALL_ERROR;
   }
 
-  RecoveryUI* ui = device->GetUI();
-
   int install_result = INSTALL_ERROR;
   std::map<MinadbdCommand, CommandFunction> command_map{
-    { MinadbdCommand::kInstall, std::bind(&AdbInstallPackageHandler, ui, &install_result) },
+    { MinadbdCommand::kInstall, std::bind(&AdbInstallPackageHandler, device, &install_result,
+                                          ask_to_continue_unverified_fn) },
     { MinadbdCommand::kRebootAndroid, std::bind(&AdbRebootHandler, MinadbdCommand::kRebootAndroid,
                                                 &install_result, reboot_action) },
     { MinadbdCommand::kRebootBootloader,
@@ -374,6 +384,8 @@
       std::bind(&AdbRebootHandler, MinadbdCommand::kRebootRescue, &install_result, reboot_action) },
   };
 
+  RecoveryUI* ui = device->GetUI();
+
   if (!rescue_mode) {
     ui->Print(
         "\n\nNow send the package you want to apply\n"
diff --git a/install/fuse_sdcard_install.cpp b/install/fuse_sdcard_install.cpp
index e528e48..4d324c2 100644
--- a/install/fuse_sdcard_install.cpp
+++ b/install/fuse_sdcard_install.cpp
@@ -136,7 +136,8 @@
   return run_fuse_sideload(std::move(file_data_reader)) == 0;
 }
 
-int ApplyFromSdcard(Device* device, RecoveryUI* ui) {
+int ApplyFromSdcard(Device* device, RecoveryUI* ui,
+                    const std::function<bool(Device*)>& ask_to_continue_unverified_fn) {
   if (ensure_path_mounted(SDCARD_ROOT) != 0) {
     LOG(ERROR) << "\n-- Couldn't mount " << SDCARD_ROOT << ".\n";
     return INSTALL_ERROR;
@@ -190,7 +191,12 @@
       }
     }
 
-    result = install_package(FUSE_SIDELOAD_HOST_PATHNAME, false, false, 0 /*retry_count*/, ui);
+    result = install_package(FUSE_SIDELOAD_HOST_PATHNAME, false, false, 0 /*retry_count*/,
+                             true /* verify */, ui);
+    if (result == INSTALL_UNVERIFIED && ask_to_continue_unverified_fn(device)) {
+      result = install_package(FUSE_SIDELOAD_HOST_PATHNAME, false, false, 0 /*retry_count*/,
+                               false /* verify */, ui);
+    }
     break;
   }
 
diff --git a/install/include/install/adb_install.h b/install/include/install/adb_install.h
index 3a0a817..4c7b1ab 100644
--- a/install/include/install/adb_install.h
+++ b/install/include/install/adb_install.h
@@ -21,4 +21,5 @@
 // Applies a package via `adb sideload` or `adb rescue`. Returns the install result (in `enum
 // InstallResult`). When a reboot has been requested, INSTALL_REBOOT will be the return value, with
 // the reboot target set in reboot_action.
-int ApplyFromAdb(Device* device, bool rescue_mode, Device::BuiltinAction* reboot_action);
+int ApplyFromAdb(Device* device, bool rescue_mode, Device::BuiltinAction* reboot_action,
+                 const std::function<bool(Device*)>& ask_to_continue_unverified = nullptr);
diff --git a/install/include/install/fuse_sdcard_install.h b/install/include/install/fuse_sdcard_install.h
index d9214ca..7f47535 100644
--- a/install/include/install/fuse_sdcard_install.h
+++ b/install/include/install/fuse_sdcard_install.h
@@ -19,4 +19,5 @@
 #include "recovery_ui/device.h"
 #include "recovery_ui/ui.h"
 
-int ApplyFromSdcard(Device* device, RecoveryUI* ui);
+int ApplyFromSdcard(Device* device, RecoveryUI* ui,
+                    const std::function<bool(Device*)>& ask_to_continue_unverified_fn);
diff --git a/install/include/install/install.h b/install/include/install/install.h
index c0a8f1f..fe4c87e 100644
--- a/install/include/install/install.h
+++ b/install/include/install/install.h
@@ -36,6 +36,7 @@
   INSTALL_RETRY,
   INSTALL_KEY_INTERRUPTED,
   INSTALL_REBOOT,
+  INSTALL_UNVERIFIED,
 };
 
 enum class OtaType {
@@ -48,7 +49,7 @@
 // successful installation if |should_wipe_cache| is true or an updater command asks to wipe the
 // cache.
 int install_package(const std::string& package, bool should_wipe_cache, bool needs_mount,
-                    int retry_count, RecoveryUI* ui);
+                    int retry_count, bool verify, RecoveryUI* ui);
 
 // Verifies the package by ota keys. Returns true if the package is verified successfully,
 // otherwise returns false.
diff --git a/install/install.cpp b/install/install.cpp
index e2d4700..fd6d3f7 100644
--- a/install/install.cpp
+++ b/install/install.cpp
@@ -573,7 +573,7 @@
 
 static int really_install_package(const std::string& path, bool* wipe_cache, bool needs_mount,
                                   std::vector<std::string>* log_buffer, int retry_count,
-                                  int* max_temperature, RecoveryUI* ui) {
+                                  bool verify, int* max_temperature, RecoveryUI* ui) {
   ui->SetBackground(RecoveryUI::INSTALLING_UPDATE);
   ui->Print("Finding update package...\n");
   // Give verification half the progress bar...
@@ -600,9 +600,9 @@
   }
 
   // Verify package.
-  if (!verify_package(package.get(), ui)) {
+  if (verify && !verify_package(package.get(), ui)) {
     log_buffer->push_back(android::base::StringPrintf("error: %d", kZipVerificationFailure));
-    return INSTALL_CORRUPT;
+    return INSTALL_UNVERIFIED;
   }
 
   // Try to open the package.
@@ -633,7 +633,7 @@
 }
 
 int install_package(const std::string& path, bool should_wipe_cache, bool needs_mount,
-                    int retry_count, RecoveryUI* ui) {
+                    int retry_count, bool verify, RecoveryUI* ui) {
   CHECK(!path.empty());
 
   auto start = std::chrono::system_clock::now();
@@ -649,7 +649,7 @@
   } else {
     bool updater_wipe_cache = false;
     result = really_install_package(path, &updater_wipe_cache, needs_mount, &log_buffer,
-                                    retry_count, &max_temperature, ui);
+                                    retry_count, verify, &max_temperature, ui);
     should_wipe_cache = should_wipe_cache || updater_wipe_cache;
   }
 
diff --git a/recovery.cpp b/recovery.cpp
index fdd72bf..9973726 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -177,6 +177,15 @@
   return (chosen_item == 1);
 }
 
+static bool ask_to_continue_unverified_fn(Device* device) {
+  if (get_build_type() == "user") {
+    return false;
+  } else {
+    ui->SetProgressType(RecoveryUI::EMPTY);
+    return yes_no(device, "Signature verification failed", "Install anyway?");
+  }
+}
+
 static bool ask_to_wipe_data(Device* device) {
   std::vector<std::string> headers{ "Wipe all user data?", "  THIS CAN NOT BE UNDONE!" };
   std::vector<std::string> items{ " Cancel", " Factory data reset" };
@@ -574,10 +583,11 @@
           ui->ShowText(false);
           status = ApplyFromAdb(device, true /* rescue_mode */, &reboot_action);
         } else if (chosen_action == Device::APPLY_ADB_SIDELOAD) {
-          status = ApplyFromAdb(device, false /* rescue_mode */, &reboot_action);
+          status = ApplyFromAdb(device, false /* rescue_mode */, &reboot_action,
+                                ask_to_continue_unverified_fn);
         } else {
           adb = false;
-          status = ApplyFromSdcard(device, ui);
+          status = ApplyFromSdcard(device, ui, ask_to_continue_unverified_fn);
         }
 
         ui->Print("\nInstall from %s completed with status %d.\n", adb ? "ADB" : "SD card", status);
@@ -900,7 +910,8 @@
         set_retry_bootloader_message(retry_count + 1, args);
       }
 
-      status = install_package(update_package, should_wipe_cache, true, retry_count, ui);
+      status = install_package(update_package, should_wipe_cache, true, retry_count,
+                               true /* verify */, ui);
       if (status != INSTALL_SUCCESS) {
         ui->Print("Installation aborted.\n");
 
@@ -965,7 +976,8 @@
     if (!sideload_auto_reboot) {
       ui->ShowText(true);
     }
-    status = ApplyFromAdb(device, false /* rescue_mode */, &next_action);
+    status = ApplyFromAdb(device, false /* rescue_mode */, &next_action,
+                          !sideload_auto_reboot ? ask_to_continue_unverified_fn : nullptr);
     ui->Print("\nInstall from ADB complete (status: %d).\n", status);
     if (sideload_auto_reboot) {
       status = INSTALL_REBOOT;