Update to latest AOSP master
Merge in latest commits from AOSP master and fix merge conflicts
This commit is contained in:
+22
-7
@@ -40,15 +40,27 @@ LOCAL_MODULE := recovery
|
||||
#LOCAL_FORCE_STATIC_EXECUTABLE := true
|
||||
|
||||
RECOVERY_API_VERSION := 3
|
||||
RECOVERY_FSTAB_VERSION := 2
|
||||
LOCAL_CFLAGS += -DRECOVERY_API_VERSION=$(RECOVERY_API_VERSION)
|
||||
|
||||
#LOCAL_STATIC_LIBRARIES := \
|
||||
# libext4_utils \
|
||||
# libext4_utils_static \
|
||||
# libsparse_static \
|
||||
# libminzip \
|
||||
# libz \
|
||||
# libmtdutils \
|
||||
# libmincrypt \
|
||||
# libminadbd \
|
||||
# libpixelflinger_static
|
||||
# libminui \
|
||||
# libpixelflinger_static \
|
||||
# libpng \
|
||||
# libfs_mgr \
|
||||
# libcutils \
|
||||
# liblog \
|
||||
# libselinux \
|
||||
# libstdc++ \
|
||||
# libm \
|
||||
# libc
|
||||
|
||||
LOCAL_C_INCLUDES += bionic external/stlport/stlport
|
||||
|
||||
@@ -67,7 +79,7 @@ ifeq ($(TARGET_USERIMAGES_USE_EXT4), true)
|
||||
LOCAL_C_INCLUDES += system/extras/ext4_utils
|
||||
LOCAL_SHARED_LIBRARIES += libext4_utils
|
||||
endif
|
||||
LOCAL_C_INCLUDES += external/libselinux/include
|
||||
|
||||
ifeq ($(HAVE_SELINUX), true)
|
||||
#LOCAL_C_INCLUDES += external/libselinux/include
|
||||
#LOCAL_STATIC_LIBRARIES += libselinux
|
||||
@@ -90,11 +102,11 @@ endif
|
||||
# TODO: Build the ramdisk image in a more principled way.
|
||||
LOCAL_MODULE_TAGS := eng
|
||||
|
||||
ifeq ($(TARGET_RECOVERY_UI_LIB),)
|
||||
#ifeq ($(TARGET_RECOVERY_UI_LIB),)
|
||||
LOCAL_SRC_FILES += default_device.cpp
|
||||
else
|
||||
LOCAL_STATIC_LIBRARIES += $(TARGET_RECOVERY_UI_LIB)
|
||||
endif
|
||||
#else
|
||||
# LOCAL_STATIC_LIBRARIES += $(TARGET_RECOVERY_UI_LIB)
|
||||
#endif
|
||||
|
||||
LOCAL_C_INCLUDES += system/extras/ext4_utils
|
||||
|
||||
@@ -289,6 +301,9 @@ LOCAL_MODULE := libaosprecovery
|
||||
LOCAL_MODULE_TAGS := eng
|
||||
LOCAL_MODULES_TAGS = optional
|
||||
LOCAL_CFLAGS =
|
||||
ifneq ($(wildcard system/core/libmincrypt/rsa_e_3.c),)
|
||||
LOCAL_CFLAGS += -DHAS_EXPONENT
|
||||
endif
|
||||
LOCAL_SRC_FILES = adb_install.cpp bootloader.cpp verifier.cpp mtdutils/mtdutils.c
|
||||
LOCAL_SHARED_LIBRARIES += libc liblog libcutils libmtdutils
|
||||
LOCAL_STATIC_LIBRARIES += libmincrypt
|
||||
|
||||
@@ -47,3 +47,4 @@
|
||||
# ************************************************
|
||||
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
|
||||
# ************************************************
|
||||
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/recovery_intermediates)
|
||||
|
||||
+129
-18
@@ -39,7 +39,8 @@ static int GenerateTarget(FileContents* source_file,
|
||||
const char* source_filename,
|
||||
const char* target_filename,
|
||||
const uint8_t target_sha1[SHA_DIGEST_SIZE],
|
||||
size_t target_size);
|
||||
size_t target_size,
|
||||
const Value* bonus_data);
|
||||
|
||||
static int mtd_partitions_scanned = 0;
|
||||
|
||||
@@ -420,18 +421,111 @@ int WriteToPartition(unsigned char* data, size_t len,
|
||||
break;
|
||||
|
||||
case EMMC:
|
||||
;
|
||||
FILE* f = fopen(partition, "wb");
|
||||
if (fwrite(data, 1, len, f) != len) {
|
||||
printf("short write writing to %s (%s)\n",
|
||||
partition, strerror(errno));
|
||||
{
|
||||
size_t start = 0;
|
||||
int success = 0;
|
||||
int fd = open(partition, O_RDWR | O_SYNC);
|
||||
if (fd < 0) {
|
||||
printf("failed to open %s: %s\n", partition, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (fclose(f) != 0) {
|
||||
int attempt;
|
||||
|
||||
for (attempt = 0; attempt < 10; ++attempt) {
|
||||
size_t next_sync = start + (1<<20);
|
||||
printf("raw O_SYNC write %s attempt %d start at %d\n", partition, attempt+1, start);
|
||||
lseek(fd, start, SEEK_SET);
|
||||
while (start < len) {
|
||||
size_t to_write = len - start;
|
||||
if (to_write > 4096) to_write = 4096;
|
||||
|
||||
ssize_t written = write(fd, data+start, to_write);
|
||||
if (written < 0) {
|
||||
if (errno == EINTR) {
|
||||
written = 0;
|
||||
} else {
|
||||
printf("failed write writing to %s (%s)\n",
|
||||
partition, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
start += written;
|
||||
if (start >= next_sync) {
|
||||
fsync(fd);
|
||||
next_sync = start + (1<<20);
|
||||
}
|
||||
}
|
||||
fsync(fd);
|
||||
|
||||
// drop caches so our subsequent verification read
|
||||
// won't just be reading the cache.
|
||||
sync();
|
||||
int dc = open("/proc/sys/vm/drop_caches", O_WRONLY);
|
||||
write(dc, "3\n", 2);
|
||||
close(dc);
|
||||
sleep(1);
|
||||
printf(" caches dropped\n");
|
||||
|
||||
// verify
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
unsigned char buffer[4096];
|
||||
start = len;
|
||||
size_t p;
|
||||
for (p = 0; p < len; p += sizeof(buffer)) {
|
||||
size_t to_read = len - p;
|
||||
if (to_read > sizeof(buffer)) to_read = sizeof(buffer);
|
||||
|
||||
size_t so_far = 0;
|
||||
while (so_far < to_read) {
|
||||
ssize_t read_count = read(fd, buffer+so_far, to_read-so_far);
|
||||
if (read_count < 0) {
|
||||
if (errno == EINTR) {
|
||||
read_count = 0;
|
||||
} else {
|
||||
printf("verify read error %s at %d: %s\n",
|
||||
partition, p, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if ((size_t)read_count < to_read) {
|
||||
printf("short verify read %s at %d: %d %d %s\n",
|
||||
partition, p, read_count, to_read, strerror(errno));
|
||||
}
|
||||
so_far += read_count;
|
||||
}
|
||||
|
||||
if (memcmp(buffer, data+p, to_read)) {
|
||||
printf("verification failed starting at %d\n", p);
|
||||
start = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (start == len) {
|
||||
printf("verification read succeeded (attempt %d)\n", attempt+1);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
|
||||
sleep(2);
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
printf("failed to verify after all attempts\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (close(fd) != 0) {
|
||||
printf("error closing %s (%s)\n", partition, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
// hack: sync and sleep after closing in hopes of getting
|
||||
// the data actually onto flash.
|
||||
printf("sleeping after close\n");
|
||||
sync();
|
||||
sleep(5);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(copy);
|
||||
@@ -472,7 +566,7 @@ int ParseSha1(const char* str, uint8_t* digest) {
|
||||
// Search an array of sha1 strings for one matching the given sha1.
|
||||
// Return the index of the match on success, or -1 if no match is
|
||||
// found.
|
||||
int FindMatchingPatch(uint8_t* sha1, const char** patch_sha1_str,
|
||||
int FindMatchingPatch(uint8_t* sha1, char* const * const patch_sha1_str,
|
||||
int num_patches) {
|
||||
int i;
|
||||
uint8_t patch_sha1[SHA_DIGEST_SIZE];
|
||||
@@ -584,6 +678,14 @@ int CacheSizeCheck(size_t bytes) {
|
||||
}
|
||||
}
|
||||
|
||||
static void print_short_sha1(const uint8_t sha1[SHA_DIGEST_SIZE]) {
|
||||
int i;
|
||||
const char* hex = "0123456789abcdef";
|
||||
for (i = 0; i < 4; ++i) {
|
||||
putchar(hex[(sha1[i]>>4) & 0xf]);
|
||||
putchar(hex[sha1[i] & 0xf]);
|
||||
}
|
||||
}
|
||||
|
||||
// This function applies binary patches to files in a way that is safe
|
||||
// (the original file is not touched until we have the desired
|
||||
@@ -617,8 +719,9 @@ int applypatch(const char* source_filename,
|
||||
size_t target_size,
|
||||
int num_patches,
|
||||
char** const patch_sha1_str,
|
||||
Value** patch_data) {
|
||||
printf("\napplying patch to %s\n", source_filename);
|
||||
Value** patch_data,
|
||||
Value* bonus_data) {
|
||||
printf("patch %s: ", source_filename);
|
||||
|
||||
if (target_filename[0] == '-' &&
|
||||
target_filename[1] == '\0') {
|
||||
@@ -644,8 +747,9 @@ int applypatch(const char* source_filename,
|
||||
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.
|
||||
printf("\"%s\" is already target; no patch needed\n",
|
||||
target_filename);
|
||||
printf("already ");
|
||||
print_short_sha1(target_sha1);
|
||||
putchar('\n');
|
||||
free(source_file.data);
|
||||
return 0;
|
||||
}
|
||||
@@ -699,7 +803,7 @@ int applypatch(const char* source_filename,
|
||||
int result = GenerateTarget(&source_file, source_patch_value,
|
||||
©_file, copy_patch_value,
|
||||
source_filename, target_filename,
|
||||
target_sha1, target_size);
|
||||
target_sha1, target_size, bonus_data);
|
||||
free(source_file.data);
|
||||
free(copy_file.data);
|
||||
|
||||
@@ -713,7 +817,8 @@ static int GenerateTarget(FileContents* source_file,
|
||||
const char* source_filename,
|
||||
const char* target_filename,
|
||||
const uint8_t target_sha1[SHA_DIGEST_SIZE],
|
||||
size_t target_size) {
|
||||
size_t target_size,
|
||||
const Value* bonus_data) {
|
||||
int retry = 1;
|
||||
SHA_CTX ctx;
|
||||
int output;
|
||||
@@ -766,8 +871,10 @@ static int GenerateTarget(FileContents* source_file,
|
||||
enough_space =
|
||||
(free_space > (256 << 10)) && // 256k (two-block) minimum
|
||||
(free_space > (target_size * 3 / 2)); // 50% margin of error
|
||||
printf("target %ld bytes; free space %ld bytes; retry %d; enough %d\n",
|
||||
(long)target_size, (long)free_space, retry, enough_space);
|
||||
if (!enough_space) {
|
||||
printf("target %ld bytes; free space %ld bytes; retry %d; enough %d\n",
|
||||
(long)target_size, (long)free_space, retry, enough_space);
|
||||
}
|
||||
}
|
||||
|
||||
if (!enough_space) {
|
||||
@@ -802,7 +909,7 @@ static int GenerateTarget(FileContents* source_file,
|
||||
unlink(source_filename);
|
||||
|
||||
size_t free_space = FreeSpaceForFile(target_fs);
|
||||
printf("(now %ld bytes free for target)\n", (long)free_space);
|
||||
printf("(now %ld bytes free for target) ", (long)free_space);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -867,7 +974,7 @@ static int GenerateTarget(FileContents* source_file,
|
||||
} else if (header_bytes_read >= 8 &&
|
||||
memcmp(header, "IMGDIFF2", 8) == 0) {
|
||||
result = ApplyImagePatch(source_to_use->data, source_to_use->size,
|
||||
patch, sink, token, &ctx);
|
||||
patch, sink, token, &ctx, bonus_data);
|
||||
} else {
|
||||
printf("Unknown patch file format\n");
|
||||
return 1;
|
||||
@@ -898,6 +1005,10 @@ static int GenerateTarget(FileContents* source_file,
|
||||
if (memcmp(current_target_sha1, target_sha1, SHA_DIGEST_SIZE) != 0) {
|
||||
printf("patch did not produce expected sha1\n");
|
||||
return 1;
|
||||
} else {
|
||||
printf("now ");
|
||||
print_short_sha1(target_sha1);
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
if (output < 0) {
|
||||
|
||||
@@ -55,7 +55,8 @@ int applypatch(const char* source_filename,
|
||||
size_t target_size,
|
||||
int num_patches,
|
||||
char** const patch_sha1_str,
|
||||
Value** patch_data);
|
||||
Value** patch_data,
|
||||
Value* bonus_data);
|
||||
int applypatch_check(const char* filename,
|
||||
int num_patches,
|
||||
char** const patch_sha1_str);
|
||||
@@ -64,7 +65,7 @@ int LoadFileContents(const char* filename, FileContents* file,
|
||||
int retouch_flag);
|
||||
int SaveFileContents(const char* filename, const FileContents* file);
|
||||
void FreeFileContents(FileContents* file);
|
||||
int FindMatchingPatch(uint8_t* sha1, const char** patch_sha1_str,
|
||||
int FindMatchingPatch(uint8_t* sha1, char* const * const patch_sha1_str,
|
||||
int num_patches);
|
||||
|
||||
// bsdiff.c
|
||||
@@ -79,7 +80,8 @@ int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size,
|
||||
// imgpatch.c
|
||||
int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
|
||||
const Value* patch,
|
||||
SinkFn sink, void* token, SHA_CTX* ctx);
|
||||
SinkFn sink, void* token, SHA_CTX* ctx,
|
||||
const Value* bonus_data);
|
||||
|
||||
// freecache.c
|
||||
int MakeFreeSpaceOnCache(size_t bytes_needed);
|
||||
|
||||
+49
-8
@@ -111,6 +111,14 @@
|
||||
*
|
||||
* After the header there are 'chunk count' bsdiff patches; the offset
|
||||
* of each from the beginning of the file is specified in the header.
|
||||
*
|
||||
* This tool can take an optional file of "bonus data". This is an
|
||||
* extra file of data that is appended to chunk #1 after it is
|
||||
* compressed (it must be a CHUNK_DEFLATE chunk). The same file must
|
||||
* be available (and passed to applypatch with -b) when applying the
|
||||
* patch. This is used to reduce the size of recovery-from-boot
|
||||
* patches by combining the boot image with recovery ramdisk
|
||||
* information that is stored on the system partition.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
@@ -772,21 +780,45 @@ void DumpChunks(ImageChunk* chunks, int num_chunks) {
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc != 4 && argc != 5) {
|
||||
usage:
|
||||
printf("usage: %s [-z] <src-img> <tgt-img> <patch-file>\n",
|
||||
argv[0]);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int zip_mode = 0;
|
||||
|
||||
if (strcmp(argv[1], "-z") == 0) {
|
||||
if (argc >= 2 && strcmp(argv[1], "-z") == 0) {
|
||||
zip_mode = 1;
|
||||
--argc;
|
||||
++argv;
|
||||
}
|
||||
|
||||
size_t bonus_size = 0;
|
||||
unsigned char* bonus_data = NULL;
|
||||
if (argc >= 3 && strcmp(argv[1], "-b") == 0) {
|
||||
struct stat st;
|
||||
if (stat(argv[2], &st) != 0) {
|
||||
printf("failed to stat bonus file %s: %s\n", argv[2], strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
bonus_size = st.st_size;
|
||||
bonus_data = malloc(bonus_size);
|
||||
FILE* f = fopen(argv[2], "rb");
|
||||
if (f == NULL) {
|
||||
printf("failed to open bonus file %s: %s\n", argv[2], strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
if (fread(bonus_data, 1, bonus_size, f) != bonus_size) {
|
||||
printf("failed to read bonus file %s: %s\n", argv[2], strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
argc -= 2;
|
||||
argv += 2;
|
||||
}
|
||||
|
||||
if (argc != 4) {
|
||||
usage:
|
||||
printf("usage: %s [-z] [-b <bonus-file>] <src-img> <tgt-img> <patch-file>\n",
|
||||
argv[0]);
|
||||
return 2;
|
||||
}
|
||||
|
||||
int num_src_chunks;
|
||||
ImageChunk* src_chunks;
|
||||
@@ -909,6 +941,8 @@ int main(int argc, char** argv) {
|
||||
// Compute bsdiff patches for each chunk's data (the uncompressed
|
||||
// data, in the case of deflate chunks).
|
||||
|
||||
DumpChunks(src_chunks, num_src_chunks);
|
||||
|
||||
printf("Construct patches for %d chunks...\n", num_tgt_chunks);
|
||||
unsigned char** patch_data = malloc(num_tgt_chunks * sizeof(unsigned char*));
|
||||
size_t* patch_size = malloc(num_tgt_chunks * sizeof(size_t));
|
||||
@@ -923,6 +957,13 @@ int main(int argc, char** argv) {
|
||||
patch_data[i] = MakePatch(src_chunks, tgt_chunks+i, patch_size+i);
|
||||
}
|
||||
} else {
|
||||
if (i == 1 && bonus_data) {
|
||||
printf(" using %d bytes of bonus data for chunk %d\n", bonus_size, i);
|
||||
src_chunks[i].data = realloc(src_chunks[i].data, src_chunks[i].len + bonus_size);
|
||||
memcpy(src_chunks[i].data+src_chunks[i].len, bonus_data, bonus_size);
|
||||
src_chunks[i].len += bonus_size;
|
||||
}
|
||||
|
||||
patch_data[i] = MakePatch(src_chunks+i, tgt_chunks+i, patch_size+i);
|
||||
}
|
||||
printf("patch %3d is %d bytes (of %d)\n",
|
||||
|
||||
+17
-4
@@ -37,7 +37,8 @@
|
||||
*/
|
||||
int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
|
||||
const Value* patch,
|
||||
SinkFn sink, void* token, SHA_CTX* ctx) {
|
||||
SinkFn sink, void* token, SHA_CTX* ctx,
|
||||
const Value* bonus_data) {
|
||||
ssize_t pos = 12;
|
||||
char* header = patch->data;
|
||||
if (patch->size < 12) {
|
||||
@@ -123,6 +124,12 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
|
||||
// Decompress the source data; the chunk header tells us exactly
|
||||
// how big we expect it to be when decompressed.
|
||||
|
||||
// Note: expanded_len will include the bonus data size if
|
||||
// the patch was constructed with bonus data. The
|
||||
// deflation will come up 'bonus_size' bytes short; these
|
||||
// must be appended from the bonus_data value.
|
||||
size_t bonus_size = (i == 1 && bonus_data != NULL) ? bonus_data->size : 0;
|
||||
|
||||
unsigned char* expanded_source = malloc(expanded_len);
|
||||
if (expanded_source == NULL) {
|
||||
printf("failed to allocate %d bytes for expanded_source\n",
|
||||
@@ -153,13 +160,19 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
|
||||
printf("source inflation returned %d\n", ret);
|
||||
return -1;
|
||||
}
|
||||
// We should have filled the output buffer exactly.
|
||||
if (strm.avail_out != 0) {
|
||||
printf("source inflation short by %d bytes\n", strm.avail_out);
|
||||
// We should have filled the output buffer exactly, except
|
||||
// for the bonus_size.
|
||||
if (strm.avail_out != bonus_size) {
|
||||
printf("source inflation short by %d bytes\n", strm.avail_out-bonus_size);
|
||||
return -1;
|
||||
}
|
||||
inflateEnd(&strm);
|
||||
|
||||
if (bonus_size) {
|
||||
memcpy(expanded_source + (expanded_len - bonus_size),
|
||||
bonus_data->data, bonus_size);
|
||||
}
|
||||
|
||||
// Next, apply the bsdiff patch (in memory) to the uncompressed
|
||||
// data.
|
||||
unsigned char* uncompressed_target_data;
|
||||
|
||||
+21
-2
@@ -100,6 +100,21 @@ static int ParsePatchArgs(int argc, char** argv,
|
||||
}
|
||||
|
||||
int PatchMode(int argc, char** argv) {
|
||||
Value* bonus = NULL;
|
||||
if (argc >= 3 && strcmp(argv[1], "-b") == 0) {
|
||||
FileContents fc;
|
||||
if (LoadFileContents(argv[2], &fc, RETOUCH_DONT_MASK) != 0) {
|
||||
printf("failed to load bonus file %s\n", argv[2]);
|
||||
return 1;
|
||||
}
|
||||
bonus = malloc(sizeof(Value));
|
||||
bonus->type = VAL_BLOB;
|
||||
bonus->size = fc.size;
|
||||
bonus->data = (char*)fc.data;
|
||||
argc -= 2;
|
||||
argv += 2;
|
||||
}
|
||||
|
||||
if (argc < 6) {
|
||||
return 2;
|
||||
}
|
||||
@@ -120,7 +135,7 @@ int PatchMode(int argc, char** argv) {
|
||||
}
|
||||
|
||||
int result = applypatch(argv[1], argv[2], argv[3], target_size,
|
||||
num_patches, sha1s, patches);
|
||||
num_patches, sha1s, patches, bonus);
|
||||
|
||||
int i;
|
||||
for (i = 0; i < num_patches; ++i) {
|
||||
@@ -130,6 +145,10 @@ int PatchMode(int argc, char** argv) {
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
if (bonus) {
|
||||
free(bonus->data);
|
||||
free(bonus);
|
||||
}
|
||||
free(sha1s);
|
||||
free(patches);
|
||||
|
||||
@@ -163,7 +182,7 @@ int main(int argc, char** argv) {
|
||||
if (argc < 2) {
|
||||
usage:
|
||||
printf(
|
||||
"usage: %s <src-file> <tgt-file> <tgt-sha1> <tgt-size> "
|
||||
"usage: %s [-b <bonus-file>] <src-file> <tgt-file> <tgt-sha1> <tgt-size> "
|
||||
"[<src-sha1>:<patch> ...]\n"
|
||||
" or %s -c <file> [<sha1> ...]\n"
|
||||
" or %s -s <bytes>\n"
|
||||
|
||||
+106
-38
@@ -14,6 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
#include <fs_mgr.h>
|
||||
*/
|
||||
#include "bootloader.h"
|
||||
#include "common.h"
|
||||
extern "C" {
|
||||
@@ -27,38 +30,42 @@ extern "C" {
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static char device_type = 'e'; // e for emmc or m for mtd, default is emmc
|
||||
static char device_name[256];
|
||||
|
||||
/*
|
||||
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);
|
||||
static int get_bootloader_message_block(struct bootloader_message *out, const Volume* v);
|
||||
static int set_bootloader_message_block(const struct bootloader_message *in, const Volume* v);
|
||||
|
||||
*/
|
||||
int get_bootloader_message(struct bootloader_message *out) {
|
||||
Volume* v = NULL;//volume_for_path("/misc");
|
||||
if (v == NULL) {
|
||||
//volume_for_path("/misc");
|
||||
if (device_name[0] == 0) {
|
||||
LOGE("Cannot load volume /misc!\n");
|
||||
return -1;
|
||||
}
|
||||
if (strcmp(v->fs_type, "mtd") == 0) {
|
||||
return get_bootloader_message_mtd(out, v);
|
||||
} else if (strcmp(v->fs_type, "emmc") == 0) {
|
||||
return get_bootloader_message_block(out, v);
|
||||
if (device_type == 'm') {
|
||||
return get_bootloader_message_mtd_name(out);
|
||||
} else if (device_type == 'e') {
|
||||
return get_bootloader_message_block_name(out);
|
||||
}
|
||||
LOGE("unknown misc partition fs_type \"%s\"\n", v->fs_type);
|
||||
LOGE("unknown misc partition fs_type \"%c\"\n", device_type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int set_bootloader_message(const struct bootloader_message *in) {
|
||||
Volume* v = NULL;//volume_for_path("/misc");
|
||||
if (v == NULL) {
|
||||
//volume_for_path("/misc");
|
||||
if (device_name[0] == 0) {
|
||||
LOGE("Cannot load volume /misc!\n");
|
||||
return -1;
|
||||
}
|
||||
if (strcmp(v->fs_type, "mtd") == 0) {
|
||||
return set_bootloader_message_mtd(in, v);
|
||||
} else if (strcmp(v->fs_type, "emmc") == 0) {
|
||||
return set_bootloader_message_block(in, v);
|
||||
if (device_type == 'm') {
|
||||
return set_bootloader_message_mtd_name(in, device_name);
|
||||
} else if (device_type == 'e') {
|
||||
return set_bootloader_message_block_name(in, device_name);
|
||||
}
|
||||
LOGE("unknown misc partition fs_type \"%s\"\n", v->fs_type);
|
||||
LOGE("unknown misc partition type \"%c\"\n", device_type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -68,27 +75,27 @@ int set_bootloader_message(const struct bootloader_message *in) {
|
||||
|
||||
static const int MISC_PAGES = 3; // number of pages to save
|
||||
static const int MISC_COMMAND_PAGE = 1; // bootloader command is this page
|
||||
|
||||
/*
|
||||
static int get_bootloader_message_mtd(struct bootloader_message *out,
|
||||
const Volume* v) {
|
||||
size_t write_size;
|
||||
mtd_scan_partitions();
|
||||
const MtdPartition *part = mtd_find_partition_by_name(v->device);
|
||||
const MtdPartition *part = mtd_find_partition_by_name(v->blk_device);
|
||||
if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) {
|
||||
LOGE("Can't find %s\n", v->device);
|
||||
LOGE("Can't find %s\n", v->blk_device);
|
||||
return -1;
|
||||
}
|
||||
|
||||
MtdReadContext *read = mtd_read_partition(part);
|
||||
if (read == NULL) {
|
||||
LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno));
|
||||
LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
const ssize_t size = write_size * MISC_PAGES;
|
||||
char data[size];
|
||||
ssize_t r = mtd_read_data(read, data, size);
|
||||
if (r != size) LOGE("Can't read %s\n(%s)\n", v->device, strerror(errno));
|
||||
if (r != size) LOGE("Can't read %s\n(%s)\n", v->blk_device, strerror(errno));
|
||||
mtd_read_close(read);
|
||||
if (r != size) return -1;
|
||||
|
||||
@@ -99,22 +106,22 @@ static int set_bootloader_message_mtd(const struct bootloader_message *in,
|
||||
const Volume* v) {
|
||||
size_t write_size;
|
||||
mtd_scan_partitions();
|
||||
const MtdPartition *part = mtd_find_partition_by_name(v->device);
|
||||
const MtdPartition *part = mtd_find_partition_by_name(v->blk_device);
|
||||
if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) {
|
||||
LOGE("Can't find %s\n", v->device);
|
||||
LOGE("Can't find %s\n", v->blk_device);
|
||||
return -1;
|
||||
}
|
||||
|
||||
MtdReadContext *read = mtd_read_partition(part);
|
||||
if (read == NULL) {
|
||||
LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno));
|
||||
LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t size = write_size * MISC_PAGES;
|
||||
char data[size];
|
||||
ssize_t r = mtd_read_data(read, data, size);
|
||||
if (r != size) LOGE("Can't read %s\n(%s)\n", v->device, strerror(errno));
|
||||
if (r != size) LOGE("Can't read %s\n(%s)\n", v->blk_device, strerror(errno));
|
||||
mtd_read_close(read);
|
||||
if (r != size) return -1;
|
||||
|
||||
@@ -122,22 +129,61 @@ static int set_bootloader_message_mtd(const struct bootloader_message *in,
|
||||
|
||||
MtdWriteContext *write = mtd_write_partition(part);
|
||||
if (write == NULL) {
|
||||
LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno));
|
||||
LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (mtd_write_data(write, data, size) != size) {
|
||||
LOGE("Can't write %s\n(%s)\n", v->device, strerror(errno));
|
||||
LOGE("Can't write %s\n(%s)\n", v->blk_device, strerror(errno));
|
||||
mtd_write_close(write);
|
||||
return -1;
|
||||
}
|
||||
if (mtd_write_close(write)) {
|
||||
LOGE("Can't finish %s\n(%s)\n", v->device, strerror(errno));
|
||||
LOGE("Can't finish %s\n(%s)\n", v->blk_device, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOGI("Set boot command \"%s\"\n", in->command[0] != 255 ? in->command : "");
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
void set_device_type(char new_type) {
|
||||
device_type = new_type;
|
||||
}
|
||||
|
||||
void set_device_name(const char* new_name) {
|
||||
if (strlen(new_name) >= sizeof(device_name)) {
|
||||
LOGE("New device name of '%s' is too large for bootloader.cpp\n", new_name);
|
||||
} else {
|
||||
strcpy(device_name, new_name);
|
||||
}
|
||||
}
|
||||
|
||||
int get_bootloader_message_mtd_name(struct bootloader_message *out) {
|
||||
size_t write_size;
|
||||
mtd_scan_partitions();
|
||||
const MtdPartition *part = mtd_find_partition_by_name(device_name);
|
||||
if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) {
|
||||
LOGE("Can't find %s\n", device_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
MtdReadContext *read = mtd_read_partition(part);
|
||||
if (read == NULL) {
|
||||
LOGE("Can't open %s\n(%s)\n", device_name, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
const ssize_t size = write_size * MISC_PAGES;
|
||||
char data[size];
|
||||
ssize_t r = mtd_read_data(read, data, size);
|
||||
if (r != size) LOGE("Can't read %s\n(%s)\n", device_name, strerror(errno));
|
||||
mtd_read_close(read);
|
||||
if (r != size) return -1;
|
||||
|
||||
memcpy(out, &data[write_size * MISC_COMMAND_PAGE], sizeof(*out));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int set_bootloader_message_mtd_name(const struct bootloader_message *in,
|
||||
const char* mtd_name) {
|
||||
@@ -203,23 +249,23 @@ static void wait_for_device(const char* fn) {
|
||||
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");
|
||||
wait_for_device(v->blk_device);
|
||||
FILE* f = fopen(v->blk_device, "rb");
|
||||
if (f == NULL) {
|
||||
LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno));
|
||||
LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
struct bootloader_message temp;
|
||||
int count = fread(&temp, sizeof(temp), 1, f);
|
||||
if (count != 1) {
|
||||
LOGE("Failed reading %s\n(%s)\n", v->device, strerror(errno));
|
||||
LOGE("Failed reading %s\n(%s)\n", v->blk_device, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (fclose(f) != 0) {
|
||||
LOGE("Failed closing %s\n(%s)\n", v->device, strerror(errno));
|
||||
LOGE("Failed closing %s\n(%s)\n", v->blk_device, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
memcpy(out, &temp, sizeof(temp));
|
||||
@@ -228,23 +274,45 @@ 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");
|
||||
wait_for_device(v->blk_device);
|
||||
FILE* f = fopen(v->blk_device, "wb");
|
||||
if (f == NULL) {
|
||||
LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno));
|
||||
LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
int count = fwrite(in, sizeof(*in), 1, f);
|
||||
if (count != 1) {
|
||||
LOGE("Failed writing %s\n(%s)\n", v->device, strerror(errno));
|
||||
LOGE("Failed writing %s\n(%s)\n", v->blk_device, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (fclose(f) != 0) {
|
||||
LOGE("Failed closing %s\n(%s)\n", v->device, strerror(errno));
|
||||
LOGE("Failed closing %s\n(%s)\n", v->blk_device, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
int get_bootloader_message_block_name(struct bootloader_message *out) {
|
||||
wait_for_device(device_name);
|
||||
FILE* f = fopen(device_name, "rb");
|
||||
if (f == NULL) {
|
||||
LOGE("Can't open %s\n(%s)\n", device_name, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
struct bootloader_message temp;
|
||||
int count = fread(&temp, sizeof(temp), 1, f);
|
||||
if (count != 1) {
|
||||
LOGE("Failed reading %s\n(%s)\n", device_name, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (fclose(f) != 0) {
|
||||
LOGE("Failed closing %s\n(%s)\n", device_name, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
memcpy(out, &temp, sizeof(temp));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int set_bootloader_message_block_name(const struct bootloader_message *in,
|
||||
const char* block_name) {
|
||||
|
||||
@@ -48,10 +48,17 @@ struct bootloader_message {
|
||||
/* Read and write the bootloader command from the "misc" partition.
|
||||
* These return zero on success.
|
||||
*/
|
||||
/*
|
||||
int get_bootloader_message(struct bootloader_message *out);
|
||||
int set_bootloader_message(const struct bootloader_message *in);
|
||||
*/
|
||||
|
||||
void set_device_type(char new_type);
|
||||
void set_device_name(const char* new_name);
|
||||
|
||||
int get_bootloader_message_mtd_name(struct bootloader_message *out);
|
||||
int set_bootloader_message_mtd_name(const struct bootloader_message *in, const char* mtd_name);
|
||||
int get_bootloader_message_block_name(struct bootloader_message *out);
|
||||
int set_bootloader_message_block_name(const struct bootloader_message *in, const char* block_name);
|
||||
|
||||
void get_args(int *argc, char ***argv);
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#define RECOVERY_COMMON_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -44,28 +45,13 @@ static long tmplog_offset = 0;
|
||||
#define STRINGIFY(x) #x
|
||||
#define EXPAND(x) STRINGIFY(x)
|
||||
|
||||
typedef struct {
|
||||
const char* mount_point; // eg. "/cache". must live in the root directory.
|
||||
|
||||
const char* fs_type; // "yaffs2" or "ext4" or "vfat"
|
||||
|
||||
const char* device; // MTD partition name if fs_type == "yaffs"
|
||||
// block device if fs_type == "ext4" or "vfat"
|
||||
|
||||
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).
|
||||
} Volume;
|
||||
typedef struct fstab_rec Volume;
|
||||
|
||||
// fopen a file, mounting volumes and making parent dirs as necessary.
|
||||
FILE* fopen_path(const char *path, const char *mode);
|
||||
|
||||
//void ui_print(const char* format, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
@@ -0,0 +1,93 @@
|
||||
Copyright (c) 2011, Raph Levien (firstname.lastname@gmail.com), Copyright (c) 2012, Cyreal (cyreal.org)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
@@ -0,0 +1,6 @@
|
||||
The images in this directory were generated using the font
|
||||
Inconsolata, which is released under the OFL license and was obtained
|
||||
from:
|
||||
|
||||
https://code.google.com/p/googlefontdirectory/source/browse/ofl/inconsolata/
|
||||
|
||||
+1
-77
@@ -174,86 +174,10 @@ try_update_binary(const char *path, ZipArchive *zip, int* wipe_cache) {
|
||||
return INSTALL_SUCCESS;
|
||||
}
|
||||
|
||||
// Reads a file containing one or more public keys as produced by
|
||||
// DumpPublicKey: this is an RSAPublicKey struct as it would appear
|
||||
// as a C source literal, eg:
|
||||
//
|
||||
// "{64,0xc926ad21,{1795090719,...,-695002876},{-857949815,...,1175080310}}"
|
||||
//
|
||||
// (Note that the braces and commas in this example are actual
|
||||
// characters the parser expects to find in the file; the ellipses
|
||||
// indicate more numbers omitted from this example.)
|
||||
//
|
||||
// The file may contain multiple keys in this format, separated by
|
||||
// commas. The last key must not be followed by a comma.
|
||||
//
|
||||
// Returns NULL if the file failed to parse, or if it contain zero keys.
|
||||
RSAPublicKey*
|
||||
load_keys(const char* filename, int* numKeys) {
|
||||
RSAPublicKey* out = NULL;
|
||||
*numKeys = 0;
|
||||
|
||||
FILE* f = fopen(filename, "r");
|
||||
if (f == NULL) {
|
||||
LOGE("opening %s: %s\n", filename, strerror(errno));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
{
|
||||
int i;
|
||||
bool done = false;
|
||||
while (!done) {
|
||||
++*numKeys;
|
||||
out = (RSAPublicKey*)realloc(out, *numKeys * sizeof(RSAPublicKey));
|
||||
RSAPublicKey* key = out + (*numKeys - 1);
|
||||
if (fscanf(f, " { %i , 0x%x , { %u",
|
||||
&(key->len), &(key->n0inv), &(key->n[0])) != 3) {
|
||||
goto exit;
|
||||
}
|
||||
if (key->len != RSANUMWORDS) {
|
||||
LOGE("key length (%d) does not match expected size\n", key->len);
|
||||
goto exit;
|
||||
}
|
||||
for (i = 1; i < key->len; ++i) {
|
||||
if (fscanf(f, " , %u", &(key->n[i])) != 1) goto exit;
|
||||
}
|
||||
if (fscanf(f, " } , { %u", &(key->rr[0])) != 1) goto exit;
|
||||
for (i = 1; i < key->len; ++i) {
|
||||
if (fscanf(f, " , %u", &(key->rr[i])) != 1) goto exit;
|
||||
}
|
||||
fscanf(f, " } } ");
|
||||
|
||||
// if the line ends in a comma, this file has more keys.
|
||||
switch (fgetc(f)) {
|
||||
case ',':
|
||||
// more keys to come.
|
||||
break;
|
||||
|
||||
case EOF:
|
||||
done = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOGE("unexpected character between keys\n");
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return out;
|
||||
|
||||
exit:
|
||||
if (f) fclose(f);
|
||||
free(out);
|
||||
*numKeys = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
really_install_package(const char *path, int* wipe_cache)
|
||||
{
|
||||
ui->SetBackground(RecoveryUI::INSTALLING);
|
||||
ui->SetBackground(RecoveryUI::INSTALLING_UPDATE);
|
||||
ui->Print("Finding update package...\n");
|
||||
ui->SetProgressType(RecoveryUI::INDETERMINATE);
|
||||
LOGI("Update location: %s\n", path);
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT };
|
||||
enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT, INSTALL_NONE };
|
||||
// Install the package specified by root_path. If INSTALL_SUCCESS is
|
||||
// returned and *wipe_cache is true on exit, caller should wipe the
|
||||
// cache partition.
|
||||
|
||||
@@ -29,8 +29,6 @@
|
||||
#include "adb.h"
|
||||
|
||||
#include <private/android_filesystem_config.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/prctl.h>
|
||||
|
||||
#if ADB_TRACE
|
||||
ADB_MUTEX_DEFINE( D_lock );
|
||||
|
||||
+12
-2
@@ -9,11 +9,21 @@ LOCAL_C_INCLUDES +=\
|
||||
LOCAL_STATIC_LIBRARY := libpng
|
||||
LOCAL_MODULE := libminui
|
||||
|
||||
ifeq ($(TARGET_RECOVERY_PIXEL_FORMAT),"RGBX_8888")
|
||||
# This used to compare against values in double-quotes (which are just
|
||||
# ordinary characters in this context). Strip double-quotes from the
|
||||
# value so that either will work.
|
||||
|
||||
ifeq ($(subst ",,$(TARGET_RECOVERY_PIXEL_FORMAT)),RGBX_8888)
|
||||
LOCAL_CFLAGS += -DRECOVERY_RGBX
|
||||
endif
|
||||
ifeq ($(TARGET_RECOVERY_PIXEL_FORMAT),"BGRA_8888")
|
||||
ifeq ($(subst ",,$(TARGET_RECOVERY_PIXEL_FORMAT)),BGRA_8888)
|
||||
LOCAL_CFLAGS += -DRECOVERY_BGRA
|
||||
endif
|
||||
|
||||
ifneq ($(TARGET_RECOVERY_OVERSCAN_PERCENT),)
|
||||
LOCAL_CFLAGS += -DOVERSCAN_PERCENT=$(TARGET_RECOVERY_OVERSCAN_PERCENT)
|
||||
else
|
||||
LOCAL_CFLAGS += -DOVERSCAN_PERCENT=0
|
||||
endif
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
+85
-32
@@ -44,20 +44,24 @@
|
||||
#define PIXEL_SIZE 2
|
||||
#endif
|
||||
|
||||
#define NUM_BUFFERS 2
|
||||
|
||||
typedef struct {
|
||||
GGLSurface texture;
|
||||
GGLSurface* texture;
|
||||
unsigned cwidth;
|
||||
unsigned cheight;
|
||||
unsigned ascent;
|
||||
} GRFont;
|
||||
|
||||
static GRFont *gr_font = 0;
|
||||
static GGLContext *gr_context = 0;
|
||||
static GGLSurface gr_font_texture;
|
||||
static GGLSurface gr_framebuffer[2];
|
||||
static GGLSurface gr_framebuffer[NUM_BUFFERS];
|
||||
static GGLSurface gr_mem_surface;
|
||||
static unsigned gr_active_fb = 0;
|
||||
static unsigned double_buffering = 0;
|
||||
static int overscan_percent = OVERSCAN_PERCENT;
|
||||
static int overscan_offset_x = 0;
|
||||
static int overscan_offset_y = 0;
|
||||
|
||||
static int gr_fb_fd = -1;
|
||||
static int gr_vt_fd = -1;
|
||||
@@ -130,6 +134,9 @@ static int get_framebuffer(GGLSurface *fb)
|
||||
return -1;
|
||||
}
|
||||
|
||||
overscan_offset_x = vi.xres * overscan_percent / 100;
|
||||
overscan_offset_y = vi.yres * overscan_percent / 100;
|
||||
|
||||
fb->version = sizeof(*fb);
|
||||
fb->width = vi.xres;
|
||||
fb->height = vi.yres;
|
||||
@@ -169,7 +176,7 @@ static void get_memory_surface(GGLSurface* ms) {
|
||||
static void set_active_framebuffer(unsigned n)
|
||||
{
|
||||
if (n > 1 || !double_buffering) return;
|
||||
vi.yres_virtual = vi.yres * PIXEL_SIZE;
|
||||
vi.yres_virtual = vi.yres * NUM_BUFFERS;
|
||||
vi.yoffset = n * vi.yres;
|
||||
vi.bits_per_pixel = PIXEL_SIZE * 8;
|
||||
if (ioctl(gr_fb_fd, FBIOPUT_VSCREENINFO, &vi) < 0) {
|
||||
@@ -216,15 +223,20 @@ void gr_font_size(int *x, int *y)
|
||||
*y = gr_font->cheight;
|
||||
}
|
||||
|
||||
int gr_text(int x, int y, const char *s)
|
||||
int gr_text(int x, int y, const char *s, int bold)
|
||||
{
|
||||
GGLContext *gl = gr_context;
|
||||
GRFont *font = gr_font;
|
||||
unsigned off;
|
||||
|
||||
y -= font->ascent;
|
||||
if (!font->texture) return x;
|
||||
|
||||
gl->bindTexture(gl, &font->texture);
|
||||
bold = bold && (font->texture->height != font->cheight);
|
||||
|
||||
x += overscan_offset_x;
|
||||
y += overscan_offset_y;
|
||||
|
||||
gl->bindTexture(gl, font->texture);
|
||||
gl->texEnvi(gl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
|
||||
gl->texGeni(gl, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
|
||||
gl->texGeni(gl, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
|
||||
@@ -233,7 +245,8 @@ int gr_text(int x, int y, const char *s)
|
||||
while((off = *s++)) {
|
||||
off -= 32;
|
||||
if (off < 96) {
|
||||
gl->texCoord2i(gl, (off * font->cwidth) - x, 0 - y);
|
||||
gl->texCoord2i(gl, (off * font->cwidth) - x,
|
||||
(bold ? font->cheight : 0) - y);
|
||||
gl->recti(gl, x, y, x + font->cwidth, y + font->cheight);
|
||||
}
|
||||
x += font->cwidth;
|
||||
@@ -242,19 +255,50 @@ int gr_text(int x, int y, const char *s)
|
||||
return x;
|
||||
}
|
||||
|
||||
void gr_fill(int x, int y, int w, int h)
|
||||
void gr_texticon(int x, int y, gr_surface icon) {
|
||||
if (gr_context == NULL || icon == NULL) {
|
||||
return;
|
||||
}
|
||||
GGLContext* gl = gr_context;
|
||||
|
||||
x += overscan_offset_x;
|
||||
y += overscan_offset_y;
|
||||
|
||||
gl->bindTexture(gl, (GGLSurface*) icon);
|
||||
gl->texEnvi(gl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
|
||||
gl->texGeni(gl, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
|
||||
gl->texGeni(gl, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
|
||||
gl->enable(gl, GGL_TEXTURE_2D);
|
||||
|
||||
int w = gr_get_width(icon);
|
||||
int h = gr_get_height(icon);
|
||||
|
||||
gl->texCoord2i(gl, -x, -y);
|
||||
gl->recti(gl, x, y, x+gr_get_width(icon), y+gr_get_height(icon));
|
||||
}
|
||||
|
||||
void gr_fill(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
x1 += overscan_offset_x;
|
||||
y1 += overscan_offset_y;
|
||||
|
||||
x2 += overscan_offset_x;
|
||||
y2 += overscan_offset_y;
|
||||
|
||||
GGLContext *gl = gr_context;
|
||||
gl->disable(gl, GGL_TEXTURE_2D);
|
||||
gl->recti(gl, x, y, w, h);
|
||||
gl->recti(gl, x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
void gr_blit(gr_surface source, int sx, int sy, int w, int h, int dx, int dy) {
|
||||
if (gr_context == NULL) {
|
||||
if (gr_context == NULL || source == NULL) {
|
||||
return;
|
||||
}
|
||||
GGLContext *gl = gr_context;
|
||||
|
||||
dx += overscan_offset_x;
|
||||
dy += overscan_offset_y;
|
||||
|
||||
gl->bindTexture(gl, (GGLSurface*) source);
|
||||
gl->texEnvi(gl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
|
||||
gl->texGeni(gl, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
|
||||
@@ -280,31 +324,40 @@ unsigned int gr_get_height(gr_surface surface) {
|
||||
|
||||
static void gr_init_font(void)
|
||||
{
|
||||
GGLSurface *ftex;
|
||||
unsigned char *bits, *rle;
|
||||
unsigned char *in, data;
|
||||
|
||||
gr_font = calloc(sizeof(*gr_font), 1);
|
||||
ftex = &gr_font->texture;
|
||||
|
||||
bits = malloc(font.width * font.height);
|
||||
int res = res_create_surface("font", (void**)&(gr_font->texture));
|
||||
if (res == 0) {
|
||||
// The font image should be a 96x2 array of character images. The
|
||||
// columns are the printable ASCII characters 0x20 - 0x7f. The
|
||||
// top row is regular text; the bottom row is bold.
|
||||
gr_font->cwidth = gr_font->texture->width / 96;
|
||||
gr_font->cheight = gr_font->texture->height / 2;
|
||||
} else {
|
||||
printf("failed to read font: res=%d\n", res);
|
||||
|
||||
ftex->version = sizeof(*ftex);
|
||||
ftex->width = font.width;
|
||||
ftex->height = font.height;
|
||||
ftex->stride = font.width;
|
||||
ftex->data = (void*) bits;
|
||||
ftex->format = GGL_PIXEL_FORMAT_A_8;
|
||||
// fall back to the compiled-in font.
|
||||
gr_font->texture = malloc(sizeof(*gr_font->texture));
|
||||
gr_font->texture->width = font.width;
|
||||
gr_font->texture->height = font.height;
|
||||
gr_font->texture->stride = font.width;
|
||||
|
||||
in = font.rundata;
|
||||
while((data = *in++)) {
|
||||
memset(bits, (data & 0x80) ? 255 : 0, data & 0x7f);
|
||||
bits += (data & 0x7f);
|
||||
unsigned char* bits = malloc(font.width * font.height);
|
||||
gr_font->texture->data = (void*) bits;
|
||||
|
||||
unsigned char data;
|
||||
unsigned char* in = font.rundata;
|
||||
while((data = *in++)) {
|
||||
memset(bits, (data & 0x80) ? 255 : 0, data & 0x7f);
|
||||
bits += (data & 0x7f);
|
||||
}
|
||||
|
||||
gr_font->cwidth = font.cwidth;
|
||||
gr_font->cheight = font.cheight;
|
||||
}
|
||||
|
||||
gr_font->cwidth = font.cwidth;
|
||||
gr_font->cheight = font.cheight;
|
||||
gr_font->ascent = font.cheight - 2;
|
||||
// interpret the grayscale as alpha
|
||||
gr_font->texture->format = GGL_PIXEL_FORMAT_A_8;
|
||||
}
|
||||
|
||||
int gr_init(void)
|
||||
@@ -364,12 +417,12 @@ void gr_exit(void)
|
||||
|
||||
int gr_fb_width(void)
|
||||
{
|
||||
return gr_framebuffer[0].width;
|
||||
return gr_framebuffer[0].width - 2*overscan_offset_x;
|
||||
}
|
||||
|
||||
int gr_fb_height(void)
|
||||
{
|
||||
return gr_framebuffer[0].height;
|
||||
return gr_framebuffer[0].height - 2*overscan_offset_y;
|
||||
}
|
||||
|
||||
gr_pixel *gr_fb_data(void)
|
||||
|
||||
+4
-2
@@ -36,8 +36,9 @@ 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);
|
||||
void gr_fill(int x1, int y1, int x2, int y2);
|
||||
int gr_text(int x, int y, const char *s, int bold);
|
||||
void gr_texticon(int x, int y, gr_surface icon);
|
||||
int gr_measure(const char *s);
|
||||
void gr_font_size(int *x, int *y);
|
||||
|
||||
@@ -71,6 +72,7 @@ void ev_dispatch(void);
|
||||
|
||||
// Returns 0 if no error, else negative.
|
||||
int res_create_surface(const char* name, gr_surface* pSurface);
|
||||
int res_create_localized_surface(const char* name, gr_surface* pSurface);
|
||||
void res_free_surface(gr_surface surface);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
+153
-10
@@ -33,6 +33,8 @@
|
||||
|
||||
#include "minui.h"
|
||||
|
||||
extern char* locale;
|
||||
|
||||
// libpng gives "undefined reference to 'pow'" errors, and I have no
|
||||
// idea how to convince the build system to link with -lm. We don't
|
||||
// need this functionality (it's used for gamma adjustment) so provide
|
||||
@@ -91,22 +93,25 @@ int res_create_surface(const char* name, gr_surface* pSurface) {
|
||||
png_set_sig_bytes(png_ptr, sizeof(header));
|
||||
png_read_info(png_ptr, info_ptr);
|
||||
|
||||
size_t width = info_ptr->width;
|
||||
size_t height = info_ptr->height;
|
||||
size_t stride = 4 * width;
|
||||
size_t pixelSize = stride * height;
|
||||
int color_type, bit_depth;
|
||||
size_t width, height;
|
||||
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
|
||||
&color_type, NULL, NULL, NULL);
|
||||
|
||||
int channels = png_get_channels(png_ptr, info_ptr);
|
||||
|
||||
int color_type = info_ptr->color_type;
|
||||
int bit_depth = info_ptr->bit_depth;
|
||||
int channels = info_ptr->channels;
|
||||
if (!(bit_depth == 8 &&
|
||||
((channels == 3 && color_type == PNG_COLOR_TYPE_RGB) ||
|
||||
(channels == 4 && color_type == PNG_COLOR_TYPE_RGBA) ||
|
||||
(channels == 1 && color_type == PNG_COLOR_TYPE_PALETTE)))) {
|
||||
(channels == 1 && (color_type == PNG_COLOR_TYPE_PALETTE ||
|
||||
color_type == PNG_COLOR_TYPE_GRAY))))) {
|
||||
return -7;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
size_t stride = (color_type == PNG_COLOR_TYPE_GRAY ? 1 : 4) * width;
|
||||
size_t pixelSize = stride * height;
|
||||
|
||||
surface = malloc(sizeof(GGLSurface) + pixelSize);
|
||||
if (surface == NULL) {
|
||||
result = -8;
|
||||
@@ -118,8 +123,8 @@ int res_create_surface(const char* name, gr_surface* pSurface) {
|
||||
surface->height = height;
|
||||
surface->stride = width; /* Yes, pixels, not bytes */
|
||||
surface->data = pData;
|
||||
surface->format = (channels == 3) ?
|
||||
GGL_PIXEL_FORMAT_RGBX_8888 : GGL_PIXEL_FORMAT_RGBA_8888;
|
||||
surface->format = (channels == 3) ? GGL_PIXEL_FORMAT_RGBX_8888 :
|
||||
((color_type == PNG_COLOR_TYPE_PALETTE ? GGL_PIXEL_FORMAT_RGBA_8888 : GGL_PIXEL_FORMAT_L_8));
|
||||
|
||||
int alpha = 0;
|
||||
if (color_type == PNG_COLOR_TYPE_PALETTE) {
|
||||
@@ -129,6 +134,9 @@ int res_create_surface(const char* name, gr_surface* pSurface) {
|
||||
png_set_tRNS_to_alpha(png_ptr);
|
||||
alpha = 1;
|
||||
}
|
||||
if (color_type == PNG_COLOR_TYPE_GRAY) {
|
||||
alpha = 1;
|
||||
}
|
||||
|
||||
unsigned int y;
|
||||
if (channels == 3 || (channels == 1 && !alpha)) {
|
||||
@@ -173,6 +181,141 @@ exit:
|
||||
return result;
|
||||
}
|
||||
|
||||
static int matches_locale(const char* loc) {
|
||||
if (locale == NULL) return 0;
|
||||
|
||||
if (strcmp(loc, locale) == 0) return 1;
|
||||
|
||||
// if loc does *not* have an underscore, and it matches the start
|
||||
// of locale, and the next character in locale *is* an underscore,
|
||||
// that's a match. For instance, loc == "en" matches locale ==
|
||||
// "en_US".
|
||||
|
||||
int i;
|
||||
for (i = 0; loc[i] != 0 && loc[i] != '_'; ++i);
|
||||
if (loc[i] == '_') return 0;
|
||||
|
||||
return (strncmp(locale, loc, i) == 0 && locale[i] == '_');
|
||||
}
|
||||
|
||||
int res_create_localized_surface(const char* name, gr_surface* pSurface) {
|
||||
char resPath[256];
|
||||
GGLSurface* surface = NULL;
|
||||
int result = 0;
|
||||
unsigned char header[8];
|
||||
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");
|
||||
if (fp == NULL) {
|
||||
result = -1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
size_t bytesRead = fread(header, 1, sizeof(header), fp);
|
||||
if (bytesRead != sizeof(header)) {
|
||||
result = -2;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (png_sig_cmp(header, 0, sizeof(header))) {
|
||||
result = -3;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
if (!png_ptr) {
|
||||
result = -4;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
info_ptr = png_create_info_struct(png_ptr);
|
||||
if (!info_ptr) {
|
||||
result = -5;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (setjmp(png_jmpbuf(png_ptr))) {
|
||||
result = -6;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
png_init_io(png_ptr, fp);
|
||||
png_set_sig_bytes(png_ptr, sizeof(header));
|
||||
png_read_info(png_ptr, info_ptr);
|
||||
|
||||
int color_type, bit_depth;
|
||||
size_t width, height;
|
||||
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth,
|
||||
&color_type, NULL, NULL, NULL);
|
||||
int channels = png_get_channels(png_ptr, info_ptr);
|
||||
|
||||
if (!(bit_depth == 8 &&
|
||||
(channels == 1 && color_type == PNG_COLOR_TYPE_GRAY))) {
|
||||
return -7;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
unsigned char* row = malloc(width);
|
||||
int y;
|
||||
for (y = 0; y < height; ++y) {
|
||||
png_read_row(png_ptr, row, NULL);
|
||||
int w = (row[1] << 8) | row[0];
|
||||
int h = (row[3] << 8) | row[2];
|
||||
int len = row[4];
|
||||
char* loc = row+5;
|
||||
|
||||
if (y+1+h >= height || matches_locale(loc)) {
|
||||
printf(" %20s: %s (%d x %d @ %d)\n", name, loc, w, h, y);
|
||||
|
||||
surface = malloc(sizeof(GGLSurface));
|
||||
if (surface == NULL) {
|
||||
result = -8;
|
||||
goto exit;
|
||||
}
|
||||
unsigned char* pData = malloc(w*h);
|
||||
|
||||
surface->version = sizeof(GGLSurface);
|
||||
surface->width = w;
|
||||
surface->height = h;
|
||||
surface->stride = w; /* Yes, pixels, not bytes */
|
||||
surface->data = pData;
|
||||
surface->format = GGL_PIXEL_FORMAT_A_8;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < h; ++i, ++y) {
|
||||
png_read_row(png_ptr, row, NULL);
|
||||
memcpy(pData + i*w, row, w);
|
||||
}
|
||||
|
||||
*pSurface = (gr_surface) surface;
|
||||
break;
|
||||
} else {
|
||||
int i;
|
||||
for (i = 0; i < h; ++i, ++y) {
|
||||
png_read_row(png_ptr, row, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
|
||||
if (fp != NULL) {
|
||||
fclose(fp);
|
||||
}
|
||||
if (result < 0) {
|
||||
if (surface) {
|
||||
free(surface);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void res_free_surface(gr_surface surface) {
|
||||
GGLSurface* pSurface = (GGLSurface*) surface;
|
||||
if (pSurface) {
|
||||
|
||||
+2
-6
@@ -8,15 +8,11 @@ LOCAL_SRC_FILES := \
|
||||
Inlines.c \
|
||||
Zip.c
|
||||
|
||||
LOCAL_C_INCLUDES += \
|
||||
LOCAL_C_INCLUDES := \
|
||||
external/zlib \
|
||||
external/safe-iop/include
|
||||
|
||||
ifeq ($(HAVE_SELINUX),true)
|
||||
LOCAL_C_INCLUDES += external/libselinux/include
|
||||
LOCAL_STATIC_LIBRARIES += libselinux
|
||||
LOCAL_CFLAGS += -DHAVE_SELINUX
|
||||
endif
|
||||
LOCAL_STATIC_LIBRARIES := libselinux
|
||||
|
||||
LOCAL_MODULE := libminzip
|
||||
|
||||
|
||||
@@ -145,24 +145,19 @@ dirCreateHierarchy(const char *path, int mode,
|
||||
} else if (ds == DMISSING) {
|
||||
int err;
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
char *secontext = NULL;
|
||||
|
||||
if (sehnd) {
|
||||
selabel_lookup(sehnd, &secontext, cpath, mode);
|
||||
setfscreatecon(secontext);
|
||||
}
|
||||
#endif
|
||||
|
||||
err = mkdir(cpath, mode);
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
|
||||
if (secontext) {
|
||||
freecon(secontext);
|
||||
setfscreatecon(NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (err != 0) {
|
||||
free(cpath);
|
||||
|
||||
@@ -24,12 +24,8 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
#include <selinux/selinux.h>
|
||||
#include <selinux/label.h>
|
||||
#else
|
||||
struct selabel_handle;
|
||||
#endif
|
||||
|
||||
/* Like "mkdir -p", try to guarantee that all directories
|
||||
* specified in path are present, creating as many directories
|
||||
|
||||
+4
-4
@@ -95,16 +95,16 @@ int sysLoadFileInShmem(int fd, MemMapping* pMap)
|
||||
if (memPtr == NULL)
|
||||
return -1;
|
||||
|
||||
actual = read(fd, memPtr, length);
|
||||
pMap->baseAddr = pMap->addr = memPtr;
|
||||
pMap->baseLength = pMap->length = length;
|
||||
|
||||
actual = TEMP_FAILURE_RETRY(read(fd, memPtr, length));
|
||||
if (actual != length) {
|
||||
LOGE("only read %d of %d bytes\n", (int) actual, (int) length);
|
||||
sysReleaseShmem(pMap);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pMap->baseAddr = pMap->addr = memPtr;
|
||||
pMap->baseLength = pMap->length = length;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+5
-5
@@ -985,6 +985,7 @@ bool mzExtractRecursive(const ZipArchive *pArchive,
|
||||
unsigned int i;
|
||||
bool seenMatch = false;
|
||||
int ok = true;
|
||||
int extractCount = 0;
|
||||
for (i = 0; i < pArchive->numEntries; i++) {
|
||||
ZipEntry *pEntry = pArchive->pEntries + i;
|
||||
if (pEntry->fileNameLen < zipDirLen) {
|
||||
@@ -1115,23 +1116,19 @@ bool mzExtractRecursive(const ZipArchive *pArchive,
|
||||
* Open the target for writing.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
char *secontext = NULL;
|
||||
|
||||
if (sehnd) {
|
||||
selabel_lookup(sehnd, &secontext, targetFile, UNZIP_FILEMODE);
|
||||
setfscreatecon(secontext);
|
||||
}
|
||||
#endif
|
||||
|
||||
int fd = creat(targetFile, UNZIP_FILEMODE);
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
if (secontext) {
|
||||
freecon(secontext);
|
||||
setfscreatecon(NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (fd < 0) {
|
||||
LOGE("Can't create target file \"%s\": %s\n",
|
||||
@@ -1154,13 +1151,16 @@ bool mzExtractRecursive(const ZipArchive *pArchive,
|
||||
break;
|
||||
}
|
||||
|
||||
LOGD("Extracted file \"%s\"\n", targetFile);
|
||||
LOGV("Extracted file \"%s\"\n", targetFile);
|
||||
++extractCount;
|
||||
}
|
||||
}
|
||||
|
||||
if (callback != NULL) callback(targetFile, cookie);
|
||||
}
|
||||
|
||||
LOGD("Extracted %d file(s)\n", extractCount);
|
||||
|
||||
free(helper.buf);
|
||||
free(zpath);
|
||||
|
||||
|
||||
@@ -18,12 +18,8 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
#include <selinux/selinux.h>
|
||||
#include <selinux/label.h>
|
||||
#else
|
||||
struct selabel_handle;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* One entry in the Zip archive. Treat this as opaque -- use accessors below.
|
||||
|
||||
+2
-2
@@ -50,8 +50,8 @@ LOCAL_MODULE_PATH := $(PRODUCT_OUT)/utilities
|
||||
LOCAL_UNSTRIPPED_PATH := $(PRODUCT_OUT)/symbols/utilities
|
||||
LOCAL_MODULE_STEM := bml_over_mtd
|
||||
LOCAL_C_INCLUDES += bootable/recovery/mtdutils
|
||||
LOCAL_STATIC_LIBRARIES := libmtdutils libcutils libc
|
||||
LOCAL_FORCE_STATIC_EXECUTABLE := true
|
||||
LOCAL_STATIC_LIBRARIES := libmtdutils
|
||||
LOCAL_SHARED_LIBRARIES := libcutils liblog libc
|
||||
include $(BUILD_EXECUTABLE)
|
||||
endif
|
||||
|
||||
|
||||
+135
-16
@@ -15,11 +15,13 @@
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <limits.h>
|
||||
#include <linux/input.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -27,7 +29,6 @@
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include "bootloader.h"
|
||||
#include "common.h"
|
||||
@@ -70,15 +71,17 @@ static const struct option OPTIONS[] = {
|
||||
{ "wipe_cache", no_argument, NULL, 'c' },
|
||||
{ "show_text", no_argument, NULL, 't' },
|
||||
{ "just_exit", no_argument, NULL, 'x' },
|
||||
{ "nandroid", no_argument, NULL, 'n' },
|
||||
{ "locale", required_argument, NULL, 'l' },
|
||||
{ NULL, 0, NULL, 0 },
|
||||
};
|
||||
|
||||
#define LAST_LOG_FILE "/cache/recovery/last_log"
|
||||
|
||||
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 *LAST_INSTALL_FILE = "/cache/recovery/last_install";
|
||||
static const char *LOCALE_FILE = "/cache/recovery/last_locale";
|
||||
static const char *CACHE_ROOT = "/cache";
|
||||
static const char *SDCARD_ROOT = "/sdcard";
|
||||
static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log";
|
||||
@@ -86,6 +89,7 @@ static const char *TEMPORARY_INSTALL_FILE = "/tmp/last_install";
|
||||
static const char *SIDELOAD_TEMP_DIR = "/tmp/sideload";
|
||||
|
||||
RecoveryUI* ui = NULL;
|
||||
char* locale = NULL;
|
||||
|
||||
/*
|
||||
* The recovery tool communicates with the main system through /cache files.
|
||||
@@ -212,6 +216,7 @@ get_args(int *argc, char ***argv) {
|
||||
if (*argc <= 1) {
|
||||
FILE *fp = fopen_path(COMMAND_FILE, "r");
|
||||
if (fp != NULL) {
|
||||
char *token;
|
||||
char *argv0 = (*argv)[0];
|
||||
*argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
|
||||
(*argv)[0] = argv0; // use the same program name
|
||||
@@ -219,7 +224,12 @@ get_args(int *argc, char ***argv) {
|
||||
char buf[MAX_ARG_LENGTH];
|
||||
for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
|
||||
if (!fgets(buf, sizeof(buf), fp)) break;
|
||||
(*argv)[*argc] = strdup(strtok(buf, "\r\n")); // Strip newline.
|
||||
token = strtok(buf, "\r\n");
|
||||
if (token != NULL) {
|
||||
(*argv)[*argc] = strdup(token); // Strip newline.
|
||||
} else {
|
||||
--*argc;
|
||||
}
|
||||
}
|
||||
|
||||
check_and_fclose(fp, COMMAND_FILE);
|
||||
@@ -273,6 +283,21 @@ copy_log_file(const char* source, const char* destination, int append) {
|
||||
}
|
||||
}
|
||||
|
||||
// Rename last_log -> last_log.1 -> last_log.2 -> ... -> last_log.$max
|
||||
// Overwrites any existing last_log.$max.
|
||||
static void
|
||||
rotate_last_logs(int max) {
|
||||
char oldfn[256];
|
||||
char newfn[256];
|
||||
|
||||
int i;
|
||||
for (i = max-1; i >= 0; --i) {
|
||||
snprintf(oldfn, sizeof(oldfn), (i==0) ? LAST_LOG_FILE : (LAST_LOG_FILE ".%d"), i);
|
||||
snprintf(newfn, sizeof(newfn), LAST_LOG_FILE ".%d", i+1);
|
||||
// ignore errors
|
||||
rename(oldfn, newfn);
|
||||
}
|
||||
}
|
||||
|
||||
// clear the recovery command and prepare to boot a (hopefully working) system,
|
||||
// copy our log file to cache as well (for the system to read), and
|
||||
@@ -291,6 +316,18 @@ finish_recovery(const char *send_intent) {
|
||||
}
|
||||
}
|
||||
|
||||
// Save the locale to cache, so if recovery is next started up
|
||||
// without a --locale argument (eg, directly from the bootloader)
|
||||
// it will use the last-known locale.
|
||||
if (locale != NULL) {
|
||||
LOGI("Saving locale \"%s\"\n", locale);
|
||||
FILE* fp = fopen_path(LOCALE_FILE, "w");
|
||||
fwrite(locale, 1, strlen(locale), fp);
|
||||
fflush(fp);
|
||||
fsync(fileno(fp));
|
||||
check_and_fclose(fp, LOCALE_FILE);
|
||||
}
|
||||
|
||||
// Copy logs to cache so the system can find out what happened.
|
||||
copy_log_file(TEMPORARY_LOG_FILE, LOG_FILE, true);
|
||||
copy_log_file(TEMPORARY_LOG_FILE, LAST_LOG_FILE, false);
|
||||
@@ -317,8 +354,7 @@ finish_recovery(const char *send_intent) {
|
||||
|
||||
static int
|
||||
erase_volume(const char *volume) {
|
||||
return !PartitionManager.Wipe_By_Path(volume);
|
||||
ui->SetBackground(RecoveryUI::INSTALLING);
|
||||
ui->SetBackground(RecoveryUI::ERASING);
|
||||
ui->SetProgressType(RecoveryUI::INDETERMINATE);
|
||||
ui->Print("Formatting %s...\n", volume);
|
||||
|
||||
@@ -671,11 +707,22 @@ wipe_data(int confirm, Device* device) {
|
||||
}
|
||||
|
||||
static void
|
||||
prompt_and_wait(Device* device) {
|
||||
prompt_and_wait(Device* device, int status) {
|
||||
const char* const* headers = prepend_title(device->GetMenuHeaders());
|
||||
|
||||
for (;;) {
|
||||
finish_recovery(NULL);
|
||||
switch (status) {
|
||||
case INSTALL_SUCCESS:
|
||||
case INSTALL_NONE:
|
||||
ui->SetBackground(RecoveryUI::NO_COMMAND);
|
||||
break;
|
||||
|
||||
case INSTALL_ERROR:
|
||||
case INSTALL_CORRUPT:
|
||||
ui->SetBackground(RecoveryUI::ERROR);
|
||||
break;
|
||||
}
|
||||
ui->SetProgressType(RecoveryUI::EMPTY);
|
||||
|
||||
int chosen_item = get_menu_selection(headers, device->GetMenuItems(), 0, 0, device);
|
||||
@@ -685,7 +732,6 @@ prompt_and_wait(Device* device) {
|
||||
// statement below.
|
||||
chosen_item = device->InvokeMenuItem(chosen_item);
|
||||
|
||||
int status;
|
||||
int wipe_cache;
|
||||
switch (chosen_item) {
|
||||
case Device::REBOOT:
|
||||
@@ -775,6 +821,43 @@ print_property(const char *key, const char *name, void *cookie) {
|
||||
printf("%s=%s\n", key, name);
|
||||
}
|
||||
|
||||
static void
|
||||
load_locale_from_cache() {
|
||||
FILE* fp = fopen_path(LOCALE_FILE, "r");
|
||||
char buffer[80];
|
||||
if (fp != NULL) {
|
||||
fgets(buffer, sizeof(buffer), fp);
|
||||
int j = 0;
|
||||
unsigned int i;
|
||||
for (i = 0; i < sizeof(buffer) && buffer[i]; ++i) {
|
||||
if (!isspace(buffer[i])) {
|
||||
buffer[j++] = buffer[i];
|
||||
}
|
||||
}
|
||||
buffer[j] = 0;
|
||||
locale = strdup(buffer);
|
||||
check_and_fclose(fp, LOCALE_FILE);
|
||||
}
|
||||
}
|
||||
|
||||
static RecoveryUI* gCurrentUI = NULL;
|
||||
|
||||
void
|
||||
ui_print(const char* format, ...) {
|
||||
char buffer[256];
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vsnprintf(buffer, sizeof(buffer), format, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (gCurrentUI != NULL) {
|
||||
gCurrentUI->Print("%s", buffer);
|
||||
} else {
|
||||
fputs(buffer, stdout);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv) {
|
||||
// Recovery needs to install world-readable files, so clear umask
|
||||
@@ -824,12 +907,17 @@ main(int argc, char **argv) {
|
||||
gui_loadResources();
|
||||
|
||||
PartitionManager.Mount_By_Path("/cache", true);
|
||||
|
||||
load_volume_table();
|
||||
ensure_path_mounted(LAST_LOG_FILE);
|
||||
rotate_last_logs(5);
|
||||
|
||||
get_args(&argc, &argv);
|
||||
|
||||
int previous_runs = 0;
|
||||
const char *send_intent = NULL;
|
||||
const char *update_package = NULL;
|
||||
int wipe_data = 0, wipe_cache = 0;
|
||||
int wipe_data = 0, wipe_cache = 0, show_text = 0;
|
||||
bool just_exit = false;
|
||||
bool perform_backup = false;
|
||||
|
||||
@@ -841,16 +929,29 @@ main(int argc, char **argv) {
|
||||
case 'u': update_package = optarg; break;
|
||||
case 'w': wipe_data = wipe_cache = 1; break;
|
||||
case 'c': wipe_cache = 1; break;
|
||||
case 't': ui->ShowText(true); break;
|
||||
case 't': show_text = 1; break;
|
||||
case 'x': just_exit = true; break;
|
||||
case 'n': perform_backup = true; LOGI("nandroid\n"); break;
|
||||
case 'l': locale = optarg; break;
|
||||
case '?':
|
||||
LOGE("Invalid command argument\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
if (locale == NULL) {
|
||||
load_locale_from_cache();
|
||||
}
|
||||
printf("locale is [%s]\n", locale);
|
||||
|
||||
Device* device = make_device();
|
||||
ui = device->GetUI();
|
||||
gCurrentUI = ui;
|
||||
|
||||
ui->Init();
|
||||
ui->SetLocale(locale);
|
||||
ui->SetBackground(RecoveryUI::NONE);
|
||||
if (show_text) ui->ShowText(true);
|
||||
|
||||
struct selinux_opt seopts[] = {
|
||||
{ SELABEL_OPT_PATH, "/file_contexts" }
|
||||
};
|
||||
@@ -861,7 +962,6 @@ main(int argc, char **argv) {
|
||||
fprintf(stderr, "Warning: No file_contexts\n");
|
||||
ui->Print("Warning: No file_contexts\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
//device->StartRecovery();
|
||||
|
||||
@@ -936,8 +1036,19 @@ main(int argc, char **argv) {
|
||||
LOGE("Cache wipe (requested by package) failed.");
|
||||
}
|
||||
}
|
||||
if (status != INSTALL_SUCCESS) ui->Print("Installation aborted.\n");
|
||||
*/
|
||||
|
||||
if (status != INSTALL_SUCCESS) {
|
||||
ui->Print("Installation aborted.\n");
|
||||
|
||||
// If this is an eng or userdebug build, then automatically
|
||||
// turn the text display on if the script fails so the error
|
||||
// message is visible.
|
||||
char buffer[PROPERTY_VALUE_MAX+1];
|
||||
property_get("ro.build.fingerprint", buffer, "");
|
||||
if (strstr(buffer, ":userdebug/") || strstr(buffer, ":eng/")) {
|
||||
ui->ShowText(true);
|
||||
}
|
||||
}
|
||||
} else if (wipe_data) {
|
||||
if (!OpenRecoveryScript::Insert_ORS_Command("wipe data\n"))
|
||||
status = INSTALL_ERROR;
|
||||
@@ -952,7 +1063,8 @@ main(int argc, char **argv) {
|
||||
status = INSTALL_ERROR;
|
||||
if (status != INSTALL_SUCCESS) ui->Print("Cache wipe failed.\n");
|
||||
} else if (!just_exit) {
|
||||
status = INSTALL_ERROR; // No command specified
|
||||
status = INSTALL_NONE; // No command specified
|
||||
ui->SetBackground(RecoveryUI::NO_COMMAND);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -998,6 +1110,13 @@ main(int argc, char **argv) {
|
||||
PartitionManager.UnMount_By_Path("/system", false);
|
||||
}
|
||||
|
||||
if (status == INSTALL_ERROR || status == INSTALL_CORRUPT) {
|
||||
ui->SetBackground(RecoveryUI::ERROR);
|
||||
}
|
||||
if (status != INSTALL_SUCCESS || ui->IsTextVisible()) {
|
||||
prompt_and_wait(device, status);
|
||||
}
|
||||
|
||||
// Otherwise, get ready to boot the main system...
|
||||
finish_recovery(send_intent);
|
||||
ui->Print("Rebooting...\n");
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 65 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
@@ -23,6 +23,7 @@
|
||||
#include <ctype.h>
|
||||
|
||||
extern "C" {
|
||||
#include <fs_mgr.h>
|
||||
#include "mtdutils/mtdutils.h"
|
||||
#include "mtdutils/mounts.h"
|
||||
}
|
||||
@@ -31,115 +32,41 @@ extern "C" {
|
||||
#include "make_ext4fs.h"
|
||||
#include "partitions.hpp"
|
||||
|
||||
static int num_volumes = 0;
|
||||
static Volume* device_volumes = NULL;
|
||||
static struct fstab *fstab = NULL;
|
||||
|
||||
extern struct selabel_handle *sehandle;
|
||||
|
||||
static int parse_options(char* options, Volume* volume) {
|
||||
char* option;
|
||||
while ((option = strtok(options, ","))) {
|
||||
options = NULL;
|
||||
void load_volume_table()
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
if (strncmp(option, "flags=", 6) == 0) continue;
|
||||
if (strncmp(option, "length=", 7) == 0) {
|
||||
volume->length = strtoll(option+7, NULL, 10);
|
||||
} else {
|
||||
LOGE("bad option \"%s\"\n", option);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void load_volume_table() {
|
||||
int alloc = 2;
|
||||
device_volumes = (Volume*)malloc(alloc * sizeof(Volume));
|
||||
|
||||
// Insert an entry for /tmp, which is the ramdisk and is always mounted.
|
||||
device_volumes[0].mount_point = "/tmp";
|
||||
device_volumes[0].fs_type = "ramdisk";
|
||||
device_volumes[0].device = NULL;
|
||||
device_volumes[0].device2 = NULL;
|
||||
device_volumes[0].length = 0;
|
||||
num_volumes = 1;
|
||||
|
||||
FILE* fstab = fopen("/etc/recovery.fstab", "r");
|
||||
if (fstab == NULL) {
|
||||
LOGE("failed to open /etc/recovery.fstab (%s)\n", strerror(errno));
|
||||
fstab = fs_mgr_read_fstab("/etc/recovery.fstab");
|
||||
if (!fstab) {
|
||||
LOGE("failed to read /etc/recovery.fstab\n");
|
||||
return;
|
||||
}
|
||||
|
||||
char buffer[1024];
|
||||
int i;
|
||||
while (fgets(buffer, sizeof(buffer)-1, fstab)) {
|
||||
for (i = 0; buffer[i] && isspace(buffer[i]); ++i);
|
||||
if (buffer[i] == '\0' || buffer[i] == '#') continue;
|
||||
|
||||
char* original = strdup(buffer);
|
||||
|
||||
char* mount_point = strtok(buffer+i, " \t\n");
|
||||
char* fs_type = strtok(NULL, " \t\n");
|
||||
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");
|
||||
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) {
|
||||
alloc *= 2;
|
||||
device_volumes = (Volume*)realloc(device_volumes, alloc*sizeof(Volume));
|
||||
}
|
||||
device_volumes[num_volumes].mount_point = strdup(mount_point);
|
||||
device_volumes[num_volumes].fs_type = strdup(fs_type);
|
||||
device_volumes[num_volumes].device = strdup(device);
|
||||
device_volumes[num_volumes].device2 =
|
||||
device2 ? strdup(device2) : NULL;
|
||||
|
||||
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 {
|
||||
LOGE("skipping malformed recovery.fstab line: %s\n", original);
|
||||
}
|
||||
free(original);
|
||||
ret = fs_mgr_add_entry(fstab, "/tmp", "ramdisk", "ramdisk", 0);
|
||||
if (ret < 0 ) {
|
||||
LOGE("failed to add /tmp entry to fstab\n");
|
||||
fs_mgr_free_fstab(fstab);
|
||||
fstab = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
fclose(fstab);
|
||||
|
||||
printf("recovery filesystem table\n");
|
||||
printf("=========================\n");
|
||||
for (i = 0; i < num_volumes; ++i) {
|
||||
Volume* v = &device_volumes[i];
|
||||
printf(" %d %s %s %s %s %lld\n", i, v->mount_point, v->fs_type,
|
||||
v->device, v->device2, v->length);
|
||||
for (i = 0; i < fstab->num_entries; ++i) {
|
||||
Volume* v = &fstab->recs[i];
|
||||
printf(" %d %s %s %s %lld\n", i, v->mount_point, v->fs_type,
|
||||
v->blk_device, v->length);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
Volume* volume_for_path(const char* path) {
|
||||
int i;
|
||||
for (i = 0; i < num_volumes; ++i) {
|
||||
Volume* v = device_volumes+i;
|
||||
int len = strlen(v->mount_point);
|
||||
if (strncmp(path, v->mount_point, len) == 0 &&
|
||||
(path[len] == '\0' || path[len] == '/')) {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
return fs_mgr_get_entry_for_mount_point(fstab, path);
|
||||
}
|
||||
|
||||
int ensure_path_mounted(const char* path) {
|
||||
@@ -177,27 +104,19 @@ int ensure_path_mounted(const char* path) {
|
||||
// mount an MTD partition as a YAFFS2 filesystem.
|
||||
mtd_scan_partitions();
|
||||
const MtdPartition* partition;
|
||||
partition = mtd_find_partition_by_name(v->device);
|
||||
partition = mtd_find_partition_by_name(v->blk_device);
|
||||
if (partition == NULL) {
|
||||
LOGE("failed to find \"%s\" partition to mount at \"%s\"\n",
|
||||
v->device, v->mount_point);
|
||||
v->blk_device, v->mount_point);
|
||||
return -1;
|
||||
}
|
||||
return mtd_mount_partition(partition, v->mount_point, v->fs_type, 0);
|
||||
} else if (strcmp(v->fs_type, "ext4") == 0 ||
|
||||
strcmp(v->fs_type, "vfat") == 0) {
|
||||
result = mount(v->device, v->mount_point, v->fs_type,
|
||||
result = mount(v->blk_device, v->mount_point, v->fs_type,
|
||||
MS_NOATIME | MS_NODEV | MS_NODIRATIME, "");
|
||||
if (result == 0) return 0;
|
||||
|
||||
if (v->device2) {
|
||||
LOGW("failed to mount %s (%s); trying %s\n",
|
||||
v->device, strerror(errno), v->device2);
|
||||
result = mount(v->device2, v->mount_point, v->fs_type,
|
||||
MS_NOATIME | MS_NODEV | MS_NODIRATIME, "");
|
||||
if (result == 0) return 0;
|
||||
}
|
||||
|
||||
LOGE("failed to mount %s (%s)\n", v->mount_point, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
@@ -265,38 +184,31 @@ int format_volume(const char* volume) {
|
||||
|
||||
if (strcmp(v->fs_type, "yaffs2") == 0 || strcmp(v->fs_type, "mtd") == 0) {
|
||||
mtd_scan_partitions();
|
||||
const MtdPartition* partition = mtd_find_partition_by_name(v->device);
|
||||
const MtdPartition* partition = mtd_find_partition_by_name(v->blk_device);
|
||||
if (partition == NULL) {
|
||||
LOGE("format_volume: no MTD partition \"%s\"\n", v->device);
|
||||
LOGE("format_volume: no MTD partition \"%s\"\n", v->blk_device);
|
||||
return -1;
|
||||
}
|
||||
|
||||
MtdWriteContext *write = mtd_write_partition(partition);
|
||||
if (write == NULL) {
|
||||
LOGW("format_volume: can't open MTD \"%s\"\n", v->device);
|
||||
LOGW("format_volume: can't open MTD \"%s\"\n", v->blk_device);
|
||||
return -1;
|
||||
} else if (mtd_erase_blocks(write, -1) == (off_t) -1) {
|
||||
LOGW("format_volume: can't erase MTD \"%s\"\n", v->device);
|
||||
LOGW("format_volume: can't erase MTD \"%s\"\n", v->blk_device);
|
||||
mtd_write_close(write);
|
||||
return -1;
|
||||
} else if (mtd_write_close(write)) {
|
||||
LOGW("format_volume: can't close MTD \"%s\"\n", v->device);
|
||||
LOGW("format_volume: can't close MTD \"%s\"\n", v->blk_device);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(v->fs_type, "ext4") == 0) {
|
||||
#ifdef USE_EXT4
|
||||
/*
|
||||
int result = make_ext4fs(v->device, v->length, volume, sehandle);
|
||||
*/
|
||||
int result = 0;
|
||||
#else
|
||||
int result = 0;
|
||||
#endif
|
||||
int result = make_ext4fs(v->blk_device, v->length, volume, sehandle);
|
||||
if (result != 0) {
|
||||
LOGE("format_volume: make_extf4fs failed on %s\n", v->device);
|
||||
LOGE("format_volume: make_extf4fs failed on %s\n", v->blk_device);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
||||
+138
-43
@@ -40,8 +40,8 @@ int twgr_text(int x, int y, const char *s);
|
||||
}
|
||||
#include "data.hpp"
|
||||
|
||||
#define CHAR_WIDTH 10
|
||||
#define CHAR_HEIGHT 18
|
||||
static int char_width;
|
||||
static int char_height;
|
||||
|
||||
// There's only (at most) one of these objects, and global callbacks
|
||||
// (for pthread_create, and the input event system) need to find it,
|
||||
@@ -58,6 +58,7 @@ static double now() {
|
||||
ScreenRecoveryUI::ScreenRecoveryUI() :
|
||||
currentIcon(NONE),
|
||||
installingFrame(0),
|
||||
rtl_locale(false),
|
||||
progressBarType(EMPTY),
|
||||
progressScopeStart(0),
|
||||
progressScopeSize(0),
|
||||
@@ -84,7 +85,13 @@ ScreenRecoveryUI::ScreenRecoveryUI() :
|
||||
indeterminate_frames(6),
|
||||
installing_frames(7),
|
||||
install_overlay_offset_x(13),
|
||||
install_overlay_offset_y(190) {
|
||||
install_overlay_offset_y(190),
|
||||
overlay_offset_x(-1),
|
||||
overlay_offset_y(-1) {
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
backgroundIcon[i] = NULL;
|
||||
|
||||
pthread_mutex_init(&updateMutex, NULL);
|
||||
self = this;
|
||||
}
|
||||
@@ -95,12 +102,12 @@ ScreenRecoveryUI::ScreenRecoveryUI() :
|
||||
// animation. Does nothing if no overlay animation is defined.
|
||||
// Should only be called with updateMutex locked.
|
||||
void ScreenRecoveryUI::draw_install_overlay_locked(int frame) {
|
||||
if (installationOverlay == NULL) return;
|
||||
if (installationOverlay == NULL || overlay_offset_x < 0) return;
|
||||
gr_surface surface = installationOverlay[frame];
|
||||
int iconWidth = gr_get_width(surface);
|
||||
int iconHeight = gr_get_height(surface);
|
||||
gr_blit(surface, 0, 0, iconWidth, iconHeight,
|
||||
install_overlay_offset_x, install_overlay_offset_y);
|
||||
overlay_offset_x, overlay_offset_y);
|
||||
}
|
||||
|
||||
// Clear the screen and draw the currently selected background icon (if any).
|
||||
@@ -113,14 +120,26 @@ void ScreenRecoveryUI::draw_background_locked(Icon icon)
|
||||
|
||||
if (icon) {
|
||||
gr_surface surface = backgroundIcon[icon];
|
||||
gr_surface text_surface = backgroundText[icon];
|
||||
|
||||
int iconWidth = gr_get_width(surface);
|
||||
int iconHeight = gr_get_height(surface);
|
||||
int textWidth = gr_get_width(text_surface);
|
||||
int textHeight = gr_get_height(text_surface);
|
||||
|
||||
int iconX = (gr_fb_width() - iconWidth) / 2;
|
||||
int iconY = (gr_fb_height() - iconHeight) / 2;
|
||||
int iconY = (gr_fb_height() - (iconHeight+textHeight+40)) / 2;
|
||||
|
||||
int textX = (gr_fb_width() - textWidth) / 2;
|
||||
int textY = ((gr_fb_height() - (iconHeight+textHeight+40)) / 2) + iconHeight + 40;
|
||||
|
||||
gr_blit(surface, 0, 0, iconWidth, iconHeight, iconX, iconY);
|
||||
if (icon == INSTALLING) {
|
||||
if (icon == INSTALLING_UPDATE || icon == ERASING) {
|
||||
draw_install_overlay_locked(installingFrame);
|
||||
}
|
||||
|
||||
gr_color(255, 255, 255, 255);
|
||||
gr_texticon(textX, textY, text_surface);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,12 +149,12 @@ void ScreenRecoveryUI::draw_progress_locked()
|
||||
{
|
||||
if (currentIcon == ERROR) return;
|
||||
|
||||
if (currentIcon == INSTALLING) {
|
||||
if (currentIcon == INSTALLING_UPDATE || currentIcon == ERASING) {
|
||||
draw_install_overlay_locked(installingFrame);
|
||||
}
|
||||
|
||||
if (progressBarType != EMPTY) {
|
||||
int iconHeight = gr_get_height(backgroundIcon[INSTALLING]);
|
||||
int iconHeight = gr_get_height(backgroundIcon[INSTALLING_UPDATE]);
|
||||
int width = gr_get_width(progressBarEmpty);
|
||||
int height = gr_get_height(progressBarEmpty);
|
||||
|
||||
@@ -150,27 +169,42 @@ void ScreenRecoveryUI::draw_progress_locked()
|
||||
float p = progressScopeStart + progress * progressScopeSize;
|
||||
int pos = (int) (p * width);
|
||||
|
||||
if (pos > 0) {
|
||||
gr_blit(progressBarFill, 0, 0, pos, height, dx, dy);
|
||||
}
|
||||
if (pos < width-1) {
|
||||
gr_blit(progressBarEmpty, pos, 0, width-pos, height, dx+pos, dy);
|
||||
if (rtl_locale) {
|
||||
// Fill the progress bar from right to left.
|
||||
if (pos > 0) {
|
||||
gr_blit(progressBarFill, width-pos, 0, pos, height, dx+width-pos, dy);
|
||||
}
|
||||
if (pos < width-1) {
|
||||
gr_blit(progressBarEmpty, 0, 0, width-pos, height, dx, dy);
|
||||
}
|
||||
} else {
|
||||
// Fill the progress bar from left to right.
|
||||
if (pos > 0) {
|
||||
gr_blit(progressBarFill, 0, 0, pos, height, dx, dy);
|
||||
}
|
||||
if (pos < width-1) {
|
||||
gr_blit(progressBarEmpty, pos, 0, width-pos, height, dx+pos, dy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (progressBarType == INDETERMINATE) {
|
||||
static int frame = 0;
|
||||
gr_blit(progressBarIndeterminate[frame], 0, 0, width, height, dx, dy);
|
||||
frame = (frame + 1) % indeterminate_frames;
|
||||
// in RTL locales, we run the animation backwards, which
|
||||
// makes the spinner spin the other way.
|
||||
if (rtl_locale) {
|
||||
frame = (frame + indeterminate_frames - 1) % indeterminate_frames;
|
||||
} else {
|
||||
frame = (frame + 1) % indeterminate_frames;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenRecoveryUI::draw_text_line(int row, const char* t) {
|
||||
if (t[0] != '\0') {
|
||||
twgr_text(0, (row+1)*CHAR_HEIGHT-1, t);
|
||||
}
|
||||
}
|
||||
#define C_HEADER 247,0,6
|
||||
#define C_MENU 0,106,157
|
||||
#define C_LOG 249,194,0
|
||||
|
||||
// Redraw everything on the screen. Does not flip pages.
|
||||
// Should only be called with updateMutex locked.
|
||||
@@ -183,30 +217,46 @@ void ScreenRecoveryUI::draw_screen_locked()
|
||||
gr_color(0, 0, 0, 160);
|
||||
gr_fill(0, 0, gr_fb_width(), gr_fb_height());
|
||||
|
||||
int y = 0;
|
||||
int i = 0;
|
||||
if (show_menu) {
|
||||
gr_color(64, 96, 255, 255);
|
||||
gr_fill(0, (menu_top+menu_sel) * CHAR_HEIGHT,
|
||||
gr_fb_width(), (menu_top+menu_sel+1)*CHAR_HEIGHT+1);
|
||||
gr_color(C_HEADER, 255);
|
||||
|
||||
for (; i < menu_top + menu_items; ++i) {
|
||||
if (i == menu_top) gr_color(C_MENU, 255);
|
||||
|
||||
if (i == menu_top + menu_sel) {
|
||||
// draw the highlight bar
|
||||
gr_fill(0, y-2, gr_fb_width(), y+char_height+2);
|
||||
// white text of selected item
|
||||
gr_color(255, 255, 255, 255);
|
||||
draw_text_line(i, menu[i]);
|
||||
gr_color(64, 96, 255, 255);
|
||||
if (menu[i][0]) gr_text(4, y, menu[i], 1);
|
||||
gr_color(C_MENU, 255);
|
||||
} else {
|
||||
draw_text_line(i, menu[i]);
|
||||
if (menu[i][0]) gr_text(4, y, menu[i], i < menu_top);
|
||||
}
|
||||
y += char_height+4;
|
||||
}
|
||||
gr_fill(0, i*CHAR_HEIGHT+CHAR_HEIGHT/2-1,
|
||||
gr_fb_width(), i*CHAR_HEIGHT+CHAR_HEIGHT/2+1);
|
||||
gr_color(C_MENU, 255);
|
||||
y += 4;
|
||||
gr_fill(0, y, gr_fb_width(), y+2);
|
||||
y += 4;
|
||||
++i;
|
||||
}
|
||||
|
||||
gr_color(255, 255, 0, 255);
|
||||
gr_color(C_LOG, 255);
|
||||
|
||||
for (; i < text_rows; ++i) {
|
||||
draw_text_line(i, text[(i+text_top) % text_rows]);
|
||||
// display from the bottom up, until we hit the top of the
|
||||
// screen, the bottom of the menu, or we've displayed the
|
||||
// entire text buffer.
|
||||
int ty;
|
||||
int row = (text_top+text_rows-1) % text_rows;
|
||||
for (int ty = gr_fb_height() - char_height, count = 0;
|
||||
ty > y+2 && count < text_rows;
|
||||
ty -= char_height, ++count) {
|
||||
gr_text(4, ty, text[row], 0);
|
||||
--row;
|
||||
if (row < 0) row = text_rows-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -248,7 +298,8 @@ void ScreenRecoveryUI::progress_loop() {
|
||||
|
||||
// update the installation animation, if active
|
||||
// skip this if we have a text overlay (too expensive to update)
|
||||
if (currentIcon == INSTALLING && installing_frames > 0 && !show_text) {
|
||||
if ((currentIcon == INSTALLING_UPDATE || currentIcon == ERASING) &&
|
||||
installing_frames > 0 && !show_text) {
|
||||
installingFrame = (installingFrame + 1) % installing_frames;
|
||||
redraw = 1;
|
||||
}
|
||||
@@ -289,23 +340,40 @@ void ScreenRecoveryUI::LoadBitmap(const char* filename, gr_surface* surface) {
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenRecoveryUI::LoadLocalizedBitmap(const char* filename, gr_surface* surface) {
|
||||
int result = res_create_localized_surface(filename, surface);
|
||||
if (result < 0) {
|
||||
LOGE("missing bitmap %s\n(Code %d)\n", filename, result);
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenRecoveryUI::Init()
|
||||
{
|
||||
gr_init();
|
||||
|
||||
gr_font_size(&char_width, &char_height);
|
||||
|
||||
text_col = text_row = 0;
|
||||
text_rows = gr_fb_height() / CHAR_HEIGHT;
|
||||
text_rows = gr_fb_height() / char_height;
|
||||
if (text_rows > kMaxRows) text_rows = kMaxRows;
|
||||
text_top = 1;
|
||||
|
||||
text_cols = gr_fb_width() / CHAR_WIDTH;
|
||||
text_cols = gr_fb_width() / char_width;
|
||||
if (text_cols > kMaxCols - 1) text_cols = kMaxCols - 1;
|
||||
|
||||
LoadBitmap("icon_installing", &backgroundIcon[INSTALLING]);
|
||||
LoadBitmap("icon_installing", &backgroundIcon[INSTALLING_UPDATE]);
|
||||
backgroundIcon[ERASING] = backgroundIcon[INSTALLING_UPDATE];
|
||||
LoadBitmap("icon_error", &backgroundIcon[ERROR]);
|
||||
backgroundIcon[NO_COMMAND] = backgroundIcon[ERROR];
|
||||
|
||||
LoadBitmap("progress_empty", &progressBarEmpty);
|
||||
LoadBitmap("progress_fill", &progressBarFill);
|
||||
|
||||
LoadLocalizedBitmap("installing_text", &backgroundText[INSTALLING_UPDATE]);
|
||||
LoadLocalizedBitmap("erasing_text", &backgroundText[ERASING]);
|
||||
LoadLocalizedBitmap("no_command_text", &backgroundText[NO_COMMAND]);
|
||||
LoadLocalizedBitmap("error_text", &backgroundText[ERROR]);
|
||||
|
||||
int i;
|
||||
|
||||
progressBarIndeterminate = (gr_surface*)malloc(indeterminate_frames *
|
||||
@@ -327,14 +395,6 @@ void ScreenRecoveryUI::Init()
|
||||
sprintf(filename, "icon_installing_overlay%02d", i+1);
|
||||
LoadBitmap(filename, installationOverlay+i);
|
||||
}
|
||||
|
||||
// Adjust the offset to account for the positioning of the
|
||||
// base image on the screen.
|
||||
if (backgroundIcon[INSTALLING] != NULL) {
|
||||
gr_surface bg = backgroundIcon[INSTALLING];
|
||||
install_overlay_offset_x += (gr_fb_width() - gr_get_width(bg)) / 2;
|
||||
install_overlay_offset_y += (gr_fb_height() - gr_get_height(bg)) / 2;
|
||||
}
|
||||
} else {
|
||||
installationOverlay = NULL;
|
||||
}
|
||||
@@ -344,11 +404,46 @@ void ScreenRecoveryUI::Init()
|
||||
RecoveryUI::Init();
|
||||
}
|
||||
|
||||
void ScreenRecoveryUI::SetLocale(const char* locale) {
|
||||
if (locale) {
|
||||
char* lang = strdup(locale);
|
||||
for (char* p = lang; *p; ++p) {
|
||||
if (*p == '_') {
|
||||
*p = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// A bit cheesy: keep an explicit list of supported languages
|
||||
// that are RTL.
|
||||
if (strcmp(lang, "ar") == 0 || // Arabic
|
||||
strcmp(lang, "fa") == 0 || // Persian (Farsi)
|
||||
strcmp(lang, "he") == 0 || // Hebrew (new language code)
|
||||
strcmp(lang, "iw") == 0 || // Hebrew (old language code)
|
||||
strcmp(lang, "ur") == 0) { // Urdu
|
||||
rtl_locale = true;
|
||||
}
|
||||
free(lang);
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenRecoveryUI::SetBackground(Icon icon)
|
||||
{
|
||||
pthread_mutex_lock(&updateMutex);
|
||||
|
||||
// Adjust the offset to account for the positioning of the
|
||||
// base image on the screen.
|
||||
if (backgroundIcon[icon] != NULL) {
|
||||
gr_surface bg = backgroundIcon[icon];
|
||||
gr_surface text = backgroundText[icon];
|
||||
overlay_offset_x = install_overlay_offset_x + (gr_fb_width() - gr_get_width(bg)) / 2;
|
||||
overlay_offset_y = install_overlay_offset_y +
|
||||
(gr_fb_height() - (gr_get_height(bg) + gr_get_height(text) + 40)) / 2;
|
||||
}
|
||||
|
||||
currentIcon = icon;
|
||||
update_screen_locked();
|
||||
|
||||
pthread_mutex_unlock(&updateMutex);
|
||||
}
|
||||
|
||||
|
||||
+7
-4
@@ -29,6 +29,7 @@ class ScreenRecoveryUI : public RecoveryUI {
|
||||
ScreenRecoveryUI();
|
||||
|
||||
void Init();
|
||||
void SetLocale(const char* locale);
|
||||
|
||||
// overall recovery state ("background image")
|
||||
void SetBackground(Icon icon);
|
||||
@@ -55,9 +56,11 @@ class ScreenRecoveryUI : public RecoveryUI {
|
||||
private:
|
||||
Icon currentIcon;
|
||||
int installingFrame;
|
||||
bool rtl_locale;
|
||||
|
||||
pthread_mutex_t updateMutex;
|
||||
gr_surface backgroundIcon[3];
|
||||
gr_surface backgroundIcon[5];
|
||||
gr_surface backgroundText[5];
|
||||
gr_surface *installationOverlay;
|
||||
gr_surface *progressBarIndeterminate;
|
||||
gr_surface progressBarEmpty;
|
||||
@@ -73,7 +76,7 @@ class ScreenRecoveryUI : public RecoveryUI {
|
||||
bool pagesIdentical;
|
||||
|
||||
static const int kMaxCols = 96;
|
||||
static const int kMaxRows = 32;
|
||||
static const int kMaxRows = 96;
|
||||
|
||||
// Log text overlay, displayed when a magic key is pressed
|
||||
char text[kMaxRows][kMaxCols];
|
||||
@@ -92,11 +95,11 @@ class ScreenRecoveryUI : public RecoveryUI {
|
||||
int indeterminate_frames;
|
||||
int installing_frames;
|
||||
int install_overlay_offset_x, install_overlay_offset_y;
|
||||
int overlay_offset_x, overlay_offset_y;
|
||||
|
||||
void draw_install_overlay_locked(int frame);
|
||||
void draw_background_locked(Icon icon);
|
||||
void draw_progress_locked();
|
||||
void draw_text_line(int row, const char* t);
|
||||
void draw_screen_locked();
|
||||
void update_screen_locked();
|
||||
void update_progress_locked();
|
||||
@@ -104,7 +107,7 @@ class ScreenRecoveryUI : public RecoveryUI {
|
||||
void progress_loop();
|
||||
|
||||
void LoadBitmap(const char* filename, gr_surface* surface);
|
||||
|
||||
void LoadLocalizedBitmap(const char* filename, gr_surface* surface);
|
||||
};
|
||||
|
||||
#endif // RECOVERY_UI_H
|
||||
|
||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
+25
@@ -0,0 +1,25 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIENjCCAx6gAwIBAgIJAKhkCO1dDYMaMA0GCSqGSIb3DQEBBQUAMG8xCzAJBgNV
|
||||
BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBW
|
||||
aWV3MQ8wDQYDVQQKEwZHb29nbGUxEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMT
|
||||
B1Rlc3QxMjMwHhcNMTIwNzI1MTg1NzAzWhcNMzkxMjExMTg1NzAzWjBvMQswCQYD
|
||||
VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g
|
||||
VmlldzEPMA0GA1UEChMGR29vZ2xlMRAwDgYDVQQLEwdBbmRyb2lkMRAwDgYDVQQD
|
||||
EwdUZXN0MTIzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu8WwMN9x
|
||||
4Mz7YgkG2qy9g8/kl5ZoYrUM0ApHhaITAcL7RXLZaNipCf0w/YjYTQgj+75MK30x
|
||||
TsnPeWNOEwA62gkHrZyyWfxBRO6kBYuIuI4roGDBJOmKQ1OEaDeIRKu7q5V8v3Cs
|
||||
0wQDAQWTbhpxBZr9UYFgJUg8XWBfPrGJLVwsoiy4xrMhoTlNZKHfwOMMqVtSHkZX
|
||||
qydYrcIzyjh+TO0e/xSNQ8MMRRbtqWgCHN6Rzhog3IHZu0RaPoukariopjXM/s0V
|
||||
gTm3rHDHCOpna2pNblyiFlvbkoCs769mtNmx/yrDShO30jg/xaG8RypKDvTChzOT
|
||||
oWW/XQ5VEXjbHwIDAQABo4HUMIHRMB0GA1UdDgQWBBRlT2dEZJY1tmUM8mZ0xnhS
|
||||
GdD9TTCBoQYDVR0jBIGZMIGWgBRlT2dEZJY1tmUM8mZ0xnhSGdD9TaFzpHEwbzEL
|
||||
MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50
|
||||
YWluIFZpZXcxDzANBgNVBAoTBkdvb2dsZTEQMA4GA1UECxMHQW5kcm9pZDEQMA4G
|
||||
A1UEAxMHVGVzdDEyM4IJAKhkCO1dDYMaMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcN
|
||||
AQEFBQADggEBAHqnXHtE+h3hvGmHh24GT51vGAYLc68WUUtCVlMIU85zQ757wlxZ
|
||||
BmRypZ1i9hSqnXj5n+mETV5rFX3g2gvdAPVHkRycuDa2aUdZSE8cW4Z6qYFx6SaD
|
||||
e+3SyXokpUquW64RuHJrf/yd/FnGjneBe3Qpm2reuzGWNH90qZGdbsfNaCm5kx2L
|
||||
X+ZNHM3CcGMLaphY5++sM0JxSEcju5EK33ZYgLf4YdlbyMp8LDFVNd7ff0SFi9fF
|
||||
0ZlAsJWoS3QmVCj2744BFdsCu7UHpnYpG6X3MT4SHAawdOaT5zSuaCl2xx6H0O7t
|
||||
w/Fvbl/KVD1ZmLHgBKjDMNSh0OB9mSsDWpw=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -120,6 +120,18 @@ int main(int argc, char **argv) {
|
||||
bool Cache_Wipe = false, Factory_Reset = false, Perform_Backup = false;
|
||||
|
||||
{
|
||||
TWPartition* misc = PartitionManager.Find_Partition_By_Path("/misc");
|
||||
if (misc != NULL) {
|
||||
if (misc->Current_File_System == "emmc") {
|
||||
set_device_type('e');
|
||||
set_device_name(misc->Actual_Block_Device.c_str());
|
||||
} else if (misc->Current_File_System == "mtd") {
|
||||
set_device_type('m');
|
||||
set_device_name(misc->MTD_Name.c_str());
|
||||
} else {
|
||||
LOGERR("Unknown file system for /misc\n");
|
||||
}
|
||||
}
|
||||
get_args(&argc, &argv);
|
||||
|
||||
int index, index2, len;
|
||||
|
||||
@@ -47,7 +47,8 @@ static RecoveryUI* self = NULL;
|
||||
|
||||
RecoveryUI::RecoveryUI() :
|
||||
key_queue_len(0),
|
||||
key_last_down(-1) {
|
||||
key_last_down(-1),
|
||||
key_down_time(0) {
|
||||
pthread_mutex_init(&key_queue_mutex, NULL);
|
||||
pthread_cond_init(&key_queue_cond, NULL);
|
||||
self = this;
|
||||
@@ -111,19 +112,29 @@ int RecoveryUI::input_callback(int fd, short revents, void* data)
|
||||
// updown == 1 for key down events; 0 for key up events
|
||||
void RecoveryUI::process_key(int key_code, int updown) {
|
||||
bool register_key = false;
|
||||
bool long_press = false;
|
||||
|
||||
const long long_threshold = CLOCKS_PER_SEC * 750 / 1000;
|
||||
|
||||
pthread_mutex_lock(&key_queue_mutex);
|
||||
key_pressed[key_code] = updown;
|
||||
if (updown) {
|
||||
key_last_down = key_code;
|
||||
key_down_time = clock();
|
||||
} else {
|
||||
if (key_last_down == key_code)
|
||||
if (key_last_down == key_code) {
|
||||
long duration = clock() - key_down_time;
|
||||
if (duration > long_threshold) {
|
||||
long_press = true;
|
||||
}
|
||||
register_key = true;
|
||||
}
|
||||
key_last_down = -1;
|
||||
}
|
||||
pthread_mutex_unlock(&key_queue_mutex);
|
||||
|
||||
if (register_key) {
|
||||
NextCheckKeyIsLong(long_press);
|
||||
switch (CheckKey(key_code)) {
|
||||
case RecoveryUI::IGNORE:
|
||||
break;
|
||||
@@ -139,18 +150,23 @@ void RecoveryUI::process_key(int key_code, int updown) {
|
||||
break;
|
||||
|
||||
case RecoveryUI::ENQUEUE:
|
||||
pthread_mutex_lock(&key_queue_mutex);
|
||||
const int queue_max = sizeof(key_queue) / sizeof(key_queue[0]);
|
||||
if (key_queue_len < queue_max) {
|
||||
key_queue[key_queue_len++] = key_code;
|
||||
pthread_cond_signal(&key_queue_cond);
|
||||
}
|
||||
pthread_mutex_unlock(&key_queue_mutex);
|
||||
EnqueueKey(key_code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RecoveryUI::EnqueueKey(int key_code) {
|
||||
pthread_mutex_lock(&key_queue_mutex);
|
||||
const int queue_max = sizeof(key_queue) / sizeof(key_queue[0]);
|
||||
if (key_queue_len < queue_max) {
|
||||
key_queue[key_queue_len++] = key_code;
|
||||
pthread_cond_signal(&key_queue_cond);
|
||||
}
|
||||
pthread_mutex_unlock(&key_queue_mutex);
|
||||
}
|
||||
|
||||
|
||||
// Reads input events, handles special hot keys, and adds to the key queue.
|
||||
void* RecoveryUI::input_thread(void *cookie)
|
||||
{
|
||||
@@ -227,3 +243,6 @@ void RecoveryUI::FlushKeys() {
|
||||
RecoveryUI::KeyAction RecoveryUI::CheckKey(int key) {
|
||||
return RecoveryUI::ENQUEUE;
|
||||
}
|
||||
|
||||
void RecoveryUI::NextCheckKeyIsLong(bool is_long_press) {
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
|
||||
// Abstract class for controlling the user interface during recovery.
|
||||
class RecoveryUI {
|
||||
@@ -30,8 +31,11 @@ class RecoveryUI {
|
||||
// Initialize the object; called before anything else.
|
||||
virtual void Init();
|
||||
|
||||
// After calling Init(), you can tell the UI what locale it is operating in.
|
||||
virtual void SetLocale(const char* locale) { }
|
||||
|
||||
// Set the overall recovery state ("background image").
|
||||
enum Icon { NONE, INSTALLING, ERROR };
|
||||
enum Icon { NONE, INSTALLING_UPDATE, ERASING, NO_COMMAND, ERROR };
|
||||
virtual void SetBackground(Icon icon) = 0;
|
||||
|
||||
// --- progress indicator ---
|
||||
@@ -76,6 +80,8 @@ class RecoveryUI {
|
||||
enum KeyAction { ENQUEUE, TOGGLE, REBOOT, IGNORE };
|
||||
virtual KeyAction CheckKey(int key);
|
||||
|
||||
virtual void NextCheckKeyIsLong(bool is_long_press);
|
||||
|
||||
// --- menu display ---
|
||||
|
||||
// Display some header text followed by a menu of items, which appears
|
||||
@@ -92,6 +98,9 @@ class RecoveryUI {
|
||||
// statements will be displayed.
|
||||
virtual void EndMenu() = 0;
|
||||
|
||||
protected:
|
||||
void EnqueueKey(int key_code);
|
||||
|
||||
private:
|
||||
// Key event input queue
|
||||
pthread_mutex_t key_queue_mutex;
|
||||
@@ -99,6 +108,7 @@ private:
|
||||
int key_queue[256], key_queue_len;
|
||||
char key_pressed[KEY_MAX + 1]; // under key_queue_mutex
|
||||
int key_last_down; // under key_queue_mutex
|
||||
clock_t key_down_time; // under key_queue_mutex
|
||||
int rel_sum;
|
||||
|
||||
pthread_t input_t;
|
||||
|
||||
+2
-7
@@ -32,18 +32,13 @@ LOCAL_STATIC_LIBRARIES = \
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_SELINUX), true)
|
||||
LOCAL_C_INCLUDES += external/libselinux/include
|
||||
LOCAL_STATIC_LIBRARIES += libselinux
|
||||
LOCAL_CFLAGS += -DHAVE_SELINUX
|
||||
endif # HAVE_SELINUX
|
||||
|
||||
LOCAL_STATIC_LIBRARIES += $(TARGET_RECOVERY_UPDATER_LIBS) $(TARGET_RECOVERY_UPDATER_EXTRA_LIBS)
|
||||
LOCAL_STATIC_LIBRARIES += libapplypatch libedify libmtdutils libminzip libz
|
||||
LOCAL_STATIC_LIBRARIES += libflashutils libmmcutils libbmlutils
|
||||
LOCAL_STATIC_LIBRARIES += libmincrypt libbz
|
||||
LOCAL_STATIC_LIBRARIES += libminelf
|
||||
LOCAL_STATIC_LIBRARIES += libcutils libstdc++ libc
|
||||
LOCAL_STATIC_LIBRARIES += libcutils liblog libstdc++ libc
|
||||
LOCAL_STATIC_LIBRARIES += libselinux
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/..
|
||||
|
||||
# Each library in TARGET_RECOVERY_UPDATER_LIBS should have a function
|
||||
|
||||
+30
-8
@@ -78,23 +78,19 @@ Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
char *secontext = NULL;
|
||||
|
||||
if (sehandle) {
|
||||
selabel_lookup(sehandle, &secontext, mount_point, 0755);
|
||||
setfscreatecon(secontext);
|
||||
}
|
||||
#endif
|
||||
|
||||
mkdir(mount_point, 0755);
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
if (secontext) {
|
||||
freecon(secontext);
|
||||
setfscreatecon(NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (strcmp(partition_type, "MTD") == 0) {
|
||||
mtd_scan_partitions();
|
||||
@@ -456,6 +452,26 @@ Value* PackageExtractFileFn(const char* name, State* state,
|
||||
}
|
||||
}
|
||||
|
||||
// Create all parent directories of name, if necessary.
|
||||
static int make_parents(char* name) {
|
||||
char* p;
|
||||
for (p = name + (strlen(name)-1); p > name; --p) {
|
||||
if (*p != '/') continue;
|
||||
*p = '\0';
|
||||
if (make_parents(name) < 0) return -1;
|
||||
int result = mkdir(name, 0700);
|
||||
if (result == 0) fprintf(stderr, "symlink(): created [%s]\n", name);
|
||||
*p = '/';
|
||||
if (result == 0 || errno == EEXIST) {
|
||||
// successfully created or already existed; we're done
|
||||
return 0;
|
||||
} else {
|
||||
fprintf(stderr, "failed to mkdir %s: %s\n", name, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// symlink target src1 src2 ...
|
||||
// unlinks any previously existing src1, src2, etc before creating symlinks.
|
||||
@@ -483,6 +499,11 @@ Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||
++bad;
|
||||
}
|
||||
}
|
||||
if (make_parents(srcs[i])) {
|
||||
fprintf(stderr, "%s: failed to symlink %s to %s: making parents failed\n",
|
||||
name, srcs[i], target);
|
||||
++bad;
|
||||
}
|
||||
if (symlink(target, srcs[i]) < 0) {
|
||||
fprintf(stderr, "%s: failed to symlink %s to %s: %s\n",
|
||||
name, srcs[i], target, strerror(errno));
|
||||
@@ -504,7 +525,8 @@ Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||
|
||||
int min_args = 4 + (recursive ? 1 : 0);
|
||||
if (argc < min_args) {
|
||||
return ErrorAbort(state, "%s() expects %d+ args, got %d", name, argc);
|
||||
return ErrorAbort(state, "%s() expects %d+ args, got %d",
|
||||
name, min_args, argc);
|
||||
}
|
||||
|
||||
char** args = ReadVarArgs(state, argc, argv);
|
||||
@@ -626,7 +648,7 @@ Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||
|
||||
buffer = malloc(st.st_size+1);
|
||||
if (buffer == NULL) {
|
||||
ErrorAbort(state, "%s: failed to alloc %d bytes", name, st.st_size+1);
|
||||
ErrorAbort(state, "%s: failed to alloc %lld bytes", name, st.st_size+1);
|
||||
goto done;
|
||||
}
|
||||
|
||||
@@ -638,7 +660,7 @@ Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||
}
|
||||
|
||||
if (fread(buffer, 1, st.st_size, f) != st.st_size) {
|
||||
ErrorAbort(state, "%s: failed to read %d bytes from %s",
|
||||
ErrorAbort(state, "%s: failed to read %lld bytes from %s",
|
||||
name, st.st_size+1, filename);
|
||||
fclose(f);
|
||||
goto done;
|
||||
@@ -823,7 +845,7 @@ Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||
|
||||
int result = applypatch(source_filename, target_filename,
|
||||
target_sha1, target_size,
|
||||
patchcount, patch_sha_str, patches);
|
||||
patchcount, patch_sha_str, patches, NULL);
|
||||
|
||||
for (i = 0; i < patchcount; ++i) {
|
||||
FreeValue(patches[i]);
|
||||
|
||||
@@ -105,7 +105,6 @@ int main(int argc, char** argv) {
|
||||
return 6;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
struct selinux_opt seopts[] = {
|
||||
{ SELABEL_OPT_PATH, "/file_contexts" }
|
||||
};
|
||||
@@ -116,7 +115,6 @@ int main(int argc, char** argv) {
|
||||
fprintf(stderr, "Warning: No file_contexts\n");
|
||||
fprintf(cmd_pipe, "ui_print Warning: No file_contexts\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
// Evaluate the parsed script.
|
||||
|
||||
|
||||
@@ -20,12 +20,8 @@
|
||||
#include <stdio.h>
|
||||
#include "minzip/Zip.h"
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
#include <selinux/selinux.h>
|
||||
#include <selinux/label.h>
|
||||
#else
|
||||
struct selabel_handle;
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
FILE* cmd_pipe;
|
||||
|
||||
+109
-77
@@ -29,82 +29,6 @@
|
||||
|
||||
#define PUBLIC_KEYS_FILE "/res/keys"
|
||||
|
||||
// Reads a file containing one or more public keys as produced by
|
||||
// DumpPublicKey: this is an RSAPublicKey struct as it would appear
|
||||
// as a C source literal, eg:
|
||||
//
|
||||
// "{64,0xc926ad21,{1795090719,...,-695002876},{-857949815,...,1175080310}}"
|
||||
//
|
||||
// (Note that the braces and commas in this example are actual
|
||||
// characters the parser expects to find in the file; the ellipses
|
||||
// indicate more numbers omitted from this example.)
|
||||
//
|
||||
// The file may contain multiple keys in this format, separated by
|
||||
// commas. The last key must not be followed by a comma.
|
||||
//
|
||||
// Returns NULL if the file failed to parse, or if it contain zero keys.
|
||||
static RSAPublicKey*
|
||||
load_keys(const char* filename, int* numKeys) {
|
||||
RSAPublicKey* out = NULL;
|
||||
*numKeys = 0;
|
||||
|
||||
FILE* f = fopen(filename, "r");
|
||||
if (f == NULL) {
|
||||
printf("opening %s: %s\n", filename, strerror(errno));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
{
|
||||
int i;
|
||||
bool done = false;
|
||||
while (!done) {
|
||||
++*numKeys;
|
||||
out = (RSAPublicKey*)realloc(out, *numKeys * sizeof(RSAPublicKey));
|
||||
RSAPublicKey* key = out + (*numKeys - 1);
|
||||
if (fscanf(f, " { %i , 0x%x , { %u",
|
||||
&(key->len), &(key->n0inv), &(key->n[0])) != 3) {
|
||||
goto exit;
|
||||
}
|
||||
if (key->len != RSANUMWORDS) {
|
||||
printf("key length (%d) does not match expected size\n", key->len);
|
||||
goto exit;
|
||||
}
|
||||
for (i = 1; i < key->len; ++i) {
|
||||
if (fscanf(f, " , %u", &(key->n[i])) != 1) goto exit;
|
||||
}
|
||||
if (fscanf(f, " } , { %u", &(key->rr[0])) != 1) goto exit;
|
||||
for (i = 1; i < key->len; ++i) {
|
||||
if (fscanf(f, " , %u", &(key->rr[i])) != 1) goto exit;
|
||||
}
|
||||
fscanf(f, " } } ");
|
||||
|
||||
// if the line ends in a comma, this file has more keys.
|
||||
switch (fgetc(f)) {
|
||||
case ',':
|
||||
// more keys to come.
|
||||
break;
|
||||
|
||||
case EOF:
|
||||
done = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("unexpected character between keys\n");
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return out;
|
||||
|
||||
exit:
|
||||
if (f) fclose(f);
|
||||
free(out);
|
||||
*numKeys = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Look for an RSA signature embedded in the .ZIP file comment given
|
||||
// the path to the zip. Verify it matches one of the given public
|
||||
// keys.
|
||||
@@ -120,6 +44,7 @@ int verify_file(const char* path) {
|
||||
LOGE("Failed to load keys\n");
|
||||
return VERIFY_FAILURE;
|
||||
}
|
||||
/*
|
||||
LOGI("%d key(s) loaded from %s\n\n RSA Key:\n\n", numKeys, PUBLIC_KEYS_FILE);
|
||||
int rsa_size = sizeof(RSAPublicKey);
|
||||
unsigned char* ptr = (unsigned char*) loadedKeys;
|
||||
@@ -129,7 +54,7 @@ int verify_file(const char* path) {
|
||||
printf("%02x ", valuedees);
|
||||
ptr++;
|
||||
}
|
||||
printf("\n\n");
|
||||
printf("\n\n");*/
|
||||
|
||||
FILE* f = fopen(path, "rb");
|
||||
if (f == NULL) {
|
||||
@@ -274,6 +199,8 @@ int verify_file(const char* path) {
|
||||
LOGI("whole-file signature verified against key %d\n", i);
|
||||
free(eocd);
|
||||
return VERIFY_SUCCESS;
|
||||
} else {
|
||||
LOGI("failed to verify against key %d\n", i);
|
||||
}
|
||||
LOGI("i: %i, eocd_size: %i, RSANUMBYTES: %i, returned %i\n", i, eocd_size, RSANUMBYTES, dees);
|
||||
}
|
||||
@@ -281,3 +208,108 @@ int verify_file(const char* path) {
|
||||
LOGE("failed to verify whole-file signature\n");
|
||||
return VERIFY_FAILURE;
|
||||
}
|
||||
|
||||
// Reads a file containing one or more public keys as produced by
|
||||
// DumpPublicKey: this is an RSAPublicKey struct as it would appear
|
||||
// as a C source literal, eg:
|
||||
//
|
||||
// "{64,0xc926ad21,{1795090719,...,-695002876},{-857949815,...,1175080310}}"
|
||||
//
|
||||
// For key versions newer than the original 2048-bit e=3 keys
|
||||
// supported by Android, the string is preceded by a version
|
||||
// identifier, eg:
|
||||
//
|
||||
// "v2 {64,0xc926ad21,{1795090719,...,-695002876},{-857949815,...,1175080310}}"
|
||||
//
|
||||
// (Note that the braces and commas in this example are actual
|
||||
// characters the parser expects to find in the file; the ellipses
|
||||
// indicate more numbers omitted from this example.)
|
||||
//
|
||||
// The file may contain multiple keys in this format, separated by
|
||||
// commas. The last key must not be followed by a comma.
|
||||
//
|
||||
// Returns NULL if the file failed to parse, or if it contain zero keys.
|
||||
RSAPublicKey*
|
||||
load_keys(const char* filename, int* numKeys) {
|
||||
RSAPublicKey* out = NULL;
|
||||
*numKeys = 0;
|
||||
|
||||
FILE* f = fopen(filename, "r");
|
||||
if (f == NULL) {
|
||||
LOGE("opening %s: %s\n", filename, strerror(errno));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
{
|
||||
int i;
|
||||
bool done = false;
|
||||
while (!done) {
|
||||
++*numKeys;
|
||||
out = (RSAPublicKey*)realloc(out, *numKeys * sizeof(RSAPublicKey));
|
||||
RSAPublicKey* key = out + (*numKeys - 1);
|
||||
|
||||
#ifdef HAS_EXPONENT
|
||||
char start_char;
|
||||
if (fscanf(f, " %c", &start_char) != 1) goto exit;
|
||||
if (start_char == '{') {
|
||||
// a version 1 key has no version specifier.
|
||||
key->exponent = 3;
|
||||
} else if (start_char == 'v') {
|
||||
int version;
|
||||
if (fscanf(f, "%d {", &version) != 1) goto exit;
|
||||
if (version == 2) {
|
||||
key->exponent = 65537;
|
||||
} else {
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (fscanf(f, " %i , 0x%x , { %u",
|
||||
#else
|
||||
if (fscanf(f, " { %i , 0x%x , { %u",
|
||||
#endif
|
||||
&(key->len), &(key->n0inv), &(key->n[0])) != 3) {
|
||||
goto exit;
|
||||
}
|
||||
if (key->len != RSANUMWORDS) {
|
||||
LOGE("key length (%d) does not match expected size\n", key->len);
|
||||
goto exit;
|
||||
}
|
||||
for (i = 1; i < key->len; ++i) {
|
||||
if (fscanf(f, " , %u", &(key->n[i])) != 1) goto exit;
|
||||
}
|
||||
if (fscanf(f, " } , { %u", &(key->rr[0])) != 1) goto exit;
|
||||
for (i = 1; i < key->len; ++i) {
|
||||
if (fscanf(f, " , %u", &(key->rr[i])) != 1) goto exit;
|
||||
}
|
||||
fscanf(f, " } } ");
|
||||
|
||||
// if the line ends in a comma, this file has more keys.
|
||||
switch (fgetc(f)) {
|
||||
case ',':
|
||||
// more keys to come.
|
||||
break;
|
||||
|
||||
case EOF:
|
||||
done = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOGE("unexpected character between keys\n");
|
||||
goto exit;
|
||||
}
|
||||
#ifdef HAS_EXPONENT
|
||||
LOGI("read key e=%d\n", key->exponent);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return out;
|
||||
|
||||
exit:
|
||||
if (f) fclose(f);
|
||||
free(out);
|
||||
*numKeys = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@ static const float VERIFICATION_PROGRESS_FRACTION = 0.25;
|
||||
*/
|
||||
int verify_file(const char* path);
|
||||
|
||||
RSAPublicKey* load_keys(const char* filename, int* numKeys);
|
||||
|
||||
#define VERIFY_SUCCESS 0
|
||||
#define VERIFY_FAILURE 1
|
||||
|
||||
|
||||
+64
-8
@@ -18,6 +18,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "verifier.h"
|
||||
#include "ui.h"
|
||||
|
||||
@@ -56,7 +57,45 @@ RSAPublicKey test_key =
|
||||
9135381, 1625809335, -1490225159, -1342673351,
|
||||
1117190829, -57654514, 1825108855, -1281819325,
|
||||
1111251351, -1726129724, 1684324211, -1773988491,
|
||||
367251975, 810756730, -1941182952, 1175080310 }
|
||||
367251975, 810756730, -1941182952, 1175080310 },
|
||||
3
|
||||
};
|
||||
|
||||
RSAPublicKey test_f4_key =
|
||||
{ 64, 0xc9bd1f21,
|
||||
{ 293133087u, 3210546773u, 865313125u, 250921607u,
|
||||
3158780490u, 943703457u, 1242806226u, 2986289859u,
|
||||
2942743769u, 2457906415u, 2719374299u, 1783459420u,
|
||||
149579627u, 3081531591u, 3440738617u, 2788543742u,
|
||||
2758457512u, 1146764939u, 3699497403u, 2446203424u,
|
||||
1744968926u, 1159130537u, 2370028300u, 3978231572u,
|
||||
3392699980u, 1487782451u, 1180150567u, 2841334302u,
|
||||
3753960204u, 961373345u, 3333628321u, 748825784u,
|
||||
2978557276u, 1566596926u, 1613056060u, 2600292737u,
|
||||
1847226629u, 50398611u, 1890374404u, 2878700735u,
|
||||
2286201787u, 1401186359u, 619285059u, 731930817u,
|
||||
2340993166u, 1156490245u, 2992241729u, 151498140u,
|
||||
318782170u, 3480838990u, 2100383433u, 4223552555u,
|
||||
3628927011u, 4247846280u, 1759029513u, 4215632601u,
|
||||
2719154626u, 3490334597u, 1751299340u, 3487864726u,
|
||||
3668753795u, 4217506054u, 3748782284u, 3150295088u },
|
||||
{ 1772626313u, 445326068u, 3477676155u, 1758201194u,
|
||||
2986784722u, 491035581u, 3922936562u, 702212696u,
|
||||
2979856666u, 3324974564u, 2488428922u, 3056318590u,
|
||||
1626954946u, 664714029u, 398585816u, 3964097931u,
|
||||
3356701905u, 2298377729u, 2040082097u, 3025491477u,
|
||||
539143308u, 3348777868u, 2995302452u, 3602465520u,
|
||||
212480763u, 2691021393u, 1307177300u, 704008044u,
|
||||
2031136606u, 1054106474u, 3838318865u, 2441343869u,
|
||||
1477566916u, 700949900u, 2534790355u, 3353533667u,
|
||||
336163563u, 4106790558u, 2701448228u, 1571536379u,
|
||||
1103842411u, 3623110423u, 1635278839u, 1577828979u,
|
||||
910322800u, 715583630u, 138128831u, 1017877531u,
|
||||
2289162787u, 447994798u, 1897243165u, 4121561445u,
|
||||
4150719842u, 2131821093u, 2262395396u, 3305771534u,
|
||||
980753571u, 3256525190u, 3128121808u, 1072869975u,
|
||||
3507939515u, 4229109952u, 118381341u, 2209831334u },
|
||||
65537
|
||||
};
|
||||
|
||||
RecoveryUI* ui = NULL;
|
||||
@@ -75,13 +114,10 @@ class FakeUI : public RecoveryUI {
|
||||
bool IsTextVisible() { return false; }
|
||||
bool WasTextEverVisible() { return false; }
|
||||
void Print(const char* fmt, ...) {
|
||||
char buf[256];
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buf, 256, fmt, ap);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
fputs(buf, stderr);
|
||||
}
|
||||
|
||||
void StartMenu(const char* const * headers, const char* const * items,
|
||||
@@ -90,15 +126,35 @@ class FakeUI : public RecoveryUI {
|
||||
void EndMenu() { }
|
||||
};
|
||||
|
||||
void
|
||||
ui_print(const char* format, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
vfprintf(stdout, format, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: %s <package>\n", argv[0]);
|
||||
if (argc < 2 || argc > 4) {
|
||||
fprintf(stderr, "Usage: %s [-f4 | -file <keys>] <package>\n", argv[0]);
|
||||
return 2;
|
||||
}
|
||||
|
||||
RSAPublicKey* key = &test_key;
|
||||
int num_keys = 1;
|
||||
++argv;
|
||||
if (strcmp(argv[0], "-f4") == 0) {
|
||||
++argv;
|
||||
key = &test_f4_key;
|
||||
} else if (strcmp(argv[0], "-file") == 0) {
|
||||
++argv;
|
||||
key = load_keys(argv[0], &num_keys);
|
||||
++argv;
|
||||
}
|
||||
|
||||
ui = new FakeUI();
|
||||
|
||||
int result = verify_file(argv[1]);
|
||||
int result = verify_file(*argv, key, num_keys);
|
||||
if (result == VERIFY_SUCCESS) {
|
||||
printf("SUCCESS\n");
|
||||
return 0;
|
||||
|
||||
@@ -73,9 +73,24 @@ expect_fail() {
|
||||
run_command $WORK_DIR/verifier_test $WORK_DIR/package.zip && fail
|
||||
}
|
||||
|
||||
expect_succeed_f4() {
|
||||
testname "$1 (should succeed)"
|
||||
$ADB push $DATA_DIR/$1 $WORK_DIR/package.zip
|
||||
run_command $WORK_DIR/verifier_test -f4 $WORK_DIR/package.zip || fail
|
||||
}
|
||||
|
||||
expect_fail_f4() {
|
||||
testname "$1 (should fail)"
|
||||
$ADB push $DATA_DIR/$1 $WORK_DIR/package.zip
|
||||
run_command $WORK_DIR/verifier_test -f4 $WORK_DIR/package.zip && fail
|
||||
}
|
||||
|
||||
expect_fail unsigned.zip
|
||||
expect_fail jarsigned.zip
|
||||
expect_succeed otasigned.zip
|
||||
expect_fail_f4 otasigned.zip
|
||||
expect_succeed_f4 otasigned_f4.zip
|
||||
expect_fail otasigned_f4.zip
|
||||
expect_fail random.zip
|
||||
expect_fail fake-eocd.zip
|
||||
expect_fail alter-metadata.zip
|
||||
|
||||
Reference in New Issue
Block a user