This commit is contained in:
Koushik Dutta 2011-11-16 16:00:35 -08:00
commit 0df56f4db4
56 changed files with 1550 additions and 1075 deletions

View File

@ -1,6 +1,3 @@
ifneq ($(TARGET_SIMULATOR),true)
ifeq ($(TARGET_ARCH),arm)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
@ -13,15 +10,15 @@ LOCAL_SRC_FILES := \
install.c \
roots.c \
ui.c \
verifier.c \
encryptedfs_provisioning.c \
mounts.c \
extendedcommands.c \
nandroid.c \
../../system/core/toolbox/reboot.c \
firmware.c \
edifyscripting.c \
setprop.c
setprop.c \
default_recovery_ui.c \
verifier.c
ADDITIONAL_RECOVERY_FILES := $(shell echo $$ADDITIONAL_RECOVERY_FILES)
LOCAL_SRC_FILES += $(ADDITIONAL_RECOVERY_FILES)
@ -51,6 +48,12 @@ $(foreach board_define,$(BOARD_RECOVERY_DEFINES), \
) \
)
LOCAL_STATIC_LIBRARIES :=
LOCAL_CFLAGS += -DUSE_EXT4
LOCAL_C_INCLUDES += system/extras/ext4_utils
LOCAL_STATIC_LIBRARIES += libext4_utils libz
# This binary is in the recovery ramdisk, which is otherwise a copy of root.
# It gets copied there in config/Makefile. LOCAL_MODULE_TAGS suppresses
# a (redundant) copy of the binary in /system/bin for user builds.
@ -58,18 +61,16 @@ $(foreach board_define,$(BOARD_RECOVERY_DEFINES), \
LOCAL_MODULE_TAGS := eng
LOCAL_STATIC_LIBRARIES :=
ifeq ($(BOARD_CUSTOM_RECOVERY_KEYMAPPING),)
LOCAL_SRC_FILES += default_recovery_ui.c
LOCAL_SRC_FILES += default_recovery_keys.c
else
LOCAL_SRC_FILES += $(BOARD_CUSTOM_RECOVERY_KEYMAPPING)
endif
LOCAL_STATIC_LIBRARIES += librebootrecovery
LOCAL_STATIC_LIBRARIES += libext4_utils libz
LOCAL_STATIC_LIBRARIES += libminzip libunz libmincrypt
LOCAL_STATIC_LIBRARIES += libedify libbusybox libclearsilverregex libmkyaffs2image libunyaffs liberase_image libdump_image libflash_image
LOCAL_STATIC_LIBRARIES += libedify libbusybox libmkyaffs2image libunyaffs liberase_image libdump_image libflash_image
LOCAL_STATIC_LIBRARIES += libcrecovery libflashutils libmtdutils libmmcutils libbmlutils
@ -151,6 +152,7 @@ include $(commands_recovery_local_path)/bmlutils/Android.mk
include $(commands_recovery_local_path)/flashutils/Android.mk
include $(commands_recovery_local_path)/libcrecovery/Android.mk
include $(commands_recovery_local_path)/minui/Android.mk
include $(commands_recovery_local_path)/minelf/Android.mk
include $(commands_recovery_local_path)/minzip/Android.mk
include $(commands_recovery_local_path)/mtdutils/Android.mk
include $(commands_recovery_local_path)/mmcutils/Android.mk
@ -160,7 +162,3 @@ include $(commands_recovery_local_path)/updater/Android.mk
include $(commands_recovery_local_path)/applypatch/Android.mk
include $(commands_recovery_local_path)/utilities/Android.mk
commands_recovery_local_path :=
endif # TARGET_ARCH == arm
endif # !TARGET_SIMULATOR

View File

@ -12,9 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
ifneq ($(TARGET_SIMULATOR),true)
ifeq ($(TARGET_ARCH),arm)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
@ -31,7 +28,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := main.c
LOCAL_MODULE := applypatch
LOCAL_C_INCLUDES += bootable/recovery
LOCAL_STATIC_LIBRARIES += libapplypatch libmtdutils libmincrypt libbz
LOCAL_STATIC_LIBRARIES += libapplypatch libmtdutils libmincrypt libbz libminelf
LOCAL_SHARED_LIBRARIES += libz libcutils libstdc++ libc
include $(BUILD_EXECUTABLE)
@ -43,7 +40,7 @@ LOCAL_MODULE := applypatch_static
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_TAGS := eng
LOCAL_C_INCLUDES += bootable/recovery
LOCAL_STATIC_LIBRARIES += libapplypatch libmtdutils libmincrypt libbz
LOCAL_STATIC_LIBRARIES += libapplypatch libmtdutils libmincrypt libbz libminelf
LOCAL_STATIC_LIBRARIES += libz libcutils libstdc++ libc
include $(BUILD_EXECUTABLE)
@ -58,6 +55,3 @@ LOCAL_C_INCLUDES += external/zlib external/bzip2
LOCAL_STATIC_LIBRARIES += libz libbz
include $(BUILD_HOST_EXECUTABLE)
endif # TARGET_ARCH == arm
endif # !TARGET_SIMULATOR

View File

@ -30,16 +30,21 @@
#include "mtdutils/mtdutils.h"
#include "edify/expr.h"
static int SaveFileContents(const char* filename, FileContents file);
int SaveFileContents(const char* filename, FileContents file);
static int LoadPartitionContents(const char* filename, FileContents* file);
int ParseSha1(const char* str, uint8_t* digest);
static ssize_t FileSink(unsigned char* data, ssize_t len, void* token);
static int mtd_partitions_scanned = 0;
// Read a file into memory; store it and its associated metadata in
// *file. Return 0 on success.
int LoadFileContents(const char* filename, FileContents* file) {
// Read a file into memory; optionally (retouch_flag == RETOUCH_DO_MASK) mask
// the retouched entries back to their original value (such that SHA-1 checks
// don't fail due to randomization); store the file contents and associated
// metadata in *file.
//
// Return 0 on success.
int LoadFileContents(const char* filename, FileContents* file,
int retouch_flag) {
file->data = NULL;
// A special 'filename' beginning with "MTD:" or "EMMC:" means to
@ -75,6 +80,20 @@ int LoadFileContents(const char* filename, FileContents* file) {
}
fclose(f);
// apply_patch[_check] functions are blind to randomization. Randomization
// is taken care of in [Undo]RetouchBinariesFn. If there is a mismatch
// within a file, this means the file is assumed "corrupt" for simplicity.
if (retouch_flag) {
int32_t desired_offset = 0;
if (retouch_mask_data(file->data, file->size,
&desired_offset, NULL) != RETOUCH_DATA_MATCHED) {
printf("error trying to mask retouch entries\n");
free(file->data);
file->data = NULL;
return -1;
}
}
SHA(file->data, file->size, file->sha1);
return 0;
}
@ -303,7 +322,7 @@ static int LoadPartitionContents(const char* filename, FileContents* file) {
// Save the contents of the given FileContents object under the given
// filename. Return 0 on success.
static int SaveFileContents(const char* filename, FileContents file) {
int SaveFileContents(const char* filename, FileContents file) {
int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC);
if (fd < 0) {
printf("failed to open \"%s\" for write: %s\n",
@ -477,7 +496,7 @@ int applypatch_check(const char* filename,
// LoadFileContents is successful. (Useful for reading
// partitions, where the filename encodes the sha1s; no need to
// check them twice.)
if (LoadFileContents(filename, &file) != 0 ||
if (LoadFileContents(filename, &file, RETOUCH_DO_MASK) != 0 ||
(num_patches > 0 &&
FindMatchingPatch(file.sha1, patch_sha1_str, num_patches) < 0)) {
printf("file \"%s\" doesn't have any of expected "
@ -491,7 +510,7 @@ int applypatch_check(const char* filename,
// exists and matches the sha1 we're looking for, the check still
// passes.
if (LoadFileContents(CACHE_TEMP_SOURCE, &file) != 0) {
if (LoadFileContents(CACHE_TEMP_SOURCE, &file, RETOUCH_DO_MASK) != 0) {
printf("failed to load cache file\n");
return 1;
}
@ -617,7 +636,8 @@ int applypatch(const char* source_filename,
int made_copy = 0;
// We try to load the target file into the source_file object.
if (LoadFileContents(target_filename, &source_file) == 0) {
if (LoadFileContents(target_filename, &source_file,
RETOUCH_DO_MASK) == 0) {
if (memcmp(source_file.sha1, target_sha1, SHA_DIGEST_SIZE) == 0) {
// The early-exit case: the patch was already applied, this file
// has the desired hash, nothing for us to do.
@ -633,7 +653,8 @@ int applypatch(const char* source_filename,
// Need to load the source file: either we failed to load the
// target file, or we did but it's different from the source file.
free(source_file.data);
LoadFileContents(source_filename, &source_file);
LoadFileContents(source_filename, &source_file,
RETOUCH_DO_MASK);
}
if (source_file.data != NULL) {
@ -648,7 +669,8 @@ int applypatch(const char* source_filename,
free(source_file.data);
printf("source file is bad; trying copy\n");
if (LoadFileContents(CACHE_TEMP_SOURCE, &copy_file) < 0) {
if (LoadFileContents(CACHE_TEMP_SOURCE, &copy_file,
RETOUCH_DO_MASK) < 0) {
// fail.
printf("failed to read copy file\n");
return 1;

View File

@ -19,6 +19,7 @@
#include <sys/stat.h>
#include "mincrypt/sha.h"
#include "minelf/Retouch.h"
#include "edify/expr.h"
typedef struct _Patch {
@ -59,10 +60,12 @@ int applypatch_check(const char* filename,
int num_patches,
char** const patch_sha1_str);
// Read a file into memory; store it and its associated metadata in
// *file. Return 0 on success.
int LoadFileContents(const char* filename, FileContents* file);
int LoadFileContents(const char* filename, FileContents* file,
int retouch_flag);
int SaveFileContents(const char* filename, FileContents file);
void FreeFileContents(FileContents* file);
int FindMatchingPatch(uint8_t* sha1, char** const patch_sha1_str,
int num_patches);
// bsdiff.c
void ShowBSDiffLicense();

View File

@ -74,7 +74,7 @@ static int ParsePatchArgs(int argc, char** argv,
(*patches)[i] = NULL;
} else {
FileContents fc;
if (LoadFileContents(colon, &fc) != 0) {
if (LoadFileContents(colon, &fc, RETOUCH_DONT_MASK) != 0) {
goto abort;
}
(*patches)[i] = malloc(sizeof(Value));

View File

@ -22,6 +22,8 @@
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
static int get_bootloader_message_mtd(struct bootloader_message *out, const Volume* v);
static int set_bootloader_message_mtd(const struct bootloader_message *in, const Volume* v);
@ -140,8 +142,26 @@ static int set_bootloader_message_mtd(const struct bootloader_message *in,
// for misc partitions on block devices
// ------------------------------------
static void wait_for_device(const char* fn) {
int tries = 0;
int ret;
struct stat buf;
do {
++tries;
ret = stat(fn, &buf);
if (ret) {
printf("stat %s try %d: %s\n", fn, tries, strerror(errno));
sleep(1);
}
} while (ret && tries < 10);
if (ret) {
printf("failed to stat %s\n", fn);
}
}
static int get_bootloader_message_block(struct bootloader_message *out,
const Volume* v) {
wait_for_device(v->device);
FILE* f = fopen(v->device, "rb");
if (f == NULL) {
LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno));
@ -163,6 +183,7 @@ static int get_bootloader_message_block(struct bootloader_message *out,
static int set_bootloader_message_block(const struct bootloader_message *in,
const Volume* v) {
wait_for_device(v->device);
FILE* f = fopen(v->device, "wb");
if (f == NULL) {
LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno));
@ -328,4 +349,4 @@ int write_update_for_bootloader(
}
return 0;
}
}

View File

@ -26,6 +26,7 @@ void ui_init();
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();
@ -113,6 +114,13 @@ typedef struct {
const char* device2; // alternative device to try if fs_type
// == "ext4" or "vfat" and mounting
// 'device' fails
long long length; // (ext4 partition only) when
// formatting, size to use for the
// partition. 0 or negative number
// means to format all but the last
// (that much).
const char* fs_type2;
const char* fs_options;
@ -120,4 +128,26 @@ typedef struct {
const char* fs_options2;
} Volume;
typedef struct {
// number of frames in indeterminate progress bar animation
int indeterminate_frames;
// number of frames per second to try to maintain when animating
int update_fps;
// number of frames in installing animation. may be zero for a
// static installation icon.
int installing_frames;
// the install icon is animated by drawing images containing the
// changing part over the base icon. These specify the
// coordinates of the upper-left corner.
int install_overlay_offset_x;
int install_overlay_offset_y;
} UIParameters;
// fopen a file, mounting volumes and making parent dirs as necessary.
FILE* fopen_path(const char *path, const char *mode);
#endif // RECOVERY_COMMON_H

64
default_recovery_keys.c Normal file
View File

@ -0,0 +1,64 @@
#include <linux/input.h>
#include "recovery_ui.h"
#include "common.h"
#include "extendedcommands.h"
int device_toggle_display(volatile char* key_pressed, int key_code) {
int alt = key_pressed[KEY_LEFTALT] || key_pressed[KEY_RIGHTALT];
if (alt && key_code == KEY_L)
return 1;
// allow toggling of the display if the correct key is pressed, and the display toggle is allowed or the display is currently off
if (ui_get_showing_back_button()) {
return 0;
//return get_allow_toggle_display() && (key_code == KEY_HOME || key_code == KEY_MENU || key_code == KEY_END);
}
return get_allow_toggle_display() && (key_code == KEY_HOME || key_code == KEY_MENU || key_code == KEY_POWER || key_code == KEY_END);
}
int device_handle_key(int key_code, int visible) {
if (visible) {
switch (key_code) {
case KEY_CAPSLOCK:
case KEY_DOWN:
case KEY_VOLUMEDOWN:
case KEY_MENU:
return HIGHLIGHT_DOWN;
case KEY_LEFTSHIFT:
case KEY_UP:
case KEY_VOLUMEUP:
case KEY_HOME:
return HIGHLIGHT_UP;
case KEY_POWER:
if (ui_get_showing_back_button()) {
return SELECT_ITEM;
}
if (!get_allow_toggle_display())
return GO_BACK;
break;
case KEY_LEFTBRACE:
case KEY_ENTER:
case BTN_MOUSE:
case KEY_CAMERA:
case KEY_F21:
case KEY_SEND:
return SELECT_ITEM;
case KEY_END:
case KEY_BACKSPACE:
case KEY_SEARCH:
if (ui_get_showing_back_button()) {
return SELECT_ITEM;
}
if (!get_allow_toggle_display())
return GO_BACK;
case KEY_BACK:
return GO_BACK;
}
}
return NO_ACTION;
}

View File

@ -23,83 +23,25 @@
char* MENU_HEADERS[] = { NULL };
char* MENU_ITEMS[] = { "reboot system now",
"apply update from sdcard",
"install zip from sdcard",
"wipe data/factory reset",
"wipe cache partition",
"install zip from sdcard",
"backup and restore",
"mounts and storage",
"advanced",
"power off",
NULL };
void device_ui_init(UIParameters* ui_parameters) {
}
int device_recovery_start() {
return 0;
}
int device_toggle_display(volatile char* key_pressed, int key_code) {
int alt = key_pressed[KEY_LEFTALT] || key_pressed[KEY_RIGHTALT];
if (alt && key_code == KEY_L)
return 1;
// allow toggling of the display if the correct key is pressed, and the display toggle is allowed or the display is currently off
if (ui_get_showing_back_button()) {
return 0;
//return get_allow_toggle_display() && (key_code == KEY_HOME || key_code == KEY_MENU || key_code == KEY_END);
}
return get_allow_toggle_display() && (key_code == KEY_HOME || key_code == KEY_MENU || key_code == KEY_POWER || key_code == KEY_END);
}
int device_reboot_now(volatile char* key_pressed, int key_code) {
return 0;
}
int device_handle_key(int key_code, int visible) {
if (visible) {
switch (key_code) {
case KEY_CAPSLOCK:
case KEY_DOWN:
case KEY_VOLUMEDOWN:
case KEY_MENU:
return HIGHLIGHT_DOWN;
case KEY_LEFTSHIFT:
case KEY_UP:
case KEY_VOLUMEUP:
case KEY_HOME:
return HIGHLIGHT_UP;
case KEY_POWER:
if (ui_get_showing_back_button()) {
return SELECT_ITEM;
}
if (!get_allow_toggle_display())
return GO_BACK;
break;
case KEY_LEFTBRACE:
case KEY_ENTER:
case BTN_MOUSE:
case KEY_CENTER:
case KEY_CAMERA:
case KEY_F21:
case KEY_SEND:
return SELECT_ITEM;
case KEY_END:
case KEY_BACKSPACE:
case KEY_SEARCH:
if (ui_get_showing_back_button()) {
return SELECT_ITEM;
}
if (!get_allow_toggle_display())
return GO_BACK;
case KEY_BACK:
return GO_BACK;
}
}
return NO_ACTION;
}
int device_perform_action(int which) {
return which;
}

View File

@ -1,283 +0,0 @@
/*
* Copyright (C) 2009 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "encryptedfs_provisioning.h"
#include "cutils/misc.h"
#include "cutils/properties.h"
#include "common.h"
#include "mtdutils/mtdutils.h"
#include "mounts.h"
#include "roots.h"
const char* encrypted_fs_enabled_property = "persist.security.secfs.enabled";
const char* encrypted_fs_property_dir = "/data/property/";
const char* encrypted_fs_system_dir = "/data/system/";
const char* encrypted_fs_key_file_name = "/data/fs_key.dat";
const char* encrypted_fs_salt_file_name = "/data/hash_salt.dat";
const char* encrypted_fs_hash_file_src_name = "/data/system/password.key";
const char* encrypted_fs_hash_file_dst_name = "/data/hash.dat";
const char* encrypted_fs_entropy_file_src_name = "/data/system/entropy.dat";
const char* encrypted_fs_entropy_file_dst_name = "/data/ported_entropy.dat";
void get_property_file_name(char *buffer, const char *property_name) {
sprintf(buffer, "%s%s", encrypted_fs_property_dir, property_name);
}
int get_binary_file_contents(char *buffer, int buf_size, const char *file_name, int *out_size) {
FILE *in_file;
int read_bytes;
in_file = fopen(file_name, "r");
if (in_file == NULL) {
LOGE("Secure FS: error accessing key file.");
return ENCRYPTED_FS_ERROR;
}
read_bytes = fread(buffer, 1, buf_size, in_file);
if (out_size == NULL) {
if (read_bytes != buf_size) {
// Error or unexpected data
fclose(in_file);
LOGE("Secure FS: error reading conmplete key.");
return ENCRYPTED_FS_ERROR;
}
} else {
*out_size = read_bytes;
}
fclose(in_file);
return ENCRYPTED_FS_OK;
}
int set_binary_file_contents(char *buffer, int buf_size, const char *file_name) {
FILE *out_file;
int write_bytes;
out_file = fopen(file_name, "w");
if (out_file == NULL) {
LOGE("Secure FS: error setting up key file.");
return ENCRYPTED_FS_ERROR;
}
write_bytes = fwrite(buffer, 1, buf_size, out_file);
if (write_bytes != buf_size) {
// Error or unexpected data
fclose(out_file);
LOGE("Secure FS: error reading conmplete key.");
return ENCRYPTED_FS_ERROR;
}
fclose(out_file);
return ENCRYPTED_FS_OK;
}
int get_text_file_contents(char *buffer, int buf_size, char *file_name) {
FILE *in_file;
char *read_data;
in_file = fopen(file_name, "r");
if (in_file == NULL) {
LOGE("Secure FS: error accessing properties.");
return ENCRYPTED_FS_ERROR;
}
read_data = fgets(buffer, buf_size, in_file);
if (read_data == NULL) {
// Error or unexpected data
fclose(in_file);
LOGE("Secure FS: error accessing properties.");
return ENCRYPTED_FS_ERROR;
}
fclose(in_file);
return ENCRYPTED_FS_OK;
}
int set_text_file_contents(char *buffer, char *file_name) {
FILE *out_file;
int result;
out_file = fopen(file_name, "w");
if (out_file == NULL) {
LOGE("Secure FS: error setting up properties.");
return ENCRYPTED_FS_ERROR;
}
result = fputs(buffer, out_file);
if (result != 0) {
// Error or unexpected data
fclose(out_file);
LOGE("Secure FS: error setting up properties.");
return ENCRYPTED_FS_ERROR;
}
fflush(out_file);
fclose(out_file);
return ENCRYPTED_FS_OK;
}
int read_encrypted_fs_boolean_property(const char *prop_name, int *value) {
char prop_file_name[PROPERTY_KEY_MAX + 32];
char prop_value[PROPERTY_VALUE_MAX];
int result;
get_property_file_name(prop_file_name, prop_name);
result = get_text_file_contents(prop_value, PROPERTY_VALUE_MAX, prop_file_name);
if (result < 0) {
return result;
}
if (strncmp(prop_value, "1", 1) == 0) {
*value = 1;
} else if (strncmp(prop_value, "0", 1) == 0) {
*value = 0;
} else {
LOGE("Secure FS: error accessing properties.");
return ENCRYPTED_FS_ERROR;
}
return ENCRYPTED_FS_OK;
}
int write_encrypted_fs_boolean_property(const char *prop_name, int value) {
char prop_file_name[PROPERTY_KEY_MAX + 32];
char prop_value[PROPERTY_VALUE_MAX];
int result;
get_property_file_name(prop_file_name, prop_name);
// Create the directory if needed
mkdir(encrypted_fs_property_dir, 0755);
if (value == 1) {
result = set_text_file_contents("1", prop_file_name);
} else if (value == 0) {
result = set_text_file_contents("0", prop_file_name);
} else {
return ENCRYPTED_FS_ERROR;
}
if (result < 0) {
return result;
}
return ENCRYPTED_FS_OK;
}
int read_encrypted_fs_info(encrypted_fs_info *encrypted_fs_data) {
int result;
int value;
result = ensure_path_mounted("/data");
if (result != 0) {
LOGE("Secure FS: error mounting userdata partition.");
return ENCRYPTED_FS_ERROR;
}
// Read the pre-generated encrypted FS key, password hash and salt.
result = get_binary_file_contents(encrypted_fs_data->key, ENCRYPTED_FS_KEY_SIZE,
encrypted_fs_key_file_name, NULL);
if (result != 0) {
LOGE("Secure FS: error reading generated file system key.");
return ENCRYPTED_FS_ERROR;
}
result = get_binary_file_contents(encrypted_fs_data->salt, ENCRYPTED_FS_SALT_SIZE,
encrypted_fs_salt_file_name, &(encrypted_fs_data->salt_length));
if (result != 0) {
LOGE("Secure FS: error reading file system salt.");
return ENCRYPTED_FS_ERROR;
}
result = get_binary_file_contents(encrypted_fs_data->hash, ENCRYPTED_FS_MAX_HASH_SIZE,
encrypted_fs_hash_file_src_name, &(encrypted_fs_data->hash_length));
if (result != 0) {
LOGE("Secure FS: error reading password hash.");
return ENCRYPTED_FS_ERROR;
}
result = get_binary_file_contents(encrypted_fs_data->entropy, ENTROPY_MAX_SIZE,
encrypted_fs_entropy_file_src_name, &(encrypted_fs_data->entropy_length));
if (result != 0) {
LOGE("Secure FS: error reading ported entropy.");
return ENCRYPTED_FS_ERROR;
}
result = ensure_path_unmounted("/data");
if (result != 0) {
LOGE("Secure FS: error unmounting data partition.");
return ENCRYPTED_FS_ERROR;
}
return ENCRYPTED_FS_OK;
}
int restore_encrypted_fs_info(encrypted_fs_info *encrypted_fs_data) {
int result;
result = ensure_path_mounted("/data");
if (result != 0) {
LOGE("Secure FS: error mounting userdata partition.");
return ENCRYPTED_FS_ERROR;
}
// Write the pre-generated secure FS key, password hash and salt.
result = set_binary_file_contents(encrypted_fs_data->key, ENCRYPTED_FS_KEY_SIZE,
encrypted_fs_key_file_name);
if (result != 0) {
LOGE("Secure FS: error writing generated file system key.");
return ENCRYPTED_FS_ERROR;
}
result = set_binary_file_contents(encrypted_fs_data->salt, encrypted_fs_data->salt_length,
encrypted_fs_salt_file_name);
if (result != 0) {
LOGE("Secure FS: error writing file system salt.");
return ENCRYPTED_FS_ERROR;
}
result = set_binary_file_contents(encrypted_fs_data->hash, encrypted_fs_data->hash_length,
encrypted_fs_hash_file_dst_name);
if (result != 0) {
LOGE("Secure FS: error writing password hash.");
return ENCRYPTED_FS_ERROR;
}
result = set_binary_file_contents(encrypted_fs_data->entropy, encrypted_fs_data->entropy_length,
encrypted_fs_entropy_file_dst_name);
if (result != 0) {
LOGE("Secure FS: error writing ported entropy.");
return ENCRYPTED_FS_ERROR;
}
// Set the secure FS properties to their respective values
result = write_encrypted_fs_boolean_property(encrypted_fs_enabled_property, encrypted_fs_data->mode);
if (result != 0) {
return result;
}
result = ensure_path_unmounted("/data");
if (result != 0) {
LOGE("Secure FS: error unmounting data partition.");
return ENCRYPTED_FS_ERROR;
}
return ENCRYPTED_FS_OK;
}

View File

@ -1,51 +0,0 @@
/*
* Copyright (C) 2009 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.
*/
#include <stdio.h>
#ifndef __ENCRYPTEDFS_PROVISIONING_H__
#define __ENCRYPTEDFS_PROVISIONING_H__
#define MODE_ENCRYPTED_FS_DISABLED 0
#define MODE_ENCRYPTED_FS_ENABLED 1
#define ENCRYPTED_FS_OK 0
#define ENCRYPTED_FS_ERROR (-1)
#define ENCRYPTED_FS_KEY_SIZE 16
#define ENCRYPTED_FS_SALT_SIZE 16
#define ENCRYPTED_FS_MAX_HASH_SIZE 128
#define ENTROPY_MAX_SIZE 4096
struct encrypted_fs_info {
int mode;
char key[ENCRYPTED_FS_KEY_SIZE];
char salt[ENCRYPTED_FS_SALT_SIZE];
int salt_length;
char hash[ENCRYPTED_FS_MAX_HASH_SIZE];
int hash_length;
char entropy[ENTROPY_MAX_SIZE];
int entropy_length;
};
typedef struct encrypted_fs_info encrypted_fs_info;
int read_encrypted_fs_info(encrypted_fs_info *secure_fs_data);
int restore_encrypted_fs_info(encrypted_fs_info *secure_data);
#endif /* __ENCRYPTEDFS_PROVISIONING_H__ */

View File

@ -35,8 +35,20 @@ service recovery /sbin/recovery
service adbd /sbin/adbd recovery
disabled
on property:persist.service.adb.enable=1
# Always start adbd on userdebug and eng builds
on property:ro.debuggable=1
write /sys/class/android_usb/android0/enable 0
write /sys/class/android_usb/android0/idVendor 18D1
write /sys/class/android_usb/android0/idProduct D001
write /sys/class/android_usb/android0/functions adb
write /sys/class/android_usb/android0/enable 1
write /sys/class/android_usb/android0/iManufacturer $ro.product.manufacturer
write /sys/class/android_usb/android0/iProduct $ro.product.model
write /sys/class/android_usb/android0/iSerial $ro.serialno
start adbd
on property:persist.service.adb.enable=0
stop adbd
# Restart adbd so it can run as root
on property:service.adb.root=1
write /sys/class/android_usb/android0/enable 0
restart adbd
write /sys/class/android_usb/android0/enable 1

View File

@ -8,7 +8,6 @@
#include <stdlib.h>
#include <string.h>
#include <sys/reboot.h>
#include <reboot/reboot.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
@ -42,6 +41,7 @@
#include <libgen.h>
#include "mtdutils/mtdutils.h"
#include "bmlutils/bmlutils.h"
#include "cutils/android_reboot.h"
int signature_check_enabled = 1;
@ -914,7 +914,7 @@ void show_advanced_menu()
{
case 0:
{
reboot_wrapper("recovery");
android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
break;
}
case 1:

View File

@ -103,6 +103,8 @@ handle_firmware_update(char* type, char* filename, ZipArchive* zip) {
return INSTALL_SUCCESS;
}
static const char *LAST_INSTALL_FILE = "/cache/recovery/last_install";
// If the package contains an update binary, extract it and run it.
static int
try_update_binary(const char *path, ZipArchive *zip) {
@ -332,8 +334,8 @@ exit:
return NULL;
}
int
install_package(const char *path)
static int
really_install_package(const char *path)
{
ui_set_background(BACKGROUND_ICON_INSTALLING);
ui_print("Finding update package...\n");
@ -387,3 +389,23 @@ install_package(const char *path)
ui_print("Installing update...\n");
return try_update_binary(path, &zip);
}
int
install_package(const char* path)
{
FILE* install_log = fopen_path(LAST_INSTALL_FILE, "w");
if (install_log) {
fputs(path, install_log);
fputc('\n', install_log);
} else {
LOGE("failed to open last_install: %s\n", strerror(errno));
}
int result = really_install_package(path);
if (install_log) {
fputc(result == INSTALL_SUCCESS ? '1' : '0', install_log);
fputc('\n', install_log);
fclose(install_log);
chmod(LAST_INSTALL_FILE, 0644);
}
return result;
}

102
make-overlay.py Normal file
View File

@ -0,0 +1,102 @@
# 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.
"""Script to take a set of frames (PNG files) for a recovery
"installing" icon animation and turn it into a base image plus a set
of overlays, as needed by the recovery UI code. Run with the names of
all the input frames on the command line, in order."""
import sys
try:
import Image
except ImportError:
print "This script requires the Python Imaging Library to be installed."
sys.exit(1)
# Find the smallest box that contains all the pixels which change
# between images.
print "reading", sys.argv[1]
base = Image.open(sys.argv[1])
minmini = base.size[0]-1
maxmaxi = 0
minminj = base.size[1]-1
maxmaxj = 0
for top_name in sys.argv[2:]:
print "reading", top_name
top = Image.open(top_name)
assert base.size == top.size
mini = base.size[0]-1
maxi = 0
minj = base.size[1]-1
maxj = 0
h, w = base.size
for j in range(w):
for i in range(h):
b = base.getpixel((i,j))
t = top.getpixel((i,j))
if b != t:
if i < mini: mini = i
if i > maxi: maxi = i
if j < minj: minj = j
if j > maxj: maxj = j
minmini = min(minmini, mini)
maxmaxi = max(maxmaxi, maxi)
minminj = min(minminj, minj)
maxmaxj = max(maxmaxj, maxj)
w = maxmaxi - minmini + 1
h = maxmaxj - minminj + 1
# Now write out an image containing just that box, for each frame.
for num, top_name in enumerate(sys.argv[1:]):
top = Image.open(top_name)
out = Image.new("RGB", (w, h))
for i in range(w):
for j in range(h):
t = top.getpixel((i+minmini, j+minminj))
out.putpixel((i, j), t)
fn = "icon_installing_overlay%02d.png" % (num+1,)
out.save(fn)
print "saved", fn
# Write out the base icon, which is the first frame with that box
# blacked out (just to make the file smaller, since it's always
# displayed with one of the overlays on top of it).
for i in range(w):
for j in range(h):
base.putpixel((i+minmini, j+minminj), (0, 0, 0))
fn = "icon_installing.png"
base.save(fn)
print "saved", fn
# The device_ui_init() function needs to tell the recovery UI the
# position of the overlay box.
print
print "add this to your device_ui_init() function:"
print "-" * 40
print " ui_parameters->install_overlay_offset_x = %d;" % (minmini,)
print " ui_parameters->install_overlay_offset_y = %d;" % (minminj,)
print "-" * 40

27
minelf/Android.mk Normal file
View File

@ -0,0 +1,27 @@
# Copyright (C) 2009 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.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
Retouch.c
LOCAL_C_INCLUDES += bootable/recovery
LOCAL_MODULE := libminelf
LOCAL_CFLAGS += -Wall
include $(BUILD_STATIC_LIBRARY)

406
minelf/Retouch.c Normal file
View File

@ -0,0 +1,406 @@
/*
* Copyright (C) 2009 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.
*/
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include "Retouch.h"
#include "applypatch/applypatch.h"
typedef struct {
int32_t mmap_addr;
char tag[4]; /* 'P', 'R', 'E', ' ' */
} prelink_info_t __attribute__((packed));
#define false 0
#define true 1
static int32_t offs_prev;
static uint32_t cont_prev;
static void init_compression_state(void) {
offs_prev = 0;
cont_prev = 0;
}
// For details on the encoding used for relocation lists, please
// refer to build/tools/retouch/retouch-prepare.c. The intent is to
// save space by removing most of the inherent redundancy.
static void decode_bytes(uint8_t *encoded_bytes, int encoded_size,
int32_t *dst_offset, uint32_t *dst_contents) {
if (encoded_size == 2) {
*dst_offset = offs_prev + (((encoded_bytes[0]&0x60)>>5)+1)*4;
// if the original was negative, we need to 1-pad before applying delta
int32_t tmp = (((encoded_bytes[0] & 0x0000001f) << 8) |
encoded_bytes[1]);
if (tmp & 0x1000) tmp = 0xffffe000 | tmp;
*dst_contents = cont_prev + tmp;
} else if (encoded_size == 3) {
*dst_offset = offs_prev + (((encoded_bytes[0]&0x30)>>4)+1)*4;
// if the original was negative, we need to 1-pad before applying delta
int32_t tmp = (((encoded_bytes[0] & 0x0000000f) << 16) |
(encoded_bytes[1] << 8) |
encoded_bytes[2]);
if (tmp & 0x80000) tmp = 0xfff00000 | tmp;
*dst_contents = cont_prev + tmp;
} else {
*dst_offset =
(encoded_bytes[0]<<24) |
(encoded_bytes[1]<<16) |
(encoded_bytes[2]<<8) |
encoded_bytes[3];
if (*dst_offset == 0x3fffffff) *dst_offset = -1;
*dst_contents =
(encoded_bytes[4]<<24) |
(encoded_bytes[5]<<16) |
(encoded_bytes[6]<<8) |
encoded_bytes[7];
}
}
static uint8_t *decode_in_memory(uint8_t *encoded_bytes,
int32_t *offset, uint32_t *contents) {
int input_size, charIx;
uint8_t input[8];
input[0] = *(encoded_bytes++);
if (input[0] & 0x80)
input_size = 2;
else if (input[0] & 0x40)
input_size = 3;
else
input_size = 8;
// we already read one byte..
charIx = 1;
while (charIx < input_size) {
input[charIx++] = *(encoded_bytes++);
}
// depends on the decoder state!
decode_bytes(input, input_size, offset, contents);
offs_prev = *offset;
cont_prev = *contents;
return encoded_bytes;
}
int retouch_mask_data(uint8_t *binary_object,
int32_t binary_size,
int32_t *desired_offset,
int32_t *retouch_offset) {
retouch_info_t *r_info;
prelink_info_t *p_info;
int32_t target_offset = 0;
if (desired_offset) target_offset = *desired_offset;
int32_t p_offs = binary_size-sizeof(prelink_info_t); // prelink_info_t
int32_t r_offs = p_offs-sizeof(retouch_info_t); // retouch_info_t
int32_t b_offs; // retouch data blob
// If not retouched, we say it was a match. This might get invoked on
// non-retouched binaries, so that's why we need to do this.
if (retouch_offset != NULL) *retouch_offset = target_offset;
if (r_offs < 0) return (desired_offset == NULL) ?
RETOUCH_DATA_NOTAPPLICABLE : RETOUCH_DATA_MATCHED;
p_info = (prelink_info_t *)(binary_object+p_offs);
r_info = (retouch_info_t *)(binary_object+r_offs);
if (strncmp(p_info->tag, "PRE ", 4) ||
strncmp(r_info->tag, "RETOUCH ", 8))
return (desired_offset == NULL) ?
RETOUCH_DATA_NOTAPPLICABLE : RETOUCH_DATA_MATCHED;
b_offs = r_offs-r_info->blob_size;
if (b_offs < 0) {
printf("negative binary offset: %d = %d - %d\n",
b_offs, r_offs, r_info->blob_size);
return RETOUCH_DATA_ERROR;
}
uint8_t *b_ptr = binary_object+b_offs;
// Retouched: let's go through the work then.
int32_t offset_candidate = target_offset;
bool offset_set = false, offset_mismatch = false;
init_compression_state();
while (b_ptr < (uint8_t *)r_info) {
int32_t retouch_entry_offset;
uint32_t *retouch_entry;
uint32_t retouch_original_value;
b_ptr = decode_in_memory(b_ptr,
&retouch_entry_offset,
&retouch_original_value);
if (retouch_entry_offset < (-1) ||
retouch_entry_offset >= b_offs) {
printf("bad retouch_entry_offset: %d", retouch_entry_offset);
return RETOUCH_DATA_ERROR;
}
// "-1" means this is the value in prelink_info_t, which also gets
// randomized.
if (retouch_entry_offset == -1)
retouch_entry = (uint32_t *)&(p_info->mmap_addr);
else
retouch_entry = (uint32_t *)(binary_object+retouch_entry_offset);
if (desired_offset)
*retouch_entry = retouch_original_value + target_offset;
// Infer the randomization shift, compare to previously inferred.
int32_t offset_of_this_entry = (int32_t)(*retouch_entry-
retouch_original_value);
if (!offset_set) {
offset_candidate = offset_of_this_entry;
offset_set = true;
} else {
if (offset_candidate != offset_of_this_entry) {
offset_mismatch = true;
printf("offset is mismatched: %d, this entry is %d,"
" original 0x%x @ 0x%x",
offset_candidate, offset_of_this_entry,
retouch_original_value, retouch_entry_offset);
}
}
}
if (b_ptr > (uint8_t *)r_info) {
printf("b_ptr went too far: %p, while r_info is %p",
b_ptr, r_info);
return RETOUCH_DATA_ERROR;
}
if (offset_mismatch) return RETOUCH_DATA_MISMATCHED;
if (retouch_offset != NULL) *retouch_offset = offset_candidate;
return RETOUCH_DATA_MATCHED;
}
// On success, _override is set to the offset that was actually applied.
// This implies that once we randomize to an offset we stick with it.
// This in turn is necessary in order to guarantee recovery after crash.
bool retouch_one_library(const char *binary_name,
const char *binary_sha1,
int32_t retouch_offset,
int32_t *retouch_offset_override) {
bool success = true;
int result;
FileContents file;
file.data = NULL;
char binary_name_atomic[strlen(binary_name)+10];
strcpy(binary_name_atomic, binary_name);
strcat(binary_name_atomic, ".atomic");
// We need a path that exists for calling statfs() later.
//
// Assume that binary_name (eg "/system/app/Foo.apk") is located
// on the same filesystem as its top-level directory ("/system").
char target_fs[strlen(binary_name)+1];
char* slash = strchr(binary_name+1, '/');
if (slash != NULL) {
int count = slash - binary_name;
strncpy(target_fs, binary_name, count);
target_fs[count] = '\0';
} else {
strcpy(target_fs, binary_name);
}
result = LoadFileContents(binary_name, &file, RETOUCH_DONT_MASK);
if (result == 0) {
// Figure out the *apparent* offset to which this file has been
// retouched. If it looks good, we will skip processing (we might
// have crashed and during this recovery pass we don't want to
// overwrite a valuable saved file in /cache---which would happen
// if we blindly retouch everything again). NOTE: This implies
// that we might have to override the supplied retouch offset. We
// can do the override only once though: everything should match
// afterward.
int32_t inferred_offset;
int retouch_probe_result = retouch_mask_data(file.data,
file.size,
NULL,
&inferred_offset);
if (retouch_probe_result == RETOUCH_DATA_MATCHED) {
if ((retouch_offset == inferred_offset) ||
((retouch_offset != 0 && inferred_offset != 0) &&
(retouch_offset_override != NULL))) {
// This file is OK already and we are allowed to override.
// Let's just return the offset override value. It is critical
// to skip regardless of override: a broken file might need
// recovery down the list and we should not mess up the saved
// copy by doing unnecessary retouching.
//
// NOTE: If retouching was already started with a different
// value, we will not be allowed to override. This happens
// if on the retouch list there is a patched binary (which is
// masked in apply_patch()) before there is a non-patched
// binary.
if (retouch_offset_override != NULL)
*retouch_offset_override = inferred_offset;
success = true;
goto out;
} else {
// Retouch to zero (mask the retouching), to make sure that
// the SHA-1 check will pass below.
int32_t zero = 0;
retouch_mask_data(file.data, file.size, &zero, NULL);
SHA(file.data, file.size, file.sha1);
}
}
if (retouch_probe_result == RETOUCH_DATA_NOTAPPLICABLE) {
// In the case of not retouchable, fake it. We do not want
// to do the normal processing and overwrite the backup file:
// we might be recovering!
//
// We return a zero override, which tells the caller that we
// simply skipped the file.
if (retouch_offset_override != NULL)
*retouch_offset_override = 0;
success = true;
goto out;
}
// If we get here, either there was a mismatch in the offset, or
// the file has not been processed yet. Continue with normal
// processing.
}
if (result != 0 || FindMatchingPatch(file.sha1, &binary_sha1, 1) < 0) {
free(file.data);
printf("Attempting to recover source from '%s' ...\n",
CACHE_TEMP_SOURCE);
result = LoadFileContents(CACHE_TEMP_SOURCE, &file, RETOUCH_DO_MASK);
if (result != 0 || FindMatchingPatch(file.sha1, &binary_sha1, 1) < 0) {
printf(" failed.\n");
success = false;
goto out;
}
printf(" succeeded.\n");
}
// Retouch in-memory before worrying about backing up the original.
//
// Recovery steps will be oblivious to the actual retouch offset used,
// so might as well write out the already-retouched copy. Then, in the
// usual case, we will just swap the file locally, with no more writes
// needed. In the no-free-space case, we will then write the same to the
// original location.
result = retouch_mask_data(file.data, file.size, &retouch_offset, NULL);
if (result != RETOUCH_DATA_MATCHED) {
success = false;
goto out;
}
if (retouch_offset_override != NULL)
*retouch_offset_override = retouch_offset;
// How much free space do we need?
bool enough_space = false;
size_t free_space = FreeSpaceForFile(target_fs);
// 50% margin when estimating the space needed.
enough_space = (free_space > (file.size * 3 / 2));
// The experts say we have to allow for a retry of the
// whole process to avoid filesystem weirdness.
int retry = 1;
bool made_copy = false;
do {
// First figure out where to store a copy of the original.
// Ideally leave the original itself intact until the
// atomic swap. If no room on the same partition, fall back
// to the cache partition and remove the original.
if (!enough_space) {
printf("Target is %ldB; free space is %ldB: not enough.\n",
(long)file.size, (long)free_space);
retry = 0;
if (MakeFreeSpaceOnCache(file.size) < 0) {
printf("Not enough free space on '/cache'.\n");
success = false;
goto out;
}
if (SaveFileContents(CACHE_TEMP_SOURCE, file) < 0) {
printf("Failed to back up source file.\n");
success = false;
goto out;
}
made_copy = true;
unlink(binary_name);
size_t free_space = FreeSpaceForFile(target_fs);
printf("(now %ld bytes free for target)\n", (long)free_space);
}
result = SaveFileContents(binary_name_atomic, file);
if (result != 0) {
// Maybe the filesystem was optimistic: retry.
enough_space = false;
unlink(binary_name_atomic);
printf("Saving the retouched contents failed; retrying.\n");
continue;
}
// Succeeded; no need to retry.
break;
} while (retry-- > 0);
// Give the .atomic file the same owner, group, and mode of the
// original source file.
if (chmod(binary_name_atomic, file.st.st_mode) != 0) {
printf("chmod of \"%s\" failed: %s\n",
binary_name_atomic, strerror(errno));
success = false;
goto out;
}
if (chown(binary_name_atomic, file.st.st_uid, file.st.st_gid) != 0) {
printf("chown of \"%s\" failed: %s\n",
binary_name_atomic,
strerror(errno));
success = false;
goto out;
}
// Finally, rename the .atomic file to replace the target file.
if (rename(binary_name_atomic, binary_name) != 0) {
printf("rename of .atomic to \"%s\" failed: %s\n",
binary_name, strerror(errno));
success = false;
goto out;
}
// If this run created a copy, and we're here, we can delete it.
if (made_copy) unlink(CACHE_TEMP_SOURCE);
out:
// clean up
free(file.data);
unlink(binary_name_atomic);
return success;
}

51
minelf/Retouch.h Normal file
View File

@ -0,0 +1,51 @@
/*
* Copyright (C) 2009 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 _MINELF_RETOUCH
#define _MINELF_RETOUCH
#include <stdbool.h>
#include <sys/types.h>
typedef struct {
char tag[8]; /* "RETOUCH ", not zero-terminated */
uint32_t blob_size; /* in bytes, located right before this struct */
} retouch_info_t __attribute__((packed));
// Retouch a file. Use CACHED_SOURCE_TEMP to store a copy.
bool retouch_one_library(const char *binary_name,
const char *binary_sha1,
int32_t retouch_offset,
int32_t *retouch_offset_override);
#define RETOUCH_DONT_MASK 0
#define RETOUCH_DO_MASK 1
#define RETOUCH_DATA_ERROR 0 // This is bad. Should not happen.
#define RETOUCH_DATA_MATCHED 1 // Up to an uniform random offset.
#define RETOUCH_DATA_MISMATCHED 2 // Partially randomized, or total mess.
#define RETOUCH_DATA_NOTAPPLICABLE 3 // Not retouched. Only when inferring.
// Mask retouching in-memory. Used before apply_patch[_check].
// Also used to determine status of retouching after a crash.
//
// If desired_offset is not NULL, then apply retouching instead,
// and return that in retouch_offset.
int retouch_mask_data(uint8_t *binary_object,
int32_t binary_size,
int32_t *desired_offset,
int32_t *retouch_offset);
#endif

View File

@ -1,29 +1,19 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := events.c resources.c
ifneq ($(BOARD_CUSTOM_GRAPHICS),)
LOCAL_SRC_FILES += $(BOARD_CUSTOM_GRAPHICS)
else
LOCAL_SRC_FILES += graphics.c
endif
LOCAL_SRC_FILES := graphics.c events.c resources.c
LOCAL_C_INCLUDES +=\
external/libpng\
external/zlib
ifneq ($(BOARD_LDPI_RECOVERY),)
LOCAL_CFLAGS += -DBOARD_LDPI_RECOVERY='"$(BOARD_LDPI_RECOVERY)"'
endif
ifneq ($(BOARD_HAS_JANKY_BACKBUFFER),)
LOCAL_CFLAGS += -DBOARD_HAS_JANKY_BACKBUFFER
endif
ifeq ($(BOARD_HAS_FLIPPED_SCREEN), true)
LOCAL_CFLAGS += -DBOARD_HAS_FLIPPED_SCREEN
endif
LOCAL_MODULE := libminui
ifeq ($(TARGET_RECOVERY_PIXEL_FORMAT),"RGBX_8888")
LOCAL_CFLAGS += -DRECOVERY_RGBX
endif
ifeq ($(TARGET_RECOVERY_PIXEL_FORMAT),"BGRA_8888")
LOCAL_CFLAGS += -DRECOVERY_BGRA
endif
include $(BUILD_STATIC_LIBRARY)

View File

@ -19,167 +19,33 @@
#include <fcntl.h>
#include <dirent.h>
#include <sys/poll.h>
#include <limits.h>
#include <linux/input.h>
#include "../common.h"
#include "minui.h"
#define MAX_DEVICES 16
#define MAX_MISC_FDS 16
#define VIBRATOR_TIMEOUT_FILE "/sys/class/timed_output/vibrator/enable"
#define VIBRATOR_TIME_MS 50
#define BITS_PER_LONG (sizeof(unsigned long) * 8)
#define BITS_TO_LONGS(x) (((x) + BITS_PER_LONG - 1) / BITS_PER_LONG)
#define PRESS_THRESHHOLD 10
#define test_bit(bit, array) \
((array)[(bit)/BITS_PER_LONG] & (1 << ((bit) % BITS_PER_LONG)))
#define ABS_MT_POSITION_X 0x35
#define ABS_MT_POSITION_Y 0x36
#define ABS_MT_TOUCH_MAJOR 0x30
#define SYN_MT_REPORT 2
struct virtualkey {
int scancode;
int centerx, centery;
int width, height;
struct fd_info {
ev_callback cb;
void *data;
};
struct position {
int x, y;
int pressed;
struct input_absinfo xi, yi;
};
static struct pollfd ev_fds[MAX_DEVICES + MAX_MISC_FDS];
static struct fd_info ev_fdinfo[MAX_DEVICES + MAX_MISC_FDS];
struct ev {
struct pollfd *fd;
struct virtualkey *vks;
int vk_count;
struct position p, mt_p;
int sent, mt_idx;
};
static struct pollfd ev_fds[MAX_DEVICES];
static struct ev evs[MAX_DEVICES];
static unsigned ev_count = 0;
static unsigned ev_dev_count = 0;
static unsigned ev_misc_count = 0;
static inline int ABS(int x) {
return x<0?-x:x;
}
int vibrate(int timeout_ms)
{
char str[20];
int fd;
int ret;
fd = open(VIBRATOR_TIMEOUT_FILE, O_WRONLY);
if (fd < 0)
return -1;
ret = snprintf(str, sizeof(str), "%d", timeout_ms);
ret = write(fd, str, ret);
close(fd);
if (ret < 0)
return -1;
return 0;
}
/* Returns empty tokens */
static char *vk_strtok_r(char *str, const char *delim, char **save_str)
{
if(!str) {
if(!*save_str) return NULL;
str = (*save_str) + 1;
}
*save_str = strpbrk(str, delim);
if(*save_str) **save_str = '\0';
return str;
}
static int vk_init(struct ev *e)
{
char vk_path[PATH_MAX] = "/sys/board_properties/virtualkeys.";
char vks[2048], *ts;
ssize_t len;
int vk_fd;
int i;
e->vk_count = 0;
len = strlen(vk_path);
len = ioctl(e->fd->fd, EVIOCGNAME(sizeof(vk_path) - len), vk_path + len);
if (len <= 0)
return -1;
vk_fd = open(vk_path, O_RDONLY);
if (vk_fd < 0)
return -1;
len = read(vk_fd, vks, sizeof(vks)-1);
close(vk_fd);
if (len <= 0)
return -1;
vks[len] = '\0';
/* Parse a line like:
keytype:keycode:centerx:centery:width:height:keytype2:keycode2:centerx2:...
*/
for (ts = vks, e->vk_count = 1; *ts; ++ts) {
if (*ts == ':')
++e->vk_count;
}
if (e->vk_count % 6) {
LOGW("minui: %s is %d %% 6\n", vk_path, e->vk_count % 6);
}
e->vk_count /= 6;
if (e->vk_count <= 0)
return -1;
e->sent = 0;
e->mt_idx = 0;
ioctl(e->fd->fd, EVIOCGABS(ABS_X), &e->p.xi);
ioctl(e->fd->fd, EVIOCGABS(ABS_Y), &e->p.yi);
e->p.pressed = 0;
ioctl(e->fd->fd, EVIOCGABS(ABS_MT_POSITION_X), &e->mt_p.xi);
ioctl(e->fd->fd, EVIOCGABS(ABS_MT_POSITION_Y), &e->mt_p.yi);
e->mt_p.pressed = 0;
e->vks = malloc(sizeof(*e->vks) * e->vk_count);
for (i = 0; i < e->vk_count; ++i) {
char *token[6];
int j;
for (j = 0; j < 6; ++j) {
token[j] = vk_strtok_r((i||j)?NULL:vks, ":", &ts);
}
if (strcmp(token[0], "0x01") != 0) {
/* Java does string compare, so we do too. */
LOGW("minui: %s: ignoring unknown virtual key type %s\n", vk_path, token[0]);
continue;
}
e->vks[i].scancode = strtol(token[1], NULL, 0);
e->vks[i].centerx = strtol(token[2], NULL, 0);
e->vks[i].centery = strtol(token[3], NULL, 0);
e->vks[i].width = strtol(token[4], NULL, 0);
e->vks[i].height = strtol(token[5], NULL, 0);
}
return 0;
}
int ev_init(void)
int ev_init(ev_callback input_cb, void *data)
{
DIR *dir;
struct dirent *de;
@ -188,177 +54,122 @@ int ev_init(void)
dir = opendir("/dev/input");
if(dir != 0) {
while((de = readdir(dir))) {
unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)];
// fprintf(stderr,"/dev/input/%s\n", de->d_name);
if(strncmp(de->d_name,"event",5)) continue;
fd = openat(dirfd(dir), de->d_name, O_RDONLY);
if(fd < 0) continue;
/* read the evbits of the input device */
if (ioctl(fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) < 0) {
close(fd);
continue;
}
/* TODO: add ability to specify event masks. For now, just assume
* that only EV_KEY and EV_REL event types are ever needed. */
if (!test_bit(EV_KEY, ev_bits) && !test_bit(EV_REL, ev_bits)) {
close(fd);
continue;
}
ev_fds[ev_count].fd = fd;
ev_fds[ev_count].events = POLLIN;
evs[ev_count].fd = &ev_fds[ev_count];
/* Load virtualkeys if there are any */
vk_init(&evs[ev_count]);
ev_fdinfo[ev_count].cb = input_cb;
ev_fdinfo[ev_count].data = data;
ev_count++;
if(ev_count == MAX_DEVICES) break;
ev_dev_count++;
if(ev_dev_count == MAX_DEVICES) break;
}
}
return 0;
}
int ev_add_fd(int fd, ev_callback cb, void *data)
{
if (ev_misc_count == MAX_MISC_FDS || cb == NULL)
return -1;
ev_fds[ev_count].fd = fd;
ev_fds[ev_count].events = POLLIN;
ev_fdinfo[ev_count].cb = cb;
ev_fdinfo[ev_count].data = data;
ev_count++;
ev_misc_count++;
return 0;
}
void ev_exit(void)
{
while (ev_count-- > 0) {
if (evs[ev_count].vk_count) {
free(evs[ev_count].vks);
evs[ev_count].vk_count = 0;
}
close(ev_fds[ev_count].fd);
while (ev_count > 0) {
close(ev_fds[--ev_count].fd);
}
ev_misc_count = 0;
ev_dev_count = 0;
}
static int vk_inside_display(__s32 value, struct input_absinfo *info, int screen_size)
{
int screen_pos;
if (info->minimum == info->maximum)
return 0;
screen_pos = (value - info->minimum) * (screen_size - 1) / (info->maximum - info->minimum);
return (screen_pos >= 0 && screen_pos < screen_size);
}
static int vk_tp_to_screen(struct position *p, int *x, int *y)
{
if (p->xi.minimum == p->xi.maximum || p->yi.minimum == p->yi.maximum)
return 0;
*x = (p->x - p->xi.minimum) * (gr_fb_width() - 1) / (p->xi.maximum - p->xi.minimum);
*y = (p->y - p->yi.minimum) * (gr_fb_height() - 1) / (p->yi.maximum - p->yi.minimum);
if (*x >= 0 && *x < gr_fb_width() &&
*y >= 0 && *y < gr_fb_height()) {
return 0;
}
return 1;
}
/* Translate a virtual key in to a real key event, if needed */
/* Returns non-zero when the event should be consumed */
static int vk_modify(struct ev *e, struct input_event *ev)
{
int i;
int x, y;
if (ev->type == EV_KEY) {
if (ev->code == BTN_TOUCH)
e->p.pressed = ev->value;
return 0;
}
if (ev->type == EV_ABS) {
switch (ev->code) {
case ABS_X:
e->p.x = ev->value;
return !vk_inside_display(e->p.x, &e->p.xi, gr_fb_width());
case ABS_Y:
e->p.y = ev->value;
return !vk_inside_display(e->p.y, &e->p.yi, gr_fb_height());
case ABS_MT_POSITION_X:
if (e->mt_idx) return 1;
e->mt_p.x = ev->value;
return !vk_inside_display(e->mt_p.x, &e->mt_p.xi, gr_fb_width());
case ABS_MT_POSITION_Y:
if (e->mt_idx) return 1;
e->mt_p.y = ev->value;
return !vk_inside_display(e->mt_p.y, &e->mt_p.yi, gr_fb_height());
case ABS_MT_TOUCH_MAJOR:
if (e->mt_idx) return 1;
if (e->sent)
e->mt_p.pressed = (ev->value > 0);
else
e->mt_p.pressed = (ev->value > PRESS_THRESHHOLD);
return 0;
}
return 0;
}
if (ev->type != EV_SYN)
return 0;
if (ev->code == SYN_MT_REPORT) {
/* Ignore the rest of the points */
++e->mt_idx;
return 1;
}
if (ev->code != SYN_REPORT)
return 0;
/* Report complete */
e->mt_idx = 0;
if (!e->p.pressed && !e->mt_p.pressed) {
/* No touch */
e->sent = 0;
return 0;
}
if (!(e->p.pressed && vk_tp_to_screen(&e->p, &x, &y)) &&
!(e->mt_p.pressed && vk_tp_to_screen(&e->mt_p, &x, &y))) {
/* No touch inside vk area */
return 0;
}
if (e->sent) {
/* We've already sent a fake key for this touch */
return 1;
}
/* The screen is being touched on the vk area */
e->sent = 1;
for (i = 0; i < e->vk_count; ++i) {
int xd = ABS(e->vks[i].centerx - x);
int yd = ABS(e->vks[i].centery - y);
if (xd < e->vks[i].width/2 && yd < e->vks[i].height/2) {
/* Fake a key event */
ev->type = EV_KEY;
ev->code = e->vks[i].scancode;
ev->value = 1;
vibrate(VIBRATOR_TIME_MS);
return 0;
}
}
return 1;
}
int ev_get(struct input_event *ev, unsigned dont_wait)
int ev_wait(int timeout)
{
int r;
r = poll(ev_fds, ev_count, timeout);
if (r <= 0)
return -1;
return 0;
}
void ev_dispatch(void)
{
unsigned n;
int ret;
do {
r = poll(ev_fds, ev_count, dont_wait ? 0 : -1);
for (n = 0; n < ev_count; n++) {
ev_callback cb = ev_fdinfo[n].cb;
if (cb && (ev_fds[n].revents & ev_fds[n].events))
cb(ev_fds[n].fd, ev_fds[n].revents, ev_fdinfo[n].data);
}
}
if(r > 0) {
for(n = 0; n < ev_count; n++) {
if(ev_fds[n].revents & POLLIN) {
r = read(ev_fds[n].fd, ev, sizeof(*ev));
if(r == sizeof(*ev)) {
if (!vk_modify(&evs[n], ev))
return 0;
}
}
}
}
} while(dont_wait == 0);
int ev_get_input(int fd, short revents, struct input_event *ev)
{
int r;
if (revents & POLLIN) {
r = read(fd, ev, sizeof(*ev));
if (r == sizeof(*ev))
return 0;
}
return -1;
}
int ev_sync_key_state(ev_set_key_callback set_key_cb, void *data)
{
unsigned long key_bits[BITS_TO_LONGS(KEY_MAX)];
unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)];
unsigned i;
int ret;
for (i = 0; i < ev_dev_count; i++) {
int code;
memset(key_bits, 0, sizeof(key_bits));
memset(ev_bits, 0, sizeof(ev_bits));
ret = ioctl(ev_fds[i].fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits);
if (ret < 0 || !test_bit(EV_KEY, ev_bits))
continue;
ret = ioctl(ev_fds[i].fd, EVIOCGKEY(sizeof(key_bits)), key_bits);
if (ret < 0)
continue;
for (code = 0; code <= KEY_MAX; code++) {
if (test_bit(code, key_bits))
set_key_cb(code, 1, data);
}
}
return 0;
}

View File

@ -14,6 +14,7 @@
* limitations under the License.
*/
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
@ -29,14 +30,20 @@
#include <pixelflinger/pixelflinger.h>
#ifndef BOARD_LDPI_RECOVERY
#include "font_10x18.h"
#else
#include "font_7x16.h"
#endif
#include "font_10x18.h"
#include "minui.h"
#if defined(RECOVERY_BGRA)
#define PIXEL_FORMAT GGL_PIXEL_FORMAT_BGRA_8888
#define PIXEL_SIZE 4
#elif defined(RECOVERY_RGBX)
#define PIXEL_FORMAT GGL_PIXEL_FORMAT_RGBX_8888
#define PIXEL_SIZE 4
#else
#define PIXEL_FORMAT GGL_PIXEL_FORMAT_RGB_565
#define PIXEL_SIZE 2
#endif
typedef struct {
GGLSurface texture;
unsigned cwidth;
@ -55,11 +62,11 @@ static int gr_fb_fd = -1;
static int gr_vt_fd = -1;
static struct fb_var_screeninfo vi;
static struct fb_fix_screeninfo fi;
static int get_framebuffer(GGLSurface *fb)
{
int fd;
struct fb_fix_screeninfo fi;
void *bits;
fd = open("/dev/graphics/fb0", O_RDWR);
@ -68,13 +75,48 @@ static int get_framebuffer(GGLSurface *fb)
return -1;
}
if (ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) {
if (ioctl(fd, FBIOGET_VSCREENINFO, &vi) < 0) {
perror("failed to get fb0 info");
close(fd);
return -1;
}
if (ioctl(fd, FBIOGET_VSCREENINFO, &vi) < 0) {
vi.bits_per_pixel = PIXEL_SIZE * 8;
if (PIXEL_FORMAT == GGL_PIXEL_FORMAT_BGRA_8888) {
vi.red.offset = 8;
vi.red.length = 8;
vi.green.offset = 16;
vi.green.length = 8;
vi.blue.offset = 24;
vi.blue.length = 8;
vi.transp.offset = 0;
vi.transp.length = 8;
} else if (PIXEL_FORMAT == GGL_PIXEL_FORMAT_RGBX_8888) {
vi.red.offset = 24;
vi.red.length = 8;
vi.green.offset = 16;
vi.green.length = 8;
vi.blue.offset = 8;
vi.blue.length = 8;
vi.transp.offset = 0;
vi.transp.length = 8;
} else { /* RGB565*/
vi.red.offset = 11;
vi.red.length = 5;
vi.green.offset = 5;
vi.green.length = 6;
vi.blue.offset = 0;
vi.blue.length = 5;
vi.transp.offset = 0;
vi.transp.length = 0;
}
if (ioctl(fd, FBIOPUT_VSCREENINFO, &vi) < 0) {
perror("failed to put fb0 info");
close(fd);
return -1;
}
if (ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) {
perror("failed to get fb0 info");
close(fd);
return -1;
@ -90,29 +132,20 @@ static int get_framebuffer(GGLSurface *fb)
fb->version = sizeof(*fb);
fb->width = vi.xres;
fb->height = vi.yres;
#ifdef BOARD_HAS_JANKY_BACKBUFFER
fb->stride = fi.line_length/2;
#else
fb->stride = vi.xres;
#endif
fb->stride = fi.line_length/PIXEL_SIZE;
fb->data = bits;
fb->format = GGL_PIXEL_FORMAT_RGB_565;
memset(fb->data, 0, vi.yres * vi.xres * 2);
fb->format = PIXEL_FORMAT;
memset(fb->data, 0, vi.yres * fi.line_length);
fb++;
fb->version = sizeof(*fb);
fb->width = vi.xres;
fb->height = vi.yres;
#ifdef BOARD_HAS_JANKY_BACKBUFFER
fb->stride = fi.line_length/2;
fb->stride = fi.line_length/PIXEL_SIZE;
fb->data = (void*) (((unsigned) bits) + vi.yres * fi.line_length);
#else
fb->stride = vi.xres;
fb->data = (void*) (((unsigned) bits) + vi.yres * vi.xres * 2);
#endif
fb->format = GGL_PIXEL_FORMAT_RGB_565;
memset(fb->data, 0, vi.yres * vi.xres * 2);
fb->format = PIXEL_FORMAT;
memset(fb->data, 0, vi.yres * fi.line_length);
return fd;
}
@ -121,17 +154,17 @@ static void get_memory_surface(GGLSurface* ms) {
ms->version = sizeof(*ms);
ms->width = vi.xres;
ms->height = vi.yres;
ms->stride = vi.xres;
ms->data = malloc(vi.xres * vi.yres * 2);
ms->format = GGL_PIXEL_FORMAT_RGB_565;
ms->stride = fi.line_length/PIXEL_SIZE;
ms->data = malloc(fi.line_length * vi.yres);
ms->format = PIXEL_FORMAT;
}
static void set_active_framebuffer(unsigned n)
{
if (n > 1) return;
vi.yres_virtual = vi.yres * 2;
vi.yres_virtual = vi.yres * PIXEL_SIZE;
vi.yoffset = n * vi.yres;
vi.bits_per_pixel = 16;
vi.bits_per_pixel = PIXEL_SIZE * 8;
if (ioctl(gr_fb_fd, FBIOPUT_VSCREENINFO, &vi) < 0) {
perror("active fb swap failed");
}
@ -144,20 +177,10 @@ void gr_flip(void)
/* swap front and back buffers */
gr_active_fb = (gr_active_fb + 1) & 1;
#ifdef BOARD_HAS_FLIPPED_SCREEN
/* flip buffer 180 degrees for devices with physicaly inverted screens */
unsigned int i;
for (i = 1; i < (vi.xres * vi.yres); i++) {
unsigned short tmp = gr_mem_surface.data[i];
gr_mem_surface.data[i] = gr_mem_surface.data[(vi.xres * vi.yres * 2) - i];
gr_mem_surface.data[(vi.xres * vi.yres * 2) - i] = tmp;
}
#endif
/* copy data from the in-memory surface to the buffer we're about
* to make active. */
memcpy(gr_framebuffer[gr_active_fb].data, gr_mem_surface.data,
vi.xres * vi.yres * 2);
fi.line_length * vi.yres);
/* inform the display driver */
set_active_framebuffer(gr_active_fb);
@ -179,6 +202,12 @@ int gr_measure(const char *s)
return gr_font->cwidth * strlen(s);
}
void gr_font_size(int *x, int *y)
{
*x = gr_font->cwidth;
*y = gr_font->cheight;
}
int gr_text(int x, int y, const char *s)
{
GGLContext *gl = gr_context;
@ -307,6 +336,9 @@ int gr_init(void)
gl->enable(gl, GGL_BLEND);
gl->blendFunc(gl, GGL_SRC_ALPHA, GGL_ONE_MINUS_SRC_ALPHA);
gr_fb_blank(true);
gr_fb_blank(false);
return 0;
}
@ -337,3 +369,11 @@ gr_pixel *gr_fb_data(void)
return (unsigned short *) gr_mem_surface.data;
}
void gr_fb_blank(bool blank)
{
int ret;
ret = ioctl(gr_fb_fd, FBIOBLANK, blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK);
if (ret < 0)
perror("ioctl(): blank");
}

View File

@ -17,6 +17,8 @@
#ifndef _MINUI_H_
#define _MINUI_H_
#include <stdbool.h>
typedef void* gr_surface;
typedef unsigned short gr_pixel;
@ -27,11 +29,13 @@ int gr_fb_width(void);
int gr_fb_height(void);
gr_pixel *gr_fb_data(void);
void gr_flip(void);
void gr_fb_blank(bool blank);
void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a);
void gr_fill(int x, int y, int w, int h);
int gr_text(int x, int y, const char *s);
int gr_measure(const char *s);
void gr_font_size(int *x, int *y);
void gr_blit(gr_surface source, int sx, int sy, int w, int h, int dx, int dy);
unsigned int gr_get_width(gr_surface surface);
@ -41,9 +45,23 @@ unsigned int gr_get_height(gr_surface surface);
// see http://www.mjmwired.net/kernel/Documentation/input/ for info.
struct input_event;
int ev_init(void);
typedef int (*ev_callback)(int fd, short revents, void *data);
typedef int (*ev_set_key_callback)(int code, int value, void *data);
int ev_init(ev_callback input_cb, void *data);
void ev_exit(void);
int ev_get(struct input_event *ev, unsigned dont_wait);
int ev_add_fd(int fd, ev_callback cb, void *data);
int ev_sync_key_state(ev_set_key_callback set_key_cb, void *data);
/* timeout has the same semantics as for poll
* 0 : don't block
* < 0 : block forever
* > 0 : block for 'timeout' milliseconds
*/
int ev_wait(int timeout);
int ev_get_input(int fd, short revents, struct input_event *ev);
void ev_dispatch(void);
// Resources

View File

@ -49,6 +49,8 @@ int res_create_surface(const char* name, gr_surface* pSurface) {
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
*pSurface = NULL;
snprintf(resPath, sizeof(resPath)-1, "/res/images/%s.png", name);
resPath[sizeof(resPath)-1] = '\0';
FILE* fp = fopen(resPath, "rb");
@ -119,13 +121,18 @@ int res_create_surface(const char* name, gr_surface* pSurface) {
surface->format = (channels == 3) ?
GGL_PIXEL_FORMAT_RGBX_8888 : GGL_PIXEL_FORMAT_RGBA_8888;
int alpha = 0;
if (color_type == PNG_COLOR_TYPE_PALETTE) {
png_set_palette_to_rgb(png_ptr);
png_set_palette_to_rgb(png_ptr);
}
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
png_set_tRNS_to_alpha(png_ptr);
alpha = 1;
}
int y;
if (channels == 3) {
for (y = 0; y < (int)height; ++y) {
if (channels == 3 || (channels == 1 && !alpha)) {
for (y = 0; y < height; ++y) {
unsigned char* pRow = pData + y * stride;
png_read_row(png_ptr, pRow, NULL);
@ -144,7 +151,7 @@ int res_create_surface(const char* name, gr_surface* pSurface) {
}
}
} else {
for (y = 0; y < (int)height; ++y) {
for (y = 0; y < height; ++y) {
unsigned char* pRow = pData + y * stride;
png_read_row(png_ptr, pRow, NULL);
}

View File

@ -1,6 +1,3 @@
ifneq ($(TARGET_SIMULATOR),true)
ifeq ($(TARGET_ARCH),arm)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
@ -30,6 +27,3 @@ LOCAL_STATIC_LIBRARIES := libmtdutils libcutils libc
LOCAL_FORCE_STATIC_EXECUTABLE := true
include $(BUILD_EXECUTABLE)
endif
endif # TARGET_ARCH == arm
endif # !TARGET_SIMULATOR

View File

@ -262,8 +262,8 @@ MtdReadContext *mtd_read_partition(const MtdPartition *partition)
sprintf(mtddevname, "/dev/mtd/mtd%d", partition->device_index);
ctx->fd = open(mtddevname, O_RDONLY);
if (ctx->fd < 0) {
free(ctx);
free(ctx->buffer);
free(ctx);
return NULL;
}

View File

@ -24,7 +24,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/reboot.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
@ -35,12 +34,12 @@
#include "bootloader.h"
#include "common.h"
#include "cutils/properties.h"
#include "cutils/android_reboot.h"
#include "install.h"
#include "minui/minui.h"
#include "minzip/DirUtil.h"
#include "roots.h"
#include "recovery_ui.h"
#include "encryptedfs_provisioning.h"
#include "extendedcommands.h"
#include "flashutils/flashutils.h"
@ -50,7 +49,6 @@ static const struct option OPTIONS[] = {
{ "update_package", required_argument, NULL, 'u' },
{ "wipe_data", no_argument, NULL, 'w' },
{ "wipe_cache", no_argument, NULL, 'c' },
{ "set_encrypted_filesystems", required_argument, NULL, 'e' },
{ "show_text", no_argument, NULL, 't' },
{ NULL, 0, NULL, 0 },
};
@ -59,6 +57,7 @@ static const char *COMMAND_FILE = "/cache/recovery/command";
static const char *INTENT_FILE = "/cache/recovery/intent";
static const char *LOG_FILE = "/cache/recovery/log";
static const char *LAST_LOG_FILE = "/cache/recovery/last_log";
static const char *CACHE_ROOT = "/cache";
static const char *SDCARD_ROOT = "/sdcard";
static int allow_display_toggle = 1;
static int poweroff = 0;
@ -66,6 +65,8 @@ static const char *SDCARD_PACKAGE_FILE = "/sdcard/update.zip";
static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log";
static const char *SIDELOAD_TEMP_DIR = "/tmp/sideload";
extern UIParameters ui_parameters; // from ui.c
/*
* The recovery tool communicates with the main system through /cache files.
* /cache/recovery/command - INPUT - command line for tool, one arg per line
@ -122,33 +123,13 @@ static const char *SIDELOAD_TEMP_DIR = "/tmp/sideload";
* 8g. finish_recovery() erases BCB
* -- after this, rebooting will (try to) restart the main system --
* 9. main() calls reboot() to boot main system
*
* SECURE FILE SYSTEMS ENABLE/DISABLE
* 1. user selects "enable encrypted file systems"
* 2. main system writes "--set_encrypted_filesystems=on|off" to
* /cache/recovery/command
* 3. main system reboots into recovery
* 4. get_args() writes BCB with "boot-recovery" and
* "--set_encrypted_filesystems=on|off"
* -- after this, rebooting will restart the transition --
* 5. read_encrypted_fs_info() retrieves encrypted file systems settings from /data
* Settings include: property to specify the Encrypted FS istatus and
* FS encryption key if enabled (not yet implemented)
* 6. erase_volume() reformats /data
* 7. erase_volume() reformats /cache
* 8. restore_encrypted_fs_info() writes required encrypted file systems settings to /data
* Settings include: property to specify the Encrypted FS status and
* FS encryption key if enabled (not yet implemented)
* 9. finish_recovery() erases BCB
* -- after this, rebooting will restart the main system --
* 10. main() calls reboot() to boot main system
*/
static const int MAX_ARG_LENGTH = 4096;
static const int MAX_ARGS = 100;
// open a given path, mounting partitions as necessary
static FILE*
FILE*
fopen_path(const char *path, const char *mode) {
if (ensure_path_mounted(path) != 0) {
LOGE("Can't mount %s\n", path);
@ -467,6 +448,16 @@ get_menu_selection(char** headers, char** items, int menu_only,
int key = ui_wait_key();
int visible = ui_text_visible();
if (key == -1) { // ui_wait_key() timed out
if (ui_text_ever_visible()) {
continue;
} else {
LOGI("timed out waiting for key input; rebooting.\n");
ui_end_menu();
return ITEM_REBOOT;
}
}
int action = device_handle_key(key, visible);
int old_selected = selected;
@ -525,8 +516,8 @@ static int compare_string(const void* a, const void* b) {
}
static int
sdcard_directory(const char* path) {
ensure_path_mounted(SDCARD_ROOT);
update_directory(const char* path, const char* unmount_when_done) {
ensure_path_mounted(path);
const char* MENU_HEADERS[] = { "Choose a package to install:",
path,
@ -537,7 +528,9 @@ sdcard_directory(const char* path) {
d = opendir(path);
if (d == NULL) {
LOGE("error opening %s: %s\n", path, strerror(errno));
ensure_path_unmounted(SDCARD_ROOT);
if (unmount_when_done != NULL) {
ensure_path_unmounted(unmount_when_done);
}
return 0;
}
@ -602,7 +595,7 @@ sdcard_directory(const char* path) {
char* item = zips[chosen_item];
int item_len = strlen(item);
if (chosen_item == 0) { // item 0 is always "../"
// go up but continue browsing (if the caller is sdcard_directory)
// go up but continue browsing (if the caller is update_directory)
result = -1;
break;
} else if (item[item_len-1] == '/') {
@ -612,7 +605,7 @@ sdcard_directory(const char* path) {
strlcat(new_path, "/", PATH_MAX);
strlcat(new_path, item, PATH_MAX);
new_path[strlen(new_path)-1] = '\0'; // truncate the trailing '/'
result = sdcard_directory(new_path);
result = update_directory(new_path, unmount_when_done);
if (result >= 0) break;
} else {
// selected a zip file: attempt to install it, and return
@ -625,7 +618,9 @@ sdcard_directory(const char* path) {
ui_print("\n-- Install %s ...\n", path);
set_sdcard_update_bootloader_message();
char* copy = copy_sideloaded_package(new_path);
ensure_path_unmounted(SDCARD_ROOT);
if (unmount_when_done != NULL) {
ensure_path_unmounted(unmount_when_done);
}
if (copy) {
result = install_package(copy);
free(copy);
@ -641,7 +636,9 @@ sdcard_directory(const char* path) {
free(zips);
free(headers);
ensure_path_unmounted(SDCARD_ROOT);
if (unmount_when_done != NULL) {
ensure_path_unmounted(unmount_when_done);
}
return result;
}
@ -706,6 +703,7 @@ prompt_and_wait() {
// statement below.
chosen_item = device_perform_action(chosen_item);
int status;
switch (chosen_item) {
case ITEM_REBOOT:
poweroff=0;
@ -727,34 +725,23 @@ prompt_and_wait() {
break;
case ITEM_APPLY_SDCARD:
if (confirm_selection("Confirm install?", "Yes - Install /sdcard/update.zip"))
{
ui_print("\n-- Install from sdcard...\n");
int status = install_package(SDCARD_PACKAGE_FILE);
if (status != INSTALL_SUCCESS) {
ui_set_background(BACKGROUND_ICON_ERROR);
ui_print("Installation aborted.\n");
} else if (!ui_text_visible()) {
return; // reboot if logs aren't visible
} else {
ui_print("\nInstall from sdcard complete.\n");
}
}
break;
case ITEM_INSTALL_ZIP:
show_install_update_menu();
break;
case ITEM_NANDROID:
show_nandroid_menu();
break;
case ITEM_PARTITION:
show_partition_menu();
break;
case ITEM_ADVANCED:
show_advanced_menu();
break;
case ITEM_POWEROFF:
poweroff=1;
poweroff = 1;
return;
}
}
@ -811,6 +798,7 @@ main(int argc, char **argv) {
freopen(TEMPORARY_LOG_FILE, "a", stderr); setbuf(stderr, NULL);
printf("Starting recovery on %s", ctime(&start));
device_ui_init(&ui_parameters);
ui_init();
ui_print(EXPAND(RECOVERY_VERSION)"\n");
load_volume_table();
@ -821,10 +809,7 @@ main(int argc, char **argv) {
int previous_runs = 0;
const char *send_intent = NULL;
const char *update_package = NULL;
const char *encrypted_fs_mode = NULL;
int wipe_data = 0, wipe_cache = 0;
int toggle_secure_fs = 0;
encrypted_fs_info encrypted_fs_data;
LOGI("Checking arguments.\n");
int arg;
@ -839,7 +824,6 @@ main(int argc, char **argv) {
#endif
break;
case 'c': wipe_cache = 1; break;
case 'e': encrypted_fs_mode = optarg; toggle_secure_fs = 1; break;
case 't': ui_show_text(1); break;
case '?':
LOGE("Invalid command argument\n");
@ -876,44 +860,8 @@ main(int argc, char **argv) {
printf("\n");
int status = INSTALL_SUCCESS;
if (toggle_secure_fs) {
if (strcmp(encrypted_fs_mode,"on") == 0) {
encrypted_fs_data.mode = MODE_ENCRYPTED_FS_ENABLED;
ui_print("Enabling Encrypted FS.\n");
} else if (strcmp(encrypted_fs_mode,"off") == 0) {
encrypted_fs_data.mode = MODE_ENCRYPTED_FS_DISABLED;
ui_print("Disabling Encrypted FS.\n");
} else {
ui_print("Error: invalid Encrypted FS setting.\n");
status = INSTALL_ERROR;
}
// Recovery strategy: if the data partition is damaged, disable encrypted file systems.
// This preventsthe device recycling endlessly in recovery mode.
if ((encrypted_fs_data.mode == MODE_ENCRYPTED_FS_ENABLED) &&
(read_encrypted_fs_info(&encrypted_fs_data))) {
ui_print("Encrypted FS change aborted, resetting to disabled state.\n");
encrypted_fs_data.mode = MODE_ENCRYPTED_FS_DISABLED;
}
if (status != INSTALL_ERROR) {
if (erase_volume("/data")) {
ui_print("Data wipe failed.\n");
status = INSTALL_ERROR;
} else if (erase_volume("/cache")) {
ui_print("Cache wipe failed.\n");
status = INSTALL_ERROR;
} else if ((encrypted_fs_data.mode == MODE_ENCRYPTED_FS_ENABLED) &&
(restore_encrypted_fs_info(&encrypted_fs_data))) {
ui_print("Encrypted FS change aborted.\n");
status = INSTALL_ERROR;
} else {
ui_print("Successfully updated Encrypted FS.\n");
status = INSTALL_SUCCESS;
}
}
} else if (update_package != NULL) {
if (update_package != NULL) {
status = install_package(update_package);
if (status != INSTALL_SUCCESS) ui_print("Installation aborted.\n");
} else if (wipe_data) {
@ -960,12 +908,16 @@ main(int argc, char **argv) {
// Otherwise, get ready to boot the main system...
finish_recovery(send_intent);
if(!poweroff)
ui_print("Rebooting...\n");
else
ui_print("Shutting down...\n");
sync();
reboot((!poweroff) ? RB_AUTOBOOT : RB_POWER_OFF);
if(!poweroff) {
ui_print("Rebooting...\n");
android_reboot(ANDROID_RB_RESTART, 0, 0);
}
else {
ui_print("Shutting down...\n");
android_reboot(ANDROID_RB_POWEROFF, 0, 0);
}
return EXIT_SUCCESS;
}

View File

@ -17,6 +17,12 @@
#ifndef _RECOVERY_UI_H
#define _RECOVERY_UI_H
#include "common.h"
// 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);
// Called when recovery starts up. Returns 0.
extern int device_recovery_start();
@ -67,14 +73,16 @@ int device_wipe_data();
#define GO_BACK -5
#define ITEM_REBOOT 0
#define ITEM_APPLY_SDCARD 1
#define ITEM_APPLY_EXT 1
#define ITEM_APPLY_SDCARD 1 // historical synonym for ITEM_APPLY_EXT
#define ITEM_WIPE_DATA 2
#define ITEM_WIPE_CACHE 3
#define ITEM_INSTALL_ZIP 4
#define ITEM_NANDROID 5
#define ITEM_PARTITION 6
#define ITEM_ADVANCED 7
#define ITEM_POWEROFF 8
// unused in cwr
#define ITEM_APPLY_CACHE 4
#define ITEM_NANDROID 4
#define ITEM_PARTITION 5
#define ITEM_ADVANCED 6
#define ITEM_POWEROFF 7
// Header text to display above the main menu.
extern char* MENU_HEADERS[];

BIN
res/images/icon_error.png Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 19 KiB

BIN
res/images/icon_installing.png Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 687 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 661 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 665 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 683 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 676 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 361 B

After

Width:  |  Height:  |  Size: 118 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 286 B

After

Width:  |  Height:  |  Size: 404 B

61
roots.c
View File

@ -56,6 +56,28 @@ static char* dupe_string(const char* sz) {
return strdup(sz);
}
static int parse_options(char* options, Volume* volume) {
char* option;
while (option = strtok(options, ",")) {
options = NULL;
if (strncmp(option, "length=", 7) == 0) {
volume->length = strtoll(option+7, NULL, 10);
} else if (strncmp(option, "fstype2=", 8) == 0) {
volume->fs_type2 = volume->fs_type;
volume->fs_type = strdup(option);
} else if (strncmp(option, "fs_options=", 11) == 0) {
volume->fs_options = strdup(option);
} else if (strncmp(option, "fs_options2=", 12) == 0) {
volume->fs_options2 = strdup(option);
} else {
LOGE("bad option \"%s\"\n", option);
return -1;
}
}
return 0;
}
void load_volume_table() {
int alloc = 2;
device_volumes = malloc(alloc * sizeof(Volume));
@ -65,8 +87,10 @@ void load_volume_table() {
device_volumes[0].fs_type = "ramdisk";
device_volumes[0].device = NULL;
device_volumes[0].device2 = NULL;
device_volumes[0].fs_type2 = NULL;
device_volumes[0].fs_options = NULL;
device_volumes[0].fs_options2 = NULL;
device_volumes[0].length = 0;
num_volumes = 1;
FILE* fstab = fopen("/etc/recovery.fstab", "r");
@ -88,10 +112,16 @@ void load_volume_table() {
char* device = strtok(NULL, " \t\n");
// lines may optionally have a second device, to use if
// mounting the first one fails.
char* options = NULL;
char* device2 = strtok(NULL, " \t\n");
char* fs_type2 = strtok(NULL, " \t\n");
char* fs_options = strtok(NULL, " \t\n");
char* fs_options2 = strtok(NULL, " \t\n");
if (device2) {
if (device2[0] == '/') {
options = strtok(NULL, " \t\n");
} else {
options = device2;
device2 = NULL;
}
}
if (mount_point && fs_type && device) {
while (num_volumes >= alloc) {
@ -99,21 +129,17 @@ void load_volume_table() {
device_volumes = realloc(device_volumes, alloc*sizeof(Volume));
}
device_volumes[num_volumes].mount_point = strdup(mount_point);
device_volumes[num_volumes].fs_type = !is_null(fs_type2) ? strdup(fs_type2) : strdup(fs_type);
device_volumes[num_volumes].fs_type = strdup(fs_type);
device_volumes[num_volumes].device = strdup(device);
device_volumes[num_volumes].device2 =
!is_null(device2) ? strdup(device2) : NULL;
device_volumes[num_volumes].fs_type2 = !is_null(fs_type2) ? strdup(fs_type) : NULL;
device2 ? strdup(device2) : NULL;
if (!is_null(fs_type2)) {
device_volumes[num_volumes].fs_options2 = dupe_string(fs_options);
device_volumes[num_volumes].fs_options = dupe_string(fs_options2);
device_volumes[num_volumes].length = 0;
if (parse_options(options, device_volumes + num_volumes) != 0) {
LOGE("skipping malformed recovery.fstab line: %s\n", original);
} else {
++num_volumes;
}
else {
device_volumes[num_volumes].fs_options2 = NULL;
device_volumes[num_volumes].fs_options = dupe_string(fs_options);
}
++num_volumes;
} else {
LOGE("skipping malformed recovery.fstab line: %s\n", original);
}
@ -126,8 +152,8 @@ void load_volume_table() {
printf("=========================\n");
for (i = 0; i < num_volumes; ++i) {
Volume* v = &device_volumes[i];
printf(" %d %s %s %s %s\n", i, v->mount_point, v->fs_type,
v->device, v->device2);
printf(" %d %s %s %s %s %lld\n", i, v->mount_point, v->fs_type,
v->device, v->device2, v->length);
}
printf("\n");
}
@ -345,8 +371,7 @@ int format_volume(const char* volume) {
}
if (strcmp(v->fs_type, "ext4") == 0) {
reset_ext4fs_info();
int result = make_ext4fs(v->device, NULL, NULL, 0, 0, 0);
int result = make_ext4fs(v->device, v->length);
if (result != 0) {
LOGE("format_volume: make_extf4fs failed on %s\n", v->device);
return -1;

View File

@ -14,8 +14,6 @@
LOCAL_PATH := $(call my-dir)
ifneq ($(TARGET_SIMULATOR),true)
include $(CLEAR_VARS)
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE := add-property-tag
@ -33,5 +31,3 @@ LOCAL_MODULE_TAGS := debug
LOCAL_SRC_FILES := check-lost+found.c
LOCAL_STATIC_LIBRARIES := libcutils libc
include $(BUILD_EXECUTABLE)
endif # !TARGET_SIMULATOR

393
ui.c
View File

@ -14,18 +14,22 @@
* limitations under the License.
*/
#include <errno.h>
#include <fcntl.h>
#include <linux/input.h>
#include <pthread.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/reboot.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#include "common.h"
#include <cutils/android_reboot.h>
#include "minui/minui.h"
#include "recovery_ui.h"
@ -51,12 +55,19 @@ static int gShowBackButton = 0;
#define CHAR_HEIGHT 16
#endif
#define PROGRESSBAR_INDETERMINATE_STATES 6
#define PROGRESSBAR_INDETERMINATE_FPS 15
#define UI_WAIT_KEY_TIMEOUT_SEC 120
UIParameters ui_parameters = {
6, // indeterminate progress bar frames
20, // fps
7, // installation icon frames (0 == static image)
13, 190, // installation icon overlay offset
};
static pthread_mutex_t gUpdateMutex = PTHREAD_MUTEX_INITIALIZER;
static gr_surface gBackgroundIcon[NUM_BACKGROUND_ICONS];
static gr_surface gProgressBarIndeterminate[PROGRESSBAR_INDETERMINATE_STATES];
static gr_surface *gInstallationOverlay;
static gr_surface *gProgressBarIndeterminate;
static gr_surface gProgressBarEmpty;
static gr_surface gProgressBarFill;
static int ui_has_initialized = 0;
@ -68,18 +79,13 @@ static const struct { gr_surface* surface; const char *name; } BITMAPS[] = {
{ &gBackgroundIcon[BACKGROUND_ICON_CLOCKWORK], "icon_clockwork" },
{ &gBackgroundIcon[BACKGROUND_ICON_FIRMWARE_INSTALLING], "icon_firmware_install" },
{ &gBackgroundIcon[BACKGROUND_ICON_FIRMWARE_ERROR], "icon_firmware_error" },
{ &gProgressBarIndeterminate[0], "indeterminate1" },
{ &gProgressBarIndeterminate[1], "indeterminate2" },
{ &gProgressBarIndeterminate[2], "indeterminate3" },
{ &gProgressBarIndeterminate[3], "indeterminate4" },
{ &gProgressBarIndeterminate[4], "indeterminate5" },
{ &gProgressBarIndeterminate[5], "indeterminate6" },
{ &gProgressBarEmpty, "progress_empty" },
{ &gProgressBarFill, "progress_fill" },
{ NULL, NULL },
};
static gr_surface gCurrentIcon = NULL;
static int gCurrentIcon = 0;
static int gInstallingFrame = 0;
static enum ProgressBarType {
PROGRESSBAR_TYPE_NONE,
@ -89,7 +95,7 @@ static enum ProgressBarType {
// Progress bar scope of current operation
static float gProgressScopeStart = 0, gProgressScopeSize = 0, gProgress = 0;
static time_t gProgressScopeTime, gProgressScopeDuration;
static double gProgressScopeTime, gProgressScopeDuration;
// Set to 1 when both graphics pages are the same (except for the progress bar)
static int gPagesIdentical = 0;
@ -99,6 +105,7 @@ static char text[MAX_ROWS][MAX_COLS];
static int text_cols = 0, text_rows = 0;
static int text_col = 0, text_row = 0, text_top = 0;
static int show_text = 0;
static int show_text_ever = 0; // has show_text ever been 1?
static char menu[MENU_MAX_ROWS][MENU_MAX_COLS];
static int show_menu = 0;
@ -111,20 +118,46 @@ static pthread_cond_t key_queue_cond = PTHREAD_COND_INITIALIZER;
static int key_queue[256], key_queue_len = 0;
static volatile char key_pressed[KEY_MAX + 1];
// Return the current time as a double (including fractions of a second).
static double now() {
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec + tv.tv_usec / 1000000.0;
}
// Draw the given frame over the installation overlay animation. The
// background is not cleared or draw with the base icon first; we
// assume that the frame already contains some other frame of the
// animation. Does nothing if no overlay animation is defined.
// Should only be called with gUpdateMutex locked.
static void draw_install_overlay_locked(int frame) {
if (gInstallationOverlay == NULL) return;
gr_surface surface = gInstallationOverlay[frame];
int iconWidth = gr_get_width(surface);
int iconHeight = gr_get_height(surface);
gr_blit(surface, 0, 0, iconWidth, iconHeight,
ui_parameters.install_overlay_offset_x,
ui_parameters.install_overlay_offset_y);
}
// Clear the screen and draw the currently selected background icon (if any).
// Should only be called with gUpdateMutex locked.
static void draw_background_locked(gr_surface icon)
static void draw_background_locked(int icon)
{
gPagesIdentical = 0;
gr_color(0, 0, 0, 255);
gr_fill(0, 0, gr_fb_width(), gr_fb_height());
if (icon) {
int iconWidth = gr_get_width(icon);
int iconHeight = gr_get_height(icon);
gr_surface surface = gBackgroundIcon[icon];
int iconWidth = gr_get_width(surface);
int iconHeight = gr_get_height(surface);
int iconX = (gr_fb_width() - iconWidth) / 2;
int iconY = (gr_fb_height() - iconHeight) / 2;
gr_blit(icon, 0, 0, iconWidth, iconHeight, iconX, iconY);
gr_blit(surface, 0, 0, iconWidth, iconHeight, iconX, iconY);
if (icon == BACKGROUND_ICON_INSTALLING) {
draw_install_overlay_locked(gInstallingFrame);
}
}
}
@ -132,35 +165,39 @@ static void draw_background_locked(gr_surface icon)
// Should only be called with gUpdateMutex locked.
static void draw_progress_locked()
{
if (gProgressBarType == PROGRESSBAR_TYPE_NONE) return;
int iconHeight = gr_get_height(gBackgroundIcon[BACKGROUND_ICON_INSTALLING]);
int width = gr_get_width(gProgressBarEmpty);
int height = gr_get_height(gProgressBarEmpty);
int dx = (gr_fb_width() - width)/2;
int dy = (3*gr_fb_height() + iconHeight - 2*height)/4;
// Erase behind the progress bar (in case this was a progress-only update)
gr_color(0, 0, 0, 255);
gr_fill(dx, dy, width, height);
if (gProgressBarType == PROGRESSBAR_TYPE_NORMAL) {
float progress = gProgressScopeStart + gProgress * gProgressScopeSize;
int pos = (int) (progress * width);
if (pos > 0) {
gr_blit(gProgressBarFill, 0, 0, pos, height, dx, dy);
}
if (pos < width-1) {
gr_blit(gProgressBarEmpty, pos, 0, width-pos, height, dx+pos, dy);
}
if (gCurrentIcon == BACKGROUND_ICON_INSTALLING) {
draw_install_overlay_locked(gInstallingFrame);
}
if (gProgressBarType == PROGRESSBAR_TYPE_INDETERMINATE) {
static int frame = 0;
gr_blit(gProgressBarIndeterminate[frame], 0, 0, width, height, dx, dy);
frame = (frame + 1) % PROGRESSBAR_INDETERMINATE_STATES;
if (gProgressBarType != PROGRESSBAR_TYPE_NONE) {
int iconHeight = gr_get_height(gBackgroundIcon[BACKGROUND_ICON_INSTALLING]);
int width = gr_get_width(gProgressBarEmpty);
int height = gr_get_height(gProgressBarEmpty);
int dx = (gr_fb_width() - width)/2;
int dy = (3*gr_fb_height() + iconHeight - 2*height)/4;
// Erase behind the progress bar (in case this was a progress-only update)
gr_color(0, 0, 0, 255);
gr_fill(dx, dy, width, height);
if (gProgressBarType == PROGRESSBAR_TYPE_NORMAL) {
float progress = gProgressScopeStart + gProgress * gProgressScopeSize;
int pos = (int) (progress * width);
if (pos > 0) {
gr_blit(gProgressBarFill, 0, 0, pos, height, dx, dy);
}
if (pos < width-1) {
gr_blit(gProgressBarEmpty, pos, 0, width-pos, height, dx+pos, dy);
}
}
if (gProgressBarType == PROGRESSBAR_TYPE_INDETERMINATE) {
static int frame = 0;
gr_blit(gProgressBarIndeterminate[frame], 0, 0, width, height, dx, dy);
frame = (frame + 1) % ui_parameters.indeterminate_frames;
}
}
}
@ -247,7 +284,7 @@ static void update_progress_locked(void)
draw_screen_locked(); // Must redraw the whole screen
gPagesIdentical = 1;
} else {
draw_progress_locked(); // Draw only the progress bar
draw_progress_locked(); // Draw only the progress bar and overlays
}
gr_flip();
}
@ -255,97 +292,130 @@ static void update_progress_locked(void)
// Keeps the progress bar updated, even when the process is otherwise busy.
static void *progress_thread(void *cookie)
{
double interval = 1.0 / ui_parameters.update_fps;
for (;;) {
usleep(1000000 / PROGRESSBAR_INDETERMINATE_FPS);
double start = now();
pthread_mutex_lock(&gUpdateMutex);
int redraw = 0;
// update the installation animation, if active
// skip this if we have a text overlay (too expensive to update)
if (gCurrentIcon == BACKGROUND_ICON_INSTALLING &&
ui_parameters.installing_frames > 0 &&
!show_text) {
gInstallingFrame =
(gInstallingFrame + 1) % ui_parameters.installing_frames;
redraw = 1;
}
// update the progress bar animation, if active
// skip this if we have a text overlay (too expensive to update)
if (gProgressBarType == PROGRESSBAR_TYPE_INDETERMINATE && !show_text) {
update_progress_locked();
redraw = 1;
}
// move the progress bar forward on timed intervals, if configured
int duration = gProgressScopeDuration;
if (gProgressBarType == PROGRESSBAR_TYPE_NORMAL && duration > 0) {
int elapsed = time(NULL) - gProgressScopeTime;
double elapsed = now() - gProgressScopeTime;
float progress = 1.0 * elapsed / duration;
if (progress > 1.0) progress = 1.0;
if (progress > gProgress) {
gProgress = progress;
update_progress_locked();
redraw = 1;
}
}
if (redraw) update_progress_locked();
pthread_mutex_unlock(&gUpdateMutex);
double end = now();
// minimum of 20ms delay between frames
double delay = interval - (end-start);
if (delay < 0.02) delay = 0.02;
usleep((long)(delay * 1000000));
}
return NULL;
}
static int rel_sum = 0;
static int input_callback(int fd, short revents, void *data)
{
struct input_event ev;
int ret;
int fake_key = 0;
ret = ev_get_input(fd, revents, &ev);
if (ret)
return -1;
if (ev.type == EV_SYN) {
return 0;
} else if (ev.type == EV_REL) {
if (ev.code == REL_Y) {
// accumulate the up or down motion reported by
// the trackball. When it exceeds a threshold
// (positive or negative), fake an up/down
// key event.
rel_sum += ev.value;
if (rel_sum > 3) {
fake_key = 1;
ev.type = EV_KEY;
ev.code = KEY_DOWN;
ev.value = 1;
rel_sum = 0;
} else if (rel_sum < -3) {
fake_key = 1;
ev.type = EV_KEY;
ev.code = KEY_UP;
ev.value = 1;
rel_sum = 0;
}
}
} else {
rel_sum = 0;
}
if (ev.type != EV_KEY || ev.code > KEY_MAX)
return 0;
pthread_mutex_lock(&key_queue_mutex);
if (!fake_key) {
// our "fake" keys only report a key-down event (no
// key-up), so don't record them in the key_pressed
// table.
key_pressed[ev.code] = ev.value;
}
const int queue_max = sizeof(key_queue) / sizeof(key_queue[0]);
if (ev.value > 0 && key_queue_len < queue_max) {
key_queue[key_queue_len++] = ev.code;
pthread_cond_signal(&key_queue_cond);
}
pthread_mutex_unlock(&key_queue_mutex);
if (ev.value > 0 && device_toggle_display(key_pressed, ev.code)) {
pthread_mutex_lock(&gUpdateMutex);
show_text = !show_text;
if (show_text) show_text_ever = 1;
update_screen_locked();
pthread_mutex_unlock(&gUpdateMutex);
}
if (ev.value > 0 && device_reboot_now(key_pressed, ev.code)) {
android_reboot(ANDROID_RB_RESTART, 0, 0);
}
return 0;
}
// Reads input events, handles special hot keys, and adds to the key queue.
static void *input_thread(void *cookie)
{
int rel_sum = 0;
int fake_key = 0;
for (;;) {
// wait for the next key event
struct input_event ev;
do {
ev_get(&ev, 0);
if (ev.type == EV_SYN) {
continue;
} else if (ev.type == EV_REL) {
if (ev.code == REL_Y) {
// accumulate the up or down motion reported by
// the trackball. When it exceeds a threshold
// (positive or negative), fake an up/down
// key event.
rel_sum += ev.value;
if (rel_sum > 3) {
fake_key = 1;
ev.type = EV_KEY;
ev.code = KEY_DOWN;
ev.value = 1;
rel_sum = 0;
} else if (rel_sum < -3) {
fake_key = 1;
ev.type = EV_KEY;
ev.code = KEY_UP;
ev.value = 1;
rel_sum = 0;
}
}
} else {
rel_sum = 0;
}
} while (ev.type != EV_KEY || ev.code > KEY_MAX);
pthread_mutex_lock(&key_queue_mutex);
if (!fake_key) {
// our "fake" keys only report a key-down event (no
// key-up), so don't record them in the key_pressed
// table.
key_pressed[ev.code] = ev.value;
}
fake_key = 0;
const int queue_max = sizeof(key_queue) / sizeof(key_queue[0]);
if (ev.value > 0 && key_queue_len < queue_max) {
key_queue[key_queue_len++] = ev.code;
pthread_cond_signal(&key_queue_cond);
}
pthread_mutex_unlock(&key_queue_mutex);
if (ev.value > 0 && device_toggle_display(key_pressed, ev.code)) {
pthread_mutex_lock(&gUpdateMutex);
show_text = !show_text;
update_screen_locked();
pthread_mutex_unlock(&gUpdateMutex);
}
if (ev.value > 0 && device_reboot_now(key_pressed, ev.code)) {
reboot(RB_AUTOBOOT);
}
if (!ev_wait(-1))
ev_dispatch();
}
return NULL;
}
@ -354,7 +424,7 @@ void ui_init(void)
{
ui_has_initialized = 1;
gr_init();
ev_init();
ev_init(input_callback, NULL);
text_col = text_row = 0;
text_rows = gr_fb_height() / CHAR_HEIGHT;
@ -368,15 +438,49 @@ void ui_init(void)
for (i = 0; BITMAPS[i].name != NULL; ++i) {
int result = res_create_surface(BITMAPS[i].name, BITMAPS[i].surface);
if (result < 0) {
if (result == -2) {
LOGI("Bitmap %s missing header\n", BITMAPS[i].name);
} else {
LOGE("Missing bitmap %s\n(Code %d)\n", BITMAPS[i].name, result);
}
*BITMAPS[i].surface = NULL;
LOGE("Missing bitmap %s\n(Code %d)\n", BITMAPS[i].name, result);
}
}
gProgressBarIndeterminate = malloc(ui_parameters.indeterminate_frames *
sizeof(gr_surface));
for (i = 0; i < ui_parameters.indeterminate_frames; ++i) {
char filename[40];
// "indeterminate01.png", "indeterminate02.png", ...
sprintf(filename, "indeterminate%02d", i+1);
int result = res_create_surface(filename, gProgressBarIndeterminate+i);
if (result < 0) {
LOGE("Missing bitmap %s\n(Code %d)\n", filename, result);
}
}
if (ui_parameters.installing_frames > 0) {
gInstallationOverlay = malloc(ui_parameters.installing_frames *
sizeof(gr_surface));
for (i = 0; i < ui_parameters.installing_frames; ++i) {
char filename[40];
// "icon_installing_overlay01.png",
// "icon_installing_overlay02.png", ...
sprintf(filename, "icon_installing_overlay%02d", i+1);
int result = res_create_surface(filename, gInstallationOverlay+i);
if (result < 0) {
LOGE("Missing bitmap %s\n(Code %d)\n", filename, result);
}
}
// Adjust the offset to account for the positioning of the
// base image on the screen.
if (gBackgroundIcon[BACKGROUND_ICON_INSTALLING] != NULL) {
gr_surface bg = gBackgroundIcon[BACKGROUND_ICON_INSTALLING];
ui_parameters.install_overlay_offset_x +=
(gr_fb_width() - gr_get_width(bg)) / 2;
ui_parameters.install_overlay_offset_y +=
(gr_fb_height() - gr_get_height(bg)) / 2;
}
} else {
gInstallationOverlay = NULL;
}
pthread_t t;
pthread_create(&t, NULL, progress_thread, NULL);
pthread_create(&t, NULL, input_thread, NULL);
@ -402,7 +506,7 @@ char *ui_copy_image(int icon, int *width, int *height, int *bpp) {
void ui_set_background(int icon)
{
pthread_mutex_lock(&gUpdateMutex);
gCurrentIcon = gBackgroundIcon[icon];
gCurrentIcon = icon;
update_screen_locked();
pthread_mutex_unlock(&gUpdateMutex);
}
@ -423,7 +527,7 @@ void ui_show_progress(float portion, int seconds)
gProgressBarType = PROGRESSBAR_TYPE_NORMAL;
gProgressScopeStart += gProgressScopeSize;
gProgressScopeSize = portion;
gProgressScopeTime = time(NULL);
gProgressScopeTime = now();
gProgressScopeDuration = seconds;
gProgress = 0;
update_progress_locked();
@ -599,23 +703,68 @@ int ui_text_visible()
return visible;
}
int ui_text_ever_visible()
{
pthread_mutex_lock(&gUpdateMutex);
int ever_visible = show_text_ever;
pthread_mutex_unlock(&gUpdateMutex);
return ever_visible;
}
void ui_show_text(int visible)
{
pthread_mutex_lock(&gUpdateMutex);
show_text = visible;
if (show_text) show_text_ever = 1;
update_screen_locked();
pthread_mutex_unlock(&gUpdateMutex);
}
// Return true if USB is connected.
static int usb_connected() {
int fd = open("/sys/class/android_usb/android0/state", O_RDONLY);
if (fd < 0) {
printf("failed to open /sys/class/android_usb/android0/state: %s\n",
strerror(errno));
return 0;
}
char buf;
/* USB is connected if android_usb state is CONNECTED or CONFIGURED */
int connected = (read(fd, &buf, 1) == 1) && (buf == 'C');
if (close(fd) < 0) {
printf("failed to close /sys/class/android_usb/android0/state: %s\n",
strerror(errno));
}
return connected;
}
int ui_wait_key()
{
pthread_mutex_lock(&key_queue_mutex);
while (key_queue_len == 0) {
pthread_cond_wait(&key_queue_cond, &key_queue_mutex);
}
int key = key_queue[0];
memcpy(&key_queue[0], &key_queue[1], sizeof(int) * --key_queue_len);
// Time out after UI_WAIT_KEY_TIMEOUT_SEC, unless a USB cable is
// plugged in.
do {
struct timeval now;
struct timespec timeout;
gettimeofday(&now, NULL);
timeout.tv_sec = now.tv_sec;
timeout.tv_nsec = now.tv_usec * 1000;
timeout.tv_sec += UI_WAIT_KEY_TIMEOUT_SEC;
int rc = 0;
while (key_queue_len == 0 && rc != ETIMEDOUT) {
rc = pthread_cond_timedwait(&key_queue_cond, &key_queue_mutex,
&timeout);
}
} while (usb_connected() && key_queue_len == 0);
int key = -1;
if (key_queue_len > 0) {
key = key_queue[0];
memcpy(&key_queue[0], &key_queue[1], sizeof(int) * --key_queue_len);
}
pthread_mutex_unlock(&key_queue_mutex);
return key;
}

View File

@ -30,6 +30,7 @@ LOCAL_STATIC_LIBRARIES += libflashutils libmtdutils libmmcutils libbmlutils
LOCAL_STATIC_LIBRARIES += $(TARGET_RECOVERY_UPDATER_LIBS) $(TARGET_RECOVERY_UPDATER_EXTRA_LIBS)
LOCAL_STATIC_LIBRARIES += libapplypatch libedify libmtdutils libminzip libz
LOCAL_STATIC_LIBRARIES += libmincrypt libbz
LOCAL_STATIC_LIBRARIES += libminelf
LOCAL_STATIC_LIBRARIES += libcutils libstdc++ libc
LOCAL_C_INCLUDES += $(LOCAL_PATH)/..
@ -60,9 +61,9 @@ $(inc) : libs := $(TARGET_RECOVERY_UPDATER_LIBS)
$(inc) : $(inc).list
$(hide) mkdir -p $(dir $@)
$(hide) echo "" > $@
$(hide) $(foreach lib,$(libs),echo "extern void Register_$(lib)(void);" >> $@)
$(hide) $(foreach lib,$(libs),echo "extern void Register_$(lib)(void);" >> $@;)
$(hide) echo "void RegisterDeviceExtensions() {" >> $@
$(hide) $(foreach lib,$(libs),echo " Register_$(lib)();" >> $@)
$(hide) $(foreach lib,$(libs),echo " Register_$(lib)();" >> $@;)
$(hide) echo "}" >> $@
$(call intermediates-dir-for,EXECUTABLES,updater)/updater.o : $(inc)
@ -72,10 +73,4 @@ LOCAL_MODULE := updater
LOCAL_FORCE_STATIC_EXECUTABLE := true
include $(BUILD_EXECUTABLE)
file := $(PRODUCT_OUT)/utilities/update-binary
ALL_PREBUILT += $(file)
$(file) : $(TARGET_OUT)/bin/updater | $(ACP)
$(transform-prebuilt-to-target)
include $(BUILD_EXECUTABLE)

View File

@ -25,12 +25,15 @@
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include "cutils/misc.h"
#include "cutils/properties.h"
#include "edify/expr.h"
#include "mincrypt/sha.h"
#include "minzip/DirUtil.h"
#include "minelf/Retouch.h"
#include "mounts.h"
#include "mtdutils/mtdutils.h"
#include "updater.h"
@ -176,19 +179,23 @@ done:
}
// format(fs_type, partition_type, location)
// format(fs_type, partition_type, location, fs_size)
//
// fs_type="yaffs2" partition_type="MTD" location=partition
// fs_type="ext4" partition_type="EMMC" location=device
// fs_type="yaffs2" partition_type="MTD" location=partition fs_size=<bytes>
// fs_type="ext4" partition_type="EMMC" location=device fs_size=<bytes>
// if fs_size == 0, then make_ext4fs uses the entire partition.
// if fs_size > 0, that is the size to use
// if fs_size < 0, then reserve that many bytes at the end of the partition
Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
char* result = NULL;
if (argc != 3) {
return ErrorAbort(state, "%s() expects 3 args, got %d", name, argc);
if (argc != 4) {
return ErrorAbort(state, "%s() expects 4 args, got %d", name, argc);
}
char* fs_type;
char* partition_type;
char* location;
if (ReadArgs(state, argv, 3, &fs_type, &partition_type, &location) < 0) {
char* fs_size;
if (ReadArgs(state, argv, 4, &fs_type, &partition_type, &location, &fs_size) < 0) {
return NULL;
}
@ -235,8 +242,7 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
result = location;
#ifdef USE_EXT4
} else if (strcmp(fs_type, "ext4") == 0) {
reset_ext4fs_info();
int status = make_ext4fs(location, NULL, NULL, 0, 0, 0);
int status = make_ext4fs(location, atoll(fs_size));
if (status != 0) {
fprintf(stderr, "%s: make_ext4fs failed (%d) on %s",
name, status, location);
@ -449,6 +455,121 @@ Value* PackageExtractFileFn(const char* name, State* state,
}
// retouch_binaries(lib1, lib2, ...)
Value* RetouchBinariesFn(const char* name, State* state,
int argc, Expr* argv[]) {
UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
char **retouch_entries = ReadVarArgs(state, argc, argv);
if (retouch_entries == NULL) {
return StringValue(strdup("t"));
}
// some randomness from the clock
int32_t override_base;
bool override_set = false;
int32_t random_base = time(NULL) % 1024;
// some more randomness from /dev/random
FILE *f_random = fopen("/dev/random", "rb");
uint16_t random_bits = 0;
if (f_random != NULL) {
fread(&random_bits, 2, 1, f_random);
random_bits = random_bits % 1024;
fclose(f_random);
}
random_base = (random_base + random_bits) % 1024;
fprintf(ui->cmd_pipe, "ui_print Random offset: 0x%x\n", random_base);
fprintf(ui->cmd_pipe, "ui_print\n");
// make sure we never randomize to zero; this let's us look at a file
// and know for sure whether it has been processed; important in the
// crash recovery process
if (random_base == 0) random_base = 1;
// make sure our randomization is page-aligned
random_base *= -0x1000;
override_base = random_base;
int i = 0;
bool success = true;
while (i < (argc - 1)) {
success = success && retouch_one_library(retouch_entries[i],
retouch_entries[i+1],
random_base,
override_set ?
NULL :
&override_base);
if (!success)
ErrorAbort(state, "Failed to retouch '%s'.", retouch_entries[i]);
free(retouch_entries[i]);
free(retouch_entries[i+1]);
i += 2;
if (success && override_base != 0) {
random_base = override_base;
override_set = true;
}
}
if (i < argc) {
free(retouch_entries[i]);
success = false;
}
free(retouch_entries);
if (!success) {
Value* v = malloc(sizeof(Value));
v->type = VAL_STRING;
v->data = NULL;
v->size = -1;
return v;
}
return StringValue(strdup("t"));
}
// undo_retouch_binaries(lib1, lib2, ...)
Value* UndoRetouchBinariesFn(const char* name, State* state,
int argc, Expr* argv[]) {
UpdaterInfo* ui = (UpdaterInfo*)(state->cookie);
char **retouch_entries = ReadVarArgs(state, argc, argv);
if (retouch_entries == NULL) {
return StringValue(strdup("t"));
}
int i = 0;
bool success = true;
int32_t override_base;
while (i < (argc-1)) {
success = success && retouch_one_library(retouch_entries[i],
retouch_entries[i+1],
0 /* undo => offset==0 */,
NULL);
if (!success)
ErrorAbort(state, "Failed to unretouch '%s'.",
retouch_entries[i]);
free(retouch_entries[i]);
free(retouch_entries[i+1]);
i += 2;
}
if (i < argc) {
free(retouch_entries[i]);
success = false;
}
free(retouch_entries);
if (!success) {
Value* v = malloc(sizeof(Value));
v->type = VAL_STRING;
v->data = NULL;
v->size = -1;
return v;
}
return StringValue(strdup("t"));
}
// symlink target src1 src2 ...
// unlinks any previously existing src1, src2, etc before creating symlinks.
Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) {
@ -681,21 +802,26 @@ static bool write_raw_image_cb(const unsigned char* data,
return false;
}
// write_raw_image(file, partition)
// write_raw_image(filename_or_blob, partition)
Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) {
char* result = NULL;
char* partition;
char* filename;
if (ReadArgs(state, argv, 2, &filename, &partition) < 0) {
Value* partition_value;
Value* contents;
if (ReadValueArgs(state, argv, 2, &contents, &partition_value) < 0) {
return NULL;
}
if (partition_value->type != VAL_STRING) {
ErrorAbort(state, "partition argument to %s must be string", name);
goto done;
}
char* partition = partition_value->data;
if (strlen(partition) == 0) {
ErrorAbort(state, "partition argument to %s can't be empty", name);
goto done;
}
if (strlen(filename) == 0) {
if (contents->type == VAL_STRING && strlen((char*) contents->data) == 0) {
ErrorAbort(state, "file argument to %s can't be empty", name);
goto done;
}
@ -704,10 +830,12 @@ Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) {
result = strdup(partition);
else
result = strdup("");
goto done;
}
done:
if (result != partition) free(partition);
free(filename);
if (result != partition) FreeValue(partition_value);
FreeValue(contents);
return StringValue(result);
}
@ -980,7 +1108,7 @@ Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) {
return args[i];
}
// Read a local file and return its contents (the char* returned
// Read a local file and return its contents (the Value* returned
// is actually a FileContents*).
Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) {
if (argc != 1) {
@ -993,7 +1121,7 @@ Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) {
v->type = VAL_BLOB;
FileContents fc;
if (LoadFileContents(filename, &fc) != 0) {
if (LoadFileContents(filename, &fc, RETOUCH_DONT_MASK) != 0) {
ErrorAbort(state, "%s() loading \"%s\" failed: %s",
name, filename, strerror(errno));
free(filename);
@ -1020,6 +1148,8 @@ void RegisterInstallFunctions() {
RegisterFunction("delete_recursive", DeleteFn);
RegisterFunction("package_extract_dir", PackageExtractDirFn);
RegisterFunction("package_extract_file", PackageExtractFileFn);
RegisterFunction("retouch_binaries", RetouchBinariesFn);
RegisterFunction("undo_retouch_binaries", UndoRetouchBinariesFn);
RegisterFunction("symlink", SymlinkFn);
RegisterFunction("set_perm", SetPermFn);
RegisterFunction("set_perm_recursive", SetPermFn);

View File

@ -173,7 +173,7 @@ int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKey
// the signing tool appends after the signature itself.
if (RSA_verify(pKeys+i, eocd + eocd_size - 6 - RSANUMBYTES,
RSANUMBYTES, sha1)) {
LOGI("whole-file signature verified\n");
LOGI("whole-file signature verified against key %d\n", i);
free(eocd);
return VERIFY_SUCCESS;
}