turn recovery into a C++ binary

Change-Id: I423a23581048d451d53eef46e5f5eac485b77555
This commit is contained in:
Doug Zongker 2011-10-28 10:33:05 -07:00
parent d0181b8fcd
commit 28ce47cfa6
20 changed files with 253 additions and 147 deletions

View file

@ -4,12 +4,12 @@ include $(CLEAR_VARS)
commands_recovery_local_path := $(LOCAL_PATH)
LOCAL_SRC_FILES := \
recovery.c \
bootloader.c \
install.c \
roots.c \
ui.c \
verifier.c
recovery.cpp \
bootloader.cpp \
install.cpp \
roots.cpp \
ui.cpp \
verifier.cpp
LOCAL_MODULE := recovery
@ -50,7 +50,7 @@ include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := verifier_test.c verifier.c
LOCAL_SRC_FILES := verifier_test.cpp verifier.cpp
LOCAL_MODULE := verifier_test

View file

@ -17,6 +17,10 @@
#ifndef _RECOVERY_BOOTLOADER_H
#define _RECOVERY_BOOTLOADER_H
#ifdef __cplusplus
extern "C" {
#endif
/* Bootloader Message
*
* This structure describes the content of a block in flash
@ -47,4 +51,8 @@ struct bootloader_message {
int get_bootloader_message(struct bootloader_message *out);
int set_bootloader_message(const struct bootloader_message *in);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -19,61 +19,12 @@
#include <stdio.h>
// Initialize the graphics system.
void ui_init();
#ifdef __cplusplus
extern "C" {
#endif
// Use KEY_* codes from <linux/input.h> or KEY_DREAM_* from "minui/minui.h".
int ui_wait_key(); // waits for a key/button press, returns the code
int ui_key_pressed(int key); // returns >0 if the code is currently pressed
int ui_text_visible(); // returns >0 if text log is currently visible
int ui_text_ever_visible(); // returns >0 if text log was ever visible
void ui_show_text(int visible);
void ui_clear_key_queue();
// Write a message to the on-screen log shown with Alt-L (also to stderr).
// The screen is small, and users may need to report these messages to support,
// so keep the output short and not too cryptic.
void ui_print(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
// Display some header text followed by a menu of items, which appears
// at the top of the screen (in place of any scrolling ui_print()
// output, if necessary).
void ui_start_menu(char** headers, char** items, int initial_selection);
// Set the menu highlight to the given index, and return it (capped to
// the range [0..numitems).
int ui_menu_select(int sel);
// End menu mode, resetting the text overlay so that ui_print()
// statements will be displayed.
void ui_end_menu();
// Set the icon (normally the only thing visible besides the progress bar).
enum {
BACKGROUND_ICON_NONE,
BACKGROUND_ICON_INSTALLING,
BACKGROUND_ICON_ERROR,
NUM_BACKGROUND_ICONS
};
void ui_set_background(int icon);
// Show a progress bar and define the scope of the next operation:
// portion - fraction of the progress bar the next operation will use
// seconds - expected time interval (progress bar moves at this minimum rate)
void ui_show_progress(float portion, int seconds);
void ui_set_progress(float fraction); // 0.0 - 1.0 within the defined scope
// Default allocation of progress bar segments to operations
static const int VERIFICATION_PROGRESS_TIME = 60;
static const float VERIFICATION_PROGRESS_FRACTION = 0.25;
static const float DEFAULT_FILES_PROGRESS_FRACTION = 0.4;
static const float DEFAULT_IMAGE_PROGRESS_FRACTION = 0.1;
// Show a rotating "barberpole" for ongoing operations. Updates automatically.
void ui_show_indeterminate_progress();
// Hide and reset the progress bar.
void ui_reset_progress();
#define LOGE(...) ui_print("E:" __VA_ARGS__)
// TODO: restore ui_print for LOGE
#define LOGE(...) fprintf(stdout, "E:" __VA_ARGS__)
#define LOGW(...) fprintf(stdout, "W:" __VA_ARGS__)
#define LOGI(...) fprintf(stdout, "I:" __VA_ARGS__)
@ -129,4 +80,8 @@ typedef struct {
// fopen a file, mounting volumes and making parent dirs as necessary.
FILE* fopen_path(const char *path, const char *mode);
#ifdef __cplusplus
}
#endif
#endif // RECOVERY_COMMON_H

View file

@ -32,6 +32,7 @@
#include "mtdutils/mtdutils.h"
#include "roots.h"
#include "verifier.h"
#include "ui.h"
#define ASSUMED_UPDATE_BINARY_NAME "META-INF/com/google/android/update-binary"
#define PUBLIC_KEYS_FILE "/res/keys"
@ -46,7 +47,7 @@ try_update_binary(const char *path, ZipArchive *zip, int* wipe_cache) {
return INSTALL_CORRUPT;
}
char* binary = "/tmp/update_binary";
const char* binary = "/tmp/update_binary";
unlink(binary);
int fd = creat(binary, 0755);
if (fd < 0) {
@ -100,18 +101,19 @@ try_update_binary(const char *path, ZipArchive *zip, int* wipe_cache) {
// - the name of the package zip file.
//
char** args = malloc(sizeof(char*) * 5);
const char** args = (const char**)malloc(sizeof(char*) * 5);
args[0] = binary;
args[1] = EXPAND(RECOVERY_API_VERSION); // defined in Android.mk
args[2] = malloc(10);
sprintf(args[2], "%d", pipefd[1]);
char* temp = (char*)malloc(10);
sprintf(temp, "%d", pipefd[1]);
args[2] = temp;
args[3] = (char*)path;
args[4] = NULL;
pid_t pid = fork();
if (pid == 0) {
close(pipefd[0]);
execv(binary, args);
execv(binary, (char* const*)args);
fprintf(stdout, "E:Can't run %s (%s)\n", binary, strerror(errno));
_exit(-1);
}
@ -188,11 +190,12 @@ load_keys(const char* filename, int* numKeys) {
goto exit;
}
{
int i;
bool done = false;
while (!done) {
++*numKeys;
out = realloc(out, *numKeys * sizeof(RSAPublicKey));
out = (RSAPublicKey*)realloc(out, *numKeys * sizeof(RSAPublicKey));
RSAPublicKey* key = out + (*numKeys - 1);
if (fscanf(f, " { %i , 0x%x , { %u",
&(key->len), &(key->n0inv), &(key->n[0])) != 3) {
@ -226,6 +229,7 @@ load_keys(const char* filename, int* numKeys) {
goto exit;
}
}
}
fclose(f);
return out;

View file

@ -19,6 +19,10 @@
#include "common.h"
#ifdef __cplusplus
extern "C" {
#endif
enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT };
// Install the package specified by root_path. If INSTALL_SUCCESS is
// returned and *wipe_cache is true on exit, caller should wipe the
@ -26,4 +30,8 @@ enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT };
int install_package(const char *root_path, int* wipe_cache,
const char* install_file);
#ifdef __cplusplus
}
#endif
#endif // RECOVERY_INSTALL_H_

View file

@ -19,6 +19,10 @@
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef void* gr_surface;
typedef unsigned short gr_pixel;
@ -69,4 +73,8 @@ void ev_dispatch(void);
int res_create_surface(const char* name, gr_surface* pSurface);
void res_free_surface(gr_surface surface);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -20,6 +20,10 @@
#include <stdbool.h>
#include <utime.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Like "mkdir -p", try to guarantee that all directories
* specified in path are present, creating as many directories
* as necessary. The specified mode is passed to all mkdir
@ -48,4 +52,8 @@ int dirUnlinkHierarchy(const char *path);
int dirSetHierarchyPermissions(const char *path,
int uid, int gid, int dirMode, int fileMode);
#ifdef __cplusplus
}
#endif
#endif // MINZIP_DIRUTIL_H_

View file

@ -14,6 +14,10 @@
#include "Hash.h"
#include "SysUtil.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
* One entry in the Zip archive. Treat this as opaque -- use accessors below.
*
@ -210,4 +214,8 @@ bool mzExtractRecursive(const ZipArchive *pArchive,
int flags, const struct utimbuf *timestamp,
void (*callback)(const char *fn, void*), void *cookie);
#ifdef __cplusplus
}
#endif
#endif /*_MINZIP_ZIP*/

View file

@ -17,6 +17,10 @@
#ifndef MTDUTILS_MOUNTS_H_
#define MTDUTILS_MOUNTS_H_
#ifdef __cplusplus
extern "C" {
#endif
typedef struct MountedVolume MountedVolume;
int scan_mounted_volumes(void);
@ -30,4 +34,8 @@ int unmount_mounted_volume(const MountedVolume *volume);
int remount_read_only(const MountedVolume* volume);
#ifdef __cplusplus
}
#endif
#endif // MTDUTILS_MOUNTS_H_

View file

@ -19,6 +19,10 @@
#include <sys/types.h> // for size_t, etc.
#ifdef __cplusplus
extern "C" {
#endif
typedef struct MtdPartition MtdPartition;
int mtd_scan_partitions(void);
@ -53,4 +57,8 @@ off_t mtd_erase_blocks(MtdWriteContext *, int blocks); /* 0 ok, -1 for all */
off_t mtd_find_write_start(MtdWriteContext *ctx, off_t pos);
int mtd_write_close(MtdWriteContext *);
#ifdef __cplusplus
}
#endif
#endif // MTDUTILS_H_

View file

@ -38,6 +38,7 @@
#include "minzip/DirUtil.h"
#include "roots.h"
#include "recovery_ui.h"
#include "ui.h"
static const struct option OPTIONS[] = {
{ "send_intent", required_argument, NULL, 's' },
@ -349,7 +350,7 @@ copy_sideloaded_package(const char* original_path) {
strcpy(copy_path, SIDELOAD_TEMP_DIR);
strcat(copy_path, "/package.zip");
char* buffer = malloc(BUFSIZ);
char* buffer = (char*)malloc(BUFSIZ);
if (buffer == NULL) {
LOGE("Failed to allocate buffer\n");
return NULL;
@ -396,9 +397,9 @@ copy_sideloaded_package(const char* original_path) {
return strdup(copy_path);
}
static char**
static const char**
prepend_title(const char** headers) {
char* title[] = { "Android system recovery <"
const char* title[] = { "Android system recovery <"
EXPAND(RECOVERY_API_VERSION) "e>",
"",
NULL };
@ -406,12 +407,12 @@ prepend_title(const char** headers) {
// count the number of lines in our title, plus the
// caller-provided headers.
int count = 0;
char** p;
const char** p;
for (p = title; *p; ++p, ++count);
for (p = headers; *p; ++p, ++count);
char** new_headers = malloc((count+1) * sizeof(char*));
char** h = new_headers;
const char** new_headers = (const char**)malloc((count+1) * sizeof(char*));
const char** h = new_headers;
for (p = title; *p; ++p, ++h) *h = *p;
for (p = headers; *p; ++p, ++h) *h = *p;
*h = NULL;
@ -420,8 +421,8 @@ prepend_title(const char** headers) {
}
static int
get_menu_selection(char** headers, char** items, int menu_only,
int initial_selection) {
get_menu_selection(const char* const * headers, const char* const * items,
int menu_only, int initial_selection) {
// throw away keys pressed previously, so user doesn't
// accidentally trigger menu items.
ui_clear_key_queue();
@ -495,14 +496,14 @@ update_directory(const char* path, const char* unmount_when_done,
return 0;
}
char** headers = prepend_title(MENU_HEADERS);
const char** headers = prepend_title(MENU_HEADERS);
int d_size = 0;
int d_alloc = 10;
char** dirs = malloc(d_alloc * sizeof(char*));
char** dirs = (char**)malloc(d_alloc * sizeof(char*));
int z_size = 1;
int z_alloc = 10;
char** zips = malloc(z_alloc * sizeof(char*));
char** zips = (char**)malloc(z_alloc * sizeof(char*));
zips[0] = strdup("../");
while ((de = readdir(d)) != NULL) {
@ -516,9 +517,9 @@ update_directory(const char* path, const char* unmount_when_done,
if (d_size >= d_alloc) {
d_alloc *= 2;
dirs = realloc(dirs, d_alloc * sizeof(char*));
dirs = (char**)realloc(dirs, d_alloc * sizeof(char*));
}
dirs[d_size] = malloc(name_len + 2);
dirs[d_size] = (char*)malloc(name_len + 2);
strcpy(dirs[d_size], de->d_name);
dirs[d_size][name_len] = '/';
dirs[d_size][name_len+1] = '\0';
@ -528,7 +529,7 @@ update_directory(const char* path, const char* unmount_when_done,
strncasecmp(de->d_name + (name_len-4), ".zip", 4) == 0) {
if (z_size >= z_alloc) {
z_alloc *= 2;
zips = realloc(zips, z_alloc * sizeof(char*));
zips = (char**)realloc(zips, z_alloc * sizeof(char*));
}
zips[z_size++] = strdup(de->d_name);
}
@ -541,7 +542,7 @@ update_directory(const char* path, const char* unmount_when_done,
// append dirs to the zips list
if (d_size + z_size + 1 > z_alloc) {
z_alloc = d_size + z_size + 1;
zips = realloc(zips, z_alloc * sizeof(char*));
zips = (char**)realloc(zips, z_alloc * sizeof(char*));
}
memcpy(zips + z_size, dirs, d_size * sizeof(char*));
free(dirs);
@ -606,17 +607,17 @@ update_directory(const char* path, const char* unmount_when_done,
static void
wipe_data(int confirm) {
if (confirm) {
static char** title_headers = NULL;
static const char** title_headers = NULL;
if (title_headers == NULL) {
char* headers[] = { "Confirm wipe of all user data?",
const char* headers[] = { "Confirm wipe of all user data?",
" THIS CAN NOT BE UNDONE.",
"",
NULL };
title_headers = prepend_title((const char**)headers);
}
char* items[] = { " No",
const char* items[] = { " No",
" No",
" No",
" No",
@ -644,7 +645,7 @@ wipe_data(int confirm) {
static void
prompt_and_wait() {
char** headers = prepend_title((const char**)MENU_HEADERS);
const char** headers = prepend_title((const char**)MENU_HEADERS);
for (;;) {
finish_recovery(NULL);
@ -777,7 +778,7 @@ main(int argc, char **argv) {
// "/cache/foo".
if (strncmp(update_package, "CACHE:", 6) == 0) {
int len = strlen(update_package) + 10;
char* modified_path = malloc(len);
char* modified_path = (char*)malloc(len);
strlcpy(modified_path, "/cache/", len);
strlcat(modified_path, update_package+6, len);
printf("(replacing path \"%s\" with \"%s\")\n",

View file

@ -19,6 +19,10 @@
#include "common.h"
#ifdef __cplusplus
extern "C" {
#endif
// Called before UI library is initialized. Can change things like
// how many frames are included in various animations, etc.
extern void device_ui_init(UIParameters* ui_parameters);
@ -84,4 +88,8 @@ extern char* MENU_HEADERS[];
// Text of menu items.
extern char* MENU_ITEMS[];
#ifdef __cplusplus
}
#endif
#endif

View file

@ -33,7 +33,7 @@ static Volume* device_volumes = NULL;
static int parse_options(char* options, Volume* volume) {
char* option;
while (option = strtok(options, ",")) {
while ((option = strtok(options, ","))) {
options = NULL;
if (strncmp(option, "length=", 7) == 0) {
@ -48,7 +48,7 @@ static int parse_options(char* options, Volume* volume) {
void load_volume_table() {
int alloc = 2;
device_volumes = malloc(alloc * sizeof(Volume));
device_volumes = (Volume*)malloc(alloc * sizeof(Volume));
// Insert an entry for /tmp, which is the ramdisk and is always mounted.
device_volumes[0].mount_point = "/tmp";
@ -91,7 +91,7 @@ void load_volume_table() {
if (mount_point && fs_type && device) {
while (num_volumes >= alloc) {
alloc *= 2;
device_volumes = realloc(device_volumes, alloc*sizeof(Volume));
device_volumes = (Volume*)realloc(device_volumes, alloc*sizeof(Volume));
}
device_volumes[num_volumes].mount_point = strdup(mount_point);
device_volumes[num_volumes].fs_type = strdup(fs_type);

View file

@ -19,6 +19,10 @@
#include "common.h"
#ifdef __cplusplus
extern "C" {
#endif
// Load and parse volume data from /etc/recovery.fstab.
void load_volume_table();
@ -38,4 +42,8 @@ int ensure_path_unmounted(const char* path);
// it is mounted.
int format_volume(const char* volume);
#ifdef __cplusplus
}
#endif
#endif // RECOVERY_ROOTS_H_

View file

@ -32,6 +32,7 @@
#include <cutils/android_reboot.h>
#include "minui/minui.h"
#include "recovery_ui.h"
#include "ui.h"
#define MAX_COLS 96
#define MAX_ROWS 32
@ -397,7 +398,7 @@ void ui_init(void)
}
}
gProgressBarIndeterminate = malloc(ui_parameters.indeterminate_frames *
gProgressBarIndeterminate = (gr_surface*)malloc(ui_parameters.indeterminate_frames *
sizeof(gr_surface));
for (i = 0; i < ui_parameters.indeterminate_frames; ++i) {
char filename[40];
@ -410,7 +411,7 @@ void ui_init(void)
}
if (ui_parameters.installing_frames > 0) {
gInstallationOverlay = malloc(ui_parameters.installing_frames *
gInstallationOverlay = (gr_surface*)malloc(ui_parameters.installing_frames *
sizeof(gr_surface));
for (i = 0; i < ui_parameters.installing_frames; ++i) {
char filename[40];
@ -529,7 +530,8 @@ void ui_print(const char *fmt, ...)
pthread_mutex_unlock(&gUpdateMutex);
}
void ui_start_menu(char** headers, char** items, int initial_selection) {
void ui_start_menu(const char* const * headers, const char* const * items,
int initial_selection) {
int i;
pthread_mutex_lock(&gUpdateMutex);
if (text_rows > 0 && text_cols > 0) {

75
ui.h Normal file
View file

@ -0,0 +1,75 @@
/*
* Copyright (C) 2011 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.
*/
#ifndef RECOVERY_UI_H
#define RECOVERY_UI_H
// Initialize the graphics system.
void ui_init();
// Use KEY_* codes from <linux/input.h> or KEY_DREAM_* from "minui/minui.h".
int ui_wait_key(); // waits for a key/button press, returns the code
int ui_key_pressed(int key); // returns >0 if the code is currently pressed
int ui_text_visible(); // returns >0 if text log is currently visible
int ui_text_ever_visible(); // returns >0 if text log was ever visible
void ui_show_text(int visible);
void ui_clear_key_queue();
// Write a message to the on-screen log shown with Alt-L (also to stderr).
// The screen is small, and users may need to report these messages to support,
// so keep the output short and not too cryptic.
void ui_print(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
// Display some header text followed by a menu of items, which appears
// at the top of the screen (in place of any scrolling ui_print()
// output, if necessary).
void ui_start_menu(const char* const * headers, const char* const * items,
int initial_selection);
// Set the menu highlight to the given index, and return it (capped to
// the range [0..numitems).
int ui_menu_select(int sel);
// End menu mode, resetting the text overlay so that ui_print()
// statements will be displayed.
void ui_end_menu();
// Set the icon (normally the only thing visible besides the progress bar).
enum {
BACKGROUND_ICON_NONE,
BACKGROUND_ICON_INSTALLING,
BACKGROUND_ICON_ERROR,
NUM_BACKGROUND_ICONS
};
void ui_set_background(int icon);
// Show a progress bar and define the scope of the next operation:
// portion - fraction of the progress bar the next operation will use
// seconds - expected time interval (progress bar moves at this minimum rate)
void ui_show_progress(float portion, int seconds);
void ui_set_progress(float fraction); // 0.0 - 1.0 within the defined scope
// Default allocation of progress bar segments to operations
static const int VERIFICATION_PROGRESS_TIME = 60;
static const float VERIFICATION_PROGRESS_FRACTION = 0.25;
static const float DEFAULT_FILES_PROGRESS_FRACTION = 0.4;
static const float DEFAULT_IMAGE_PROGRESS_FRACTION = 0.1;
// Show a rotating "barberpole" for ongoing operations. Updates automatically.
void ui_show_indeterminate_progress();
// Hide and reset the progress bar.
void ui_reset_progress();
#endif // RECOVERY_UI_H

View file

@ -16,6 +16,7 @@
#include "common.h"
#include "verifier.h"
#include "ui.h"
#include "mincrypt/rsa.h"
#include "mincrypt/sha.h"
@ -69,8 +70,8 @@ int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKey
return VERIFY_FAILURE;
}
int comment_size = footer[4] + (footer[5] << 8);
int signature_start = footer[0] + (footer[1] << 8);
size_t comment_size = footer[4] + (footer[5] << 8);
size_t signature_start = footer[0] + (footer[1] << 8);
LOGI("comment is %d bytes; signature %d bytes from end\n",
comment_size, signature_start);
@ -99,7 +100,7 @@ int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKey
// bytes) and the comment data.
size_t signed_len = ftell(f) + EOCD_HEADER_SIZE - 2;
unsigned char* eocd = malloc(eocd_size);
unsigned char* eocd = (unsigned char*)malloc(eocd_size);
if (eocd == NULL) {
LOGE("malloc for EOCD record failed\n");
fclose(f);
@ -120,7 +121,7 @@ int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKey
return VERIFY_FAILURE;
}
int i;
size_t i;
for (i = 4; i < eocd_size-3; ++i) {
if (eocd[i ] == 0x50 && eocd[i+1] == 0x4b &&
eocd[i+2] == 0x05 && eocd[i+3] == 0x06) {
@ -138,7 +139,7 @@ int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKey
SHA_CTX ctx;
SHA_init(&ctx);
unsigned char* buffer = malloc(BUFFER_SIZE);
unsigned char* buffer = (unsigned char*)malloc(BUFFER_SIZE);
if (buffer == NULL) {
LOGE("failed to alloc memory for sha1 buffer\n");
fclose(f);
@ -149,7 +150,7 @@ int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKey
size_t so_far = 0;
fseek(f, 0, SEEK_SET);
while (so_far < signed_len) {
int size = BUFFER_SIZE;
size_t size = BUFFER_SIZE;
if (signed_len - so_far < size) size = signed_len - so_far;
if (fread(buffer, 1, size, f) != size) {
LOGE("failed to read data from %s (%s)\n", path, strerror(errno));

View file

@ -1,11 +1,7 @@
#!/bin/bash
#
# A test suite for applypatch. Run in a client where you have done
# envsetup, choosecombo, etc.
#
# DO NOT RUN THIS ON A DEVICE YOU CARE ABOUT. It will mess up your
# system partition.
#
# A test suite for recovery's package signature verifier. Run in a
# client where you have done envsetup, lunch, etc.
#
# TODO: find some way to get this run regularly along with the rest of
# the tests.