Call update_engine_sideload from recovery.

am: 4344d636d4

Change-Id: Ic9586cb3176bf608d2044e37b89e570c71130dcc
This commit is contained in:
Alex Deymo
2016-08-12 18:06:56 +00:00
committed by android-build-merger
2 changed files with 190 additions and 43 deletions

View File

@@ -16,36 +16,15 @@
#include "device.h" #include "device.h"
#if defined(AB_OTA_UPDATER)
static const char* MENU_ITEMS[] = {
"Reboot system now",
"Reboot to bootloader",
"Wipe data/factory reset",
"Mount /system",
"Run graphics test",
"Power off",
NULL,
};
static const Device::BuiltinAction MENU_ACTIONS[] = {
Device::REBOOT,
Device::REBOOT_BOOTLOADER,
Device::WIPE_DATA,
Device::MOUNT_SYSTEM,
Device::RUN_GRAPHICS_TEST,
Device::SHUTDOWN,
};
#else
static const char* MENU_ITEMS[] = { static const char* MENU_ITEMS[] = {
"Reboot system now", "Reboot system now",
"Reboot to bootloader", "Reboot to bootloader",
"Apply update from ADB", "Apply update from ADB",
"Apply update from SD card", "Apply update from SD card",
"Wipe data/factory reset", "Wipe data/factory reset",
#ifndef AB_OTA_UPDATER
"Wipe cache partition", "Wipe cache partition",
#endif // !AB_OTA_UPDATER
"Mount /system", "Mount /system",
"View recovery logs", "View recovery logs",
"Run graphics test", "Run graphics test",
@@ -59,14 +38,19 @@ static const Device::BuiltinAction MENU_ACTIONS[] = {
Device::APPLY_ADB_SIDELOAD, Device::APPLY_ADB_SIDELOAD,
Device::APPLY_SDCARD, Device::APPLY_SDCARD,
Device::WIPE_DATA, Device::WIPE_DATA,
#ifndef AB_OTA_UPDATER
Device::WIPE_CACHE, Device::WIPE_CACHE,
#endif // !AB_OTA_UPDATER
Device::MOUNT_SYSTEM, Device::MOUNT_SYSTEM,
Device::VIEW_RECOVERY_LOGS, Device::VIEW_RECOVERY_LOGS,
Device::RUN_GRAPHICS_TEST, Device::RUN_GRAPHICS_TEST,
Device::SHUTDOWN, Device::SHUTDOWN,
}; };
#endif static_assert(sizeof(MENU_ITEMS) / sizeof(MENU_ITEMS[0]) ==
sizeof(MENU_ACTIONS) / sizeof(MENU_ACTIONS[0]) + 1,
"MENU_ITEMS and MENU_ACTIONS should have the same length, "
"except for the extra NULL entry in MENU_ITEMS.");
const char* const* Device::GetMenuItems() { const char* const* Device::GetMenuItems() {
return MENU_ITEMS; return MENU_ITEMS;

View File

@@ -24,12 +24,15 @@
#include <unistd.h> #include <unistd.h>
#include <chrono> #include <chrono>
#include <limits>
#include <map>
#include <string> #include <string>
#include <vector> #include <vector>
#include <android-base/parseint.h> #include <android-base/parseint.h>
#include <android-base/stringprintf.h> #include <android-base/stringprintf.h>
#include <android-base/strings.h> #include <android-base/strings.h>
#include <cutils/properties.h>
#include "common.h" #include "common.h"
#include "error_code.h" #include "error_code.h"
@@ -46,6 +49,8 @@
extern RecoveryUI* ui; extern RecoveryUI* ui;
#define ASSUMED_UPDATE_BINARY_NAME "META-INF/com/google/android/update-binary" #define ASSUMED_UPDATE_BINARY_NAME "META-INF/com/google/android/update-binary"
static constexpr const char* AB_OTA_PAYLOAD_PROPERTIES = "payload_properties.txt";
static constexpr const char* AB_OTA_PAYLOAD = "payload.bin";
#define PUBLIC_KEYS_FILE "/res/keys" #define PUBLIC_KEYS_FILE "/res/keys"
static constexpr const char* METADATA_PATH = "META-INF/com/android/metadata"; static constexpr const char* METADATA_PATH = "META-INF/com/android/metadata";
@@ -113,17 +118,152 @@ static void read_source_target_build(ZipArchive* zip, std::vector<std::string>&
} }
} }
// If the package contains an update binary, extract it and run it. // Extract the update binary from the open zip archive |zip| located at |path|
// and store into |cmd| the command line that should be called. The |status_fd|
// is the file descriptor the child process should use to report back the
// progress of the update.
static int static int
try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache, update_binary_command(const char* path, ZipArchive* zip, int retry_count,
std::vector<std::string>& log_buffer, int retry_count) int status_fd, std::vector<std::string>* cmd);
{
read_source_target_build(zip, log_buffer);
#ifdef AB_OTA_UPDATER
// Parses the metadata of the OTA package in |zip| and checks whether we are
// allowed to accept this A/B package. Downgrading is not allowed unless
// explicitly enabled in the package and only for incremental packages.
static int check_newer_ab_build(ZipArchive* zip)
{
std::string metadata_str;
if (!read_metadata_from_package(zip, &metadata_str)) {
return INSTALL_CORRUPT;
}
std::map<std::string, std::string> metadata;
for (const std::string& line : android::base::Split(metadata_str, "\n")) {
size_t eq = line.find('=');
if (eq != std::string::npos) {
metadata[line.substr(0, eq)] = line.substr(eq + 1);
}
}
char value[PROPERTY_VALUE_MAX];
property_get("ro.product.device", value, "");
const std::string& pkg_device = metadata["pre-device"];
if (pkg_device != value || pkg_device.empty()) {
LOGE("Package is for product %s but expected %s\n",
pkg_device.c_str(), value);
return INSTALL_ERROR;
}
// We allow the package to not have any serialno, but if it has a non-empty
// value it should match.
property_get("ro.serialno", value, "");
const std::string& pkg_serial_no = metadata["serialno"];
if (!pkg_serial_no.empty() && pkg_serial_no != value) {
LOGE("Package is for serial %s\n", pkg_serial_no.c_str());
return INSTALL_ERROR;
}
if (metadata["ota-type"] != "AB") {
LOGE("Package is not A/B\n");
return INSTALL_ERROR;
}
// Incremental updates should match the current build.
property_get("ro.build.version.incremental", value, "");
const std::string& pkg_pre_build = metadata["pre-build-incremental"];
if (!pkg_pre_build.empty() && pkg_pre_build != value) {
LOGE("Package is for source build %s but expected %s\n",
pkg_pre_build.c_str(), value);
return INSTALL_ERROR;
}
property_get("ro.build.fingerprint", value, "");
const std::string& pkg_pre_build_fingerprint = metadata["pre-build"];
if (!pkg_pre_build_fingerprint.empty() &&
pkg_pre_build_fingerprint != value) {
LOGE("Package is for source build %s but expected %s\n",
pkg_pre_build_fingerprint.c_str(), value);
return INSTALL_ERROR;
}
// Check for downgrade version.
int64_t build_timestampt = property_get_int64(
"ro.build.date.utc", std::numeric_limits<int64_t>::max());
int64_t pkg_post_timespampt = 0;
// We allow to full update to the same version we are running, in case there
// is a problem with the current copy of that version.
if (metadata["post-timestamp"].empty() ||
!android::base::ParseInt(metadata["post-timestamp"].c_str(),
&pkg_post_timespampt) ||
pkg_post_timespampt < build_timestampt) {
if (metadata["ota-downgrade"] != "yes") {
LOGE("Update package is older than the current build, expected a "
"build newer than timestamp %" PRIu64 " but package has "
"timestamp %" PRIu64 " and downgrade not allowed.\n",
build_timestampt, pkg_post_timespampt);
return INSTALL_ERROR;
}
if (pkg_pre_build_fingerprint.empty()) {
LOGE("Downgrade package must have a pre-build version set, not "
"allowed.\n");
return INSTALL_ERROR;
}
}
return 0;
}
static int
update_binary_command(const char* path, ZipArchive* zip, int retry_count,
int status_fd, std::vector<std::string>* cmd)
{
int ret = check_newer_ab_build(zip);
if (ret) {
return ret;
}
// For A/B updates we extract the payload properties to a buffer and obtain
// the RAW payload offset in the zip file.
const ZipEntry* properties_entry =
mzFindZipEntry(zip, AB_OTA_PAYLOAD_PROPERTIES);
if (!properties_entry) {
LOGE("Can't find %s\n", AB_OTA_PAYLOAD_PROPERTIES);
return INSTALL_CORRUPT;
}
std::vector<unsigned char> payload_properties(
mzGetZipEntryUncompLen(properties_entry));
if (!mzExtractZipEntryToBuffer(zip, properties_entry,
payload_properties.data())) {
LOGE("Can't extract %s\n", AB_OTA_PAYLOAD_PROPERTIES);
return INSTALL_CORRUPT;
}
const ZipEntry* payload_entry = mzFindZipEntry(zip, AB_OTA_PAYLOAD);
if (!payload_entry) {
LOGE("Can't find %s\n", AB_OTA_PAYLOAD);
return INSTALL_CORRUPT;
}
long payload_offset = mzGetZipEntryOffset(payload_entry);
*cmd = {
"/sbin/update_engine_sideload",
android::base::StringPrintf("--payload=file://%s", path),
android::base::StringPrintf("--offset=%ld", payload_offset),
"--headers=" + std::string(payload_properties.begin(),
payload_properties.end()),
android::base::StringPrintf("--status_fd=%d", status_fd),
};
return 0;
}
#else // !AB_OTA_UPDATER
static int
update_binary_command(const char* path, ZipArchive* zip, int retry_count,
int status_fd, std::vector<std::string>* cmd)
{
// On traditional updates we extract the update binary from the package.
const ZipEntry* binary_entry = const ZipEntry* binary_entry =
mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME); mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME);
if (binary_entry == NULL) { if (binary_entry == NULL) {
mzCloseZipArchive(zip);
return INSTALL_CORRUPT; return INSTALL_CORRUPT;
} }
@@ -131,22 +271,48 @@ try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache,
unlink(binary); unlink(binary);
int fd = creat(binary, 0755); int fd = creat(binary, 0755);
if (fd < 0) { if (fd < 0) {
mzCloseZipArchive(zip);
LOGE("Can't make %s\n", binary); LOGE("Can't make %s\n", binary);
return INSTALL_ERROR; return INSTALL_ERROR;
} }
bool ok = mzExtractZipEntryToFile(zip, binary_entry, fd); bool ok = mzExtractZipEntryToFile(zip, binary_entry, fd);
close(fd); close(fd);
mzCloseZipArchive(zip);
if (!ok) { if (!ok) {
LOGE("Can't copy %s\n", ASSUMED_UPDATE_BINARY_NAME); LOGE("Can't copy %s\n", ASSUMED_UPDATE_BINARY_NAME);
return INSTALL_ERROR; return INSTALL_ERROR;
} }
*cmd = {
binary,
EXPAND(RECOVERY_API_VERSION), // defined in Android.mk
std::to_string(status_fd),
path,
};
if (retry_count > 0)
cmd->push_back("retry");
return 0;
}
#endif // !AB_OTA_UPDATER
// If the package contains an update binary, extract it and run it.
static int
try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache,
std::vector<std::string>& log_buffer, int retry_count)
{
read_source_target_build(zip, log_buffer);
int pipefd[2]; int pipefd[2];
pipe(pipefd); pipe(pipefd);
std::vector<std::string> args;
int ret = update_binary_command(path, zip, retry_count, pipefd[1], &args);
mzCloseZipArchive(zip);
if (ret) {
close(pipefd[0]);
close(pipefd[1]);
return ret;
}
// When executing the update binary contained in the package, the // When executing the update binary contained in the package, the
// arguments passed are: // arguments passed are:
// //
@@ -196,22 +362,19 @@ try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache,
// update attempt. // update attempt.
// //
const char** args = (const char**)malloc(sizeof(char*) * 6); // Convert the vector to a NULL-terminated char* array suitable for execv.
args[0] = binary; const char* chr_args[args.size() + 1];
args[1] = EXPAND(RECOVERY_API_VERSION); // defined in Android.mk chr_args[args.size()] = NULL;
char* temp = (char*)malloc(10); for (size_t i = 0; i < args.size(); i++) {
sprintf(temp, "%d", pipefd[1]); chr_args[i] = args[i].c_str();
args[2] = temp; }
args[3] = (char*)path;
args[4] = retry_count > 0 ? "retry" : NULL;
args[5] = NULL;
pid_t pid = fork(); pid_t pid = fork();
if (pid == 0) { if (pid == 0) {
umask(022); umask(022);
close(pipefd[0]); close(pipefd[0]);
execv(binary, (char* const*)args); execv(chr_args[0], const_cast<char**>(chr_args));
fprintf(stdout, "E:Can't run %s (%s)\n", binary, strerror(errno)); fprintf(stdout, "E:Can't run %s (%s)\n", chr_args[0], strerror(errno));
_exit(-1); _exit(-1);
} }
close(pipefd[1]); close(pipefd[1]);