Update to 7.0

Change-Id: I621cc47352f7ac552d9602485825ae3a6f9ae516
This commit is contained in:
Ethan Yonker
2016-08-24 15:32:18 -05:00
217 changed files with 9937 additions and 4536 deletions
+59 -49
View File
@@ -68,14 +68,17 @@ LOCAL_MODULE := recovery
#LOCAL_FORCE_STATIC_EXECUTABLE := true
#ifeq ($(TARGET_USERIMAGES_USE_F2FS),true)
#ifeq ($(HOST_OS),linux)
#LOCAL_REQUIRED_MODULES := mkfs.f2fs
#endif
#endif
RECOVERY_API_VERSION := 3
RECOVERY_FSTAB_VERSION := 2
LOCAL_CFLAGS += -DRECOVERY_API_VERSION=$(RECOVERY_API_VERSION)
LOCAL_CFLAGS += -Wno-unused-parameter
LOCAL_CLANG := true
#LOCAL_STATIC_LIBRARIES := \
# libext4_utils_static \
@@ -103,7 +106,7 @@ LOCAL_C_INCLUDES += \
system/core/libsparse \
external/zlib
LOCAL_C_INCLUDES += bionic external/openssl/include $(LOCAL_PATH)/libmincrypt/includes
LOCAL_C_INCLUDES += bionic external/openssl/include
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 23; echo $$?),0)
LOCAL_C_INCLUDES += external/stlport/stlport
endif
@@ -112,8 +115,8 @@ LOCAL_STATIC_LIBRARIES :=
LOCAL_SHARED_LIBRARIES :=
LOCAL_STATIC_LIBRARIES += libguitwrp
LOCAL_SHARED_LIBRARIES += libz libc libcutils libstdc++ libtar libblkid libminuitwrp libminadbd libmtdutils libminzip libaosprecovery libtwadbbu
LOCAL_SHARED_LIBRARIES += libcrecovery
LOCAL_SHARED_LIBRARIES += libaosprecovery libz libc libcutils libstdc++ libtar libblkid libminuitwrp libminadbd libmtdutils libminzip libtwadbbu
LOCAL_SHARED_LIBRARIES += libcrecovery libbase libcrypto
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 23; echo $$?),0)
LOCAL_SHARED_LIBRARIES += libstlport
@@ -132,6 +135,7 @@ ifeq ($(TW_OEM_BUILD),true)
TW_EXCLUDE_SUPERSU := true
TW_EXCLUDE_MTP := true
endif
ifeq ($(TARGET_USERIMAGES_USE_EXT4), true)
LOCAL_CFLAGS += -DUSE_EXT4
LOCAL_C_INCLUDES += system/extras/ext4_utils
@@ -336,7 +340,6 @@ LOCAL_ADDITIONAL_DEPENDENCIES := \
mke2fs.conf \
pigz \
teamwin \
toolbox_symlinks \
twrp \
unpigz_symlink \
fsck.fat \
@@ -381,7 +384,7 @@ ifeq ($(BOARD_HAS_NO_REAL_SDCARD),)
endif
endif
ifneq ($(TW_EXCLUDE_ENCRYPTED_BACKUPS), true)
LOCAL_ADDITIONAL_DEPENDENCIES += openaes ../openaes/LICENSE
LOCAL_ADDITIONAL_DEPENDENCIES += openaes openaes_license
endif
ifeq ($(TW_INCLUDE_DUMLOCK), true)
LOCAL_ADDITIONAL_DEPENDENCIES += \
@@ -448,6 +451,10 @@ ifeq ($(shell test $(CM_PLATFORM_SDK_VERSION) -ge 3; echo $$?),0)
endif
endif
ifeq ($(BOARD_CACHEIMAGE_PARTITION_SIZE),)
LOCAL_REQUIRED_MODULES := recovery-persist recovery-refresh
endif
include $(BUILD_EXECUTABLE)
ifneq ($(TW_USE_TOOLBOX), true)
@@ -494,56 +501,47 @@ include $(BUILD_PHONY_PACKAGE)
RECOVERY_BUSYBOX_SYMLINKS :=
endif # !TW_USE_TOOLBOX
# All the APIs for testing
# recovery-persist (system partition dynamic executable run after /data mounts)
# ===============================
include $(CLEAR_VARS)
LOCAL_MODULE := libverifier
LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := \
asn1_decoder.cpp
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := fuse_sideload.c
LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter
LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := libfusesideload
LOCAL_C_INCLUDES := $(LOCAL_PATH)/libmincrypt/includes
LOCAL_SHARED_LIBRARIES := libcutils libc libmincrypttwrp
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := verifier_test
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_TAGS := tests
LOCAL_C_INCLUDES := $(LOCAL_PATH)/libmincrypt/includes
LOCAL_CFLAGS += -DNO_RECOVERY_MOUNT
LOCAL_CFLAGS += -Wno-unused-parameter
LOCAL_SRC_FILES := \
verifier_test.cpp \
asn1_decoder.cpp \
verifier.cpp \
ui.cpp
LOCAL_STATIC_LIBRARIES := \
libmincrypttwrp \
libminui \
libminzip \
libcutils \
libstdc++ \
libc
LOCAL_SRC_FILES := recovery-persist.cpp
LOCAL_MODULE := recovery-persist
LOCAL_SHARED_LIBRARIES := liblog libbase
LOCAL_CFLAGS := -Werror
LOCAL_INIT_RC := recovery-persist.rc
include $(BUILD_EXECUTABLE)
# recovery-refresh (system partition dynamic executable run at init)
# ===============================
include $(CLEAR_VARS)
LOCAL_SRC_FILES := recovery-refresh.cpp
LOCAL_MODULE := recovery-refresh
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_CFLAGS := -Werror
LOCAL_INIT_RC := recovery-refresh.rc
include $(BUILD_EXECUTABLE)
# shared libfusesideload
# ===============================
include $(CLEAR_VARS)
LOCAL_SRC_FILES := fuse_sideload.cpp
LOCAL_CLANG := true
LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter
LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := libfusesideload
LOCAL_SHARED_LIBRARIES := libcutils libc libcrypto
include $(BUILD_SHARED_LIBRARY)
# shared libaosprecovery for Apache code
# ===============================
include $(CLEAR_VARS)
LOCAL_MODULE := libaosprecovery
LOCAL_MODULE_TAGS := eng optional
LOCAL_C_INCLUDES := $(LOCAL_PATH)/libmincrypt/includes
LOCAL_SRC_FILES := adb_install.cpp asn1_decoder.cpp bootloader.cpp legacy_property_service.c verifier.cpp set_metadata.c tw_atomic.cpp
LOCAL_SHARED_LIBRARIES += libc liblog libcutils libmtdutils libfusesideload libmincrypttwrp libselinux
LOCAL_SHARED_LIBRARIES += libc liblog libcutils libmtdutils libfusesideload libselinux libcrypto
ifneq ($(BOARD_RECOVERY_BLDRMSG_OFFSET),)
LOCAL_CFLAGS += -DBOARD_RECOVERY_BLDRMSG_OFFSET=$(BOARD_RECOVERY_BLDRMSG_OFFSET)
@@ -551,11 +549,25 @@ endif
include $(BUILD_SHARED_LIBRARY)
# All the APIs for testing
include $(CLEAR_VARS)
LOCAL_CLANG := true
LOCAL_MODULE := libverifier
LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := \
asn1_decoder.cpp \
verifier.cpp \
ui.cpp
LOCAL_STATIC_LIBRARIES := libcrypto
include $(BUILD_STATIC_LIBRARY)
commands_recovery_local_path := $(LOCAL_PATH)
include $(LOCAL_PATH)/tests/Android.mk \
$(LOCAL_PATH)/tools/Android.mk \
$(LOCAL_PATH)/edify/Android.mk \
$(LOCAL_PATH)/otafault/Android.mk \
$(LOCAL_PATH)/updater/Android.mk \
$(LOCAL_PATH)/update_verifier/Android.mk \
$(LOCAL_PATH)/applypatch/Android.mk
ifeq ($(wildcard system/core/uncrypt/Android.mk),)
@@ -586,8 +598,6 @@ include $(commands_recovery_local_path)/injecttwrp/Android.mk \
$(commands_recovery_local_path)/libblkid/Android.mk \
$(commands_recovery_local_path)/minuitwrp/Android.mk \
$(commands_recovery_local_path)/openaes/Android.mk \
$(commands_recovery_local_path)/toolbox/Android.mk \
$(commands_recovery_local_path)/libmincrypt/Android.mk \
$(commands_recovery_local_path)/twrpTarMain/Android.mk \
$(commands_recovery_local_path)/mtp/Android.mk \
$(commands_recovery_local_path)/minzip/Android.mk \
+2 -1
View File
@@ -31,6 +31,7 @@
#include "adb_install.h"
#include "minadbd/fuse_adb_provider.h"
#include "fuse_sideload.h"
#include "verifier.h"
static RecoveryUI* ui = NULL;
@@ -106,7 +107,7 @@ apply_from_adb(const char* install_file, pid_t* child_pid) {
// FUSE_SIDELOAD_HOST_PATHNAME will start to exist once the host
// connects and starts serving a package. Poll for its
// appearance. (Note that inotify doesn't work with FUSE.)
int result;
int result = INSTALL_ERROR;
int status;
bool waited = false;
struct stat st;
+1 -1
View File
@@ -5,7 +5,7 @@ LOCAL_SRC_FILES:= \
twrpback.cpp \
../twrpDigest.cpp \
../digest/md5.c
LOCAL_SHARED_LIBRARIES += libstdc++ libz
LOCAL_SHARED_LIBRARIES += libstdc++ libz libselinux
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 23; echo $$?),0)
LOCAL_C_INCLUDES += external/stlport/stlport
LOCAL_SHARED_LIBRARIES += libstlport
+32 -23
View File
@@ -13,6 +13,7 @@
# limitations under the License.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
BOARD_RECOVERY_DEFINES := BOARD_BML_BOOT BOARD_BML_RECOVERY
@@ -23,47 +24,55 @@ $(foreach board_define,$(BOARD_RECOVERY_DEFINES), \
) \
)
LOCAL_SRC_FILES := applypatch.c bspatch.c freecache.c imgpatch.c utils.c
LOCAL_MODULE := libapplypatch
LOCAL_MODULE_TAGS := eng
LOCAL_C_INCLUDES += \
external/bzip2 \
external/zlib \
$(commands_recovery_local_path)
LOCAL_STATIC_LIBRARIES += libmtdutils libmincrypttwrp libbz libz
LOCAL_CLANG := true
LOCAL_SRC_FILES := applypatch.cpp bspatch.cpp freecache.cpp imgpatch.cpp utils.cpp
LOCAL_MODULE := libapplypatch
LOCAL_MODULE_TAGS := eng
LOCAL_C_INCLUDES += bootable/recovery
LOCAL_STATIC_LIBRARIES += libbase libotafault libmtdutils libmincrypttwrp libbz libz
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := main.c
ifeq ($(HOST_OS),linux)
include $(CLEAR_VARS)
LOCAL_CLANG := true
LOCAL_SRC_FILES := bspatch.cpp imgpatch.cpp utils.cpp
LOCAL_MODULE := libimgpatch
LOCAL_C_INCLUDES += bootable/recovery
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_STATIC_LIBRARIES += libcrypto_static libbz libz
include $(BUILD_HOST_STATIC_LIBRARY)
endif # HOST_OS == linux
include $(CLEAR_VARS)
LOCAL_CLANG := true
LOCAL_SRC_FILES := main.cpp
LOCAL_MODULE := applypatch
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES += $(commands_recovery_local_path)
LOCAL_STATIC_LIBRARIES += libapplypatch libmtdutils libmincrypttwrp libbz
LOCAL_SHARED_LIBRARIES += libz libcutils libstdc++ libc
LOCAL_C_INCLUDES += bootable/recovery
LOCAL_STATIC_LIBRARIES += libapplypatch libbase libotafault libmtdutils libcrypto_static libbz \
libedify \
LOCAL_SHARED_LIBRARIES += libz libcutils libc
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := main.c
LOCAL_MODULE := applypatch_static
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_TAGS := optional eng
LOCAL_C_INCLUDES += $(commands_recovery_local_path)
LOCAL_STATIC_LIBRARIES += libapplypatch libmtdutils libmincrypttwrp libbz
LOCAL_STATIC_LIBRARIES += libz libcutils libstdc++ libc
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := imgdiff.c utils.c bsdiff.c
LOCAL_CLANG := true
LOCAL_SRC_FILES := imgdiff.cpp utils.cpp bsdiff.cpp
LOCAL_MODULE := imgdiff
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_C_INCLUDES += external/zlib external/bzip2
LOCAL_STATIC_LIBRARIES += libz libbz
LOCAL_MODULE_TAGS := eng
include $(BUILD_HOST_EXECUTABLE)
File diff suppressed because it is too large Load Diff
+14 -15
View File
@@ -18,20 +18,17 @@
#define _APPLYPATCH_H
#include <sys/stat.h>
#include "mincrypt/sha.h"
#include <vector>
#include "openssl/sha.h"
#include "edify/expr.h"
typedef struct _Patch {
uint8_t sha1[SHA_DIGEST_SIZE];
const char* patch_filename;
} Patch;
typedef struct _FileContents {
uint8_t sha1[SHA_DIGEST_SIZE];
unsigned char* data;
ssize_t size;
struct FileContents {
uint8_t sha1[SHA_DIGEST_LENGTH];
std::vector<unsigned char> data;
struct stat st;
} FileContents;
};
// When there isn't enough room on the target filesystem to hold the
// patched version of the file, we copy the original here and delete
@@ -48,6 +45,8 @@ size_t FreeSpaceForFile(const char* filename);
int CacheSizeCheck(size_t bytes);
int ParseSha1(const char* str, uint8_t* digest);
int applypatch_flash(const char* source_filename, const char* target_filename,
const char* target_sha1_str, size_t target_size);
int applypatch(const char* source_filename,
const char* target_filename,
const char* target_sha1_str,
@@ -66,22 +65,22 @@ void FreeFileContents(FileContents* file);
int FindMatchingPatch(uint8_t* sha1, char* const * const patch_sha1_str,
int num_patches);
// bsdiff.c
// bsdiff.cpp
void ShowBSDiffLicense();
int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size,
const Value* patch, ssize_t patch_offset,
SinkFn sink, void* token, SHA_CTX* ctx);
int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size,
const Value* patch, ssize_t patch_offset,
unsigned char** new_data, ssize_t* new_size);
std::vector<unsigned char>* new_data);
// imgpatch.c
// imgpatch.cpp
int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
const Value* patch,
SinkFn sink, void* token, SHA_CTX* ctx,
const Value* bonus_data);
// freecache.c
// freecache.cpp
int MakeFreeSpaceOnCache(size_t bytes_needed);
#endif
+24 -24
View File
@@ -156,24 +156,24 @@ static void qsufsort(off_t *I,off_t *V,u_char *old,off_t oldsize)
for(i=0;i<oldsize+1;i++) I[V[i]]=i;
}
static off_t matchlen(u_char *old,off_t oldsize,u_char *new,off_t newsize)
static off_t matchlen(u_char *olddata,off_t oldsize,u_char *newdata,off_t newsize)
{
off_t i;
for(i=0;(i<oldsize)&&(i<newsize);i++)
if(old[i]!=new[i]) break;
if(olddata[i]!=newdata[i]) break;
return i;
}
static off_t search(off_t *I,u_char *old,off_t oldsize,
u_char *new,off_t newsize,off_t st,off_t en,off_t *pos)
u_char *newdata,off_t newsize,off_t st,off_t en,off_t *pos)
{
off_t x,y;
if(en-st<2) {
x=matchlen(old+I[st],oldsize-I[st],new,newsize);
y=matchlen(old+I[en],oldsize-I[en],new,newsize);
x=matchlen(old+I[st],oldsize-I[st],newdata,newsize);
y=matchlen(old+I[en],oldsize-I[en],newdata,newsize);
if(x>y) {
*pos=I[st];
@@ -185,10 +185,10 @@ static off_t search(off_t *I,u_char *old,off_t oldsize,
};
x=st+(en-st)/2;
if(memcmp(old+I[x],new,MIN(oldsize-I[x],newsize))<0) {
return search(I,old,oldsize,new,newsize,x,en,pos);
if(memcmp(old+I[x],newdata,MIN(oldsize-I[x],newsize))<0) {
return search(I,old,oldsize,newdata,newsize,x,en,pos);
} else {
return search(I,old,oldsize,new,newsize,st,x,pos);
return search(I,old,oldsize,newdata,newsize,st,x,pos);
};
}
@@ -212,8 +212,8 @@ static void offtout(off_t x,u_char *buf)
// This is main() from bsdiff.c, with the following changes:
//
// - old, oldsize, new, newsize are arguments; we don't load this
// data from files. old and new are owned by the caller; we
// - old, oldsize, newdata, newsize are arguments; we don't load this
// data from files. old and newdata are owned by the caller; we
// don't free them at the end.
//
// - the "I" block of memory is owned by the caller, who passes a
@@ -221,7 +221,7 @@ static void offtout(off_t x,u_char *buf)
// bsdiff() multiple times with the same 'old' data, we only do
// the qsufsort() step the first time.
//
int bsdiff(u_char* old, off_t oldsize, off_t** IP, u_char* new, off_t newsize,
int bsdiff(u_char* old, off_t oldsize, off_t** IP, u_char* newdata, off_t newsize,
const char* patch_filename)
{
int fd;
@@ -242,15 +242,15 @@ int bsdiff(u_char* old, off_t oldsize, off_t** IP, u_char* new, off_t newsize,
if (*IP == NULL) {
off_t* V;
*IP = malloc((oldsize+1) * sizeof(off_t));
V = malloc((oldsize+1) * sizeof(off_t));
*IP = reinterpret_cast<off_t*>(malloc((oldsize+1) * sizeof(off_t)));
V = reinterpret_cast<off_t*>(malloc((oldsize+1) * sizeof(off_t)));
qsufsort(*IP, V, old, oldsize);
free(V);
}
I = *IP;
if(((db=malloc(newsize+1))==NULL) ||
((eb=malloc(newsize+1))==NULL)) err(1,NULL);
if(((db=reinterpret_cast<u_char*>(malloc(newsize+1)))==NULL) ||
((eb=reinterpret_cast<u_char*>(malloc(newsize+1)))==NULL)) err(1,NULL);
dblen=0;
eblen=0;
@@ -284,26 +284,26 @@ int bsdiff(u_char* old, off_t oldsize, off_t** IP, u_char* new, off_t newsize,
oldscore=0;
for(scsc=scan+=len;scan<newsize;scan++) {
len=search(I,old,oldsize,new+scan,newsize-scan,
len=search(I,old,oldsize,newdata+scan,newsize-scan,
0,oldsize,&pos);
for(;scsc<scan+len;scsc++)
if((scsc+lastoffset<oldsize) &&
(old[scsc+lastoffset] == new[scsc]))
(old[scsc+lastoffset] == newdata[scsc]))
oldscore++;
if(((len==oldscore) && (len!=0)) ||
(len>oldscore+8)) break;
if((scan+lastoffset<oldsize) &&
(old[scan+lastoffset] == new[scan]))
(old[scan+lastoffset] == newdata[scan]))
oldscore--;
};
if((len!=oldscore) || (scan==newsize)) {
s=0;Sf=0;lenf=0;
for(i=0;(lastscan+i<scan)&&(lastpos+i<oldsize);) {
if(old[lastpos+i]==new[lastscan+i]) s++;
if(old[lastpos+i]==newdata[lastscan+i]) s++;
i++;
if(s*2-i>Sf*2-lenf) { Sf=s; lenf=i; };
};
@@ -312,7 +312,7 @@ int bsdiff(u_char* old, off_t oldsize, off_t** IP, u_char* new, off_t newsize,
if(scan<newsize) {
s=0;Sb=0;
for(i=1;(scan>=lastscan+i)&&(pos>=i);i++) {
if(old[pos-i]==new[scan-i]) s++;
if(old[pos-i]==newdata[scan-i]) s++;
if(s*2-i>Sb*2-lenb) { Sb=s; lenb=i; };
};
};
@@ -321,9 +321,9 @@ int bsdiff(u_char* old, off_t oldsize, off_t** IP, u_char* new, off_t newsize,
overlap=(lastscan+lenf)-(scan-lenb);
s=0;Ss=0;lens=0;
for(i=0;i<overlap;i++) {
if(new[lastscan+lenf-overlap+i]==
if(newdata[lastscan+lenf-overlap+i]==
old[lastpos+lenf-overlap+i]) s++;
if(new[scan-lenb+i]==
if(newdata[scan-lenb+i]==
old[pos-lenb+i]) s--;
if(s>Ss) { Ss=s; lens=i+1; };
};
@@ -333,9 +333,9 @@ int bsdiff(u_char* old, off_t oldsize, off_t** IP, u_char* new, off_t newsize,
};
for(i=0;i<lenf;i++)
db[dblen+i]=new[lastscan+i]-old[lastpos+i];
db[dblen+i]=newdata[lastscan+i]-old[lastpos+i];
for(i=0;i<(scan-lenb)-(lastscan+lenf);i++)
eb[eblen+i]=new[lastscan+lenf+i];
eb[eblen+i]=newdata[lastscan+lenf+i];
dblen+=lenf;
eblen+=(scan-lenb)-(lastscan+lenf);
+16 -25
View File
@@ -22,14 +22,14 @@
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <malloc.h>
#include <unistd.h>
#include <string.h>
#include <bzlib.h>
#include "mincrypt/sha.h"
#include "openssl/sha.h"
#include "applypatch.h"
void ShowBSDiffLicense() {
@@ -102,26 +102,22 @@ int ApplyBSDiffPatch(const unsigned char* old_data, ssize_t old_size,
const Value* patch, ssize_t patch_offset,
SinkFn sink, void* token, SHA_CTX* ctx) {
unsigned char* new_data;
ssize_t new_size;
if (ApplyBSDiffPatchMem(old_data, old_size, patch, patch_offset,
&new_data, &new_size) != 0) {
std::vector<unsigned char> new_data;
if (ApplyBSDiffPatchMem(old_data, old_size, patch, patch_offset, &new_data) != 0) {
return -1;
}
if (sink(new_data, new_size, token) < new_size) {
if (sink(new_data.data(), new_data.size(), token) < static_cast<ssize_t>(new_data.size())) {
printf("short write of output: %d (%s)\n", errno, strerror(errno));
return 1;
}
if (ctx) SHA_update(ctx, new_data, new_size);
free(new_data);
if (ctx) SHA1_Update(ctx, new_data.data(), new_data.size());
return 0;
}
int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size,
const Value* patch, ssize_t patch_offset,
unsigned char** new_data, ssize_t* new_size) {
std::vector<unsigned char>* new_data) {
// Patch data format:
// 0 8 "BSDIFF40"
// 8 8 X
@@ -140,12 +136,12 @@ int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size,
return 1;
}
ssize_t ctrl_len, data_len;
ssize_t ctrl_len, data_len, new_size;
ctrl_len = offtin(header+8);
data_len = offtin(header+16);
*new_size = offtin(header+24);
new_size = offtin(header+24);
if (ctrl_len < 0 || data_len < 0 || *new_size < 0) {
if (ctrl_len < 0 || data_len < 0 || new_size < 0) {
printf("corrupt patch file header (data lengths)\n");
return 1;
}
@@ -182,19 +178,14 @@ int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size,
printf("failed to bzinit extra stream (%d)\n", bzerr);
}
*new_data = malloc(*new_size);
if (*new_data == NULL) {
printf("failed to allocate %ld bytes of memory for output file\n",
(long)*new_size);
return 1;
}
new_data->resize(new_size);
off_t oldpos = 0, newpos = 0;
off_t ctrl[3];
off_t len_read;
int i;
unsigned char buf[24];
while (newpos < *new_size) {
while (newpos < new_size) {
// Read control data
if (FillBuffer(buf, 24, &cstream) != 0) {
printf("error while reading control stream\n");
@@ -210,13 +201,13 @@ int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size,
}
// Sanity check
if (newpos + ctrl[0] > *new_size) {
if (newpos + ctrl[0] > new_size) {
printf("corrupt patch (new file overrun)\n");
return 1;
}
// Read diff string
if (FillBuffer(*new_data + newpos, ctrl[0], &dstream) != 0) {
if (FillBuffer(new_data->data() + newpos, ctrl[0], &dstream) != 0) {
printf("error while reading diff stream\n");
return 1;
}
@@ -233,13 +224,13 @@ int ApplyBSDiffPatchMem(const unsigned char* old_data, ssize_t old_size,
oldpos += ctrl[0];
// Sanity check
if (newpos + ctrl[1] > *new_size) {
if (newpos + ctrl[1] > new_size) {
printf("corrupt patch (new file overrun)\n");
return 1;
}
// Read extra string
if (FillBuffer(*new_data + newpos, ctrl[1], &estream) != 0) {
if (FillBuffer(new_data->data() + newpos, ctrl[1], &estream) != 0) {
printf("error while reading extra stream\n");
return 1;
}
-172
View File
@@ -1,172 +0,0 @@
#include <errno.h>
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/statfs.h>
#include <unistd.h>
#include <dirent.h>
#include <ctype.h>
#include "applypatch.h"
static int EliminateOpenFiles(char** files, int file_count) {
DIR* d;
struct dirent* de;
d = opendir("/proc");
if (d == NULL) {
printf("error opening /proc: %s\n", strerror(errno));
return -1;
}
while ((de = readdir(d)) != 0) {
int i;
for (i = 0; de->d_name[i] != '\0' && isdigit(de->d_name[i]); ++i);
if (de->d_name[i]) continue;
// de->d_name[i] is numeric
char path[FILENAME_MAX];
strcpy(path, "/proc/");
strcat(path, de->d_name);
strcat(path, "/fd/");
DIR* fdd;
struct dirent* fdde;
fdd = opendir(path);
if (fdd == NULL) {
printf("error opening %s: %s\n", path, strerror(errno));
continue;
}
while ((fdde = readdir(fdd)) != 0) {
char fd_path[FILENAME_MAX];
char link[FILENAME_MAX];
strcpy(fd_path, path);
strcat(fd_path, fdde->d_name);
int count;
count = readlink(fd_path, link, sizeof(link)-1);
if (count >= 0) {
link[count] = '\0';
// This is inefficient, but it should only matter if there are
// lots of files in /cache, and lots of them are open (neither
// of which should be true, especially in recovery).
if (strncmp(link, "/cache/", 7) == 0) {
int j;
for (j = 0; j < file_count; ++j) {
if (files[j] && strcmp(files[j], link) == 0) {
printf("%s is open by %s\n", link, de->d_name);
free(files[j]);
files[j] = NULL;
}
}
}
}
}
closedir(fdd);
}
closedir(d);
return 0;
}
int FindExpendableFiles(char*** names, int* entries) {
DIR* d;
struct dirent* de;
int size = 32;
*entries = 0;
*names = malloc(size * sizeof(char*));
char path[FILENAME_MAX];
// We're allowed to delete unopened regular files in any of these
// directories.
const char* dirs[2] = {"/cache", "/cache/recovery/otatest"};
unsigned int i;
for (i = 0; i < sizeof(dirs)/sizeof(dirs[0]); ++i) {
d = opendir(dirs[i]);
if (d == NULL) {
printf("error opening %s: %s\n", dirs[i], strerror(errno));
continue;
}
// Look for regular files in the directory (not in any subdirectories).
while ((de = readdir(d)) != 0) {
strcpy(path, dirs[i]);
strcat(path, "/");
strcat(path, de->d_name);
// We can't delete CACHE_TEMP_SOURCE; if it's there we might have
// restarted during installation and could be depending on it to
// be there.
if (strcmp(path, CACHE_TEMP_SOURCE) == 0) continue;
struct stat st;
if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) {
if (*entries >= size) {
size *= 2;
*names = realloc(*names, size * sizeof(char*));
}
(*names)[(*entries)++] = strdup(path);
}
}
closedir(d);
}
printf("%d regular files in deletable directories\n", *entries);
if (EliminateOpenFiles(*names, *entries) < 0) {
return -1;
}
return 0;
}
int MakeFreeSpaceOnCache(size_t bytes_needed) {
size_t free_now = FreeSpaceForFile("/cache");
printf("%ld bytes free on /cache (%ld needed)\n",
(long)free_now, (long)bytes_needed);
if (free_now >= bytes_needed) {
return 0;
}
char** names;
int entries;
if (FindExpendableFiles(&names, &entries) < 0) {
return -1;
}
if (entries == 0) {
// nothing we can delete to free up space!
printf("no files can be deleted to free space on /cache\n");
return -1;
}
// We could try to be smarter about which files to delete: the
// biggest ones? the smallest ones that will free up enough space?
// the oldest? the newest?
//
// Instead, we'll be dumb.
int i;
for (i = 0; i < entries && free_now < bytes_needed; ++i) {
if (names[i]) {
unlink(names[i]);
free_now = FreeSpaceForFile("/cache");
printf("deleted %s; now %ld bytes free\n", names[i], (long)free_now);
free(names[i]);
}
}
for (; i < entries; ++i) {
free(names[i]);
}
free(names);
return (free_now >= bytes_needed) ? 0 : -1;
}
+143
View File
@@ -0,0 +1,143 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <errno.h>
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/statfs.h>
#include <unistd.h>
#include <dirent.h>
#include <ctype.h>
#include <memory>
#include <set>
#include <string>
#include <android-base/parseint.h>
#include <android-base/stringprintf.h>
#include "applypatch.h"
static int EliminateOpenFiles(std::set<std::string>* files) {
std::unique_ptr<DIR, decltype(&closedir)> d(opendir("/proc"), closedir);
if (!d) {
printf("error opening /proc: %s\n", strerror(errno));
return -1;
}
struct dirent* de;
while ((de = readdir(d.get())) != 0) {
unsigned int pid;
if (!android::base::ParseUint(de->d_name, &pid)) {
continue;
}
std::string path = android::base::StringPrintf("/proc/%s/fd/", de->d_name);
struct dirent* fdde;
std::unique_ptr<DIR, decltype(&closedir)> fdd(opendir(path.c_str()), closedir);
if (!fdd) {
printf("error opening %s: %s\n", path.c_str(), strerror(errno));
continue;
}
while ((fdde = readdir(fdd.get())) != 0) {
std::string fd_path = path + fdde->d_name;
char link[FILENAME_MAX];
int count = readlink(fd_path.c_str(), link, sizeof(link)-1);
if (count >= 0) {
link[count] = '\0';
if (strncmp(link, "/cache/", 7) == 0) {
if (files->erase(link) > 0) {
printf("%s is open by %s\n", link, de->d_name);
}
}
}
}
}
return 0;
}
static std::set<std::string> FindExpendableFiles() {
std::set<std::string> files;
// We're allowed to delete unopened regular files in any of these
// directories.
const char* dirs[2] = {"/cache", "/cache/recovery/otatest"};
for (size_t i = 0; i < sizeof(dirs)/sizeof(dirs[0]); ++i) {
std::unique_ptr<DIR, decltype(&closedir)> d(opendir(dirs[i]), closedir);
if (!d) {
printf("error opening %s: %s\n", dirs[i], strerror(errno));
continue;
}
// Look for regular files in the directory (not in any subdirectories).
struct dirent* de;
while ((de = readdir(d.get())) != 0) {
std::string path = std::string(dirs[i]) + "/" + de->d_name;
// We can't delete CACHE_TEMP_SOURCE; if it's there we might have
// restarted during installation and could be depending on it to
// be there.
if (path == CACHE_TEMP_SOURCE) {
continue;
}
struct stat st;
if (stat(path.c_str(), &st) == 0 && S_ISREG(st.st_mode)) {
files.insert(path);
}
}
}
printf("%zu regular files in deletable directories\n", files.size());
if (EliminateOpenFiles(&files) < 0) {
return std::set<std::string>();
}
return files;
}
int MakeFreeSpaceOnCache(size_t bytes_needed) {
size_t free_now = FreeSpaceForFile("/cache");
printf("%zu bytes free on /cache (%zu needed)\n", free_now, bytes_needed);
if (free_now >= bytes_needed) {
return 0;
}
std::set<std::string> files = FindExpendableFiles();
if (files.empty()) {
// nothing we can delete to free up space!
printf("no files can be deleted to free space on /cache\n");
return -1;
}
// We could try to be smarter about which files to delete: the
// biggest ones? the smallest ones that will free up enough space?
// the oldest? the newest?
//
// Instead, we'll be dumb.
for (const auto& file : files) {
unlink(file.c_str());
free_now = FreeSpaceForFile("/cache");
printf("deleted %s; now %zu bytes free\n", file.c_str(), free_now);
if (free_now < bytes_needed) {
break;
}
}
return (free_now >= bytes_needed) ? 0 : -1;
}
+68 -45
View File
@@ -122,6 +122,7 @@
*/
#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -179,7 +180,7 @@ static int fileentry_compare(const void* a, const void* b) {
}
// from bsdiff.c
int bsdiff(u_char* old, off_t oldsize, off_t** IP, u_char* new, off_t newsize,
int bsdiff(u_char* old, off_t oldsize, off_t** IP, u_char* newdata, off_t newsize,
const char* patch_filename);
unsigned char* ReadZip(const char* filename,
@@ -191,9 +192,10 @@ unsigned char* ReadZip(const char* filename,
return NULL;
}
unsigned char* img = malloc(st.st_size);
size_t sz = static_cast<size_t>(st.st_size);
unsigned char* img = reinterpret_cast<unsigned char*>(malloc(sz));
FILE* f = fopen(filename, "rb");
if (fread(img, 1, st.st_size, f) != st.st_size) {
if (fread(img, 1, sz, f) != sz) {
printf("failed to read \"%s\" %s\n", filename, strerror(errno));
fclose(f);
return NULL;
@@ -218,7 +220,8 @@ unsigned char* ReadZip(const char* filename,
int cdcount = Read2(img+i+8);
int cdoffset = Read4(img+i+16);
ZipFileEntry* temp_entries = malloc(cdcount * sizeof(ZipFileEntry));
ZipFileEntry* temp_entries = reinterpret_cast<ZipFileEntry*>(malloc(
cdcount * sizeof(ZipFileEntry)));
int entrycount = 0;
unsigned char* cd = img+cdoffset;
@@ -235,7 +238,7 @@ unsigned char* ReadZip(const char* filename,
int mlen = Read2(cd+32); // file comment len
int hoffset = Read4(cd+42); // local header offset
char* filename = malloc(nlen+1);
char* filename = reinterpret_cast<char*>(malloc(nlen+1));
memcpy(filename, cd+46, nlen);
filename[nlen] = '\0';
@@ -284,7 +287,7 @@ unsigned char* ReadZip(const char* filename,
#endif
*num_chunks = 0;
*chunks = malloc((entrycount*2+2) * sizeof(ImageChunk));
*chunks = reinterpret_cast<ImageChunk*>(malloc((entrycount*2+2) * sizeof(ImageChunk)));
ImageChunk* curr = *chunks;
if (include_pseudo_chunk) {
@@ -311,7 +314,7 @@ unsigned char* ReadZip(const char* filename,
curr->I = NULL;
curr->len = temp_entries[nextentry].uncomp_len;
curr->data = malloc(curr->len);
curr->data = reinterpret_cast<unsigned char*>(malloc(curr->len));
z_stream strm;
strm.zalloc = Z_NULL;
@@ -381,9 +384,10 @@ unsigned char* ReadImage(const char* filename,
return NULL;
}
unsigned char* img = malloc(st.st_size + 4);
size_t sz = static_cast<size_t>(st.st_size);
unsigned char* img = reinterpret_cast<unsigned char*>(malloc(sz + 4));
FILE* f = fopen(filename, "rb");
if (fread(img, 1, st.st_size, f) != st.st_size) {
if (fread(img, 1, sz, f) != sz) {
printf("failed to read \"%s\" %s\n", filename, strerror(errno));
fclose(f);
return NULL;
@@ -393,17 +397,18 @@ unsigned char* ReadImage(const char* filename,
// append 4 zero bytes to the data so we can always search for the
// four-byte string 1f8b0800 starting at any point in the actual
// file data, without special-casing the end of the data.
memset(img+st.st_size, 0, 4);
memset(img+sz, 0, 4);
size_t pos = 0;
*num_chunks = 0;
*chunks = NULL;
while (pos < st.st_size) {
while (pos < sz) {
unsigned char* p = img+pos;
if (st.st_size - pos >= 4 &&
bool processed_deflate = false;
if (sz - pos >= 4 &&
p[0] == 0x1f && p[1] == 0x8b &&
p[2] == 0x08 && // deflate compression
p[3] == 0x00) { // no header flags
@@ -411,7 +416,8 @@ unsigned char* ReadImage(const char* filename,
size_t chunk_offset = pos;
*num_chunks += 3;
*chunks = realloc(*chunks, *num_chunks * sizeof(ImageChunk));
*chunks = reinterpret_cast<ImageChunk*>(realloc(*chunks,
*num_chunks * sizeof(ImageChunk)));
ImageChunk* curr = *chunks + (*num_chunks-3);
// create a normal chunk for the header.
@@ -435,7 +441,7 @@ unsigned char* ReadImage(const char* filename,
size_t allocated = 32768;
curr->len = 0;
curr->data = malloc(allocated);
curr->data = reinterpret_cast<unsigned char*>(malloc(allocated));
curr->start = pos;
curr->deflate_data = p;
@@ -443,7 +449,7 @@ unsigned char* ReadImage(const char* filename,
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = st.st_size - pos;
strm.avail_in = sz - pos;
strm.next_in = p;
// -15 means we are decoding a 'raw' deflate stream; zlib will
@@ -455,21 +461,27 @@ unsigned char* ReadImage(const char* filename,
strm.next_out = curr->data + curr->len;
ret = inflate(&strm, Z_NO_FLUSH);
if (ret < 0) {
printf("Error: inflate failed [%s] at file offset [%zu]\n"
"imgdiff only supports gzip kernel compression,"
" did you try CONFIG_KERNEL_LZO?\n",
strm.msg, chunk_offset);
free(img);
return NULL;
if (!processed_deflate) {
// This is the first chunk, assume that it's just a spurious
// gzip header instead of a real one.
break;
}
printf("Error: inflate failed [%s] at file offset [%zu]\n"
"imgdiff only supports gzip kernel compression,"
" did you try CONFIG_KERNEL_LZO?\n",
strm.msg, chunk_offset);
free(img);
return NULL;
}
curr->len = allocated - strm.avail_out;
if (strm.avail_out == 0) {
allocated *= 2;
curr->data = realloc(curr->data, allocated);
curr->data = reinterpret_cast<unsigned char*>(realloc(curr->data, allocated));
}
processed_deflate = true;
} while (ret != Z_STREAM_END);
curr->deflate_len = st.st_size - strm.avail_in - pos;
curr->deflate_len = sz - strm.avail_in - pos;
inflateEnd(&strm);
pos += curr->deflate_len;
p += curr->deflate_len;
@@ -493,8 +505,8 @@ unsigned char* ReadImage(const char* filename,
// the decompression.
size_t footer_size = Read4(p-4);
if (footer_size != curr[-2].len) {
printf("Error: footer size %d != decompressed size %d\n",
footer_size, curr[-2].len);
printf("Error: footer size %zu != decompressed size %zu\n",
footer_size, curr[-2].len);
free(img);
return NULL;
}
@@ -502,7 +514,7 @@ unsigned char* ReadImage(const char* filename,
// Reallocate the list for every chunk; we expect the number of
// chunks to be small (5 for typical boot and recovery images).
++*num_chunks;
*chunks = realloc(*chunks, *num_chunks * sizeof(ImageChunk));
*chunks = reinterpret_cast<ImageChunk*>(realloc(*chunks, *num_chunks * sizeof(ImageChunk)));
ImageChunk* curr = *chunks + (*num_chunks-1);
curr->start = pos;
curr->I = NULL;
@@ -512,7 +524,7 @@ unsigned char* ReadImage(const char* filename,
curr->type = CHUNK_NORMAL;
curr->data = p;
for (curr->len = 0; curr->len < (st.st_size - pos); ++curr->len) {
for (curr->len = 0; curr->len < (sz - pos); ++curr->len) {
if (p[curr->len] == 0x1f &&
p[curr->len+1] == 0x8b &&
p[curr->len+2] == 0x08 &&
@@ -587,7 +599,7 @@ int ReconstructDeflateChunk(ImageChunk* chunk) {
}
size_t p = 0;
unsigned char* out = malloc(BUFFER_SIZE);
unsigned char* out = reinterpret_cast<unsigned char*>(malloc(BUFFER_SIZE));
// We only check two combinations of encoder parameters: level 6
// (the default) and level 9 (the maximum).
@@ -623,7 +635,15 @@ unsigned char* MakePatch(ImageChunk* src, ImageChunk* tgt, size_t* size) {
}
char ptemp[] = "/tmp/imgdiff-patch-XXXXXX";
mkstemp(ptemp);
int fd = mkstemp(ptemp);
if (fd == -1) {
printf("MakePatch failed to create a temporary file: %s\n",
strerror(errno));
return NULL;
}
close(fd); // temporary file is created and we don't need its file
// descriptor
int r = bsdiff(src->data, src->len, &(src->I), tgt->data, tgt->len, ptemp);
if (r != 0) {
@@ -638,9 +658,11 @@ unsigned char* MakePatch(ImageChunk* src, ImageChunk* tgt, size_t* size) {
return NULL;
}
unsigned char* data = malloc(st.st_size);
size_t sz = static_cast<size_t>(st.st_size);
// TODO: Memory leak on error return.
unsigned char* data = reinterpret_cast<unsigned char*>(malloc(sz));
if (tgt->type == CHUNK_NORMAL && tgt->len <= st.st_size) {
if (tgt->type == CHUNK_NORMAL && tgt->len <= sz) {
unlink(ptemp);
tgt->type = CHUNK_RAW;
@@ -648,14 +670,14 @@ unsigned char* MakePatch(ImageChunk* src, ImageChunk* tgt, size_t* size) {
return tgt->data;
}
*size = st.st_size;
*size = sz;
FILE* f = fopen(ptemp, "rb");
if (f == NULL) {
printf("failed to open patch %s: %s\n", ptemp, strerror(errno));
return NULL;
}
if (fread(data, 1, st.st_size, f) != st.st_size) {
if (fread(data, 1, sz, f) != sz) {
printf("failed to read patch %s: %s\n", ptemp, strerror(errno));
return NULL;
}
@@ -781,9 +803,8 @@ ImageChunk* FindChunkByName(const char* name,
}
void DumpChunks(ImageChunk* chunks, int num_chunks) {
int i;
for (i = 0; i < num_chunks; ++i) {
printf("chunk %d: type %d start %d len %d\n",
for (int i = 0; i < num_chunks; ++i) {
printf("chunk %d: type %d start %zu len %zu\n",
i, chunks[i].type, chunks[i].start, chunks[i].len);
}
}
@@ -806,7 +827,7 @@ int main(int argc, char** argv) {
return 1;
}
bonus_size = st.st_size;
bonus_data = malloc(bonus_size);
bonus_data = reinterpret_cast<unsigned char*>(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));
@@ -953,8 +974,9 @@ int main(int argc, char** argv) {
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));
unsigned char** patch_data = reinterpret_cast<unsigned char**>(malloc(
num_tgt_chunks * sizeof(unsigned char*)));
size_t* patch_size = reinterpret_cast<size_t*>(malloc(num_tgt_chunks * sizeof(size_t)));
for (i = 0; i < num_tgt_chunks; ++i) {
if (zip_mode) {
ImageChunk* src;
@@ -967,15 +989,16 @@ int main(int argc, char** argv) {
}
} 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);
printf(" using %zu bytes of bonus data for chunk %d\n", bonus_size, i);
src_chunks[i].data = reinterpret_cast<unsigned char*>(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",
printf("patch %3d is %zu bytes (of %zu)\n",
i, patch_size[i], tgt_chunks[i].source_len);
}
@@ -1012,7 +1035,7 @@ int main(int argc, char** argv) {
switch (tgt_chunks[i].type) {
case CHUNK_NORMAL:
printf("chunk %3d: normal (%10d, %10d) %10d\n", i,
printf("chunk %3d: normal (%10zu, %10zu) %10zu\n", i,
tgt_chunks[i].start, tgt_chunks[i].len, patch_size[i]);
Write8(tgt_chunks[i].source_start, f);
Write8(tgt_chunks[i].source_len, f);
@@ -1021,7 +1044,7 @@ int main(int argc, char** argv) {
break;
case CHUNK_DEFLATE:
printf("chunk %3d: deflate (%10d, %10d) %10d %s\n", i,
printf("chunk %3d: deflate (%10zu, %10zu) %10zu %s\n", i,
tgt_chunks[i].start, tgt_chunks[i].deflate_len, patch_size[i],
tgt_chunks[i].filename);
Write8(tgt_chunks[i].source_start, f);
@@ -1038,7 +1061,7 @@ int main(int argc, char** argv) {
break;
case CHUNK_RAW:
printf("chunk %3d: raw (%10d, %10d)\n", i,
printf("chunk %3d: raw (%10zu, %10zu)\n", i,
tgt_chunks[i].start, tgt_chunks[i].len);
Write4(patch_size[i], f);
fwrite(patch_data[i], 1, patch_size[i], f);
@@ -21,23 +21,33 @@
#include <sys/cdefs.h>
#include <sys/stat.h>
#include <errno.h>
#include <malloc.h>
#include <unistd.h>
#include <string.h>
#include <vector>
#include "zlib.h"
#include "mincrypt/sha.h"
#include "openssl/sha.h"
#include "applypatch.h"
#include "imgdiff.h"
#include "utils.h"
int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
const unsigned char* patch_data, ssize_t patch_size,
SinkFn sink, void* token) {
Value patch = {VAL_BLOB, patch_size,
reinterpret_cast<char*>(const_cast<unsigned char*>(patch_data))};
return ApplyImagePatch(
old_data, old_size, &patch, sink, token, nullptr, nullptr);
}
/*
* Apply the patch given in 'patch_filename' to the source data given
* by (old_data, old_size). Write the patched output to the 'output'
* file, and update the SHA context with the output data as well.
* Return 0 on success.
*/
int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size __unused,
int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
const Value* patch,
SinkFn sink, void* token, SHA_CTX* ctx,
const Value* bonus_data) {
@@ -80,6 +90,10 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size __unused,
size_t src_len = Read8(normal_header+8);
size_t patch_offset = Read8(normal_header+16);
if (src_start + src_len > static_cast<size_t>(old_size)) {
printf("source data too short\n");
return -1;
}
ApplyBSDiffPatch(old_data + src_start, src_len,
patch, patch_offset, sink, token, ctx);
} else if (type == CHUNK_RAW) {
@@ -96,7 +110,7 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size __unused,
printf("failed to read chunk %d raw data\n", i);
return -1;
}
if (ctx) SHA_update(ctx, patch->data + pos, data_len);
if (ctx) SHA1_Update(ctx, patch->data + pos, data_len);
if (sink((unsigned char*)patch->data + pos,
data_len, token) != data_len) {
printf("failed to write chunk %d raw data\n", i);
@@ -116,13 +130,17 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size __unused,
size_t src_len = Read8(deflate_header+8);
size_t patch_offset = Read8(deflate_header+16);
size_t expanded_len = Read8(deflate_header+24);
size_t target_len = Read8(deflate_header+32);
int level = Read4(deflate_header+40);
int method = Read4(deflate_header+44);
int windowBits = Read4(deflate_header+48);
int memLevel = Read4(deflate_header+52);
int strategy = Read4(deflate_header+56);
if (src_start + src_len > static_cast<size_t>(old_size)) {
printf("source data too short\n");
return -1;
}
// Decompress the source data; the chunk header tells us exactly
// how big we expect it to be when decompressed.
@@ -132,57 +150,54 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size __unused,
// 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 %zu bytes for expanded_source\n",
expanded_len);
return -1;
}
std::vector<unsigned char> expanded_source(expanded_len);
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = src_len;
strm.next_in = (unsigned char*)(old_data + src_start);
strm.avail_out = expanded_len;
strm.next_out = expanded_source;
// inflate() doesn't like strm.next_out being a nullptr even with
// avail_out being zero (Z_STREAM_ERROR).
if (expanded_len != 0) {
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = src_len;
strm.next_in = (unsigned char*)(old_data + src_start);
strm.avail_out = expanded_len;
strm.next_out = expanded_source.data();
int ret;
ret = inflateInit2(&strm, -15);
if (ret != Z_OK) {
printf("failed to init source inflation: %d\n", ret);
return -1;
}
int ret;
ret = inflateInit2(&strm, -15);
if (ret != Z_OK) {
printf("failed to init source inflation: %d\n", ret);
return -1;
}
// Because we've provided enough room to accommodate the output
// data, we expect one call to inflate() to suffice.
ret = inflate(&strm, Z_SYNC_FLUSH);
if (ret != Z_STREAM_END) {
printf("source inflation returned %d\n", ret);
return -1;
}
// We should have filled the output buffer exactly, except
// for the bonus_size.
if (strm.avail_out != bonus_size) {
printf("source inflation short by %zu bytes\n", strm.avail_out-bonus_size);
return -1;
}
inflateEnd(&strm);
// Because we've provided enough room to accommodate the output
// data, we expect one call to inflate() to suffice.
ret = inflate(&strm, Z_SYNC_FLUSH);
if (ret != Z_STREAM_END) {
printf("source inflation returned %d\n", ret);
return -1;
}
// We should have filled the output buffer exactly, except
// for the bonus_size.
if (strm.avail_out != bonus_size) {
printf("source inflation short by %zu 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);
if (bonus_size) {
memcpy(expanded_source.data() + (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;
ssize_t uncompressed_target_size;
if (ApplyBSDiffPatchMem(expanded_source, expanded_len,
std::vector<unsigned char> uncompressed_target_data;
if (ApplyBSDiffPatchMem(expanded_source.data(), expanded_len,
patch, patch_offset,
&uncompressed_target_data,
&uncompressed_target_size) != 0) {
&uncompressed_target_data) != 0) {
return -1;
}
@@ -190,40 +205,40 @@ int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size __unused,
// we're done with the expanded_source data buffer, so we'll
// reuse that memory to receive the output of deflate.
unsigned char* temp_data = expanded_source;
ssize_t temp_size = expanded_len;
if (temp_size < 32768) {
// ... unless the buffer is too small, in which case we'll
// allocate a fresh one.
free(temp_data);
temp_data = malloc(32768);
temp_size = 32768;
if (expanded_source.size() < 32768U) {
expanded_source.resize(32768U);
}
// now the deflate stream
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = uncompressed_target_size;
strm.next_in = uncompressed_target_data;
ret = deflateInit2(&strm, level, method, windowBits, memLevel, strategy);
do {
strm.avail_out = temp_size;
strm.next_out = temp_data;
ret = deflate(&strm, Z_FINISH);
ssize_t have = temp_size - strm.avail_out;
{
std::vector<unsigned char>& temp_data = expanded_source;
if (sink(temp_data, have, token) != have) {
printf("failed to write %ld compressed bytes to output\n",
(long)have);
// now the deflate stream
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = uncompressed_target_data.size();
strm.next_in = uncompressed_target_data.data();
int ret = deflateInit2(&strm, level, method, windowBits, memLevel, strategy);
if (ret != Z_OK) {
printf("failed to init uncompressed data deflation: %d\n", ret);
return -1;
}
if (ctx) SHA_update(ctx, temp_data, have);
} while (ret != Z_STREAM_END);
deflateEnd(&strm);
do {
strm.avail_out = temp_data.size();
strm.next_out = temp_data.data();
ret = deflate(&strm, Z_FINISH);
ssize_t have = temp_data.size() - strm.avail_out;
free(temp_data);
free(uncompressed_target_data);
if (sink(temp_data.data(), have, token) != have) {
printf("failed to write %ld compressed bytes to output\n",
(long)have);
return -1;
}
if (ctx) SHA1_Update(ctx, temp_data.data(), have);
} while (ret != Z_STREAM_END);
deflateEnd(&strm);
}
} else {
printf("patch chunk %d is unknown type %d\n", i, type);
return -1;
+26
View File
@@ -0,0 +1,26 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _IMGPATCH_H
#define _IMGPATCH_H
typedef ssize_t (*SinkFn)(const unsigned char*, ssize_t, void*);
int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
const unsigned char* patch_data, ssize_t patch_size,
SinkFn sink, void* token);
#endif //_IMGPATCH_H
+64 -78
View File
@@ -19,18 +19,21 @@
#include <string.h>
#include <unistd.h>
#include <memory>
#include <vector>
#include "applypatch.h"
#include "edify/expr.h"
#include "mincrypt/sha.h"
#include "openssl/sha.h"
int CheckMode(int argc, char** argv) {
static int CheckMode(int argc, char** argv) {
if (argc < 3) {
return 2;
}
return applypatch_check(argv[2], argc-3, argv+3);
}
int SpaceMode(int argc, char** argv) {
static int SpaceMode(int argc, char** argv) {
if (argc != 3) {
return 2;
}
@@ -43,79 +46,60 @@ int SpaceMode(int argc, char** argv) {
return CacheSizeCheck(bytes);
}
// Parse arguments (which should be of the form "<sha1>" or
// "<sha1>:<filename>" into the new parallel arrays *sha1s and
// *patches (loading file contents into the patches). Returns 0 on
// Parse arguments (which should be of the form "<sha1>:<filename>"
// into the new parallel arrays *sha1s and *files.Returns true on
// success.
static int ParsePatchArgs(int argc, char** argv,
char*** sha1s, Value*** patches, int* num_patches) {
*num_patches = argc;
*sha1s = malloc(*num_patches * sizeof(char*));
*patches = malloc(*num_patches * sizeof(Value*));
memset(*patches, 0, *num_patches * sizeof(Value*));
static bool ParsePatchArgs(int argc, char** argv, std::vector<char*>* sha1s,
std::vector<FileContents>* files) {
uint8_t digest[SHA_DIGEST_LENGTH];
uint8_t digest[SHA_DIGEST_SIZE];
int i;
for (i = 0; i < *num_patches; ++i) {
for (int i = 0; i < argc; ++i) {
char* colon = strchr(argv[i], ':');
if (colon != NULL) {
*colon = '\0';
++colon;
if (colon == nullptr) {
printf("no ':' in patch argument \"%s\"\n", argv[i]);
return false;
}
*colon = '\0';
++colon;
if (ParseSha1(argv[i], digest) != 0) {
printf("failed to parse sha1 \"%s\"\n", argv[i]);
return -1;
return false;
}
(*sha1s)[i] = argv[i];
if (colon == NULL) {
(*patches)[i] = NULL;
} else {
FileContents fc;
if (LoadFileContents(colon, &fc) != 0) {
goto abort;
}
(*patches)[i] = malloc(sizeof(Value));
(*patches)[i]->type = VAL_BLOB;
(*patches)[i]->size = fc.size;
(*patches)[i]->data = (char*)fc.data;
sha1s->push_back(argv[i]);
FileContents fc;
if (LoadFileContents(colon, &fc) != 0) {
return false;
}
files->push_back(std::move(fc));
}
return 0;
abort:
for (i = 0; i < *num_patches; ++i) {
Value* p = (*patches)[i];
if (p != NULL) {
free(p->data);
free(p);
}
}
free(*sha1s);
free(*patches);
return -1;
return true;
}
int PatchMode(int argc, char** argv) {
Value* bonus = NULL;
static int FlashMode(const char* src_filename, const char* tgt_filename,
const char* tgt_sha1, size_t tgt_size) {
return applypatch_flash(src_filename, tgt_filename, tgt_sha1, tgt_size);
}
static int PatchMode(int argc, char** argv) {
FileContents bonusFc;
Value bonusValue;
Value* bonus = nullptr;
if (argc >= 3 && strcmp(argv[1], "-b") == 0) {
FileContents fc;
if (LoadFileContents(argv[2], &fc) != 0) {
if (LoadFileContents(argv[2], &bonusFc) != 0) {
printf("failed to load bonus file %s\n", argv[2]);
return 1;
}
bonus = malloc(sizeof(Value));
bonus = &bonusValue;
bonus->type = VAL_BLOB;
bonus->size = fc.size;
bonus->data = (char*)fc.data;
bonus->size = bonusFc.data.size();
bonus->data = reinterpret_cast<char*>(bonusFc.data.data());
argc -= 2;
argv += 2;
}
if (argc < 6) {
if (argc < 4) {
return 2;
}
@@ -126,33 +110,31 @@ int PatchMode(int argc, char** argv) {
return 1;
}
char** sha1s;
Value** patches;
int num_patches;
if (ParsePatchArgs(argc-5, argv+5, &sha1s, &patches, &num_patches) != 0) {
// If no <src-sha1>:<patch> is provided, it is in flash mode.
if (argc == 5) {
if (bonus != nullptr) {
printf("bonus file not supported in flash mode\n");
return 1;
}
return FlashMode(argv[1], argv[2], argv[3], target_size);
}
std::vector<char*> sha1s;
std::vector<FileContents> files;
if (!ParsePatchArgs(argc-5, argv+5, &sha1s, &files)) {
printf("failed to parse patch args\n");
return 1;
}
int result = applypatch(argv[1], argv[2], argv[3], target_size,
num_patches, sha1s, patches, bonus);
int i;
for (i = 0; i < num_patches; ++i) {
Value* p = patches[i];
if (p != NULL) {
free(p->data);
free(p);
}
std::vector<Value> patches(files.size());
std::vector<Value*> patch_ptrs(files.size());
for (size_t i = 0; i < files.size(); ++i) {
patches[i].type = VAL_BLOB;
patches[i].size = files[i].data.size();
patches[i].data = reinterpret_cast<char*>(files[i].data.data());
patch_ptrs[i] = &patches[i];
}
if (bonus) {
free(bonus->data);
free(bonus);
}
free(sha1s);
free(patches);
return result;
return applypatch(argv[1], argv[2], argv[3], target_size,
patch_ptrs.size(), sha1s.data(),
patch_ptrs.data(), bonus);
}
// This program applies binary patches to files in a way that is safe
@@ -163,6 +145,10 @@ int PatchMode(int argc, char** argv) {
// - if the sha1 hash of <tgt-file> is <tgt-sha1>, does nothing and exits
// successfully.
//
// - otherwise, if no <src-sha1>:<patch> is provided, flashes <tgt-file> with
// <src-file>. <tgt-file> must be a partition name, while <src-file> must
// be a regular image file. <src-file> will not be deleted on success.
//
// - otherwise, if the sha1 hash of <src-file> is <src-sha1>, applies the
// bsdiff <patch> to <src-file> to produce a new file (the type of patch
// is automatically detected from the file header). If that new
+3 -3
View File
@@ -39,13 +39,13 @@ void Write8(long long value, FILE* f) {
}
int Read2(void* pv) {
unsigned char* p = pv;
unsigned char* p = reinterpret_cast<unsigned char*>(pv);
return (int)(((unsigned int)p[1] << 8) |
(unsigned int)p[0]);
}
int Read4(void* pv) {
unsigned char* p = pv;
unsigned char* p = reinterpret_cast<unsigned char*>(pv);
return (int)(((unsigned int)p[3] << 24) |
((unsigned int)p[2] << 16) |
((unsigned int)p[1] << 8) |
@@ -53,7 +53,7 @@ int Read4(void* pv) {
}
long long Read8(void* pv) {
unsigned char* p = pv;
unsigned char* p = reinterpret_cast<unsigned char*>(pv);
return (long long)(((unsigned long long)p[7] << 56) |
((unsigned long long)p[6] << 48) |
((unsigned long long)p[5] << 40) |
+76 -62
View File
@@ -14,24 +14,26 @@
* limitations under the License.
*/
/*
#include <fs_mgr.h>
*/
#include "bootloader.h"
#include "common.h"
extern "C" {
#include "mtdutils/mtdutils.h"
}
/*
#include "roots.h"
*/
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include "bootloader.h"
#include "common.h"
#include "mtdutils/mtdutils.h"
//#include "roots.h"
#include "unique_fd.h"
// fake Volume struct that allows us to use the AOSP code easily
struct Volume
{
@@ -50,17 +52,17 @@ void set_misc_device(const char* type, const char* name) {
}
}
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);
static int get_bootloader_message_mtd(bootloader_message* out, const Volume* v);
static int set_bootloader_message_mtd(const bootloader_message* in, const Volume* v);
static int get_bootloader_message_block(bootloader_message* out, const Volume* v);
static int set_bootloader_message_block(const bootloader_message* in, const Volume* v);
int get_bootloader_message(struct bootloader_message *out) {
int get_bootloader_message(bootloader_message* out) {
#if 0
Volume* v = volume_for_path("/misc");
if (v == NULL) {
LOGE("Cannot load volume /misc!\n");
return -1;
if (v == nullptr) {
LOGE("Cannot load volume /misc!\n");
return -1;
}
#else
Volume* v = &misc;
@@ -78,12 +80,12 @@ int get_bootloader_message(struct bootloader_message *out) {
return -1;
}
int set_bootloader_message(const struct bootloader_message *in) {
int set_bootloader_message(const bootloader_message* in) {
#if 0
Volume* v = volume_for_path("/misc");
if (v == NULL) {
LOGE("Cannot load volume /misc!\n");
return -1;
if (v == nullptr) {
LOGE("Cannot load volume /misc!\n");
return -1;
}
#else
Volume* v = &misc;
@@ -108,69 +110,69 @@ 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,
static int get_bootloader_message_mtd(bootloader_message* out,
const Volume* v) {
size_t write_size;
mtd_scan_partitions();
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->blk_device);
const MtdPartition* part = mtd_find_partition_by_name(v->blk_device);
if (part == nullptr || mtd_partition_info(part, nullptr, nullptr, &write_size)) {
LOGE("failed to 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->blk_device, strerror(errno));
MtdReadContext* read = mtd_read_partition(part);
if (read == nullptr) {
LOGE("failed to open \"%s\": %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->blk_device, strerror(errno));
if (r != size) LOGE("failed to read \"%s\": %s\n", v->blk_device, strerror(errno));
mtd_read_close(read);
if (r != size) return -1;
memcpy(out, &data[write_size * MISC_COMMAND_PAGE], sizeof(*out));
return 0;
}
static int set_bootloader_message_mtd(const struct bootloader_message *in,
static int set_bootloader_message_mtd(const bootloader_message* in,
const Volume* v) {
size_t write_size;
mtd_scan_partitions();
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->blk_device);
const MtdPartition* part = mtd_find_partition_by_name(v->blk_device);
if (part == nullptr || mtd_partition_info(part, nullptr, nullptr, &write_size)) {
LOGE("failed to 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->blk_device, strerror(errno));
MtdReadContext* read = mtd_read_partition(part);
if (read == nullptr) {
LOGE("failed to open \"%s\": %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->blk_device, strerror(errno));
if (r != size) LOGE("failed to read \"%s\": %s\n", v->blk_device, strerror(errno));
mtd_read_close(read);
if (r != size) return -1;
memcpy(&data[write_size * MISC_COMMAND_PAGE], in, sizeof(*in));
MtdWriteContext *write = mtd_write_partition(part);
if (write == NULL) {
LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
MtdWriteContext* write = mtd_write_partition(part);
if (write == nullptr) {
LOGE("failed to open \"%s\": %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->blk_device, strerror(errno));
LOGE("failed to write \"%s\": %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->blk_device, strerror(errno));
LOGE("failed to finish \"%s\": %s\n", v->blk_device, strerror(errno));
return -1;
}
@@ -186,63 +188,75 @@ static int set_bootloader_message_mtd(const struct bootloader_message *in,
static void wait_for_device(const char* fn) {
int tries = 0;
int ret;
struct stat buf;
do {
++tries;
struct stat buf;
ret = stat(fn, &buf);
if (ret) {
printf("stat %s try %d: %s\n", fn, tries, strerror(errno));
if (ret == -1) {
printf("failed to stat \"%s\" try %d: %s\n", fn, tries, strerror(errno));
sleep(1);
}
} while (ret && tries < 10);
if (ret) {
printf("failed to stat %s\n", fn);
printf("failed to stat \"%s\"\n", fn);
}
}
static int get_bootloader_message_block(struct bootloader_message *out,
static int get_bootloader_message_block(bootloader_message* out,
const Volume* v) {
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->blk_device, strerror(errno));
if (f == nullptr) {
LOGE("failed to open \"%s\": %s\n", v->blk_device, strerror(errno));
return -1;
}
#ifdef BOARD_RECOVERY_BLDRMSG_OFFSET
fseek(f, BOARD_RECOVERY_BLDRMSG_OFFSET, SEEK_SET);
#endif
struct bootloader_message temp;
bootloader_message temp;
int count = fread(&temp, sizeof(temp), 1, f);
if (count != 1) {
LOGE("Failed reading %s\n(%s)\n", v->blk_device, strerror(errno));
LOGE("failed to read \"%s\": %s\n", v->blk_device, strerror(errno));
return -1;
}
if (fclose(f) != 0) {
LOGE("Failed closing %s\n(%s)\n", v->blk_device, strerror(errno));
LOGE("failed to close \"%s\": %s\n", v->blk_device, strerror(errno));
return -1;
}
memcpy(out, &temp, sizeof(temp));
return 0;
}
static int set_bootloader_message_block(const struct bootloader_message *in,
static int set_bootloader_message_block(const bootloader_message* in,
const Volume* v) {
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->blk_device, strerror(errno));
unique_fd fd(open(v->blk_device, O_WRONLY | O_SYNC));
if (fd.get() == -1) {
LOGE("failed to open \"%s\": %s\n", v->blk_device, strerror(errno));
return -1;
}
#ifdef BOARD_RECOVERY_BLDRMSG_OFFSET
fseek(f, BOARD_RECOVERY_BLDRMSG_OFFSET, SEEK_SET);
lseek(fd.get(), BOARD_RECOVERY_BLDRMSG_OFFSET, SEEK_SET);
#endif
int count = fwrite(in, sizeof(*in), 1, f);
if (count != 1) {
LOGE("Failed writing %s\n(%s)\n", v->blk_device, strerror(errno));
return -1;
size_t written = 0;
const uint8_t* start = reinterpret_cast<const uint8_t*>(in);
size_t total = sizeof(*in);
while (written < total) {
ssize_t wrote = TEMP_FAILURE_RETRY(write(fd.get(), start + written, total - written));
if (wrote == -1) {
LOGE("failed to write %" PRId64 " bytes: %s\n",
static_cast<off64_t>(written), strerror(errno));
return -1;
}
written += wrote;
}
if (fclose(f) != 0) {
LOGE("Failed closing %s\n(%s)\n", v->blk_device, strerror(errno));
if (fsync(fd.get()) == -1) {
LOGE("failed to fsync \"%s\": %s\n", v->blk_device, strerror(errno));
return -1;
}
return 0;
+9 -9
View File
@@ -17,10 +17,6 @@
#ifndef _RECOVERY_BOOTLOADER_H
#define _RECOVERY_BOOTLOADER_H
#ifdef __cplusplus
extern "C" {
#endif
/* Bootloader Message
*
* This structure describes the content of a block in flash
@@ -43,6 +39,13 @@ extern "C" {
* multiple times, so that the UI can reflect which invocation of the
* package it is. If the value is of the format "#/#" (eg, "1/3"),
* the UI will add a simple indicator of that status.
*
* The slot_suffix field is used for A/B implementations where the
* bootloader does not set the androidboot.ro.boot.slot_suffix kernel
* commandline parameter. This is used by fs_mgr to mount /system and
* other partitions with the slotselect flag set in fstab. A/B
* implementations are free to use all 32 bytes and may store private
* data past the first NUL-byte in this field.
*/
struct bootloader_message {
char command[32];
@@ -55,7 +58,8 @@ struct bootloader_message {
// stage string (for multistage packages) and possible future
// expansion.
char stage[32];
char reserved[224];
char slot_suffix[32];
char reserved[192];
};
/* Read and write the bootloader command from the "misc" partition.
@@ -67,8 +71,4 @@ int set_bootloader_message(const struct bootloader_message *in);
void set_misc_device(const char* type, const char* name);
void get_args(int *argc, char ***argv);
#ifdef __cplusplus
}
#endif
#endif
+1
View File
@@ -22,6 +22,7 @@
#include <sstream>
#include <cctype>
#include <cutils/properties.h>
#include <unistd.h>
#include "variables.h"
#include "data.hpp"
+3 -1
View File
@@ -25,6 +25,7 @@ static const char* MENU_ITEMS[] = {
"Wipe cache partition",
"Mount /system",
"View recovery logs",
"Run graphics test",
"Power off",
NULL
};
@@ -43,7 +44,8 @@ Device::BuiltinAction Device::InvokeMenuItem(int menu_position) {
case 5: return WIPE_CACHE;
case 6: return MOUNT_SYSTEM;
case 7: return VIEW_RECOVERY_LOGS;
case 8: return SHUTDOWN;
case 8: return RUN_GRAPHICS_TEST;
case 9: return SHUTDOWN;
default: return NO_ACTION;
}
}
+1
View File
@@ -68,6 +68,7 @@ class Device {
SHUTDOWN = 8,
VIEW_RECOVERY_LOGS = 9,
MOUNT_SYSTEM = 10,
RUN_GRAPHICS_TEST = 11,
};
// Return the list of menu items (an array of strings,
+15 -13
View File
@@ -3,14 +3,9 @@
LOCAL_PATH := $(call my-dir)
edify_src_files := \
lexer.l \
parser.y \
expr.c
# "-x c" forces the lex/yacc files to be compiled as c the build system
# otherwise forces them to be c++. Need to also add an explicit -std because the
# build system will soon default C++ to -std=c++11.
edify_cflags := -x c -std=gnu89
lexer.ll \
parser.yy \
expr.cpp
#
# Build the host-side command line tool
@@ -19,12 +14,16 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
$(edify_src_files) \
main.c
main.cpp
LOCAL_CFLAGS := $(edify_cflags) -g -O0
LOCAL_CPPFLAGS := -g -O0
LOCAL_MODULE := edify
LOCAL_YACCFLAGS := -v
LOCAL_CFLAGS += -Wno-unused-parameter
LOCAL_CPPFLAGS += -Wno-unused-parameter
LOCAL_CPPFLAGS += -Wno-deprecated-register
LOCAL_CLANG := true
LOCAL_C_INCLUDES += $(LOCAL_PATH)/..
LOCAL_STATIC_LIBRARIES += libbase
include $(BUILD_HOST_EXECUTABLE)
@@ -35,8 +34,11 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(edify_src_files)
LOCAL_CFLAGS := $(edify_cflags)
LOCAL_CFLAGS += -Wno-unused-parameter
LOCAL_CPPFLAGS := -Wno-unused-parameter
LOCAL_CPPFLAGS += -Wno-deprecated-register
LOCAL_MODULE := libedify
LOCAL_CLANG := true
LOCAL_C_INCLUDES += $(LOCAL_PATH)/..
LOCAL_STATIC_LIBRARIES += libbase
include $(BUILD_STATIC_LIBRARY)
+45 -24
View File
@@ -21,6 +21,11 @@
#include <stdarg.h>
#include <unistd.h>
#include <string>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include "expr.h"
// Functions should:
@@ -36,7 +41,7 @@ char* Evaluate(State* state, Expr* expr) {
Value* v = expr->fn(expr->name, state, expr->argc, expr->argv);
if (v == NULL) return NULL;
if (v->type != VAL_STRING) {
ErrorAbort(state, "expecting string, got value type %d", v->type);
ErrorAbort(state, kArgsParsingFailure, "expecting string, got value type %d", v->type);
FreeValue(v);
return NULL;
}
@@ -51,7 +56,7 @@ Value* EvaluateValue(State* state, Expr* expr) {
Value* StringValue(char* str) {
if (str == NULL) return NULL;
Value* v = malloc(sizeof(Value));
Value* v = reinterpret_cast<Value*>(malloc(sizeof(Value)));
v->type = VAL_STRING;
v->size = strlen(str);
v->data = str;
@@ -68,7 +73,7 @@ Value* ConcatFn(const char* name, State* state, int argc, Expr* argv[]) {
if (argc == 0) {
return StringValue(strdup(""));
}
char** strings = malloc(argc * sizeof(char*));
char** strings = reinterpret_cast<char**>(malloc(argc * sizeof(char*)));
int i;
for (i = 0; i < argc; ++i) {
strings[i] = NULL;
@@ -83,8 +88,9 @@ Value* ConcatFn(const char* name, State* state, int argc, Expr* argv[]) {
length += strlen(strings[i]);
}
result = malloc(length+1);
int p = 0;
result = reinterpret_cast<char*>(malloc(length+1));
int p;
p = 0;
for (i = 0; i < argc; ++i) {
strcpy(result+p, strings[i]);
p += strlen(strings[i]);
@@ -149,7 +155,7 @@ Value* AssertFn(const char* name, State* state, int argc, Expr* argv[]) {
if (!b) {
int prefix_len;
int len = argv[i]->end - argv[i]->start;
char* err_src = malloc(len + 20);
char* err_src = reinterpret_cast<char*>(malloc(len + 20));
strcpy(err_src, "assert failed: ");
prefix_len = strlen(err_src);
memcpy(err_src + prefix_len, state->script + argv[i]->start, len);
@@ -290,7 +296,8 @@ Value* LessThanIntFn(const char* name, State* state, int argc, Expr* argv[]) {
goto done;
}
long r_int = strtol(right, &end, 10);
long r_int;
r_int = strtol(right, &end, 10);
if (right[0] == '\0' || *end != '\0') {
goto done;
}
@@ -325,11 +332,11 @@ Value* Literal(const char* name, State* state, int argc, Expr* argv[]) {
Expr* Build(Function fn, YYLTYPE loc, int count, ...) {
va_list v;
va_start(v, count);
Expr* e = malloc(sizeof(Expr));
Expr* e = reinterpret_cast<Expr*>(malloc(sizeof(Expr)));
e->fn = fn;
e->name = "(operator)";
e->argc = count;
e->argv = malloc(count * sizeof(Expr*));
e->argv = reinterpret_cast<Expr**>(malloc(count * sizeof(Expr*)));
int i;
for (i = 0; i < count; ++i) {
e->argv[i] = va_arg(v, Expr*);
@@ -351,7 +358,7 @@ NamedFunction* fn_table = NULL;
void RegisterFunction(const char* name, Function fn) {
if (fn_entries >= fn_size) {
fn_size = fn_size*2 + 1;
fn_table = realloc(fn_table, fn_size * sizeof(NamedFunction));
fn_table = reinterpret_cast<NamedFunction*>(realloc(fn_table, fn_size * sizeof(NamedFunction)));
}
fn_table[fn_entries].name = name;
fn_table[fn_entries].fn = fn;
@@ -371,8 +378,8 @@ void FinishRegistration() {
Function FindFunction(const char* name) {
NamedFunction key;
key.name = name;
NamedFunction* nf = bsearch(&key, fn_table, fn_entries,
sizeof(NamedFunction), fn_entry_compare);
NamedFunction* nf = reinterpret_cast<NamedFunction*>(bsearch(&key, fn_table, fn_entries,
sizeof(NamedFunction), fn_entry_compare));
if (nf == NULL) {
return NULL;
}
@@ -401,7 +408,7 @@ void RegisterBuiltins() {
// zero or more char** to put them in). If any expression evaluates
// to NULL, free the rest and return -1. Return 0 on success.
int ReadArgs(State* state, Expr* argv[], int count, ...) {
char** args = malloc(count * sizeof(char*));
char** args = reinterpret_cast<char**>(malloc(count * sizeof(char*)));
va_list v;
va_start(v, count);
int i;
@@ -427,7 +434,7 @@ int ReadArgs(State* state, Expr* argv[], int count, ...) {
// zero or more Value** to put them in). If any expression evaluates
// to NULL, free the rest and return -1. Return 0 on success.
int ReadValueArgs(State* state, Expr* argv[], int count, ...) {
Value** args = malloc(count * sizeof(Value*));
Value** args = reinterpret_cast<Value**>(malloc(count * sizeof(Value*)));
va_list v;
va_start(v, count);
int i;
@@ -491,15 +498,29 @@ Value** ReadValueVarArgs(State* state, int argc, Expr* argv[]) {
return args;
}
// Use printf-style arguments to compose an error message to put into
// *state. Returns NULL.
Value* ErrorAbort(State* state, const char* format, ...) {
char* buffer = malloc(4096);
va_list v;
va_start(v, format);
vsnprintf(buffer, 4096, format, v);
va_end(v);
static void ErrorAbortV(State* state, const char* format, va_list ap) {
std::string buffer;
android::base::StringAppendV(&buffer, format, ap);
free(state->errmsg);
state->errmsg = buffer;
return NULL;
state->errmsg = strdup(buffer.c_str());
return;
}
// Use printf-style arguments to compose an error message to put into
// *state. Returns nullptr.
Value* ErrorAbort(State* state, const char* format, ...) {
va_list ap;
va_start(ap, format);
ErrorAbortV(state, format, ap);
va_end(ap);
return nullptr;
}
Value* ErrorAbort(State* state, CauseCode cause_code, const char* format, ...) {
va_list ap;
va_start(ap, format);
ErrorAbortV(state, format, ap);
va_end(ap);
state->cause_code = cause_code;
return nullptr;
}
+20 -10
View File
@@ -19,12 +19,9 @@
#include <unistd.h>
#include "error_code.h"
#include "yydefs.h"
#ifdef __cplusplus
extern "C" {
#endif
#define MAX_STRING_LEN 1024
typedef struct Expr Expr;
@@ -43,6 +40,17 @@ typedef struct {
// Should be NULL initially, will be either NULL or a malloc'd
// pointer after Evaluate() returns.
char* errmsg;
// error code indicates the type of failure (e.g. failure to update system image)
// during the OTA process.
ErrorCode error_code = kNoError;
// cause code provides more detailed reason of an OTA failure (e.g. fsync error)
// in addition to the error code.
CauseCode cause_code = kNoCause;
bool is_retry = false;
} State;
#define VAL_STRING 1 // data will be NULL-terminated; size doesn't count null
@@ -59,7 +67,7 @@ typedef Value* (*Function)(const char* name, State* state,
struct Expr {
Function fn;
char* name;
const char* name;
int argc;
Expr** argv;
int start, end;
@@ -156,7 +164,13 @@ Value** ReadValueVarArgs(State* state, int argc, Expr* argv[]);
// Use printf-style arguments to compose an error message to put into
// *state. Returns NULL.
Value* ErrorAbort(State* state, const char* format, ...) __attribute__((format(printf, 2, 3)));
Value* ErrorAbort(State* state, const char* format, ...)
__attribute__((format(printf, 2, 3), deprecated));
// ErrorAbort has an optional (but recommended) argument 'cause_code'. If the cause code
// is set, it will be logged into last_install and provides reason of OTA failures.
Value* ErrorAbort(State* state, CauseCode cause_code, const char* format, ...)
__attribute__((format(printf, 3, 4)));
// Wrap a string into a Value, taking ownership of the string.
Value* StringValue(char* str);
@@ -166,8 +180,4 @@ void FreeValue(Value* v);
int parse_string(const char* str, Expr** root, int* error_count);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // _EXPRESSION_H
+11 -13
View File
@@ -16,6 +16,7 @@
*/
#include <string.h>
#include <string>
#include "expr.h"
#include "yydefs.h"
@@ -25,9 +26,7 @@ int gLine = 1;
int gColumn = 1;
int gPos = 0;
// TODO: enforce MAX_STRING_LEN during lexing
char string_buffer[MAX_STRING_LEN];
char* string_pos;
std::string string_buffer;
#define ADVANCE do {yylloc.start=gPos; yylloc.end=gPos+yyleng; \
gColumn+=yyleng; gPos+=yyleng;} while(0)
@@ -43,7 +42,7 @@ char* string_pos;
\" {
BEGIN(STR);
string_pos = string_buffer;
string_buffer.clear();
yylloc.start = gPos;
++gColumn;
++gPos;
@@ -54,36 +53,35 @@ char* string_pos;
++gColumn;
++gPos;
BEGIN(INITIAL);
*string_pos = '\0';
yylval.str = strdup(string_buffer);
yylval.str = strdup(string_buffer.c_str());
yylloc.end = gPos;
return STRING;
}
\\n { gColumn += yyleng; gPos += yyleng; *string_pos++ = '\n'; }
\\t { gColumn += yyleng; gPos += yyleng; *string_pos++ = '\t'; }
\\\" { gColumn += yyleng; gPos += yyleng; *string_pos++ = '\"'; }
\\\\ { gColumn += yyleng; gPos += yyleng; *string_pos++ = '\\'; }
\\n { gColumn += yyleng; gPos += yyleng; string_buffer.push_back('\n'); }
\\t { gColumn += yyleng; gPos += yyleng; string_buffer.push_back('\t'); }
\\\" { gColumn += yyleng; gPos += yyleng; string_buffer.push_back('\"'); }
\\\\ { gColumn += yyleng; gPos += yyleng; string_buffer.push_back('\\'); }
\\x[0-9a-fA-F]{2} {
gColumn += yyleng;
gPos += yyleng;
int val;
sscanf(yytext+2, "%x", &val);
*string_pos++ = val;
string_buffer.push_back(static_cast<char>(val));
}
\n {
++gLine;
++gPos;
gColumn = 1;
*string_pos++ = yytext[0];
string_buffer.push_back(yytext[0]);
}
. {
++gColumn;
++gPos;
*string_pos++ = yytext[0];
string_buffer.push_back(yytext[0]);
}
}
+5
View File
@@ -18,6 +18,8 @@
#include <stdlib.h>
#include <string.h>
#include <string>
#include "expr.h"
#include "parser.h"
@@ -151,6 +153,9 @@ int test() {
expect("greater_than_int(x, 3)", "", &errors);
expect("greater_than_int(3, x)", "", &errors);
// big string
expect(std::string(8192, 's').c_str(), std::string(8192, 's').c_str(), &errors);
printf("\n");
return errors;
+4 -4
View File
@@ -70,7 +70,7 @@ input: expr { *root = $1; }
;
expr: STRING {
$$ = malloc(sizeof(Expr));
$$ = reinterpret_cast<Expr*>(malloc(sizeof(Expr)));
$$->fn = Literal;
$$->name = $1;
$$->argc = 0;
@@ -91,7 +91,7 @@ expr: STRING {
| IF expr THEN expr ENDIF { $$ = Build(IfElseFn, @$, 2, $2, $4); }
| IF expr THEN expr ELSE expr ENDIF { $$ = Build(IfElseFn, @$, 3, $2, $4, $6); }
| STRING '(' arglist ')' {
$$ = malloc(sizeof(Expr));
$$ = reinterpret_cast<Expr*>(malloc(sizeof(Expr)));
$$->fn = FindFunction($1);
if ($$->fn == NULL) {
char buffer[256];
@@ -113,12 +113,12 @@ arglist: /* empty */ {
}
| expr {
$$.argc = 1;
$$.argv = malloc(sizeof(Expr*));
$$.argv = reinterpret_cast<Expr**>(malloc(sizeof(Expr*)));
$$.argv[0] = $1;
}
| arglist ',' expr {
$$.argc = $1.argc + 1;
$$.argv = realloc($$.argv, $$.argc * sizeof(Expr*));
$$.argv = reinterpret_cast<Expr**>(realloc($$.argv, $$.argc * sizeof(Expr*)));
$$.argv[$$.argc-1] = $3;
}
;
+46
View File
@@ -0,0 +1,46 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _ERROR_CODE_H_
#define _ERROR_CODE_H_
enum ErrorCode {
kNoError = -1,
kLowBattery = 20,
kZipVerificationFailure,
kZipOpenFailure
};
enum CauseCode {
kNoCause = -1,
kArgsParsingFailure = 100,
kStashCreationFailure,
kFileOpenFailure,
kLseekFailure,
kFreadFailure,
kFwriteFailure,
kFsyncFailure,
kLibfecFailure,
kFileGetPropFailure,
kFileRenameFailure,
kSymlinkFailure,
kSetMetadataFailure,
kTune2FsFailure,
kRebootFailure,
kVendorFailure = 200
};
#endif
+10
View File
@@ -10,6 +10,9 @@ on early-init
# This should occur before anything else (e.g. ueventd) is started.
setcon u:r:init:s0
# Set the security context of /postinstall if present.
restorecon /postinstall
start ueventd
start healthd
@@ -20,6 +23,7 @@ service set_permissive /sbin/permissive.sh
on init
export PATH /sbin:/system/bin
export LD_LIBRARY_PATH .:/sbin
export ANDROID_ROOT /system
export ANDROID_DATA /data
export EXTERNAL_STORAGE /sdcard
@@ -77,6 +81,11 @@ on late-init
# Load properties, pre-Android 6.0
trigger load_all_props_action
# Load properties from /system/ + /factory after fs mount. Place
# this in another action so that the load will be scheduled after the prior
# issued fs triggers have completed.
trigger load_system_props_action
# Load properties, Android 6.0+
trigger load_system_props_action
@@ -101,6 +110,7 @@ service healthd /sbin/healthd -r
seclabel u:r:healthd:s0
service recovery /sbin/recovery
seclabel u:r:recovery:s0
service adbd /sbin/adbd --root_seclabel=u:r:su:s0 --device_banner=recovery
disabled
@@ -18,7 +18,6 @@
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -34,7 +33,7 @@ struct file_data {
};
static int read_block_file(void* cookie, uint32_t block, uint8_t* buffer, uint32_t fetch_size) {
struct file_data* fd = (struct file_data*)cookie;
file_data* fd = reinterpret_cast<file_data*>(cookie);
off64_t offset = ((off64_t) block) * fd->block_size;
if (TEMP_FAILURE_RETRY(lseek64(fd->fd, offset, SEEK_SET)) == -1) {
@@ -56,85 +55,34 @@ static int read_block_file(void* cookie, uint32_t block, uint8_t* buffer, uint32
}
static void close_file(void* cookie) {
struct file_data* fd = (struct file_data*)cookie;
file_data* fd = reinterpret_cast<file_data*>(cookie);
close(fd->fd);
}
struct token {
pthread_t th;
const char* path;
int result;
};
static void* run_sdcard_fuse(void* cookie) {
struct token* t = (struct token*)cookie;
bool start_sdcard_fuse(const char* path) {
struct stat sb;
if (stat(t->path, &sb) < 0) {
fprintf(stderr, "failed to stat %s: %s\n", t->path, strerror(errno));
t->result = -1;
return NULL;
if (stat(path, &sb) == -1) {
fprintf(stderr, "failed to stat %s: %s\n", path, strerror(errno));
return false;
}
struct file_data fd;
struct provider_vtab vtab;
fd.fd = open(t->path, O_RDONLY);
if (fd.fd < 0) {
fprintf(stderr, "failed to open %s: %s\n", t->path, strerror(errno));
t->result = -1;
return NULL;
file_data fd;
fd.fd = open(path, O_RDONLY);
if (fd.fd == -1) {
fprintf(stderr, "failed to open %s: %s\n", path, strerror(errno));
return false;
}
fd.file_size = sb.st_size;
fd.block_size = 65536;
provider_vtab vtab;
vtab.read_block = read_block_file;
vtab.close = close_file;
t->result = run_fuse_sideload(&vtab, &fd, fd.file_size, fd.block_size);
return NULL;
}
// How long (in seconds) we wait for the fuse-provided package file to
// appear, before timing out.
#define SDCARD_INSTALL_TIMEOUT 10
void* start_sdcard_fuse(const char* path) {
struct token* t = malloc(sizeof(struct token));
t->path = path;
pthread_create(&(t->th), NULL, run_sdcard_fuse, t);
struct stat st;
int i;
for (i = 0; i < SDCARD_INSTALL_TIMEOUT; ++i) {
if (stat(FUSE_SIDELOAD_HOST_PATHNAME, &st) != 0) {
if (errno == ENOENT && i < SDCARD_INSTALL_TIMEOUT-1) {
sleep(1);
continue;
} else {
return NULL;
}
}
}
// The installation process expects to find the sdcard unmounted.
// Unmount it with MNT_DETACH so that our open file continues to
// work but new references see it as unmounted.
umount2("/sdcard", MNT_DETACH);
return t;
}
void finish_sdcard_fuse(void* cookie) {
if (cookie == NULL) return;
struct token* t = (struct token*)cookie;
// Calling stat() on this magic filename signals the fuse
// filesystem to shut down.
struct stat st;
stat(FUSE_SIDELOAD_HOST_EXIT_PATHNAME, &st);
pthread_join(t->th, NULL);
free(t);
return run_fuse_sideload(&vtab, &fd, fd.file_size, fd.block_size) == 0;
}
+1 -8
View File
@@ -17,13 +17,6 @@
#ifndef __FUSE_SDCARD_PROVIDER_H
#define __FUSE_SDCARD_PROVIDER_H
#include <sys/cdefs.h>
__BEGIN_DECLS
void* start_sdcard_fuse(const char* path);
void finish_sdcard_fuse(void* token);
__END_DECLS
bool start_sdcard_fuse(const char* path);
#endif
+16 -15
View File
@@ -61,7 +61,8 @@
#include <sys/uio.h>
#include <unistd.h>
#include "mincrypt/sha256.h"
#include <openssl/sha.h>
#include "fuse_sideload.h"
#define PACKAGE_FILE_ID (FUSE_ROOT_ID+1)
@@ -120,7 +121,7 @@ static void fuse_reply(struct fuse_data* fd, __u64 unique, const void *data, siz
}
static int handle_init(void* data, struct fuse_data* fd, const struct fuse_in_header* hdr) {
const struct fuse_init_in* req = data;
const struct fuse_init_in* req = reinterpret_cast<const struct fuse_init_in*>(data);
struct fuse_init_out out;
size_t fuse_struct_size;
@@ -174,7 +175,7 @@ static void fill_attr(struct fuse_attr* attr, struct fuse_data* fd,
attr->mode = mode;
}
static int handle_getattr(void* data, struct fuse_data* fd, const struct fuse_in_header* hdr) {
static int handle_getattr(void* /* data */, struct fuse_data* fd, const struct fuse_in_header* hdr) {
struct fuse_attr_out out;
memset(&out, 0, sizeof(out));
out.attr_valid = 10;
@@ -200,12 +201,12 @@ static int handle_lookup(void* data, struct fuse_data* fd,
out.entry_valid = 10;
out.attr_valid = 10;
if (strncmp(FUSE_SIDELOAD_HOST_FILENAME, data,
if (strncmp(FUSE_SIDELOAD_HOST_FILENAME, reinterpret_cast<const char*>(data),
sizeof(FUSE_SIDELOAD_HOST_FILENAME)) == 0) {
out.nodeid = PACKAGE_FILE_ID;
out.generation = PACKAGE_FILE_ID;
fill_attr(&(out.attr), fd, PACKAGE_FILE_ID, fd->file_size, S_IFREG | 0444);
} else if (strncmp(FUSE_SIDELOAD_HOST_EXIT_FLAG, data,
} else if (strncmp(FUSE_SIDELOAD_HOST_EXIT_FLAG, reinterpret_cast<const char*>(data),
sizeof(FUSE_SIDELOAD_HOST_EXIT_FLAG)) == 0) {
out.nodeid = EXIT_FLAG_ID;
out.generation = EXIT_FLAG_ID;
@@ -218,7 +219,7 @@ static int handle_lookup(void* data, struct fuse_data* fd,
return (out.nodeid == EXIT_FLAG_ID) ? NO_STATUS_EXIT : NO_STATUS;
}
static int handle_open(void* data, struct fuse_data* fd, const struct fuse_in_header* hdr) {
static int handle_open(void* /* data */, struct fuse_data* fd, const struct fuse_in_header* hdr) {
if (hdr->nodeid == EXIT_FLAG_ID) return -EPERM;
if (hdr->nodeid != PACKAGE_FILE_ID) return -ENOENT;
@@ -273,27 +274,27 @@ static int fetch_block(struct fuse_data* fd, uint32_t block) {
// block).
// - Otherwise, return -EINVAL for the read.
uint8_t hash[SHA256_DIGEST_SIZE];
SHA256_hash(fd->block_data, fd->block_size, hash);
uint8_t* blockhash = fd->hashes + block * SHA256_DIGEST_SIZE;
if (memcmp(hash, blockhash, SHA256_DIGEST_SIZE) == 0) {
uint8_t hash[SHA256_DIGEST_LENGTH];
SHA256(fd->block_data, fd->block_size, hash);
uint8_t* blockhash = fd->hashes + block * SHA256_DIGEST_LENGTH;
if (memcmp(hash, blockhash, SHA256_DIGEST_LENGTH) == 0) {
return 0;
}
int i;
for (i = 0; i < SHA256_DIGEST_SIZE; ++i) {
for (i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
if (blockhash[i] != 0) {
fd->curr_block = -1;
return -EIO;
}
}
memcpy(blockhash, hash, SHA256_DIGEST_SIZE);
memcpy(blockhash, hash, SHA256_DIGEST_LENGTH);
return 0;
}
static int handle_read(void* data, struct fuse_data* fd, const struct fuse_in_header* hdr) {
const struct fuse_read_in* req = data;
const struct fuse_read_in* req = reinterpret_cast<const struct fuse_read_in*>(data);
struct fuse_out_header outhdr;
struct iovec vec[3];
int vec_used;
@@ -397,10 +398,10 @@ int run_fuse_sideload(struct provider_vtab* vtab, void* cookie,
goto done;
}
fd.hashes = (uint8_t*)calloc(fd.file_blocks, SHA256_DIGEST_SIZE);
fd.hashes = (uint8_t*)calloc(fd.file_blocks, SHA256_DIGEST_LENGTH);
if (fd.hashes == NULL) {
fprintf(stderr, "failed to allocate %d bites for hashes\n",
fd.file_blocks * SHA256_DIGEST_SIZE);
fd.file_blocks * SHA256_DIGEST_LENGTH);
result = -1;
goto done;
}
-6
View File
@@ -17,10 +17,6 @@
#ifndef __FUSE_SIDELOAD_H
#define __FUSE_SIDELOAD_H
#include <sys/cdefs.h>
__BEGIN_DECLS
// define the filenames created by the sideload FUSE filesystem
#define FUSE_SIDELOAD_HOST_MOUNTPOINT "/sideload"
#define FUSE_SIDELOAD_HOST_FILENAME "package.zip"
@@ -39,6 +35,4 @@ struct provider_vtab {
int run_fuse_sideload(struct provider_vtab* vtab, void* cookie,
uint64_t file_size, uint32_t block_size);
__END_DECLS
#endif
+1 -1
View File
@@ -38,7 +38,7 @@ else
LOCAL_SRC_FILES += hardwarekeyboard.cpp
endif
LOCAL_SHARED_LIBRARIES += libminuitwrp libc libstdc++ libminzip libaosprecovery
LOCAL_SHARED_LIBRARIES += libminuitwrp libc libstdc++ libminzip libaosprecovery libselinux
LOCAL_MODULE := libguitwrp
#TWRP_EVENT_LOGGING := true
+121 -25
View File
@@ -23,22 +23,31 @@
#include <sys/wait.h>
#include <unistd.h>
#include <chrono>
#include <string>
#include <vector>
#include <android-base/parseint.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include "common.h"
#include "error_code.h"
#include "install.h"
#include "mincrypt/rsa.h"
#include "minui/minui.h"
#include "minzip/SysUtil.h"
#include "minzip/Zip.h"
#include "mtdutils/mounts.h"
#include "mtdutils/mtdutils.h"
#include "roots.h"
#include "verifier.h"
#include "ui.h"
#include "verifier.h"
extern RecoveryUI* ui;
#define ASSUMED_UPDATE_BINARY_NAME "META-INF/com/google/android/update-binary"
#define PUBLIC_KEYS_FILE "/res/keys"
static constexpr const char* METADATA_PATH = "META-INF/com/android/metadata";
// Default allocation of progress bar segments to operations
static const int VERIFICATION_PROGRESS_TIME = 60;
@@ -46,9 +55,64 @@ static const float VERIFICATION_PROGRESS_FRACTION = 0.25;
static const float DEFAULT_FILES_PROGRESS_FRACTION = 0.4;
static const float DEFAULT_IMAGE_PROGRESS_FRACTION = 0.1;
// This function parses and returns the build.version.incremental
static int parse_build_number(std::string str) {
size_t pos = str.find("=");
if (pos != std::string::npos) {
std::string num_string = android::base::Trim(str.substr(pos+1));
int build_number;
if (android::base::ParseInt(num_string.c_str(), &build_number, 0)) {
return build_number;
}
}
LOGE("Failed to parse build number in %s.\n", str.c_str());
return -1;
}
// Read the build.version.incremental of src/tgt from the metadata and log it to last_install.
static void read_source_target_build(ZipArchive* zip, std::vector<std::string>& log_buffer) {
const ZipEntry* meta_entry = mzFindZipEntry(zip, METADATA_PATH);
if (meta_entry == nullptr) {
LOGE("Failed to find %s in update package.\n", METADATA_PATH);
return;
}
std::string meta_data(meta_entry->uncompLen, '\0');
if (!mzReadZipEntry(zip, meta_entry, &meta_data[0], meta_entry->uncompLen)) {
LOGE("Failed to read metadata in update package.\n");
return;
}
// Examples of the pre-build and post-build strings in metadata:
// pre-build-incremental=2943039
// post-build-incremental=2951741
std::vector<std::string> lines = android::base::Split(meta_data, "\n");
for (const std::string& line : lines) {
std::string str = android::base::Trim(line);
if (android::base::StartsWith(str, "pre-build-incremental")){
int source_build = parse_build_number(str);
if (source_build != -1) {
log_buffer.push_back(android::base::StringPrintf("source_build: %d",
source_build));
}
} else if (android::base::StartsWith(str, "post-build-incremental")) {
int target_build = parse_build_number(str);
if (target_build != -1) {
log_buffer.push_back(android::base::StringPrintf("target_build: %d",
target_build));
}
}
}
}
// If the package contains an update binary, extract it and run it.
static int
try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache) {
try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache,
std::vector<std::string>& log_buffer, int retry_count)
{
read_source_target_build(zip, log_buffer);
const ZipEntry* binary_entry =
mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME);
if (binary_entry == NULL) {
@@ -121,15 +185,19 @@ try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache) {
//
// - the name of the package zip file.
//
// - an optional argument "retry" if this update is a retry of a failed
// update attempt.
//
const char** args = (const char**)malloc(sizeof(char*) * 5);
const char** args = (const char**)malloc(sizeof(char*) * 6);
args[0] = binary;
args[1] = EXPAND(RECOVERY_API_VERSION); // defined in Android.mk
char* temp = (char*)malloc(10);
sprintf(temp, "%d", pipefd[1]);
args[2] = temp;
args[3] = (char*)path;
args[4] = NULL;
args[4] = retry_count > 0 ? "retry" : NULL;
args[5] = NULL;
pid_t pid = fork();
if (pid == 0) {
@@ -142,6 +210,7 @@ try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache) {
close(pipefd[1]);
*wipe_cache = false;
bool retry_update = false;
char buffer[1024];
FILE* from_child = fdopen(pipefd[0], "r");
@@ -164,9 +233,9 @@ try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache) {
} else if (strcmp(command, "ui_print") == 0) {
char* str = strtok(NULL, "\n");
if (str) {
ui->Print("%s", str);
ui->PrintOnScreenOnly("%s", str);
} else {
ui->Print("\n");
ui->PrintOnScreenOnly("\n");
}
fflush(stdout);
} else if (strcmp(command, "wipe_cache") == 0) {
@@ -178,6 +247,12 @@ try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache) {
// to be able to reboot during installation (useful for
// debugging packages that don't exit).
ui->SetEnableReboot(true);
} else if (strcmp(command, "retry_update") == 0) {
retry_update = true;
} else if (strcmp(command, "log") == 0) {
// Save the logging request from updater and write to
// last_install later.
log_buffer.push_back(std::string(strtok(NULL, "\n")));
} else {
LOGE("unknown command [%s]\n", command);
}
@@ -186,6 +261,9 @@ try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache) {
int status;
waitpid(pid, &status, 0);
if (retry_update) {
return INSTALL_RETRY;
}
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
LOGE("Error in %s\n(Status %d)\n", path, WEXITSTATUS(status));
return INSTALL_ERROR;
@@ -195,7 +273,8 @@ try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache) {
}
static int
really_install_package(const char *path, bool* wipe_cache, bool needs_mount)
really_install_package(const char *path, bool* wipe_cache, bool needs_mount,
std::vector<std::string>& log_buffer, int retry_count)
{
ui->SetBackground(RecoveryUI::INSTALLING_UPDATE);
ui->Print("Finding update package...\n");
@@ -221,41 +300,46 @@ really_install_package(const char *path, bool* wipe_cache, bool needs_mount)
return INSTALL_CORRUPT;
}
int numKeys;
Certificate* loadedKeys = load_keys(PUBLIC_KEYS_FILE, &numKeys);
if (loadedKeys == NULL) {
// Load keys.
std::vector<Certificate> loadedKeys;
if (!load_keys(PUBLIC_KEYS_FILE, loadedKeys)) {
LOGE("Failed to load keys\n");
return INSTALL_CORRUPT;
}
LOGI("%d key(s) loaded from %s\n", numKeys, PUBLIC_KEYS_FILE);
LOGI("%zu key(s) loaded from %s\n", loadedKeys.size(), PUBLIC_KEYS_FILE);
// Verify package.
ui->Print("Verifying update package...\n");
int err;
err = verify_file(map.addr, map.length);
free(loadedKeys);
LOGI("verify_file returned %d\n", err);
auto t0 = std::chrono::system_clock::now();
int err = verify_file(map.addr, map.length, loadedKeys);
std::chrono::duration<double> duration = std::chrono::system_clock::now() - t0;
ui->Print("Update package verification took %.1f s (result %d).\n", duration.count(), err);
if (err != VERIFY_SUCCESS) {
LOGE("signature verification failed\n");
log_buffer.push_back(android::base::StringPrintf("error: %d", kZipVerificationFailure));
sysReleaseMap(&map);
return INSTALL_CORRUPT;
}
/* Try to open the package.
*/
// Try to open the package.
ZipArchive zip;
err = mzOpenZipArchive(map.addr, map.length, &zip);
if (err != 0) {
LOGE("Can't open %s\n(%s)\n", path, err != -1 ? strerror(err) : "bad");
log_buffer.push_back(android::base::StringPrintf("error: %d", kZipOpenFailure));
sysReleaseMap(&map);
return INSTALL_CORRUPT;
}
/* Verify and install the contents of the package.
*/
// Verify and install the contents of the package.
ui->Print("Installing update...\n");
if (retry_count > 0) {
ui->Print("Retry attempt: %d\n", retry_count);
}
ui->SetEnableReboot(false);
int result = try_update_binary(path, &zip, wipe_cache);
int result = try_update_binary(path, &zip, wipe_cache, log_buffer, retry_count);
ui->SetEnableReboot(true);
ui->Print("\n");
@@ -266,9 +350,10 @@ really_install_package(const char *path, bool* wipe_cache, bool needs_mount)
int
install_package(const char* path, bool* wipe_cache, const char* install_file,
bool needs_mount)
bool needs_mount, int retry_count)
{
modified_flash = true;
auto start = std::chrono::system_clock::now();
FILE* install_log = fopen_path(install_file, "w");
if (install_log) {
@@ -278,15 +363,26 @@ install_package(const char* path, bool* wipe_cache, const char* install_file,
LOGE("failed to open last_install: %s\n", strerror(errno));
}
int result;
std::vector<std::string> log_buffer;
if (setup_install_mounts() != 0) {
LOGE("failed to set up expected mounts for install; aborting\n");
result = INSTALL_ERROR;
} else {
result = really_install_package(path, wipe_cache, needs_mount);
result = really_install_package(path, wipe_cache, needs_mount, log_buffer, retry_count);
}
if (install_log) {
if (install_log != nullptr) {
fputc(result == INSTALL_SUCCESS ? '1' : '0', install_log);
fputc('\n', install_log);
std::chrono::duration<double> duration = std::chrono::system_clock::now() - start;
int count = static_cast<int>(duration.count());
// Report the time spent to apply OTA update in seconds.
fprintf(install_log, "time_total: %d\n", count);
fprintf(install_log, "retry: %d\n", retry_count);
for (const auto& s : log_buffer) {
fprintf(install_log, "%s\n", s.c_str());
}
fclose(install_log);
}
return result;
+5 -3
View File
@@ -24,12 +24,14 @@
extern "C" {
#endif
enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT, INSTALL_NONE };
enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT, INSTALL_NONE, INSTALL_SKIPPED,
INSTALL_RETRY };
// 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.
int install_package(const char* root_path, bool* wipe_cache,
const char* install_file, bool needs_mount);
int install_package(const char* root_path, bool* wipe_cache, const char* install_file,
bool needs_mount, int retry_count);
RSAPublicKey* load_keys(const char* filename, int* numKeys);
#ifdef __cplusplus
Regular → Executable
+85 -24
View File
@@ -1,3 +1,4 @@
#!/usr/bin/env python
# Copyright (C) 2014 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,42 +13,102 @@
# See the License for the specific language governing permissions and
# limitations under the License.
"""Script to take a set of frames (PNG files) for a recovery animation
"""
Script to take a set of frames (PNG files) for a recovery animation
and turn it into a single output image which contains the input frames
interlaced by row. Run with the names of all the input frames on the
command line, in order, followed by the name of the output file."""
command line, in order, followed by the name of the output file.
"""
from __future__ import print_function
import argparse
import os.path
import sys
try:
import Image
import PngImagePlugin
except ImportError:
print "This script requires the Python Imaging Library to be installed."
print("This script requires the Python Imaging Library to be installed.")
sys.exit(1)
frames = [Image.open(fn).convert("RGB") for fn in sys.argv[1:-1]]
assert len(frames) > 0, "Must have at least one input frame."
sizes = set()
for fr in frames:
sizes.add(fr.size)
assert len(sizes) == 1, "All input images must have the same size."
w, h = sizes.pop()
N = len(frames)
def interlace(output, inputs):
frames = [Image.open(fn).convert("RGB") for fn in inputs]
assert len(frames) > 0, "Must have at least one input frame."
sizes = set()
for fr in frames:
sizes.add(fr.size)
out = Image.new("RGB", (w, h*N))
for j in range(h):
for i in range(w):
for fn, f in enumerate(frames):
out.putpixel((i, j*N+fn), f.getpixel((i, j)))
assert len(sizes) == 1, "All input images must have the same size."
w, h = sizes.pop()
N = len(frames)
# When loading this image, the graphics library expects to find a text
# chunk that specifies how many frames this animation represents. If
# you post-process the output of this script with some kind of
# optimizer tool (eg pngcrush or zopflipng) make sure that your
# optimizer preserves this text chunk.
out = Image.new("RGB", (w, h*N))
for j in range(h):
for i in range(w):
for fn, f in enumerate(frames):
out.putpixel((i, j*N+fn), f.getpixel((i, j)))
meta = PngImagePlugin.PngInfo()
meta.add_text("Frames", str(N))
# When loading this image, the graphics library expects to find a text
# chunk that specifies how many frames this animation represents. If
# you post-process the output of this script with some kind of
# optimizer tool (eg pngcrush or zopflipng) make sure that your
# optimizer preserves this text chunk.
out.save(sys.argv[-1], pnginfo=meta)
meta = PngImagePlugin.PngInfo()
meta.add_text("Frames", str(N))
out.save(output, pnginfo=meta)
def deinterlace(output, input):
# Truncate the output filename extension if it's '.png'.
if os.path.splitext(output)[1].lower() == '.png':
output = output[:-4]
img2 = Image.open(input)
print(img2.mode)
palette = img2.getpalette()
img = img2.convert("RGB")
num_frames = int(img.info.get('Frames', 1))
print('Found %d frames in %s.' % (num_frames, input))
assert num_frames > 0, 'Invalid Frames meta.'
# palette = img.getpalette()
print(palette)
width, height = img.size
height /= num_frames
for k in range(num_frames):
out = Image.new('RGB', (width, height))
out.info = img.info
for i in range(width):
for j in range(height):
out.putpixel((i, j), img.getpixel((i, j * num_frames + k)))
# out.putpalette(img.getpalette(), rawmode='RGB')
out2 = out.convert(mode='P', palette=palette)
#out2 = out
print(out2.mode)
# out2.putpalette(palette)
filename = '%s%02d.png' % (output, k)
out2.save(filename)
print('Frame %d written to %s.' % (k, filename))
def main(argv):
parser = argparse.ArgumentParser(description='Parse')
parser.add_argument('--deinterlace', '-d', action='store_true')
parser.add_argument('--output', '-o', required=True)
parser.add_argument('input', nargs='+')
args = parser.parse_args(argv)
if args.deinterlace:
# args.input is a list, and we only process the first when deinterlacing.
deinterlace(args.output, args.input[0])
else:
interlace(args.output, args.input)
if __name__ == '__main__':
main(sys.argv[1:])
+1 -2
View File
@@ -1254,8 +1254,7 @@ done:
/* same sa blkid_probe_get_buffer() but works with 512-sectors */
unsigned char *blkid_probe_get_sector(blkid_probe pr, unsigned int sector)
{
return pr ? blkid_probe_get_buffer(pr,
((blkid_loff_t) sector) << 9, 0x200) : NULL;
return blkid_probe_get_buffer(pr, ((blkid_loff_t) sector) << 9, 0x200);
}
struct blkid_prval *blkid_probe_assign_value(
+2 -2
View File
@@ -155,7 +155,7 @@ int blkid_set_tag(blkid_dev dev, const char *name,
/* Existing tag not present, add to device */
if (!(t = blkid_new_tag()))
goto errout;
t->bit_name = name ? strdup(name) : NULL;
t->bit_name = strdup(name);
t->bit_val = val;
t->bit_dev = dev;
@@ -170,7 +170,7 @@ int blkid_set_tag(blkid_dev dev, const char *name,
goto errout;
DBG(TAG, ul_debug(" creating new cache tag head %s", name));
head->bit_name = name ? strdup(name) : NULL;
head->bit_name = strdup(name);
if (!head->bit_name)
goto errout;
list_add_tail(&head->bit_tags,
+3 -2
View File
@@ -14,14 +14,15 @@ LOCAL_SRC_FILES := \
adb_main.cpp \
fuse_adb_provider.cpp \
services.cpp \
../fuse_sideload.c
../fuse_sideload.cpp
LOCAL_CLANG := true
LOCAL_MODULE := libminadbd
LOCAL_CFLAGS := $(minadbd_cflags)
LOCAL_CONLY_FLAGS := -Wimplicit-function-declaration
LOCAL_C_INCLUDES := $(LOCAL_PATH)/.. system/core/adb
LOCAL_WHOLE_STATIC_LIBRARIES := libadbd
LOCAL_SHARED_LIBRARIES := libbase liblog libmincrypttwrp libcutils libc
LOCAL_SHARED_LIBRARIES := libbase liblog libcutils libc libcrypto
include $(BUILD_SHARED_LIBRARY)
+2 -8
View File
@@ -19,21 +19,15 @@
#include <stdio.h>
#include <stdlib.h>
#define TRACE_TAG TRACE_ADB
#include "sysdeps.h"
#include "adb.h"
#include "adb_auth.h"
#include "transport.h"
int adb_main(int is_daemon, int server_port)
{
atexit(usb_cleanup);
int adb_server_main(int is_daemon, int server_port, int /* reply_fd */) {
adb_device_banner = "sideload";
// No SIGCHLD. Let the service subproc handle its children.
signal(SIGPIPE, SIG_IGN);
// We can't require authentication for sideloading. http://b/22025550.
@@ -42,7 +36,7 @@ int adb_main(int is_daemon, int server_port)
init_transport_registration();
usb_init();
D("Event loop starting\n");
VLOG(ADB) << "Event loop starting";
fdevent_loop();
return 0;
+9 -11
View File
@@ -23,7 +23,6 @@
#include "sysdeps.h"
#define TRACE_TAG TRACE_SERVICES
#include "adb.h"
#include "fdevent.h"
#include "fuse_adb_provider.h"
@@ -36,21 +35,21 @@ struct stinfo {
void *cookie;
};
void* service_bootstrap_func(void* x) {
void service_bootstrap_func(void* x) {
stinfo* sti = reinterpret_cast<stinfo*>(x);
sti->func(sti->fd, sti->cookie);
free(sti);
return 0;
}
static void sideload_host_service(int sfd, void* data) {
const char* args = reinterpret_cast<const char*>(data);
char* args = reinterpret_cast<char*>(data);
int file_size;
int block_size;
if (sscanf(args, "%d:%d", &file_size, &block_size) != 2) {
printf("bad sideload-host arguments: %s\n", args);
exit(1);
}
free(args);
printf("sideload-host file size %d block size %d\n", file_size, block_size);
@@ -61,8 +60,7 @@ static void sideload_host_service(int sfd, void* data) {
exit(result == 0 ? 0 : 1);
}
static int create_service_thread(void (*func)(int, void *), void *cookie)
{
static int create_service_thread(void (*func)(int, void *), void *cookie) {
int s[2];
if(adb_socketpair(s)) {
printf("cannot create service socket pair\n");
@@ -75,8 +73,7 @@ static int create_service_thread(void (*func)(int, void *), void *cookie)
sti->cookie = cookie;
sti->fd = s[1];
adb_thread_t t;
if (adb_thread_create( &t, service_bootstrap_func, sti)){
if (!adb_thread_create(service_bootstrap_func, sti)) {
free(sti);
adb_close(s[0]);
adb_close(s[1]);
@@ -84,11 +81,11 @@ static int create_service_thread(void (*func)(int, void *), void *cookie)
return -1;
}
D("service thread started, %d:%d\n",s[0], s[1]);
VLOG(SERVICES) << "service thread started, " << s[0] << ":" << s[1];
return s[0];
}
int service_to_fd(const char* name) {
int service_to_fd(const char* name, const atransport* transport) {
int ret = -1;
if (!strncmp(name, "sideload:", 9)) {
@@ -97,7 +94,8 @@ int service_to_fd(const char* name) {
// sideload-host).
exit(3);
} else if (!strncmp(name, "sideload-host:", 14)) {
ret = create_service_thread(sideload_host_service, (void*)(name + 14));
char* arg = strdup(name + 14);
ret = create_service_thread(sideload_host_service, arg);
}
if (ret >= 0) {
close_on_exec(ret);
+1
View File
@@ -83,6 +83,7 @@ include $(BUILD_STATIC_LIBRARY)
# Used by OEMs for factory test images.
include $(CLEAR_VARS)
LOCAL_CLANG := true
LOCAL_MODULE := libminui
LOCAL_WHOLE_STATIC_LIBRARIES += libminui
LOCAL_SHARED_LIBRARIES := libpng
-12
View File
@@ -190,18 +190,6 @@ static GRSurface* fbdev_init(minui_backend* backend) {
static GRSurface* fbdev_flip(minui_backend* backend __unused) {
if (double_buffered) {
#if defined(RECOVERY_BGRA)
// In case of BGRA, do some byte swapping
unsigned int idx;
unsigned char tmp;
unsigned char* ucfb_vaddr = (unsigned char*)gr_draw->data;
for (idx = 0 ; idx < (gr_draw->height * gr_draw->row_bytes);
idx += 4) {
tmp = ucfb_vaddr[idx];
ucfb_vaddr[idx ] = ucfb_vaddr[idx + 2];
ucfb_vaddr[idx + 2] = tmp;
}
#endif
// Change gr_draw to point to the buffer currently displayed,
// then flip the driver so we're displaying the other buffer
// instead.
+4 -2
View File
@@ -87,6 +87,8 @@ int ev_get_epollfd();
// Resources
//
bool matches_locale(const char* prefix, const char* locale);
// res_create_*_surface() functions return 0 if no error, else
// negative.
//
@@ -104,8 +106,8 @@ int res_create_display_surface(const char* name, GRSurface** pSurface);
// should have a 'Frames' text chunk whose value is the number of
// frames this image represents. The pixel data itself is interlaced
// by row.
int res_create_multi_display_surface(const char* name,
int* frames, GRSurface*** pSurface);
int res_create_multi_display_surface(const char* name, int* frames,
int* fps, GRSurface*** pSurface);
// Load a single alpha surface from a grayscale PNG image.
int res_create_alpha_surface(const char* name, GRSurface** pSurface);
+23 -21
View File
@@ -32,8 +32,6 @@
#include "minui.h"
extern char* locale;
#define SURFACE_DATA_ALIGNMENT 8
static GRSurface* malloc_surface(size_t data_size) {
@@ -237,14 +235,14 @@ int res_create_display_surface(const char* name, GRSurface** pSurface) {
return result;
}
int res_create_multi_display_surface(const char* name, int* frames, GRSurface*** pSurface) {
int res_create_multi_display_surface(const char* name, int* frames, int* fps,
GRSurface*** pSurface) {
GRSurface** surface = NULL;
int result = 0;
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
png_uint_32 width, height;
png_byte channels;
int i;
png_textp text;
int num_text;
unsigned char* p_row;
@@ -257,14 +255,23 @@ int res_create_multi_display_surface(const char* name, int* frames, GRSurface***
if (result < 0) return result;
*frames = 1;
*fps = 20;
if (png_get_text(png_ptr, info_ptr, &text, &num_text)) {
for (i = 0; i < num_text; ++i) {
for (int i = 0; i < num_text; ++i) {
if (text[i].key && strcmp(text[i].key, "Frames") == 0 && text[i].text) {
*frames = atoi(text[i].text);
break;
} else if (text[i].key && strcmp(text[i].key, "FPS") == 0 && text[i].text) {
*fps = atoi(text[i].text);
}
}
printf(" found frames = %d\n", *frames);
printf(" found fps = %d\n", *fps);
}
if (frames <= 0 || fps <= 0) {
printf("bad number of frames (%d) and/or FPS (%d)\n", *frames, *fps);
result = -10;
goto exit;
}
if (height % *frames != 0) {
@@ -278,7 +285,7 @@ int res_create_multi_display_surface(const char* name, int* frames, GRSurface***
result = -8;
goto exit;
}
for (i = 0; i < *frames; ++i) {
for (int i = 0; i < *frames; ++i) {
surface[i] = init_display_surface(width, height / *frames);
if (surface[i] == NULL) {
result = -8;
@@ -307,7 +314,7 @@ exit:
if (result < 0) {
if (surface) {
for (i = 0; i < *frames; ++i) {
for (int i = 0; i < *frames; ++i) {
if (surface[i]) free(surface[i]);
}
free(surface);
@@ -363,21 +370,16 @@ int res_create_alpha_surface(const char* name, GRSurface** pSurface) {
return result;
}
static int matches_locale(const char* loc, const char* locale) {
if (locale == NULL) return 0;
// This function tests if a locale string stored in PNG (prefix) matches
// the locale string provided by the system (locale).
bool matches_locale(const char* prefix, const char* locale) {
if (locale == NULL) return false;
if (strcmp(loc, locale) == 0) return 1;
// Return true if the whole string of prefix matches the top part of
// locale. For instance, prefix == "en" matches locale == "en_US";
// and prefix == "zh_CN" matches locale == "zh_CN_#Hans".
// 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] == '_');
return (strncmp(prefix, locale, strlen(prefix)) == 0);
}
int res_create_localized_alpha_surface(const char* name,
+10 -2
View File
@@ -22,9 +22,12 @@ LOCAL_CFLAGS += -DPLATFORM_SDK_VERSION=$(PLATFORM_SDK_VERSION)
LOCAL_MODULE := libminzip
LOCAL_CFLAGS += -Wall
LOCAL_SHARED_LIBRARIES += libz
LOCAL_CLANG := true
LOCAL_CFLAGS += -Werror -Wall
include $(BUILD_SHARED_LIBRARY)
@@ -47,9 +50,14 @@ LOCAL_STATIC_LIBRARIES += libselinux
LOCAL_CFLAGS += -DHAVE_SELINUX
endif
LOCAL_CFLAGS += -DPLATFORM_SDK_VERSION=$(PLATFORM_SDK_VERSION)
LOCAL_MODULE := libminzip
LOCAL_CFLAGS += -Wall
LOCAL_STATIC_LIBRARIES += libz
LOCAL_CLANG := true
LOCAL_CFLAGS += -Werror -Wall
include $(BUILD_STATIC_LIBRARY)
+2 -2
View File
@@ -361,7 +361,7 @@ void mzHashTableProbeCount(HashTable* pHashTable, HashCalcFunc calcFunc,
{
const void* data = (const void*)mzHashIterData(&iter);
int count;
count = countProbes(pHashTable, (*calcFunc)(data), data, cmpFunc);
numEntries++;
@@ -373,7 +373,7 @@ void mzHashTableProbeCount(HashTable* pHashTable, HashCalcFunc calcFunc,
totalProbe += count;
}
LOGI("Probe: min=%d max=%d, total=%d in %d (%d), avg=%.3f\n",
LOGV("Probe: min=%d max=%d, total=%d in %d (%d), avg=%.3f\n",
minProbe, maxProbe, totalProbe, numEntries, pHashTable->tableSize,
(float) totalProbe / (float) numEntries);
}
+8
View File
@@ -15,6 +15,10 @@
#include <stdbool.h>
#include <assert.h>
#ifdef __cplusplus
extern "C" {
#endif
/* compute the hash of an item with a specific type */
typedef unsigned int (*HashCompute)(const void* item);
@@ -183,4 +187,8 @@ typedef unsigned int (*HashCalcFunc)(const void* item);
void mzHashTableProbeCount(HashTable* pHashTable, HashCalcFunc calcFunc,
HashCompareFunc cmpFunc);
#ifdef __cplusplus
}
#endif
#endif /*_MINZIP_HASH*/
+77 -41
View File
@@ -3,17 +3,18 @@
*
* System utilities.
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <errno.h>
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define LOG_TAG "sysutil"
#include "Log.h"
@@ -57,8 +58,7 @@ static int getFileStartAndLength(int fd, loff_t *start_, size_t *length_)
* On success, returns 0 and fills out "pMap". On failure, returns a nonzero
* value and does not disturb "pMap".
*/
static int sysMapFD(int fd, MemMapping* pMap)
{
static bool sysMapFD(int fd, MemMapping* pMap) {
loff_t start;
size_t length;
void* memPtr;
@@ -75,19 +75,23 @@ static int sysMapFD(int fd, MemMapping* pMap)
memPtr = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, start);
#endif
if (memPtr == MAP_FAILED) {
LOGW("mmap(%d, R, PRIVATE, %d, %d) failed: %s\n", (int) length,
fd, (int) start, strerror(errno));
return -1;
LOGE("mmap(%d, R, PRIVATE, %d, 0) failed: %s\n", (int) length, fd, strerror(errno));
return false;
}
pMap->addr = memPtr;
pMap->length = length;
pMap->range_count = 1;
pMap->ranges = malloc(sizeof(MappedRange));
if (pMap->ranges == NULL) {
LOGE("malloc failed: %s\n", strerror(errno));
munmap(memPtr, length);
return false;
}
pMap->ranges[0].addr = memPtr;
pMap->ranges[0].length = length;
return 0;
return true;
}
static int sysMapBlockFile(FILE* mapf, MemMapping* pMap)
@@ -95,12 +99,12 @@ static int sysMapBlockFile(FILE* mapf, MemMapping* pMap)
char block_dev[PATH_MAX+1];
size_t size;
unsigned int blksize;
unsigned int blocks;
size_t blocks;
unsigned int range_count;
unsigned int i;
if (fgets(block_dev, sizeof(block_dev), mapf) == NULL) {
LOGW("failed to read block device from header\n");
LOGE("failed to read block device from header\n");
return -1;
}
for (i = 0; i < sizeof(block_dev); ++i) {
@@ -111,15 +115,24 @@ static int sysMapBlockFile(FILE* mapf, MemMapping* pMap)
}
if (fscanf(mapf, "%zu %u\n%u\n", &size, &blksize, &range_count) != 3) {
LOGW("failed to parse block map header\n");
LOGE("failed to parse block map header\n");
return -1;
}
if (blksize != 0) {
blocks = ((size-1) / blksize) + 1;
}
if (size == 0 || blksize == 0 || blocks > SIZE_MAX / blksize || range_count == 0) {
LOGE("invalid data in block map file: size %zu, blksize %u, range_count %u\n",
size, blksize, range_count);
return -1;
}
blocks = ((size-1) / blksize) + 1;
pMap->range_count = range_count;
pMap->ranges = malloc(range_count * sizeof(MappedRange));
memset(pMap->ranges, 0, range_count * sizeof(MappedRange));
pMap->ranges = calloc(range_count, sizeof(MappedRange));
if (pMap->ranges == NULL) {
LOGE("calloc(%u, %zu) failed: %s\n", range_count, sizeof(MappedRange), strerror(errno));
return -1;
}
// Reserve enough contiguous address space for the whole file.
unsigned char* reserve;
@@ -130,25 +143,34 @@ static int sysMapBlockFile(FILE* mapf, MemMapping* pMap)
reserve = mmap(NULL, blocks * blksize, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0);
#endif
if (reserve == MAP_FAILED) {
LOGW("failed to reserve address space: %s\n", strerror(errno));
LOGE("failed to reserve address space: %s\n", strerror(errno));
free(pMap->ranges);
return -1;
}
pMap->ranges[range_count-1].addr = reserve;
pMap->ranges[range_count-1].length = blocks * blksize;
int fd = open(block_dev, O_RDONLY);
if (fd < 0) {
LOGW("failed to open block device %s: %s\n", block_dev, strerror(errno));
LOGE("failed to open block device %s: %s\n", block_dev, strerror(errno));
munmap(reserve, blocks * blksize);
free(pMap->ranges);
return -1;
}
unsigned char* next = reserve;
size_t remaining_size = blocks * blksize;
bool success = true;
for (i = 0; i < range_count; ++i) {
int start, end;
if (fscanf(mapf, "%d %d\n", &start, &end) != 2) {
LOGW("failed to parse range %d in block map\n", i);
return -1;
size_t start, end;
if (fscanf(mapf, "%zu %zu\n", &start, &end) != 2) {
LOGE("failed to parse range %d in block map\n", i);
success = false;
break;
}
size_t length = (end - start) * blksize;
if (end <= start || (end - start) > SIZE_MAX / blksize || length > remaining_size) {
LOGE("unexpected range in block map: %zu %zu\n", start, end);
success = false;
break;
}
#if (PLATFORM_SDK_VERSION >= 21)
void* addr = mmap64(next, (end-start)*blksize, PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, ((off64_t)start)*blksize);
@@ -157,15 +179,28 @@ static int sysMapBlockFile(FILE* mapf, MemMapping* pMap)
void* addr = mmap(next, (end-start)*blksize, PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, ((off64_t)start)*blksize);
#endif
if (addr == MAP_FAILED) {
LOGW("failed to map block %d: %s\n", i, strerror(errno));
return -1;
LOGE("failed to map block %d: %s\n", i, strerror(errno));
success = false;
break;
}
pMap->ranges[i].addr = addr;
pMap->ranges[i].length = (end-start)*blksize;
pMap->ranges[i].length = length;
next += pMap->ranges[i].length;
next += length;
remaining_size -= length;
}
if (success && remaining_size != 0) {
LOGE("ranges in block map are invalid: remaining_size = %zu\n", remaining_size);
success = false;
}
if (!success) {
close(fd);
munmap(reserve, blocks * blksize);
free(pMap->ranges);
return -1;
}
close(fd);
pMap->addr = reserve;
pMap->length = size;
@@ -182,25 +217,26 @@ int sysMapFile(const char* fn, MemMapping* pMap)
// A map of blocks
FILE* mapf = fopen(fn+1, "r");
if (mapf == NULL) {
LOGV("Unable to open '%s': %s\n", fn+1, strerror(errno));
LOGE("Unable to open '%s': %s\n", fn+1, strerror(errno));
return -1;
}
if (sysMapBlockFile(mapf, pMap) != 0) {
LOGW("Map of '%s' failed\n", fn);
LOGE("Map of '%s' failed\n", fn);
fclose(mapf);
return -1;
}
fclose(mapf);
} else {
// This is a regular file.
int fd = open(fn, O_RDONLY, 0);
if (fd < 0) {
int fd = open(fn, O_RDONLY);
if (fd == -1) {
LOGE("Unable to open '%s': %s\n", fn, strerror(errno));
return -1;
}
if (sysMapFD(fd, pMap) != 0) {
if (!sysMapFD(fd, pMap)) {
LOGE("Map of '%s' failed\n", fn);
close(fd);
return -1;
@@ -219,7 +255,7 @@ void sysReleaseMap(MemMapping* pMap)
int i;
for (i = 0; i < pMap->range_count; ++i) {
if (munmap(pMap->ranges[i].addr, pMap->ranges[i].length) < 0) {
LOGW("munmap(%p, %d) failed: %s\n",
LOGE("munmap(%p, %d) failed: %s\n",
pMap->ranges[i].addr, (int)pMap->ranges[i].length, strerror(errno));
}
}
+7 -16
View File
@@ -198,10 +198,10 @@ static bool parseZipArchive(ZipArchive* pArchive)
*/
val = get4LE(pArchive->addr);
if (val == ENDSIG) {
LOGI("Found Zip archive, but it looks empty\n");
LOGW("Found Zip archive, but it looks empty\n");
goto bail;
} else if (val != LOCSIG) {
LOGV("Not a Zip archive (found 0x%08x)\n", val);
LOGW("Not a Zip archive (found 0x%08x)\n", val);
goto bail;
}
@@ -217,7 +217,7 @@ static bool parseZipArchive(ZipArchive* pArchive)
ptr--;
}
if (ptr < (const unsigned char*) pArchive->addr) {
LOGI("Could not find end-of-central-directory in Zip\n");
LOGW("Could not find end-of-central-directory in Zip\n");
goto bail;
}
@@ -431,7 +431,7 @@ int mzOpenZipArchive(unsigned char* addr, size_t length, ZipArchive* pArchive)
if (length < ENDHDR) {
err = -1;
LOGV("File '%s' too small to be zip (%zd)\n", fileName, map.length);
LOGW("Archive %p is too small to be zip (%zd)\n", pArchive, length);
goto bail;
}
@@ -440,7 +440,7 @@ int mzOpenZipArchive(unsigned char* addr, size_t length, ZipArchive* pArchive)
if (!parseZipArchive(pArchive)) {
err = -1;
LOGV("Parsing '%s' failed\n", fileName);
LOGW("Parsing archive %p failed\n", pArchive);
goto bail;
}
@@ -508,7 +508,6 @@ static bool processDeflatedEntry(const ZipArchive *pArchive,
void *cookie)
{
long result = -1;
unsigned char readBuf[32 * 1024];
unsigned char procBuf[32 * 1024];
z_stream zstream;
int zerr;
@@ -551,7 +550,7 @@ static bool processDeflatedEntry(const ZipArchive *pArchive,
/* uncompress the data */
zerr = inflate(&zstream, Z_NO_FLUSH);
if (zerr != Z_OK && zerr != Z_STREAM_END) {
LOGD("zlib inflate call failed (zerr=%d)\n", zerr);
LOGW("zlib inflate call failed (zerr=%d)\n", zerr);
goto z_bail;
}
@@ -605,7 +604,6 @@ bool mzProcessZipEntryContents(const ZipArchive *pArchive,
void *cookie)
{
bool ret = false;
off_t oldOff;
switch (pEntry->compression) {
case STORED:
@@ -623,13 +621,6 @@ bool mzProcessZipEntryContents(const ZipArchive *pArchive,
return ret;
}
static bool crcProcessFunction(const unsigned char *data, int dataLen,
void *crc)
{
*(unsigned long *)crc = crc32(*(unsigned long *)crc, data, dataLen);
return true;
}
typedef struct {
char *buf;
int bufLen;
@@ -1012,7 +1003,7 @@ bool mzExtractRecursive(const ZipArchive *pArchive,
if (callback != NULL) callback(targetFile, cookie);
}
LOGD("Extracted %d file(s)\n", extractCount);
LOGV("Extracted %d file(s)\n", extractCount);
free(helper.buf);
free(zpath);
+2 -1
View File
@@ -14,7 +14,7 @@ endif
LOCAL_MODULE := libmtdutils
LOCAL_STATIC_LIBRARIES := libcutils libc
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_CLANG := true
include $(BUILD_STATIC_LIBRARY)
@@ -31,6 +31,7 @@ endif
LOCAL_MODULE := libmtdutils
LOCAL_SHARED_LIBRARIES := libcutils libc
LOCAL_CLANG := true
include $(BUILD_SHARED_LIBRARY)
+4 -4
View File
@@ -297,20 +297,20 @@ static int read_block(const MtdPartition *partition, int fd, char *data)
if (TEMP_FAILURE_RETRY(lseek64(fd, pos, SEEK_SET)) != pos ||
TEMP_FAILURE_RETRY(read(fd, data, size)) != size) {
printf("mtd: read error at 0x%08llx (%s)\n",
pos, strerror(errno));
(long long)pos, strerror(errno));
} else if (ioctl(fd, ECCGETSTATS, &after)) {
printf("mtd: ECCGETSTATS error (%s)\n", strerror(errno));
return -1;
} else if (after.failed != before.failed) {
printf("mtd: ECC errors (%d soft, %d hard) at 0x%08llx\n",
after.corrected - before.corrected,
after.failed - before.failed, pos);
after.corrected - before.corrected,
after.failed - before.failed, (long long)pos);
// copy the comparison baseline for the next read.
memcpy(&before, &after, sizeof(struct mtd_ecc_stats));
} else if ((mgbb = ioctl(fd, MEMGETBADBLOCK, &pos))) {
fprintf(stderr,
"mtd: MEMGETBADBLOCK returned %d at 0x%08llx: %s\n",
mgbb, pos, strerror(errno));
mgbb, (long long)pos, strerror(errno));
} else {
return 0; // Success!
}
+1 -1
View File
@@ -32,7 +32,7 @@ LOCAL_SRC_FILES = \
twrpMtp.cpp \
mtp_MtpDatabase.cpp \
node.cpp
LOCAL_SHARED_LIBRARIES += libz libc libusbhost libstdc++ libdl libcutils libutils libaosprecovery
LOCAL_SHARED_LIBRARIES += libz libc libusbhost libstdc++ libdl libcutils libutils libaosprecovery libselinux
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 23; echo $$?),0)
LOCAL_SHARED_LIBRARIES += libstlport
+44
View File
@@ -0,0 +1,44 @@
# Copyright 2015 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific languae governing permissions and
# limitations under the License.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
otafault_static_libs := \
libbase \
libminzip \
libz \
libselinux
LOCAL_SRC_FILES := config.cpp ota_io.cpp
LOCAL_MODULE_TAGS := eng
LOCAL_MODULE := libotafault
LOCAL_CLANG := true
LOCAL_C_INCLUDES := bootable/recovery
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
LOCAL_WHOLE_STATIC_LIBRARIES := $(otafault_static_libs)
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := config.cpp ota_io.cpp test.cpp
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := otafault_test
LOCAL_STATIC_LIBRARIES := $(otafault_static_libs)
LOCAL_C_INCLUDES := bootable/recovery
LOCAL_FORCE_STATIC_EXECUTABLE := true
include $(BUILD_EXECUTABLE)
+69
View File
@@ -0,0 +1,69 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <map>
#include <string>
#include <stdio.h>
#include <unistd.h>
#include <android-base/stringprintf.h>
#include "minzip/Zip.h"
#include "config.h"
#include "ota_io.h"
#define OTAIO_MAX_FNAME_SIZE 128
static ZipArchive* archive;
static std::map<std::string, bool> should_inject_cache;
static std::string get_type_path(const char* io_type) {
return android::base::StringPrintf("%s/%s", OTAIO_BASE_DIR, io_type);
}
void ota_io_init(ZipArchive* za) {
archive = za;
ota_set_fault_files();
}
bool should_fault_inject(const char* io_type) {
// archive will be NULL if we used an entry point other
// than updater/updater.cpp:main
if (archive == NULL) {
return false;
}
const std::string type_path = get_type_path(io_type);
if (should_inject_cache.find(type_path) != should_inject_cache.end()) {
return should_inject_cache[type_path];
}
const ZipEntry* entry = mzFindZipEntry(archive, type_path.c_str());
should_inject_cache[type_path] = entry != nullptr;
return entry != NULL;
}
bool should_hit_cache() {
return should_fault_inject(OTAIO_CACHE);
}
std::string fault_fname(const char* io_type) {
std::string type_path = get_type_path(io_type);
std::string fname;
fname.resize(OTAIO_MAX_FNAME_SIZE);
const ZipEntry* entry = mzFindZipEntry(archive, type_path.c_str());
mzReadZipEntry(archive, entry, &fname[0], OTAIO_MAX_FNAME_SIZE);
return fname;
}
+74
View File
@@ -0,0 +1,74 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Read configuration files in the OTA package to determine which files, if any, will trigger errors.
*
* OTA packages can be modified to trigger errors by adding a top-level
* directory called .libotafault, which may optionally contain up to three
* files called READ, WRITE, and FSYNC. Each one of these optional files
* contains the name of a single file on the device disk which will cause
* an IO error on the first call of the appropriate I/O action to that file.
*
* Example:
* ota.zip
* <normal package contents>
* .libotafault
* WRITE
*
* If the contents of the file WRITE were /system/build.prop, the first write
* action to /system/build.prop would fail with EIO. Note that READ and
* FSYNC files are absent, so these actions will not cause an error.
*/
#ifndef _UPDATER_OTA_IO_CFG_H_
#define _UPDATER_OTA_IO_CFG_H_
#include <string>
#include <stdbool.h>
#include "minzip/Zip.h"
#define OTAIO_BASE_DIR ".libotafault"
#define OTAIO_READ "READ"
#define OTAIO_WRITE "WRITE"
#define OTAIO_FSYNC "FSYNC"
#define OTAIO_CACHE "CACHE"
/*
* Initialize libotafault by providing a reference to the OTA package.
*/
void ota_io_init(ZipArchive* za);
/*
* Return true if a config file is present for the given IO type.
*/
bool should_fault_inject(const char* io_type);
/*
* Return true if an EIO should occur on the next hit to /cache/saved.file
* instead of the next hit to the specified file.
*/
bool should_hit_cache();
/*
* Return the name of the file that should cause an error for the
* given IO type.
*/
std::string fault_fname(const char* io_type);
#endif
+176
View File
@@ -0,0 +1,176 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <map>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include "config.h"
#include "ota_io.h"
static std::map<intptr_t, const char*> filename_cache;
static std::string read_fault_file_name = "";
static std::string write_fault_file_name = "";
static std::string fsync_fault_file_name = "";
static bool get_hit_file(const char* cached_path, std::string ffn) {
return should_hit_cache()
? !strncmp(cached_path, OTAIO_CACHE_FNAME, strlen(cached_path))
: !strncmp(cached_path, ffn.c_str(), strlen(cached_path));
}
void ota_set_fault_files() {
if (should_fault_inject(OTAIO_READ)) {
read_fault_file_name = fault_fname(OTAIO_READ);
}
if (should_fault_inject(OTAIO_WRITE)) {
write_fault_file_name = fault_fname(OTAIO_WRITE);
}
if (should_fault_inject(OTAIO_FSYNC)) {
fsync_fault_file_name = fault_fname(OTAIO_FSYNC);
}
}
bool have_eio_error = false;
int ota_open(const char* path, int oflags) {
// Let the caller handle errors; we do not care if open succeeds or fails
int fd = open(path, oflags);
filename_cache[fd] = path;
return fd;
}
int ota_open(const char* path, int oflags, mode_t mode) {
int fd = open(path, oflags, mode);
filename_cache[fd] = path;
return fd; }
FILE* ota_fopen(const char* path, const char* mode) {
FILE* fh = fopen(path, mode);
filename_cache[(intptr_t)fh] = path;
return fh;
}
int ota_close(int fd) {
// descriptors can be reused, so make sure not to leave them in the cache
filename_cache.erase(fd);
return close(fd);
}
int ota_fclose(FILE* fh) {
filename_cache.erase((intptr_t)fh);
return fclose(fh);
}
size_t ota_fread(void* ptr, size_t size, size_t nitems, FILE* stream) {
if (should_fault_inject(OTAIO_READ)) {
auto cached = filename_cache.find((intptr_t)stream);
const char* cached_path = cached->second;
if (cached != filename_cache.end() &&
get_hit_file(cached_path, read_fault_file_name)) {
read_fault_file_name = "";
errno = EIO;
have_eio_error = true;
return 0;
}
}
size_t status = fread(ptr, size, nitems, stream);
if (status != nitems && errno == EIO) {
have_eio_error = true;
}
return status;
}
ssize_t ota_read(int fd, void* buf, size_t nbyte) {
if (should_fault_inject(OTAIO_READ)) {
auto cached = filename_cache.find(fd);
const char* cached_path = cached->second;
if (cached != filename_cache.end()
&& get_hit_file(cached_path, read_fault_file_name)) {
read_fault_file_name = "";
errno = EIO;
have_eio_error = true;
return -1;
}
}
ssize_t status = read(fd, buf, nbyte);
if (status == -1 && errno == EIO) {
have_eio_error = true;
}
return status;
}
size_t ota_fwrite(const void* ptr, size_t size, size_t count, FILE* stream) {
if (should_fault_inject(OTAIO_WRITE)) {
auto cached = filename_cache.find((intptr_t)stream);
const char* cached_path = cached->second;
if (cached != filename_cache.end() &&
get_hit_file(cached_path, write_fault_file_name)) {
write_fault_file_name = "";
errno = EIO;
have_eio_error = true;
return 0;
}
}
size_t status = fwrite(ptr, size, count, stream);
if (status != count && errno == EIO) {
have_eio_error = true;
}
return status;
}
ssize_t ota_write(int fd, const void* buf, size_t nbyte) {
if (should_fault_inject(OTAIO_WRITE)) {
auto cached = filename_cache.find(fd);
const char* cached_path = cached->second;
if (cached != filename_cache.end() &&
get_hit_file(cached_path, write_fault_file_name)) {
write_fault_file_name = "";
errno = EIO;
have_eio_error = true;
return -1;
}
}
ssize_t status = write(fd, buf, nbyte);
if (status == -1 && errno == EIO) {
have_eio_error = true;
}
return status;
}
int ota_fsync(int fd) {
if (should_fault_inject(OTAIO_FSYNC)) {
auto cached = filename_cache.find(fd);
const char* cached_path = cached->second;
if (cached != filename_cache.end() &&
get_hit_file(cached_path, fsync_fault_file_name)) {
fsync_fault_file_name = "";
errno = EIO;
have_eio_error = true;
return -1;
}
}
int status = fsync(fd);
if (status == -1 && errno == EIO) {
have_eio_error = true;
}
return status;
}
+53
View File
@@ -0,0 +1,53 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Provide a series of proxy functions for basic file accessors.
* The behavior of these functions can be changed to return different
* errors under a variety of conditions.
*/
#ifndef _UPDATER_OTA_IO_H_
#define _UPDATER_OTA_IO_H_
#include <stdio.h>
#include <sys/stat.h>
#define OTAIO_CACHE_FNAME "/cache/saved.file"
void ota_set_fault_files();
int ota_open(const char* path, int oflags);
int ota_open(const char* path, int oflags, mode_t mode);
FILE* ota_fopen(const char* filename, const char* mode);
int ota_close(int fd);
int ota_fclose(FILE* fh);
size_t ota_fread(void* ptr, size_t size, size_t nitems, FILE* stream);
ssize_t ota_read(int fd, void* buf, size_t nbyte);
size_t ota_fwrite(const void* ptr, size_t size, size_t count, FILE* stream);
ssize_t ota_write(int fd, const void* buf, size_t nbyte);
int ota_fsync(int fd);
#endif
+34
View File
@@ -0,0 +1,34 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include "ota_io.h"
int main(int /* argc */, char** /* argv */) {
int fd = open("testdata/test.file", O_RDWR);
char buf[8];
const char* out = "321";
int readv = ota_read(fd, buf, 4);
printf("Read returned %d\n", readv);
int writev = ota_write(fd, out, 4);
printf("Write returned %d\n", writev);
close(fd);
return 0;
}
+13 -8
View File
@@ -86,11 +86,16 @@ RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libmmcutils.so
RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libbmlutils.so
RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libflashutils.so
RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libfusesideload.so
ifeq (,$(filter $(PLATFORM_SDK_VERSION), 23))
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -lt 23; echo $$?),0)
# These libraries are no longer present in M
RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libstlport.so
RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libgccdemangle.so
endif
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 23; echo $$?),0)
RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libcrypto.so
RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libpackagelistparser.so
RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/liblzma.so
endif
ifneq (,$(filter $(PLATFORM_SDK_VERSION), 21 22))
# libraries from lollipop
RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libbacktrace.so
@@ -99,7 +104,7 @@ ifneq (,$(filter $(PLATFORM_SDK_VERSION), 21 22))
# Dynamically loaded by lollipop libc and may prevent unmounting system if it is not present in sbin
RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libnetd_client.so
else
ifneq (,$(filter $(PLATFORM_SDK_VERSION), 23))
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 23; echo $$?),0)
# Android M libraries
RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libbacktrace.so
RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libunwind.so
@@ -112,8 +117,8 @@ else
RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libcorkscrew.so
endif
endif
RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libmincrypttwrp.so
RELINK_SOURCE_FILES += $(TARGET_RECOVERY_ROOT_OUT)/sbin/toolbox
#RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libmincrypttwrp.so
#RELINK_SOURCE_FILES += $(TARGET_RECOVERY_ROOT_OUT)/sbin/toolbox
ifneq ($(TW_OEM_BUILD),true)
RELINK_SOURCE_FILES += $(TARGET_RECOVERY_ROOT_OUT)/sbin/twrp
else
@@ -180,7 +185,7 @@ ifeq ($(TARGET_USERIMAGES_USE_F2FS), true)
ifeq ($(shell test $(CM_PLATFORM_SDK_VERSION) -ge 4; echo $$?),0)
RELINK_SOURCE_FILES += $(TARGET_OUT_EXECUTABLES)/mkfs.f2fs
RELINK_SOURCE_FILES += $(TARGET_OUT_SHARED_LIBRARIES)/libf2fs.so
else ifneq (,$(filter $(PLATFORM_SDK_VERSION), 23))
else ifeq ($(shell test $(PLATFORM_SDK_VERSION) -ge 23; echo $$?),0)
RELINK_SOURCE_FILES += $(TARGET_RECOVERY_ROOT_OUT)/sbin/mkfs.f2fs
else ifneq (,$(filter $(PLATFORM_SDK_VERSION), 21 22))
RELINK_SOURCE_FILES += $(TARGET_ROOT_OUT_SBIN)/mkfs.f2fs
@@ -230,7 +235,7 @@ endif
TWRP_AUTOGEN := $(intermediates)/teamwin
GEN := $(intermediates)/teamwin
$(GEN): $(RELINK)
$(GEN): $(RELINK_SOURCE_FILES) $(call intermediates-dir-for,EXECUTABLES,recovery)/recovery
$(GEN): $(RELINK_SOURCE_FILES) $(call intermediates-dir-for,EXECUTABLES,init)/init
$(RELINK) $(TARGET_RECOVERY_ROOT_OUT)/sbin $(RELINK_SOURCE_FILES)
LOCAL_GENERATED_SOURCES := $(GEN)
@@ -280,11 +285,11 @@ endif
# copy license file for OpenAES
ifneq ($(TW_EXCLUDE_ENCRYPTED_BACKUPS), true)
include $(CLEAR_VARS)
LOCAL_MODULE := ../openaes/LICENSE
LOCAL_MODULE := openaes_license
LOCAL_MODULE_TAGS := eng
LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/license/openaes
LOCAL_SRC_FILES := $(LOCAL_MODULE)
LOCAL_SRC_FILES := ../openaes/LICENSE
include $(BUILD_PREBUILT)
endif
+47
View File
@@ -0,0 +1,47 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef RECOVERY_PRINT_SHA1_H
#define RECOVERY_PRINT_SHA1_H
#include <stdint.h>
#include <string>
#include "openssl/sha.h"
static std::string print_sha1(const uint8_t* sha1, size_t len) {
const char* hex = "0123456789abcdef";
std::string result = "";
for (size_t i = 0; i < len; ++i) {
result.push_back(hex[(sha1[i]>>4) & 0xf]);
result.push_back(hex[sha1[i] & 0xf]);
}
return result;
}
static std::string print_sha1(const uint8_t sha1[SHA_DIGEST_LENGTH]) {
return print_sha1(sha1, SHA_DIGEST_LENGTH);
}
static std::string short_sha1(const uint8_t sha1[SHA_DIGEST_LENGTH]) {
return print_sha1(sha1, 4);
}
static std::string print_hex(const uint8_t* bytes, size_t len) {
return print_sha1(bytes, len);
}
#endif // RECOVERY_PRINT_SHA1_H
+205
View File
@@ -0,0 +1,205 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "recovery-persist"
//
// Strictly to deal with reboot into system after OTA after /data
// mounts to pull the last pmsg file data and place it
// into /data/misc/recovery/ directory, rotating it in.
//
// Usage: recovery-persist [--force-persist]
//
// On systems without /cache mount, all file content representing in the
// recovery/ directory stored in /sys/fs/pstore/pmsg-ramoops-0 in logger
// format that reside in the LOG_ID_SYSTEM buffer at ANDROID_LOG_INFO
// priority or higher is transfered to the /data/misc/recovery/ directory.
// The content is matched and rotated in as need be.
//
// --force-persist ignore /cache mount, always rotate in the contents.
//
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <string>
#include <android/log.h> /* Android Log Priority Tags */
#include <android-base/file.h>
#include <log/log.h>
#include <log/logger.h> /* Android Log packet format */
#include <private/android_logger.h> /* private pmsg functions */
static const char *LAST_LOG_FILE = "/data/misc/recovery/last_log";
static const char *LAST_PMSG_FILE = "/sys/fs/pstore/pmsg-ramoops-0";
static const char *LAST_KMSG_FILE = "/data/misc/recovery/last_kmsg";
static const char *LAST_CONSOLE_FILE = "/sys/fs/pstore/console-ramoops-0";
static const char *ALT_LAST_CONSOLE_FILE = "/sys/fs/pstore/console-ramoops";
static const int KEEP_LOG_COUNT = 10;
// close a file, log an error if the error indicator is set
static void check_and_fclose(FILE *fp, const char *name) {
fflush(fp);
if (ferror(fp)) SLOGE("%s %s", name, strerror(errno));
fclose(fp);
}
static void copy_file(const char* source, const char* destination) {
FILE* dest_fp = fopen(destination, "w");
if (dest_fp == nullptr) {
SLOGE("%s %s", destination, strerror(errno));
} else {
FILE* source_fp = fopen(source, "r");
if (source_fp != nullptr) {
char buf[4096];
size_t bytes;
while ((bytes = fread(buf, 1, sizeof(buf), source_fp)) != 0) {
fwrite(buf, 1, bytes, dest_fp);
}
check_and_fclose(source_fp, source);
}
check_and_fclose(dest_fp, destination);
}
}
static bool rotated = false;
// Rename last_log -> last_log.1 -> last_log.2 -> ... -> last_log.$max.
// Similarly rename last_kmsg -> last_kmsg.1 -> ... -> last_kmsg.$max.
// Overwrite any existing last_log.$max and last_kmsg.$max.
static void rotate_logs(int max) {
// Logs should only be rotated once.
if (rotated) {
return;
}
rotated = true;
for (int i = max-1; i >= 0; --i) {
std::string old_log(LAST_LOG_FILE);
if (i > 0) {
old_log += "." + std::to_string(i);
}
std::string new_log(LAST_LOG_FILE);
new_log += "." + std::to_string(i+1);
// Ignore errors if old_log doesn't exist.
rename(old_log.c_str(), new_log.c_str());
std::string old_kmsg(LAST_KMSG_FILE);
if (i > 0) {
old_kmsg += "." + std::to_string(i);
}
std::string new_kmsg(LAST_KMSG_FILE);
new_kmsg += "." + std::to_string(i+1);
rename(old_kmsg.c_str(), new_kmsg.c_str());
}
}
ssize_t logsave(
log_id_t /* logId */,
char /* prio */,
const char *filename,
const char *buf, size_t len,
void * /* arg */) {
std::string destination("/data/misc/");
destination += filename;
std::string buffer(buf, len);
{
std::string content;
android::base::ReadFileToString(destination, &content);
if (buffer.compare(content) == 0) {
return len;
}
}
// ToDo: Any others that match? Are we pulling in multiple
// already-rotated files? Algorithm thus far is KISS: one file,
// one rotation allowed.
rotate_logs(KEEP_LOG_COUNT);
return android::base::WriteStringToFile(buffer, destination.c_str());
}
int main(int argc, char **argv) {
/* Is /cache a mount?, we have been delivered where we are not wanted */
/*
* Following code halves the size of the executable as compared to:
*
* load_volume_table();
* has_cache = volume_for_path(CACHE_ROOT) != nullptr;
*/
bool has_cache = false;
static const char mounts_file[] = "/proc/mounts";
FILE *fp = fopen(mounts_file, "r");
if (!fp) {
SLOGV("%s %s", mounts_file, strerror(errno));
} else {
char *line = NULL;
size_t len = 0;
ssize_t read;
while ((read = getline(&line, &len, fp)) != -1) {
if (strstr(line, " /cache ")) {
has_cache = true;
break;
}
}
free(line);
fclose(fp);
}
if (has_cache) {
/*
* TBD: Future location to move content from
* /cache/recovery to /data/misc/recovery/
*/
/* if --force-persist flag, then transfer pmsg data anyways */
if ((argc <= 1) || !argv[1] || strcmp(argv[1], "--force-persist")) {
return 0;
}
}
/* Is there something in pmsg? */
if (access(LAST_PMSG_FILE, R_OK)) {
return 0;
}
// Take last pmsg file contents and send it off to the logsave
__android_log_pmsg_file_read(
LOG_ID_SYSTEM, ANDROID_LOG_INFO, "recovery/", logsave, NULL);
/* Is there a last console log too? */
if (rotated) {
if (!access(LAST_CONSOLE_FILE, R_OK)) {
copy_file(LAST_CONSOLE_FILE, LAST_KMSG_FILE);
} else if (!access(ALT_LAST_CONSOLE_FILE, R_OK)) {
copy_file(ALT_LAST_CONSOLE_FILE, LAST_KMSG_FILE);
}
}
return 0;
}
+3
View File
@@ -0,0 +1,3 @@
on post-fs-data
mkdir /data/misc/recovery 0770 system log
exec - system log -- /system/bin/recovery-persist
+128
View File
@@ -0,0 +1,128 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "recovery-refresh"
//
// Strictly to deal with reboot into system after OTA, then
// reboot while in system before boot complete landing us back
// into recovery to continue with any mitigations with retained
// log history. This simply refreshes the pmsg files from
// the last pmsg file contents.
//
// Usage:
// recovery-refresh [--force-rotate|--rotate]
//
// All file content representing in the recovery/ directory stored in
// /sys/fs/pstore/pmsg-ramoops-0 in logger format that reside in the
// LOG_ID_SYSTEM buffer at ANDROID_LOG_INFO priority or higher is
// refreshed into /dev/pmsg0. This ensures that an unexpected reboot
// before recovery-persist is run will still contain the associated
// pmsg Android Logger content.
//
// --force-rotate recovery/last_kmsg and recovery.last_log files are
// rotated with .<number> suffixes upwards.
// --rotate rotated only if rocovery/last_msg or recovery/last_log
// exist, otherwise perform 1:1 refresh.
//
#include <string.h>
#include <string>
#include <android/log.h> /* Android Log Priority Tags */
#include <log/logger.h> /* Android Log packet format */
#include <private/android_logger.h> /* private pmsg functions */
static const char LAST_KMSG_FILE[] = "recovery/last_kmsg";
static const char LAST_LOG_FILE[] = "recovery/last_log";
static ssize_t logbasename(
log_id_t /* logId */,
char /* prio */,
const char *filename,
const char * /* buf */, size_t len,
void *arg) {
if (strstr(LAST_KMSG_FILE, filename) ||
strstr(LAST_LOG_FILE, filename)) {
bool *doRotate = reinterpret_cast<bool *>(arg);
*doRotate = true;
}
return len;
}
static ssize_t logrotate(
log_id_t logId,
char prio,
const char *filename,
const char *buf, size_t len,
void *arg) {
bool *doRotate = reinterpret_cast<bool *>(arg);
if (!*doRotate) {
return __android_log_pmsg_file_write(logId, prio, filename, buf, len);
}
std::string name(filename);
size_t dot = name.find_last_of(".");
std::string sub = name.substr(0, dot);
if (!strstr(LAST_KMSG_FILE, sub.c_str()) &&
!strstr(LAST_LOG_FILE, sub.c_str())) {
return __android_log_pmsg_file_write(logId, prio, filename, buf, len);
}
// filename rotation
if (dot == std::string::npos) {
name += ".1";
} else {
std::string number = name.substr(dot + 1);
if (!isdigit(number.data()[0])) {
name += ".1";
} else {
unsigned long long i = std::stoull(number);
name = sub + "." + std::to_string(i + 1);
}
}
return __android_log_pmsg_file_write(logId, prio, name.c_str(), buf, len);
}
int main(int argc, char **argv) {
static const char filter[] = "recovery/";
static const char force_rotate_flag[] = "--force-rotate";
static const char rotate_flag[] = "--rotate";
ssize_t ret;
bool doRotate = false;
// Take last pmsg contents and rewrite it to the current pmsg session.
if ((argc <= 1) || !argv[1] ||
(((doRotate = strcmp(argv[1], rotate_flag))) &&
strcmp(argv[1], force_rotate_flag))) {
doRotate = false;
} else if (!doRotate) {
// Do we need to rotate?
__android_log_pmsg_file_read(
LOG_ID_SYSTEM, ANDROID_LOG_INFO, filter,
logbasename, &doRotate);
}
// Take action to refresh pmsg contents
ret = __android_log_pmsg_file_read(
LOG_ID_SYSTEM, ANDROID_LOG_INFO, filter,
logrotate, &doRotate);
return (ret < 0) ? ret : 0;
}
+2
View File
@@ -0,0 +1,2 @@
on post-fs
exec - system log -- /system/bin/recovery-refresh
+542 -77
View File
@@ -28,33 +28,44 @@
#include <sys/klog.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#include <base/file.h>
#include <base/stringprintf.h>
#include <chrono>
#include <adb.h>
#include <android/log.h> /* Android Log Priority Tags */
#include <android-base/file.h>
#include <android-base/parseint.h>
#include <android-base/stringprintf.h>
#include <cutils/android_reboot.h>
#include <cutils/properties.h>
#include <log/logger.h> /* Android Log packet format */
#include <private/android_logger.h> /* private pmsg functions */
#include <healthd/BatteryMonitor.h>
#include "adb_install.h"
#include "bootloader.h"
#include "common.h"
#include "cutils/properties.h"
#include "cutils/android_reboot.h"
#include "device.h"
#include "error_code.h"
#include "fuse_sdcard_provider.h"
#include "fuse_sideload.h"
#include "install.h"
#include "minui/minui.h"
#include "minzip/DirUtil.h"
#include "roots.h"
#include "ui.h"
#include "screen_ui.h"
#include "device.h"
#include "adb_install.h"
#include "adb.h"
#include "fuse_sideload.h"
#include "fuse_sdcard_provider.h"
struct selabel_handle *sehandle;
static const struct option OPTIONS[] = {
{ "send_intent", required_argument, NULL, 'i' },
{ "update_package", required_argument, NULL, 'u' },
{ "retry_count", required_argument, NULL, 'n' },
{ "wipe_data", no_argument, NULL, 'w' },
{ "wipe_cache", no_argument, NULL, 'c' },
{ "show_text", no_argument, NULL, 't' },
@@ -65,6 +76,7 @@ static const struct option OPTIONS[] = {
{ "stages", required_argument, NULL, 'g' },
{ "shutdown_after", no_argument, NULL, 'p' },
{ "reason", required_argument, NULL, 'r' },
{ "security", no_argument, NULL, 'e'},
{ NULL, 0, NULL, 0 },
};
@@ -74,19 +86,31 @@ static const char *INTENT_FILE = "/cache/recovery/intent";
static const char *LOG_FILE = "/cache/recovery/log";
static const char *LAST_INSTALL_FILE = "/cache/recovery/last_install";
static const char *LOCALE_FILE = "/cache/recovery/last_locale";
static const char *CONVERT_FBE_DIR = "/tmp/convert_fbe";
static const char *CONVERT_FBE_FILE = "/tmp/convert_fbe/convert_fbe";
static const char *CACHE_ROOT = "/cache";
static const char *DATA_ROOT = "/data";
static const char *SDCARD_ROOT = "/sdcard";
static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log";
static const char *TEMPORARY_INSTALL_FILE = "/tmp/last_install";
static const char *LAST_KMSG_FILE = "/cache/recovery/last_kmsg";
static const char *LAST_LOG_FILE = "/cache/recovery/last_log";
static const int KEEP_LOG_COUNT = 10;
// We will try to apply the update package 5 times at most in case of an I/O error.
static const int EIO_RETRY_COUNT = 4;
static const int BATTERY_READ_TIMEOUT_IN_SEC = 10;
// GmsCore enters recovery mode to install package when having enough battery
// percentage. Normally, the threshold is 40% without charger and 20% with charger.
// So we should check battery with a slightly lower limitation.
static const int BATTERY_OK_PERCENTAGE = 20;
static const int BATTERY_WITH_CHARGER_OK_PERCENTAGE = 15;
RecoveryUI* ui = NULL;
char* locale = NULL;
static const char* locale = "en_US";
char* stage = NULL;
char* reason = NULL;
bool modified_flash = false;
static bool has_cache = false;
/*
* The recovery tool communicates with the main system through /cache files.
@@ -151,8 +175,7 @@ static const int MAX_ARG_LENGTH = 4096;
static const int MAX_ARGS = 100;
// open a given path, mounting partitions as necessary
FILE*
fopen_path(const char *path, const char *mode) {
FILE* fopen_path(const char *path, const char *mode) {
if (ensure_path_mounted(path) != 0) {
LOGE("Can't mount %s\n", path);
return NULL;
@@ -166,23 +189,102 @@ fopen_path(const char *path, const char *mode) {
return fp;
}
// close a file, log an error if the error indicator is set
static void check_and_fclose(FILE *fp, const char *name) {
fflush(fp);
if (ferror(fp)) LOGE("Error in %s\n(%s)\n", name, strerror(errno));
fclose(fp);
}
bool is_ro_debuggable() {
char value[PROPERTY_VALUE_MAX+1];
return (property_get("ro.debuggable", value, NULL) == 1 && value[0] == '1');
}
static void redirect_stdio(const char* filename) {
// If these fail, there's not really anywhere to complain...
freopen(filename, "a", stdout); setbuf(stdout, NULL);
freopen(filename, "a", stderr); setbuf(stderr, NULL);
}
int pipefd[2];
if (pipe(pipefd) == -1) {
LOGE("pipe failed: %s\n", strerror(errno));
// close a file, log an error if the error indicator is set
static void
check_and_fclose(FILE *fp, const char *name) {
fflush(fp);
if (ferror(fp)) LOGE("Error in %s\n(%s)\n", name, strerror(errno));
fclose(fp);
// Fall back to traditional logging mode without timestamps.
// If these fail, there's not really anywhere to complain...
freopen(filename, "a", stdout); setbuf(stdout, NULL);
freopen(filename, "a", stderr); setbuf(stderr, NULL);
return;
}
pid_t pid = fork();
if (pid == -1) {
LOGE("fork failed: %s\n", strerror(errno));
// Fall back to traditional logging mode without timestamps.
// If these fail, there's not really anywhere to complain...
freopen(filename, "a", stdout); setbuf(stdout, NULL);
freopen(filename, "a", stderr); setbuf(stderr, NULL);
return;
}
if (pid == 0) {
/// Close the unused write end.
close(pipefd[1]);
auto start = std::chrono::steady_clock::now();
// Child logger to actually write to the log file.
FILE* log_fp = fopen(filename, "a");
if (log_fp == nullptr) {
LOGE("fopen \"%s\" failed: %s\n", filename, strerror(errno));
close(pipefd[0]);
_exit(1);
}
FILE* pipe_fp = fdopen(pipefd[0], "r");
if (pipe_fp == nullptr) {
LOGE("fdopen failed: %s\n", strerror(errno));
check_and_fclose(log_fp, filename);
close(pipefd[0]);
_exit(1);
}
char* line = nullptr;
size_t len = 0;
while (getline(&line, &len, pipe_fp) != -1) {
auto now = std::chrono::steady_clock::now();
double duration = std::chrono::duration_cast<std::chrono::duration<double>>(
now - start).count();
if (line[0] == '\n') {
fprintf(log_fp, "[%12.6lf]\n", duration);
} else {
fprintf(log_fp, "[%12.6lf] %s", duration, line);
}
fflush(log_fp);
}
LOGE("getline failed: %s\n", strerror(errno));
free(line);
check_and_fclose(log_fp, filename);
close(pipefd[0]);
_exit(1);
} else {
// Redirect stdout/stderr to the logger process.
// Close the unused read end.
close(pipefd[0]);
setbuf(stdout, nullptr);
setbuf(stderr, nullptr);
if (dup2(pipefd[1], STDOUT_FILENO) == -1) {
LOGE("dup2 stdout failed: %s\n", strerror(errno));
}
if (dup2(pipefd[1], STDERR_FILENO) == -1) {
LOGE("dup2 stderr failed: %s\n", strerror(errno));
}
close(pipefd[1]);
}
}
// command line args come from, in decreasing precedence:
@@ -221,8 +323,8 @@ get_args(int *argc, char ***argv) {
}
}
// --- if that doesn't work, try the command file
if (*argc <= 1) {
// --- if that doesn't work, try the command file (if we have /cache).
if (*argc <= 1 && has_cache) {
FILE *fp = fopen_path(COMMAND_FILE, "r");
if (fp != NULL) {
char *token;
@@ -285,6 +387,18 @@ static void save_kernel_log(const char* destination) {
android::base::WriteStringToFile(buffer, destination);
}
// write content to the current pmsg session.
static ssize_t __pmsg_write(const char *filename, const char *buf, size_t len) {
return __android_log_pmsg_file_write(LOG_ID_SYSTEM, ANDROID_LOG_INFO,
filename, buf, len);
}
static void copy_log_file_to_pmsg(const char* source, const char* destination) {
std::string content;
android::base::ReadFileToString(source, &content);
__pmsg_write(destination, content.c_str(), content.length());
}
// How much of the temp log we have copied to the copy in cache.
static long tmplog_offset = 0;
@@ -326,14 +440,18 @@ static void rotate_logs(int max) {
ensure_path_mounted(LAST_KMSG_FILE);
for (int i = max-1; i >= 0; --i) {
std::string old_log = android::base::StringPrintf((i == 0) ? "%s" : "%s.%d",
LAST_LOG_FILE, i);
std::string old_log = android::base::StringPrintf("%s", LAST_LOG_FILE);
if (i > 0) {
old_log += "." + std::to_string(i);
}
std::string new_log = android::base::StringPrintf("%s.%d", LAST_LOG_FILE, i+1);
// Ignore errors if old_log doesn't exist.
rename(old_log.c_str(), new_log.c_str());
std::string old_kmsg = android::base::StringPrintf((i == 0) ? "%s" : "%s.%d",
LAST_KMSG_FILE, i);
std::string old_kmsg = android::base::StringPrintf("%s", LAST_KMSG_FILE);
if (i > 0) {
old_kmsg += "." + std::to_string(i);
}
std::string new_kmsg = android::base::StringPrintf("%s.%d", LAST_KMSG_FILE, i+1);
rename(old_kmsg.c_str(), new_kmsg.c_str());
}
@@ -348,6 +466,15 @@ static void copy_logs() {
return;
}
// Always write to pmsg, this allows the OTA logs to be caught in logcat -L
copy_log_file_to_pmsg(TEMPORARY_LOG_FILE, LAST_LOG_FILE);
copy_log_file_to_pmsg(TEMPORARY_INSTALL_FILE, LAST_INSTALL_FILE);
// We can do nothing for now if there's no /cache partition.
if (!has_cache) {
return;
}
rotate_logs(KEEP_LOG_COUNT);
// Copy logs to cache so the system can find out what happened.
@@ -371,7 +498,7 @@ static void copy_logs() {
static void
finish_recovery(const char *send_intent) {
// By this point, we're ready to return to the main system...
if (send_intent != NULL) {
if (send_intent != NULL && has_cache) {
FILE *fp = fopen_path(INTENT_FILE, "w");
if (fp == NULL) {
LOGE("Can't open %s\n", INTENT_FILE);
@@ -385,12 +512,16 @@ finish_recovery(const char *send_intent) {
// 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);
size_t len = strlen(locale);
__pmsg_write(LOCALE_FILE, locale, len);
if (has_cache) {
LOGI("Saving locale \"%s\"\n", locale);
FILE* fp = fopen_path(LOCALE_FILE, "w");
fwrite(locale, 1, len, fp);
fflush(fp);
fsync(fileno(fp));
check_and_fclose(fp, LOCALE_FILE);
}
}
copy_logs();
@@ -401,12 +532,13 @@ finish_recovery(const char *send_intent) {
set_bootloader_message(&boot);
// Remove the command file, so recovery won't repeat indefinitely.
if (ensure_path_mounted(COMMAND_FILE) != 0 ||
(unlink(COMMAND_FILE) && errno != ENOENT)) {
LOGW("Can't unlink %s\n", COMMAND_FILE);
if (has_cache) {
if (ensure_path_mounted(COMMAND_FILE) != 0 || (unlink(COMMAND_FILE) && errno != ENOENT)) {
LOGW("Can't unlink %s\n", COMMAND_FILE);
}
ensure_path_unmounted(CACHE_ROOT);
}
ensure_path_unmounted(CACHE_ROOT);
sync(); // For good measure.
}
@@ -419,6 +551,7 @@ typedef struct _saved_log_file {
static bool erase_volume(const char* volume) {
bool is_cache = (strcmp(volume, CACHE_ROOT) == 0);
bool is_data = (strcmp(volume, DATA_ROOT) == 0);
ui->SetBackground(RecoveryUI::ERASING);
ui->SetProgressType(RecoveryUI::INDETERMINATE);
@@ -473,7 +606,28 @@ static bool erase_volume(const char* volume) {
ui->Print("Formatting %s...\n", volume);
ensure_path_unmounted(volume);
int result = format_volume(volume);
int result;
if (is_data && reason && strcmp(reason, "convert_fbe") == 0) {
// Create convert_fbe breadcrumb file to signal to init
// to convert to file based encryption, not full disk encryption
if (mkdir(CONVERT_FBE_DIR, 0700) != 0) {
ui->Print("Failed to make convert_fbe dir %s\n", strerror(errno));
return true;
}
FILE* f = fopen(CONVERT_FBE_FILE, "wb");
if (!f) {
ui->Print("Failed to convert to file encryption %s\n", strerror(errno));
return true;
}
fclose(f);
result = format_volume(volume, CONVERT_FBE_DIR);
remove(CONVERT_FBE_FILE);
rmdir(CONVERT_FBE_DIR);
} else {
result = format_volume(volume);
}
if (is_cache) {
while (head) {
@@ -675,7 +829,7 @@ static bool wipe_data(int should_confirm, Device* device) {
bool success =
device->PreWipeData() &&
erase_volume("/data") &&
erase_volume("/cache") &&
(has_cache ? erase_volume("/cache") : true) &&
device->PostWipeData();
ui->Print("Data wipe %s.\n", success ? "complete" : "failed");
return success;
@@ -683,6 +837,11 @@ static bool wipe_data(int should_confirm, Device* device) {
// Return true on success.
static bool wipe_cache(bool should_confirm, Device* device) {
if (!has_cache) {
ui->Print("No /cache partition found.\n");
return false;
}
if (should_confirm && !yes_no(device, "Wipe cache?", " THIS CAN NOT BE UNDONE!")) {
return false;
}
@@ -696,6 +855,11 @@ static bool wipe_cache(bool should_confirm, Device* device) {
}
static void choose_recovery_file(Device* device) {
if (!has_cache) {
ui->Print("No /cache partition found.\n");
return;
}
// "Back" + KEEP_LOG_COUNT * 2 + terminating nullptr entry
char* entries[1 + KEEP_LOG_COUNT * 2 + 1];
memset(entries, 0, sizeof(entries));
@@ -706,7 +870,10 @@ static void choose_recovery_file(Device* device) {
// Add LAST_KMSG_FILE + LAST_KMSG_FILE.x
for (int i = 0; i < KEEP_LOG_COUNT; i++) {
char* log_file;
if (asprintf(&log_file, (i == 0) ? "%s" : "%s.%d", LAST_LOG_FILE, i) == -1) {
int ret;
ret = (i == 0) ? asprintf(&log_file, "%s", LAST_LOG_FILE) :
asprintf(&log_file, "%s.%d", LAST_LOG_FILE, i);
if (ret == -1) {
// memory allocation failure - return early. Should never happen.
return;
}
@@ -717,7 +884,9 @@ static void choose_recovery_file(Device* device) {
}
char* kmsg_file;
if (asprintf(&kmsg_file, (i == 0) ? "%s" : "%s.%d", LAST_KMSG_FILE, i) == -1) {
ret = (i == 0) ? asprintf(&kmsg_file, "%s", LAST_KMSG_FILE) :
asprintf(&kmsg_file, "%s.%d", LAST_KMSG_FILE, i);
if (ret == -1) {
// memory allocation failure - return early. Should never happen.
return;
}
@@ -736,10 +905,7 @@ static void choose_recovery_file(Device* device) {
int chosen_item = get_menu_selection(headers, entries, 1, 0, device);
if (strcmp(entries[chosen_item], "Back") == 0) break;
// TODO: do we need to redirect? ShowFile could just avoid writing to stdio.
redirect_stdio("/dev/null");
ui->ShowFile(entries[chosen_item]);
redirect_stdio(TEMPORARY_LOG_FILE);
}
for (size_t i = 0; i < (sizeof(entries) / sizeof(*entries)); i++) {
@@ -747,6 +913,41 @@ static void choose_recovery_file(Device* device) {
}
}
static void run_graphics_test(Device* device) {
// Switch to graphics screen.
ui->ShowText(false);
ui->SetProgressType(RecoveryUI::INDETERMINATE);
ui->SetBackground(RecoveryUI::INSTALLING_UPDATE);
sleep(1);
ui->SetBackground(RecoveryUI::ERROR);
sleep(1);
ui->SetBackground(RecoveryUI::NO_COMMAND);
sleep(1);
ui->SetBackground(RecoveryUI::ERASING);
sleep(1);
ui->SetBackground(RecoveryUI::INSTALLING_UPDATE);
ui->SetProgressType(RecoveryUI::DETERMINATE);
ui->ShowProgress(1.0, 10.0);
float fraction = 0.0;
for (size_t i = 0; i < 100; ++i) {
fraction += .01;
ui->SetProgress(fraction);
usleep(100000);
}
ui->ShowText(true);
}
// How long (in seconds) we wait for the fuse-provided package file to
// appear, before timing out.
#define SDCARD_INSTALL_TIMEOUT 10
static int apply_from_sdcard(Device* device, bool* wipe_cache) {
modified_flash = true;
@@ -758,19 +959,68 @@ static int apply_from_sdcard(Device* device, bool* wipe_cache) {
char* path = browse_directory(SDCARD_ROOT, device);
if (path == NULL) {
ui->Print("\n-- No package file selected.\n");
ensure_path_unmounted(SDCARD_ROOT);
return INSTALL_ERROR;
}
ui->Print("\n-- Install %s ...\n", path);
set_sdcard_update_bootloader_message();
void* token = start_sdcard_fuse(path);
int status = install_package(FUSE_SIDELOAD_HOST_PATHNAME, wipe_cache,
TEMPORARY_INSTALL_FILE, false);
// We used to use fuse in a thread as opposed to a process. Since accessing
// through fuse involves going from kernel to userspace to kernel, it leads
// to deadlock when a page fault occurs. (Bug: 26313124)
pid_t child;
if ((child = fork()) == 0) {
bool status = start_sdcard_fuse(path);
_exit(status ? EXIT_SUCCESS : EXIT_FAILURE);
}
// FUSE_SIDELOAD_HOST_PATHNAME will start to exist once the fuse in child
// process is ready.
int result = INSTALL_ERROR;
int status;
bool waited = false;
for (int i = 0; i < SDCARD_INSTALL_TIMEOUT; ++i) {
if (waitpid(child, &status, WNOHANG) == -1) {
result = INSTALL_ERROR;
waited = true;
break;
}
struct stat sb;
if (stat(FUSE_SIDELOAD_HOST_PATHNAME, &sb) == -1) {
if (errno == ENOENT && i < SDCARD_INSTALL_TIMEOUT-1) {
sleep(1);
continue;
} else {
LOGE("Timed out waiting for the fuse-provided package.\n");
result = INSTALL_ERROR;
kill(child, SIGKILL);
break;
}
}
result = install_package(FUSE_SIDELOAD_HOST_PATHNAME, wipe_cache,
TEMPORARY_INSTALL_FILE, false, 0/*retry_count*/);
break;
}
if (!waited) {
// Calling stat() on this magic filename signals the fuse
// filesystem to shut down.
struct stat sb;
stat(FUSE_SIDELOAD_HOST_EXIT_PATHNAME, &sb);
waitpid(child, &status, 0);
}
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
LOGE("Error exit from the fuse process: %d\n", WEXITSTATUS(status));
}
finish_sdcard_fuse(token);
ensure_path_unmounted(SDCARD_ROOT);
return status;
return result;
}
// Return REBOOT, SHUTDOWN, or REBOOT_BOOTLOADER. Returning NO_ACTION
@@ -852,10 +1102,29 @@ prompt_and_wait(Device* device, int status) {
choose_recovery_file(device);
break;
case Device::RUN_GRAPHICS_TEST:
run_graphics_test(device);
break;
case Device::MOUNT_SYSTEM:
if (ensure_path_mounted("/system") != -1) {
ui->Print("Mounted /system.\n");
char system_root_image[PROPERTY_VALUE_MAX];
property_get("ro.build.system_root_image", system_root_image, "");
// For a system image built with the root directory (i.e.
// system_root_image == "true"), we mount it to /system_root, and symlink /system
// to /system_root/system to make adb shell work (the symlink is created through
// the build system).
// Bug: 22855115
if (strcmp(system_root_image, "true") == 0) {
if (ensure_path_mounted_at("/", "/system_root") != -1) {
ui->Print("Mounted /system.\n");
}
} else {
if (ensure_path_mounted("/system") != -1) {
ui->Print("Mounted /system.\n");
}
}
break;
}
}
@@ -903,11 +1172,145 @@ ui_print(const char* format, ...) {
}
}
int
main(int argc, char **argv) {
time_t start = time(NULL);
static bool is_battery_ok() {
struct healthd_config healthd_config = {
.batteryStatusPath = android::String8(android::String8::kEmptyString),
.batteryHealthPath = android::String8(android::String8::kEmptyString),
.batteryPresentPath = android::String8(android::String8::kEmptyString),
.batteryCapacityPath = android::String8(android::String8::kEmptyString),
.batteryVoltagePath = android::String8(android::String8::kEmptyString),
.batteryTemperaturePath = android::String8(android::String8::kEmptyString),
.batteryTechnologyPath = android::String8(android::String8::kEmptyString),
.batteryCurrentNowPath = android::String8(android::String8::kEmptyString),
.batteryCurrentAvgPath = android::String8(android::String8::kEmptyString),
.batteryChargeCounterPath = android::String8(android::String8::kEmptyString),
.batteryFullChargePath = android::String8(android::String8::kEmptyString),
.batteryCycleCountPath = android::String8(android::String8::kEmptyString),
.energyCounter = NULL,
.boot_min_cap = 0,
.screen_on = NULL
};
healthd_board_init(&healthd_config);
redirect_stdio(TEMPORARY_LOG_FILE);
android::BatteryMonitor monitor;
monitor.init(&healthd_config);
int wait_second = 0;
while (true) {
int charge_status = monitor.getChargeStatus();
// Treat unknown status as charged.
bool charged = (charge_status != android::BATTERY_STATUS_DISCHARGING &&
charge_status != android::BATTERY_STATUS_NOT_CHARGING);
android::BatteryProperty capacity;
android::status_t status = monitor.getProperty(android::BATTERY_PROP_CAPACITY, &capacity);
ui_print("charge_status %d, charged %d, status %d, capacity %lld\n", charge_status,
charged, status, capacity.valueInt64);
// At startup, the battery drivers in devices like N5X/N6P take some time to load
// the battery profile. Before the load finishes, it reports value 50 as a fake
// capacity. BATTERY_READ_TIMEOUT_IN_SEC is set that the battery drivers are expected
// to finish loading the battery profile earlier than 10 seconds after kernel startup.
if (status == 0 && capacity.valueInt64 == 50) {
if (wait_second < BATTERY_READ_TIMEOUT_IN_SEC) {
sleep(1);
wait_second++;
continue;
}
}
// If we can't read battery percentage, it may be a device without battery. In this
// situation, use 100 as a fake battery percentage.
if (status != 0) {
capacity.valueInt64 = 100;
}
return (charged && capacity.valueInt64 >= BATTERY_WITH_CHARGER_OK_PERCENTAGE) ||
(!charged && capacity.valueInt64 >= BATTERY_OK_PERCENTAGE);
}
}
static void set_retry_bootloader_message(int retry_count, int argc, char** argv) {
struct bootloader_message boot {};
strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
for (int i = 1; i < argc; ++i) {
if (strstr(argv[i], "retry_count") == nullptr) {
strlcat(boot.recovery, argv[i], sizeof(boot.recovery));
strlcat(boot.recovery, "\n", sizeof(boot.recovery));
}
}
// Initialize counter to 1 if it's not in BCB, otherwise increment it by 1.
if (retry_count == 0) {
strlcat(boot.recovery, "--retry_count=1\n", sizeof(boot.recovery));
} else {
char buffer[20];
snprintf(buffer, sizeof(buffer), "--retry_count=%d\n", retry_count+1);
strlcat(boot.recovery, buffer, sizeof(boot.recovery));
}
set_bootloader_message(&boot);
}
static ssize_t logbasename(
log_id_t /* logId */,
char /* prio */,
const char *filename,
const char * /* buf */, size_t len,
void *arg) {
if (strstr(LAST_KMSG_FILE, filename) ||
strstr(LAST_LOG_FILE, filename)) {
bool *doRotate = reinterpret_cast<bool *>(arg);
*doRotate = true;
}
return len;
}
static ssize_t logrotate(
log_id_t logId,
char prio,
const char *filename,
const char *buf, size_t len,
void *arg) {
bool *doRotate = reinterpret_cast<bool *>(arg);
if (!*doRotate) {
return __android_log_pmsg_file_write(logId, prio, filename, buf, len);
}
std::string name(filename);
size_t dot = name.find_last_of(".");
std::string sub = name.substr(0, dot);
if (!strstr(LAST_KMSG_FILE, sub.c_str()) &&
!strstr(LAST_LOG_FILE, sub.c_str())) {
return __android_log_pmsg_file_write(logId, prio, filename, buf, len);
}
// filename rotation
if (dot == std::string::npos) {
name += ".1";
} else {
std::string number = name.substr(dot + 1);
if (!isdigit(number.data()[0])) {
name += ".1";
} else {
unsigned long long i = std::stoull(number);
name = sub + "." + std::to_string(i + 1);
}
}
return __android_log_pmsg_file_write(logId, prio, name.c_str(), buf, len);
}
int main(int argc, char **argv) {
// Take last pmsg contents and rewrite it to the current pmsg session.
static const char filter[] = "recovery/";
// Do we need to rotate?
bool doRotate = false;
__android_log_pmsg_file_read(
LOG_ID_SYSTEM, ANDROID_LOG_INFO, filter,
logbasename, &doRotate);
// Take action to refresh pmsg contents
__android_log_pmsg_file_read(
LOG_ID_SYSTEM, ANDROID_LOG_INFO, filter,
logrotate, &doRotate);
// If this binary is started with the single argument "--adbd",
// instead of being the normal recovery binary, it turns into kind
@@ -917,13 +1320,21 @@ main(int argc, char **argv) {
// only way recovery should be run with this argument is when it
// starts a copy of itself from the apply_from_adb() function.
if (argc == 2 && strcmp(argv[1], "--adbd") == 0) {
adb_main(0, DEFAULT_ADB_PORT);
adb_server_main(0, DEFAULT_ADB_PORT, -1);
return 0;
}
time_t start = time(NULL);
// redirect_stdio should be called only in non-sideload mode. Otherwise
// we may have two logger instances with different timestamps.
redirect_stdio(TEMPORARY_LOG_FILE);
printf("Starting recovery (pid %d) on %s", getpid(), ctime(&start));
load_volume_table();
has_cache = volume_for_path(CACHE_ROOT) != nullptr;
get_args(&argc, &argv);
const char *send_intent = NULL;
@@ -935,11 +1346,14 @@ main(int argc, char **argv) {
bool sideload_auto_reboot = false;
bool just_exit = false;
bool shutdown_after = false;
int retry_count = 0;
bool security_update = false;
int arg;
while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) {
switch (arg) {
case 'i': send_intent = optarg; break;
case 'n': android::base::ParseInt(optarg, &retry_count, 0); break;
case 'u': update_package = optarg; break;
case 'w': should_wipe_data = true; break;
case 'c': should_wipe_cache = true; break;
@@ -958,13 +1372,14 @@ main(int argc, char **argv) {
}
case 'p': shutdown_after = true; break;
case 'r': reason = optarg; break;
case 'e': security_update = true; break;
case '?':
LOGE("Invalid command argument\n");
continue;
}
}
if (locale == NULL) {
if (locale == nullptr && has_cache) {
load_locale_from_cache();
}
printf("locale is [%s]\n", locale);
@@ -977,6 +1392,9 @@ main(int argc, char **argv) {
ui->SetLocale(locale);
ui->Init();
// Set background string to "installing security update" for security update,
// otherwise set it to "installing system update".
ui->SetSystemUpdateText(security_update);
int st_cur, st_max;
if (stage != NULL && sscanf(stage, "%d/%d", &st_cur, &st_max) == 2) {
@@ -1011,11 +1429,15 @@ main(int argc, char **argv) {
if (strncmp(update_package, "CACHE:", 6) == 0) {
int len = strlen(update_package) + 10;
char* modified_path = (char*)malloc(len);
strlcpy(modified_path, "/cache/", len);
strlcat(modified_path, update_package+6, len);
printf("(replacing path \"%s\" with \"%s\")\n",
update_package, modified_path);
update_package = modified_path;
if (modified_path) {
strlcpy(modified_path, "/cache/", len);
strlcat(modified_path, update_package+6, len);
printf("(replacing path \"%s\" with \"%s\")\n",
update_package, modified_path);
update_package = modified_path;
}
else
printf("modified_path allocation failed\n");
}
}
printf("\n");
@@ -1028,18 +1450,57 @@ main(int argc, char **argv) {
int status = INSTALL_SUCCESS;
if (update_package != NULL) {
status = install_package(update_package, &should_wipe_cache, TEMPORARY_INSTALL_FILE, true);
if (status == INSTALL_SUCCESS && should_wipe_cache) {
wipe_cache(false, device);
}
if (status != INSTALL_SUCCESS) {
ui->Print("Installation aborted.\n");
// It's not entirely true that we will modify the flash. But we want
// to log the update attempt since update_package is non-NULL.
modified_flash = true;
// 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.
if (is_ro_debuggable()) {
ui->ShowText(true);
if (!is_battery_ok()) {
ui->Print("battery capacity is not enough for installing package, needed is %d%%\n",
BATTERY_OK_PERCENTAGE);
// Log the error code to last_install when installation skips due to
// low battery.
FILE* install_log = fopen_path(LAST_INSTALL_FILE, "w");
if (install_log != nullptr) {
fprintf(install_log, "%s\n", update_package);
fprintf(install_log, "0\n");
fprintf(install_log, "error: %d\n", kLowBattery);
fclose(install_log);
} else {
LOGE("failed to open last_install: %s\n", strerror(errno));
}
status = INSTALL_SKIPPED;
} else {
status = install_package(update_package, &should_wipe_cache,
TEMPORARY_INSTALL_FILE, true, retry_count);
if (status == INSTALL_SUCCESS && should_wipe_cache) {
wipe_cache(false, device);
}
if (status != INSTALL_SUCCESS) {
ui->Print("Installation aborted.\n");
// When I/O error happens, reboot and retry installation EIO_RETRY_COUNT
// times before we abandon this OTA update.
if (status == INSTALL_RETRY && retry_count < EIO_RETRY_COUNT) {
copy_logs();
set_retry_bootloader_message(retry_count, argc, argv);
// Print retry count on screen.
ui->Print("Retry attempt %d\n", retry_count);
// Reboot and retry the update
int ret = property_set(ANDROID_RB_PROPERTY, "reboot,recovery");
if (ret < 0) {
ui->Print("Reboot failed\n");
} else {
while (true) {
pause();
}
}
}
// 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.
if (is_ro_debuggable()) {
ui->ShowText(true);
}
}
}
} else if (should_wipe_data) {
@@ -1088,7 +1549,8 @@ main(int argc, char **argv) {
}
Device::BuiltinAction after = shutdown_after ? Device::SHUTDOWN : Device::REBOOT;
if ((status != INSTALL_SUCCESS && !sideload_auto_reboot) || ui->IsTextVisible()) {
if ((status != INSTALL_SUCCESS && status != INSTALL_SKIPPED && !sideload_auto_reboot) ||
ui->IsTextVisible()) {
Device::BuiltinAction temp = prompt_and_wait(device, status);
if (temp != Device::NO_ACTION) {
after = temp;
@@ -1114,6 +1576,9 @@ main(int argc, char **argv) {
property_set(ANDROID_RB_PROPERTY, "reboot,");
break;
}
sleep(5); // should reboot before this finishes
while (true) {
pause();
}
// Should be unreachable.
return EXIT_SUCCESS;
}
Symlink
+1
View File
@@ -0,0 +1 @@
res-xxxhdpi
+24 -26
View File
@@ -24,18 +24,14 @@
#include <ctype.h>
#include <fcntl.h>
extern "C" {
#include <fs_mgr.h>
#include "mtdutils/mtdutils.h"
#include "mtdutils/mounts.h"
}
#include "roots.h"
#include "common.h"
#include "make_ext4fs.h"
extern "C" {
#include "wipe.h"
#include "cryptfs.h"
}
static struct fstab *fstab = NULL;
@@ -74,11 +70,8 @@ Volume* volume_for_path(const char* path) {
return fs_mgr_get_entry_for_mount_point(fstab, path);
}
int ensure_path_mounted(const char* path) {
if (PartitionManager.Mount_By_Path(path, true))
return 0;
else
return -1;
// Mount the volume specified by path at the given mount_point.
int ensure_path_mounted_at(const char* path, const char* mount_point) {
Volume* v = volume_for_path(path);
if (v == NULL) {
LOGE("unknown volume for path [%s]\n", path);
@@ -96,14 +89,18 @@ int ensure_path_mounted(const char* path) {
return -1;
}
if (!mount_point) {
mount_point = v->mount_point;
}
const MountedVolume* mv =
find_mounted_volume_by_mount_point(v->mount_point);
find_mounted_volume_by_mount_point(mount_point);
if (mv) {
// volume is already mounted
return 0;
}
mkdir(v->mount_point, 0755); // in case it doesn't already exist
mkdir(mount_point, 0755); // in case it doesn't already exist
if (strcmp(v->fs_type, "yaffs2") == 0) {
// mount an MTD partition as a YAFFS2 filesystem.
@@ -112,30 +109,31 @@ int ensure_path_mounted(const char* path) {
partition = mtd_find_partition_by_name(v->blk_device);
if (partition == NULL) {
LOGE("failed to find \"%s\" partition to mount at \"%s\"\n",
v->blk_device, v->mount_point);
v->blk_device, mount_point);
return -1;
}
return mtd_mount_partition(partition, v->mount_point, v->fs_type, 0);
return mtd_mount_partition(partition, mount_point, v->fs_type, 0);
} else if (strcmp(v->fs_type, "ext4") == 0 ||
strcmp(v->fs_type, "squashfs") == 0 ||
strcmp(v->fs_type, "vfat") == 0) {
result = mount(v->blk_device, v->mount_point, v->fs_type,
result = mount(v->blk_device, mount_point, v->fs_type,
v->flags, v->fs_options);
if (result == 0) return 0;
LOGE("failed to mount %s (%s)\n", v->mount_point, strerror(errno));
LOGE("failed to mount %s (%s)\n", mount_point, strerror(errno));
return -1;
}
LOGE("unknown fs_type \"%s\" for %s\n", v->fs_type, v->mount_point);
LOGE("unknown fs_type \"%s\" for %s\n", v->fs_type, mount_point);
return -1;
}
int ensure_path_mounted(const char* path) {
// Mount at the default mount point.
return ensure_path_mounted_at(path, nullptr);
}
int ensure_path_unmounted(const char* path) {
if (PartitionManager.UnMount_By_Path(path, true))
return 0;
else
return -1;
Volume* v = volume_for_path(path);
if (v == NULL) {
LOGE("unknown volume for path [%s]\n", path);
@@ -177,11 +175,7 @@ static int exec_cmd(const char* path, char* const argv[]) {
return WEXITSTATUS(status);
}
int format_volume(const char* volume) {
if (PartitionManager.Wipe_By_Path(volume))
return 0;
else
return -1;
int format_volume(const char* volume, const char* directory) {
Volume* v = volume_for_path(volume);
if (v == NULL) {
LOGE("unknown volume \"%s\"\n", volume);
@@ -247,7 +241,7 @@ int format_volume(const char* volume) {
}
int result;
if (strcmp(v->fs_type, "ext4") == 0) {
result = make_ext4fs(v->blk_device, length, volume, sehandle);
result = make_ext4fs_directory(v->blk_device, length, volume, sehandle, directory);
} else { /* Has to be f2fs because we checked earlier. */
if (v->key_loc != NULL && strcmp(v->key_loc, "footer") == 0 && length < 0) {
LOGE("format_volume: crypt footer + negative length (%zd) not supported on %s\n", length, v->fs_type);
@@ -279,6 +273,10 @@ int format_volume(const char* volume) {
return -1;
}
int format_volume(const char* volume) {
return format_volume(volume, NULL);
}
int setup_install_mounts() {
if (fstab == NULL) {
LOGE("can't set up install mounts: no fstab loaded\n");
+10 -9
View File
@@ -19,10 +19,6 @@
#include "common.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct fstab_rec Volume;
// Load and parse volume data from /etc/recovery.fstab.
@@ -35,7 +31,10 @@ Volume* volume_for_path(const char* path);
// success (volume is mounted).
int ensure_path_mounted(const char* path);
// Make sure that the volume 'path' is on is mounted. Returns 0 on
// Similar to ensure_path_mounted, but allows one to specify the mount_point.
int ensure_path_mounted_at(const char* path, const char* mount_point);
// Make sure that the volume 'path' is on is unmounted. Returns 0 on
// success (volume is unmounted);
int ensure_path_unmounted(const char* path);
@@ -44,12 +43,14 @@ int ensure_path_unmounted(const char* path);
// it is mounted.
int format_volume(const char* volume);
// Reformat the given volume (must be the mount point only, eg
// "/cache"), no paths permitted. Attempts to unmount the volume if
// it is mounted.
// Copies 'directory' to root of the newly formatted volume
int format_volume(const char* volume, const char* directory);
// Ensure that all and only the volumes that packages expect to find
// mounted (/tmp and /cache) are mounted. Returns 0 on success.
int setup_install_mounts();
#ifdef __cplusplus
}
#endif
#endif // RECOVERY_ROOTS_H_
+209 -126
View File
@@ -14,6 +14,7 @@
* limitations under the License.
*/
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/input.h>
@@ -30,22 +31,17 @@
#include <vector>
#include "base/strings.h"
#include "cutils/properties.h"
#include <android-base/strings.h>
#include <android-base/stringprintf.h>
#include <cutils/properties.h>
#include "common.h"
#include "device.h"
#include "minui/minui.h"
#include "screen_ui.h"
#include "ui.h"
extern "C" {
#include "minuitwrp/minui.h"
int twgr_text(int x, int y, const char *s);
#include "gui/gui.h"
}
#include "data.hpp"
static int char_width;
static int char_height;
#define TEXT_INDENT 4
// Return the current time as a double (including fractions of a second).
static double now() {
@@ -56,9 +52,9 @@ static double now() {
ScreenRecoveryUI::ScreenRecoveryUI() :
currentIcon(NONE),
installingFrame(0),
locale(nullptr),
rtl_locale(false),
intro_done(false),
current_frame(0),
progressBarType(EMPTY),
progressScopeStart(0),
progressScopeSize(0),
@@ -77,83 +73,114 @@ ScreenRecoveryUI::ScreenRecoveryUI() :
menu_items(0),
menu_sel(0),
file_viewer_text_(nullptr),
animation_fps(20),
installing_frames(-1),
intro_frames(0),
loop_frames(0),
animation_fps(30), // TODO: there's currently no way to infer this.
stage(-1),
max_stage(-1) {
max_stage(-1),
updateMutex(PTHREAD_MUTEX_INITIALIZER),
rtl_locale(false) {
}
for (int i = 0; i < 5; i++) {
backgroundIcon[i] = nullptr;
GRSurface* ScreenRecoveryUI::GetCurrentFrame() {
if (currentIcon == INSTALLING_UPDATE || currentIcon == ERASING) {
return intro_done ? loopFrames[current_frame] : introFrames[current_frame];
}
pthread_mutex_init(&updateMutex, nullptr);
return error_icon;
}
GRSurface* ScreenRecoveryUI::GetCurrentText() {
switch (currentIcon) {
case ERASING: return erasing_text;
case ERROR: return error_text;
case INSTALLING_UPDATE: return installing_text;
case NO_COMMAND: return no_command_text;
case NONE: abort();
}
}
int ScreenRecoveryUI::PixelsFromDp(int dp) {
return dp * density_;
}
// Here's the intended layout:
// | regular large
// ---------+--------------------
// | 220dp 366dp
// icon | (200dp) (200dp)
// | 68dp 68dp
// text | (14sp) (14sp)
// | 32dp 32dp
// progress | (2dp) (2dp)
// | 194dp 340dp
// Note that "baseline" is actually the *top* of each icon (because that's how our drawing
// routines work), so that's the more useful measurement for calling code.
int ScreenRecoveryUI::GetAnimationBaseline() {
return GetTextBaseline() - PixelsFromDp(68) - gr_get_height(loopFrames[0]);
}
int ScreenRecoveryUI::GetTextBaseline() {
return GetProgressBaseline() - PixelsFromDp(32) - gr_get_height(installing_text);
}
int ScreenRecoveryUI::GetProgressBaseline() {
return gr_fb_height() - PixelsFromDp(is_large_ ? 340 : 194) - gr_get_height(progressBarFill);
}
// Clear the screen and draw the currently selected background icon (if any).
// Should only be called with updateMutex locked.
void ScreenRecoveryUI::draw_background_locked(Icon icon) {
void ScreenRecoveryUI::draw_background_locked() {
pagesIdentical = false;
gr_color(0, 0, 0, 255);
gr_clear();
if (icon) {
GRSurface* surface = backgroundIcon[icon];
if (icon == INSTALLING_UPDATE || icon == ERASING) {
surface = installation[installingFrame];
}
GRSurface* 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 stageHeight = gr_get_height(stageMarkerEmpty);
int sh = (max_stage >= 0) ? stageHeight : 0;
iconX = (gr_fb_width() - iconWidth) / 2;
iconY = (gr_fb_height() - (iconHeight+textHeight+40+sh)) / 2;
int textX = (gr_fb_width() - textWidth) / 2;
int textY = ((gr_fb_height() - (iconHeight+textHeight+40+sh)) / 2) + iconHeight + 40;
gr_blit(surface, 0, 0, iconWidth, iconHeight, iconX, iconY);
if (stageHeight > 0) {
int sw = gr_get_width(stageMarkerEmpty);
if (currentIcon != NONE) {
if (max_stage != -1) {
int stage_height = gr_get_height(stageMarkerEmpty);
int stage_width = gr_get_width(stageMarkerEmpty);
int x = (gr_fb_width() - max_stage * gr_get_width(stageMarkerEmpty)) / 2;
int y = iconY + iconHeight + 20;
int y = gr_fb_height() - stage_height;
for (int i = 0; i < max_stage; ++i) {
gr_blit((i < stage) ? stageMarkerFill : stageMarkerEmpty,
0, 0, sw, stageHeight, x, y);
x += sw;
GRSurface* stage_surface = (i < stage) ? stageMarkerFill : stageMarkerEmpty;
gr_blit(stage_surface, 0, 0, stage_width, stage_height, x, y);
x += stage_width;
}
}
GRSurface* text_surface = GetCurrentText();
int text_x = (gr_fb_width() - gr_get_width(text_surface)) / 2;
int text_y = GetTextBaseline();
gr_color(255, 255, 255, 255);
gr_texticon(textX, textY, text_surface);
gr_texticon(text_x, text_y, text_surface);
}
}
// Draw the progress bar (if any) on the screen. Does not flip pages.
// Draws the animation and progress bar (if any) on the screen.
// Does not flip pages.
// Should only be called with updateMutex locked.
void ScreenRecoveryUI::draw_progress_locked() {
if (currentIcon == ERROR) return;
if (currentIcon == INSTALLING_UPDATE || currentIcon == ERASING) {
GRSurface* icon = installation[installingFrame];
gr_blit(icon, 0, 0, gr_get_width(icon), gr_get_height(icon), iconX, iconY);
void ScreenRecoveryUI::draw_foreground_locked() {
if (currentIcon != NONE) {
GRSurface* frame = GetCurrentFrame();
int frame_width = gr_get_width(frame);
int frame_height = gr_get_height(frame);
int frame_x = (gr_fb_width() - frame_width) / 2;
int frame_y = GetAnimationBaseline();
gr_blit(frame, 0, 0, frame_width, frame_height, frame_x, frame_y);
}
if (progressBarType != EMPTY) {
int iconHeight = gr_get_height(backgroundIcon[INSTALLING_UPDATE]);
int width = gr_get_width(progressBarEmpty);
int height = gr_get_height(progressBarEmpty);
int dx = (gr_fb_width() - width)/2;
int dy = (3*gr_fb_height() + iconHeight - 2*height)/4;
int progress_x = (gr_fb_width() - width)/2;
int progress_y = GetProgressBaseline();
// Erase behind the progress bar (in case this was a progress-only update)
gr_color(0, 0, 0, 255);
gr_fill(dx, dy, width, height);
gr_fill(progress_x, progress_y, width, height);
if (progressBarType == DETERMINATE) {
float p = progressScopeStart + progress * progressScopeSize;
@@ -162,18 +189,20 @@ void ScreenRecoveryUI::draw_progress_locked() {
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);
gr_blit(progressBarFill, width-pos, 0, pos, height,
progress_x+width-pos, progress_y);
}
if (pos < width-1) {
gr_blit(progressBarEmpty, 0, 0, width-pos, height, dx, dy);
gr_blit(progressBarEmpty, 0, 0, width-pos, height, progress_x, progress_y);
}
} else {
// Fill the progress bar from left to right.
if (pos > 0) {
gr_blit(progressBarFill, 0, 0, pos, height, dx, dy);
gr_blit(progressBarFill, 0, 0, pos, height, progress_x, progress_y);
}
if (pos < width-1) {
gr_blit(progressBarEmpty, pos, 0, width-pos, height, dx+pos, dy);
gr_blit(progressBarEmpty, pos, 0, width-pos, height,
progress_x+pos, progress_y);
}
}
}
@@ -217,14 +246,14 @@ void ScreenRecoveryUI::DrawHorizontalRule(int* y) {
*y += 4;
}
void ScreenRecoveryUI::DrawTextLine(int* y, const char* line, bool bold) {
gr_text(4, *y, line, bold);
*y += char_height + 4;
void ScreenRecoveryUI::DrawTextLine(int x, int* y, const char* line, bool bold) {
gr_text(x, *y, line, bold);
*y += char_height_ + 4;
}
void ScreenRecoveryUI::DrawTextLines(int* y, const char* const* lines) {
void ScreenRecoveryUI::DrawTextLines(int x, int* y, const char* const* lines) {
for (size_t i = 0; lines != nullptr && lines[i] != nullptr; ++i) {
DrawTextLine(y, lines[i], false);
DrawTextLine(x, y, lines[i], false);
}
}
@@ -243,8 +272,8 @@ static const char* LONG_PRESS_HELP[] = {
// Should only be called with updateMutex locked.
void ScreenRecoveryUI::draw_screen_locked() {
if (!show_text) {
draw_background_locked(currentIcon);
draw_progress_locked();
draw_background_locked();
draw_foreground_locked();
} else {
gr_color(0, 0, 0, 255);
gr_clear();
@@ -255,14 +284,14 @@ void ScreenRecoveryUI::draw_screen_locked() {
property_get("ro.bootimage.build.fingerprint", recovery_fingerprint, "");
SetColor(INFO);
DrawTextLine(&y, "Android Recovery", true);
DrawTextLine(TEXT_INDENT, &y, "Android Recovery", true);
for (auto& chunk : android::base::Split(recovery_fingerprint, ":")) {
DrawTextLine(&y, chunk.c_str(), false);
DrawTextLine(TEXT_INDENT, &y, chunk.c_str(), false);
}
DrawTextLines(&y, HasThreeButtons() ? REGULAR_HELP : LONG_PRESS_HELP);
DrawTextLines(TEXT_INDENT, &y, HasThreeButtons() ? REGULAR_HELP : LONG_PRESS_HELP);
SetColor(HEADER);
DrawTextLines(&y, menu_headers_);
DrawTextLines(TEXT_INDENT, &y, menu_headers_);
SetColor(MENU);
DrawHorizontalRule(&y);
@@ -271,7 +300,7 @@ void ScreenRecoveryUI::draw_screen_locked() {
if (i == menu_sel) {
// Draw the highlight bar.
SetColor(IsLongPress() ? MENU_SEL_BG_ACTIVE : MENU_SEL_BG);
gr_fill(0, y - 2, gr_fb_width(), y + char_height + 2);
gr_fill(0, y - 2, gr_fb_width(), y + char_height_ + 2);
// Bold white text for the selected item.
SetColor(MENU_SEL_FG);
gr_text(4, y, menu_[i], true);
@@ -279,7 +308,7 @@ void ScreenRecoveryUI::draw_screen_locked() {
} else {
gr_text(4, y, menu_[i], false);
}
y += char_height + 4;
y += char_height_ + 4;
}
DrawHorizontalRule(&y);
}
@@ -290,9 +319,9 @@ void ScreenRecoveryUI::draw_screen_locked() {
SetColor(LOG);
int row = (text_top_ + text_rows_ - 1) % text_rows_;
size_t count = 0;
for (int ty = gr_fb_height() - char_height;
for (int ty = gr_fb_height() - char_height_;
ty >= y && count < text_rows_;
ty -= char_height, ++count) {
ty -= char_height_, ++count) {
gr_text(0, ty, text_[row], false);
--row;
if (row < 0) row = text_rows_ - 1;
@@ -309,13 +338,12 @@ void ScreenRecoveryUI::update_screen_locked() {
// Updates only the progress bar, if possible, otherwise redraws the screen.
// Should only be called with updateMutex locked.
void ScreenRecoveryUI::update_progress_locked() {
if (show_text || !pagesIdentical) {
draw_screen_locked(); // Must redraw the whole screen
pagesIdentical = true;
} else {
draw_progress_locked(); // Draw only the progress bar and overlays
draw_foreground_locked(); // Draw only the progress bar and overlays
}
gr_flip();
}
@@ -332,14 +360,23 @@ void ScreenRecoveryUI::ProgressThreadLoop() {
double start = now();
pthread_mutex_lock(&updateMutex);
int redraw = 0;
bool redraw = false;
// update the installation animation, if active
// skip this if we have a text overlay (too expensive to update)
if ((currentIcon == INSTALLING_UPDATE || currentIcon == ERASING) &&
installing_frames > 0 && !show_text) {
installingFrame = (installingFrame + 1) % installing_frames;
redraw = 1;
if ((currentIcon == INSTALLING_UPDATE || currentIcon == ERASING) && !show_text) {
if (!intro_done) {
if (current_frame == intro_frames - 1) {
intro_done = true;
current_frame = 0;
} else {
++current_frame;
}
} else {
current_frame = (current_frame + 1) % loop_frames;
}
redraw = true;
}
// move the progress bar forward on timed intervals, if configured
@@ -350,7 +387,7 @@ void ScreenRecoveryUI::ProgressThreadLoop() {
if (p > 1.0) p = 1.0;
if (p > progress) {
progress = p;
redraw = 1;
redraw = true;
}
}
@@ -368,21 +405,14 @@ void ScreenRecoveryUI::ProgressThreadLoop() {
void ScreenRecoveryUI::LoadBitmap(const char* filename, GRSurface** surface) {
int result = res_create_display_surface(filename, surface);
if (result < 0) {
LOGE("missing bitmap %s\n(Code %d)\n", filename, result);
}
}
void ScreenRecoveryUI::LoadBitmapArray(const char* filename, int* frames, GRSurface*** surface) {
int result = res_create_multi_display_surface(filename, frames, surface);
if (result < 0) {
LOGE("missing bitmap %s\n(Code %d)\n", filename, result);
LOGE("couldn't load bitmap %s (error %d)\n", filename, result);
}
}
void ScreenRecoveryUI::LoadLocalizedBitmap(const char* filename, GRSurface** surface) {
int result = res_create_localized_alpha_surface(filename, locale, surface);
if (result < 0) {
LOGE("missing bitmap %s\n(Code %d)\n", filename, result);
LOGE("couldn't load bitmap %s (error %d)\n", filename, result);
}
}
@@ -395,12 +425,25 @@ static char** Alloc2d(size_t rows, size_t cols) {
return result;
}
// Choose the right background string to display during update.
void ScreenRecoveryUI::SetSystemUpdateText(bool security_update) {
if (security_update) {
LoadLocalizedBitmap("installing_security_text", &installing_text);
} else {
LoadLocalizedBitmap("installing_text", &installing_text);
}
Redraw();
}
void ScreenRecoveryUI::Init() {
gr_init();
gr_font_size(&char_width, &char_height);
text_rows_ = gr_fb_height() / char_height;
text_cols_ = gr_fb_width() / char_width;
density_ = static_cast<float>(property_get_int32("ro.sf.lcd_density", 160)) / 160.f;
is_large_ = gr_fb_height() > PixelsFromDp(800);
gr_font_size(&char_width_, &char_height_);
text_rows_ = gr_fb_height() / char_height_;
text_cols_ = gr_fb_width() / char_width_;
text_ = Alloc2d(text_rows_, text_cols_ + 1);
file_viewer_text_ = Alloc2d(text_rows_, text_cols_ + 1);
@@ -409,31 +452,64 @@ void ScreenRecoveryUI::Init() {
text_col_ = text_row_ = 0;
text_top_ = 1;
backgroundIcon[NONE] = nullptr;
LoadBitmapArray("icon_installing", &installing_frames, &installation);
backgroundIcon[INSTALLING_UPDATE] = installing_frames ? installation[0] : nullptr;
backgroundIcon[ERASING] = backgroundIcon[INSTALLING_UPDATE];
LoadBitmap("icon_error", &backgroundIcon[ERROR]);
backgroundIcon[NO_COMMAND] = backgroundIcon[ERROR];
LoadBitmap("icon_error", &error_icon);
LoadBitmap("progress_empty", &progressBarEmpty);
LoadBitmap("progress_fill", &progressBarFill);
LoadBitmap("stage_empty", &stageMarkerEmpty);
LoadBitmap("stage_fill", &stageMarkerFill);
LoadLocalizedBitmap("installing_text", &backgroundText[INSTALLING_UPDATE]);
LoadLocalizedBitmap("erasing_text", &backgroundText[ERASING]);
LoadLocalizedBitmap("no_command_text", &backgroundText[NO_COMMAND]);
LoadLocalizedBitmap("error_text", &backgroundText[ERROR]);
// Background text for "installing_update" could be "installing update"
// or "installing security update". It will be set after UI init according
// to commands in BCB.
installing_text = nullptr;
LoadLocalizedBitmap("erasing_text", &erasing_text);
LoadLocalizedBitmap("no_command_text", &no_command_text);
LoadLocalizedBitmap("error_text", &error_text);
LoadAnimation();
pthread_create(&progress_thread_, nullptr, ProgressThreadStartRoutine, this);
RecoveryUI::Init();
}
void ScreenRecoveryUI::LoadAnimation() {
// How many frames of intro and loop do we have?
std::unique_ptr<DIR, decltype(&closedir)> dir(opendir("/res/images"), closedir);
dirent* de;
while ((de = readdir(dir.get())) != nullptr) {
int value;
if (sscanf(de->d_name, "intro%d", &value) == 1 && intro_frames < (value + 1)) {
intro_frames = value + 1;
} else if (sscanf(de->d_name, "loop%d", &value) == 1 && loop_frames < (value + 1)) {
loop_frames = value + 1;
}
}
// It's okay to not have an intro.
if (intro_frames == 0) intro_done = true;
// But you must have an animation.
if (loop_frames == 0) abort();
introFrames = new GRSurface*[intro_frames];
for (int i = 0; i < intro_frames; ++i) {
// TODO: remember the names above, so we don't have to hard-code the number of 0s.
LoadBitmap(android::base::StringPrintf("intro%05d", i).c_str(), &introFrames[i]);
}
loopFrames = new GRSurface*[loop_frames];
for (int i = 0; i < loop_frames; ++i) {
LoadBitmap(android::base::StringPrintf("loop%05d", i).c_str(), &loopFrames[i]);
}
}
void ScreenRecoveryUI::SetLocale(const char* new_locale) {
if (new_locale) {
this->locale = new_locale;
this->locale = new_locale;
this->rtl_locale = false;
if (locale) {
char* lang = strdup(locale);
for (char* p = lang; *p; ++p) {
if (*p == '_') {
@@ -442,8 +518,7 @@ void ScreenRecoveryUI::SetLocale(const char* new_locale) {
}
}
// A bit cheesy: keep an explicit list of supported languages
// that are RTL.
// A bit cheesy: keep an explicit list of supported RTL languages.
if (strcmp(lang, "ar") == 0 || // Arabic
strcmp(lang, "fa") == 0 || // Persian (Farsi)
strcmp(lang, "he") == 0 || // Hebrew (new language code)
@@ -452,8 +527,6 @@ void ScreenRecoveryUI::SetLocale(const char* new_locale) {
rtl_locale = true;
}
free(lang);
} else {
new_locale = nullptr;
}
}
@@ -513,21 +586,17 @@ void ScreenRecoveryUI::SetStage(int current, int max) {
pthread_mutex_unlock(&updateMutex);
}
void ScreenRecoveryUI::Print(const char *fmt, ...) {
char buf[256];
va_list ap;
va_start(ap, fmt);
vsnprintf(buf, 256, fmt, ap);
va_end(ap);
void ScreenRecoveryUI::PrintV(const char* fmt, bool copy_to_stdout, va_list ap) {
std::string str;
android::base::StringAppendV(&str, fmt, ap);
gui_print("%s", buf);
return;
fputs(buf, stdout);
if (copy_to_stdout) {
fputs(str.c_str(), stdout);
}
pthread_mutex_lock(&updateMutex);
if (text_rows_ > 0 && text_cols_ > 0) {
for (const char* ptr = buf; *ptr != '\0'; ++ptr) {
for (const char* ptr = str.c_str(); *ptr != '\0'; ++ptr) {
if (*ptr == '\n' || text_col_ >= text_cols_) {
text_[text_row_][text_col_] = '\0';
text_col_ = 0;
@@ -542,6 +611,20 @@ void ScreenRecoveryUI::Print(const char *fmt, ...) {
pthread_mutex_unlock(&updateMutex);
}
void ScreenRecoveryUI::Print(const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
PrintV(fmt, true, ap);
va_end(ap);
}
void ScreenRecoveryUI::PrintOnScreenOnly(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
PrintV(fmt, false, ap);
va_end(ap);
}
void ScreenRecoveryUI::PutChar(char ch) {
pthread_mutex_lock(&updateMutex);
if (ch != '\n') text_[text_row_][text_col_++] = ch;
@@ -576,7 +659,7 @@ void ScreenRecoveryUI::ShowFile(FILE* fp) {
bool show_prompt = false;
while (true) {
if (show_prompt) {
Print("--(%d%% of %d bytes)--",
PrintOnScreenOnly("--(%d%% of %d bytes)--",
static_cast<int>(100 * (double(ftell(fp)) / double(sb.st_size))),
static_cast<int>(sb.st_size));
Redraw();
+48 -18
View File
@@ -34,6 +34,7 @@ class ScreenRecoveryUI : public RecoveryUI {
// overall recovery state ("background image")
void SetBackground(Icon icon);
void SetSystemUpdateText(bool security_update);
// progress indicator
void SetProgressType(ProgressType type);
@@ -49,6 +50,7 @@ class ScreenRecoveryUI : public RecoveryUI {
// printing messages
void Print(const char* fmt, ...) __printflike(2, 3);
void PrintOnScreenOnly(const char* fmt, ...) __printflike(2, 3);
void ShowFile(const char* filename);
// menu display
@@ -66,16 +68,28 @@ class ScreenRecoveryUI : public RecoveryUI {
};
void SetColor(UIElement e);
private:
protected:
Icon currentIcon;
int installingFrame;
const char* locale;
bool rtl_locale;
pthread_mutex_t updateMutex;
GRSurface* backgroundIcon[5];
GRSurface* backgroundText[5];
GRSurface** installation;
const char* locale;
bool intro_done;
int current_frame;
// The scale factor from dp to pixels. 1.0 for mdpi, 4.0 for xxxhdpi.
float density_;
// True if we should use the large layout.
bool is_large_;
GRSurface* error_icon;
GRSurface* erasing_text;
GRSurface* error_text;
GRSurface* installing_text;
GRSurface* no_command_text;
GRSurface** introFrames;
GRSurface** loopFrames;
GRSurface* progressBarEmpty;
GRSurface* progressBarFill;
GRSurface* stageMarkerEmpty;
@@ -108,33 +122,49 @@ class ScreenRecoveryUI : public RecoveryUI {
pthread_t progress_thread_;
int animation_fps;
int installing_frames;
// Number of intro frames and loop frames in the animation.
int intro_frames;
int loop_frames;
int iconX, iconY;
// Number of frames per sec (default: 30) for both parts of the animation.
int animation_fps;
int stage, max_stage;
void draw_background_locked(Icon icon);
void draw_progress_locked();
int char_width_;
int char_height_;
pthread_mutex_t updateMutex;
bool rtl_locale;
void draw_background_locked();
void draw_foreground_locked();
void draw_screen_locked();
void update_screen_locked();
void update_progress_locked();
GRSurface* GetCurrentFrame();
GRSurface* GetCurrentText();
static void* ProgressThreadStartRoutine(void* data);
void ProgressThreadLoop();
void ShowFile(FILE*);
void PrintV(const char*, bool, va_list);
void PutChar(char);
void ClearText();
void DrawHorizontalRule(int* y);
void DrawTextLine(int* y, const char* line, bool bold);
void DrawTextLines(int* y, const char* const* lines);
void LoadAnimation();
void LoadBitmap(const char* filename, GRSurface** surface);
void LoadBitmapArray(const char* filename, int* frames, GRSurface*** surface);
void LoadLocalizedBitmap(const char* filename, GRSurface** surface);
int PixelsFromDp(int dp);
int GetAnimationBaseline();
int GetProgressBaseline();
int GetTextBaseline();
void DrawHorizontalRule(int* y);
void DrawTextLine(int x, int* y, const char* line, bool bold);
void DrawTextLines(int x, int* y, const char* const* lines);
};
#endif // RECOVERY_UI_H
+48 -4
View File
@@ -16,10 +16,54 @@
LOCAL_PATH := $(call my-dir)
# Unit tests
include $(CLEAR_VARS)
LOCAL_CLANG := true
LOCAL_MODULE := recovery_unit_test
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_STATIC_LIBRARIES := libverifier
LOCAL_SRC_FILES := asn1_decoder_test.cpp
LOCAL_MODULE := asn1_decoder_test
LOCAL_C_INCLUDES := $(LOCAL_PATH)/..
LOCAL_STATIC_LIBRARIES := \
libverifier \
libminui
LOCAL_SRC_FILES := unit/asn1_decoder_test.cpp
LOCAL_SRC_FILES += unit/recovery_test.cpp
LOCAL_SRC_FILES += unit/locale_test.cpp
LOCAL_C_INCLUDES := bootable/recovery
LOCAL_SHARED_LIBRARIES := liblog
include $(BUILD_NATIVE_TEST)
# Component tests
include $(CLEAR_VARS)
LOCAL_CLANG := true
LOCAL_CFLAGS += -Wno-unused-parameter
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
LOCAL_MODULE := recovery_component_test
LOCAL_C_INCLUDES := bootable/recovery
LOCAL_SRC_FILES := \
component/verifier_test.cpp \
component/applypatch_test.cpp
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_STATIC_LIBRARIES := \
libapplypatch \
libotafault \
libmtdutils \
libbase \
libverifier \
libcrypto_static \
libminui \
libminzip \
libcutils \
libbz \
libz \
libc
testdata_out_path := $(TARGET_OUT_DATA_NATIVE_TESTS)/recovery
testdata_files := $(call find-subdir-files, testdata/*)
GEN := $(addprefix $(testdata_out_path)/, $(testdata_files))
$(GEN): PRIVATE_PATH := $(LOCAL_PATH)
$(GEN): PRIVATE_CUSTOM_TOOL = cp $< $@
$(GEN): $(testdata_out_path)/% : $(LOCAL_PATH)/%
$(transform-generated-source)
LOCAL_GENERATED_SOURCES += $(GEN)
include $(BUILD_NATIVE_TEST)
+25
View File
@@ -0,0 +1,25 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agree to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _OTA_TEST_CONSTANTS_H
#define _OTA_TEST_CONSTANTS_H
#if defined(__LP64__)
#define NATIVE_TEST_PATH "/nativetest64"
#else
#define NATIVE_TEST_PATH "/nativetest"
#endif
#endif
+392
View File
@@ -0,0 +1,392 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agree to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <fcntl.h>
#include <gtest/gtest.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/types.h>
#include <time.h>
#include <string>
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/test_utils.h>
#include "applypatch/applypatch.h"
#include "common/test_constants.h"
#include "openssl/sha.h"
#include "print_sha1.h"
static const std::string DATA_PATH = getenv("ANDROID_DATA");
static const std::string TESTDATA_PATH = "/recovery/testdata";
static const std::string WORK_FS = "/data";
static std::string sha1sum(const std::string& fname) {
uint8_t digest[SHA_DIGEST_LENGTH];
std::string data;
android::base::ReadFileToString(fname, &data);
SHA1((const uint8_t*)data.c_str(), data.size(), digest);
return print_sha1(digest);
}
static void mangle_file(const std::string& fname) {
FILE* fh = fopen(&fname[0], "w");
int r;
for (int i=0; i < 1024; i++) {
r = rand();
fwrite(&r, sizeof(short), 1, fh);
}
fclose(fh);
}
static bool file_cmp(std::string& f1, std::string& f2) {
std::string c1;
std::string c2;
android::base::ReadFileToString(f1, &c1);
android::base::ReadFileToString(f2, &c2);
return c1 == c2;
}
static std::string from_testdata_base(const std::string fname) {
return android::base::StringPrintf("%s%s%s/%s",
&DATA_PATH[0],
&NATIVE_TEST_PATH[0],
&TESTDATA_PATH[0],
&fname[0]);
}
class ApplyPatchTest : public ::testing::Test {
public:
static void SetUpTestCase() {
// set up files
old_file = from_testdata_base("old.file");
new_file = from_testdata_base("new.file");
patch_file = from_testdata_base("patch.bsdiff");
rand_file = "/cache/applypatch_test_rand.file";
cache_file = "/cache/saved.file";
// write stuff to rand_file
android::base::WriteStringToFile("hello", rand_file);
// set up SHA constants
old_sha1 = sha1sum(old_file);
new_sha1 = sha1sum(new_file);
srand(time(NULL));
bad_sha1_a = android::base::StringPrintf("%040x", rand());
bad_sha1_b = android::base::StringPrintf("%040x", rand());
struct stat st;
stat(&new_file[0], &st);
new_size = st.st_size;
}
static std::string old_file;
static std::string new_file;
static std::string rand_file;
static std::string cache_file;
static std::string patch_file;
static std::string old_sha1;
static std::string new_sha1;
static std::string bad_sha1_a;
static std::string bad_sha1_b;
static size_t new_size;
};
std::string ApplyPatchTest::old_file;
std::string ApplyPatchTest::new_file;
static void cp(std::string src, std::string tgt) {
std::string cmd = android::base::StringPrintf("cp %s %s",
&src[0],
&tgt[0]);
system(&cmd[0]);
}
static void backup_old() {
cp(ApplyPatchTest::old_file, ApplyPatchTest::cache_file);
}
static void restore_old() {
cp(ApplyPatchTest::cache_file, ApplyPatchTest::old_file);
}
class ApplyPatchCacheTest : public ApplyPatchTest {
public:
virtual void SetUp() {
backup_old();
}
virtual void TearDown() {
restore_old();
}
};
class ApplyPatchFullTest : public ApplyPatchCacheTest {
public:
static void SetUpTestCase() {
ApplyPatchTest::SetUpTestCase();
unsigned long free_kb = FreeSpaceForFile(&WORK_FS[0]);
ASSERT_GE(free_kb * 1024, new_size * 3 / 2);
output_f = new TemporaryFile();
output_loc = std::string(output_f->path);
struct FileContents fc;
ASSERT_EQ(0, LoadFileContents(&rand_file[0], &fc));
Value* patch1 = new Value();
patch1->type = VAL_BLOB;
patch1->size = fc.data.size();
patch1->data = static_cast<char*>(malloc(fc.data.size()));
memcpy(patch1->data, fc.data.data(), fc.data.size());
patches.push_back(patch1);
ASSERT_EQ(0, LoadFileContents(&patch_file[0], &fc));
Value* patch2 = new Value();
patch2->type = VAL_BLOB;
patch2->size = fc.st.st_size;
patch2->data = static_cast<char*>(malloc(fc.data.size()));
memcpy(patch2->data, fc.data.data(), fc.data.size());
patches.push_back(patch2);
}
static void TearDownTestCase() {
delete output_f;
for (auto it = patches.begin(); it != patches.end(); ++it) {
free((*it)->data);
delete *it;
}
patches.clear();
}
static std::vector<Value*> patches;
static TemporaryFile* output_f;
static std::string output_loc;
};
class ApplyPatchDoubleCacheTest : public ApplyPatchFullTest {
public:
virtual void SetUp() {
ApplyPatchCacheTest::SetUp();
cp(cache_file, "/cache/reallysaved.file");
}
virtual void TearDown() {
cp("/cache/reallysaved.file", cache_file);
ApplyPatchCacheTest::TearDown();
}
};
std::string ApplyPatchTest::rand_file;
std::string ApplyPatchTest::patch_file;
std::string ApplyPatchTest::cache_file;
std::string ApplyPatchTest::old_sha1;
std::string ApplyPatchTest::new_sha1;
std::string ApplyPatchTest::bad_sha1_a;
std::string ApplyPatchTest::bad_sha1_b;
size_t ApplyPatchTest::new_size;
std::vector<Value*> ApplyPatchFullTest::patches;
TemporaryFile* ApplyPatchFullTest::output_f;
std::string ApplyPatchFullTest::output_loc;
TEST_F(ApplyPatchTest, CheckModeSingle) {
char* s = &old_sha1[0];
ASSERT_EQ(0, applypatch_check(&old_file[0], 1, &s));
}
TEST_F(ApplyPatchTest, CheckModeMultiple) {
char* argv[3] = {
&bad_sha1_a[0],
&old_sha1[0],
&bad_sha1_b[0]
};
ASSERT_EQ(0, applypatch_check(&old_file[0], 3, argv));
}
TEST_F(ApplyPatchTest, CheckModeFailure) {
char* argv[2] = {
&bad_sha1_a[0],
&bad_sha1_b[0]
};
ASSERT_NE(0, applypatch_check(&old_file[0], 2, argv));
}
TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedSingle) {
mangle_file(old_file);
char* s = &old_sha1[0];
ASSERT_EQ(0, applypatch_check(&old_file[0], 1, &s));
}
TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedMultiple) {
mangle_file(old_file);
char* argv[3] = {
&bad_sha1_a[0],
&old_sha1[0],
&bad_sha1_b[0]
};
ASSERT_EQ(0, applypatch_check(&old_file[0], 3, argv));
}
TEST_F(ApplyPatchCacheTest, CheckCacheCorruptedFailure) {
mangle_file(old_file);
char* argv[2] = {
&bad_sha1_a[0],
&bad_sha1_b[0]
};
ASSERT_NE(0, applypatch_check(&old_file[0], 2, argv));
}
TEST_F(ApplyPatchCacheTest, CheckCacheMissingSingle) {
unlink(&old_file[0]);
char* s = &old_sha1[0];
ASSERT_EQ(0, applypatch_check(&old_file[0], 1, &s));
}
TEST_F(ApplyPatchCacheTest, CheckCacheMissingMultiple) {
unlink(&old_file[0]);
char* argv[3] = {
&bad_sha1_a[0],
&old_sha1[0],
&bad_sha1_b[0]
};
ASSERT_EQ(0, applypatch_check(&old_file[0], 3, argv));
}
TEST_F(ApplyPatchCacheTest, CheckCacheMissingFailure) {
unlink(&old_file[0]);
char* argv[2] = {
&bad_sha1_a[0],
&bad_sha1_b[0]
};
ASSERT_NE(0, applypatch_check(&old_file[0], 2, argv));
}
TEST_F(ApplyPatchFullTest, ApplyInPlace) {
std::vector<char*> sha1s;
sha1s.push_back(&bad_sha1_a[0]);
sha1s.push_back(&old_sha1[0]);
int ap_result = applypatch(&old_file[0],
"-",
&new_sha1[0],
new_size,
2,
sha1s.data(),
patches.data(),
nullptr);
ASSERT_EQ(0, ap_result);
ASSERT_TRUE(file_cmp(old_file, new_file));
// reapply, applypatch is idempotent so it should succeed
ap_result = applypatch(&old_file[0],
"-",
&new_sha1[0],
new_size,
2,
sha1s.data(),
patches.data(),
nullptr);
ASSERT_EQ(0, ap_result);
ASSERT_TRUE(file_cmp(old_file, new_file));
}
TEST_F(ApplyPatchFullTest, ApplyInNewLocation) {
std::vector<char*> sha1s;
sha1s.push_back(&bad_sha1_a[0]);
sha1s.push_back(&old_sha1[0]);
int ap_result = applypatch(&old_file[0],
&output_loc[0],
&new_sha1[0],
new_size,
2,
sha1s.data(),
patches.data(),
nullptr);
ASSERT_EQ(0, ap_result);
ASSERT_TRUE(file_cmp(output_loc, new_file));
ap_result = applypatch(&old_file[0],
&output_loc[0],
&new_sha1[0],
new_size,
2,
sha1s.data(),
patches.data(),
nullptr);
ASSERT_EQ(0, ap_result);
ASSERT_TRUE(file_cmp(output_loc, new_file));
}
TEST_F(ApplyPatchFullTest, ApplyCorruptedInNewLocation) {
mangle_file(old_file);
std::vector<char*> sha1s;
sha1s.push_back(&bad_sha1_a[0]);
sha1s.push_back(&old_sha1[0]);
int ap_result = applypatch(&old_file[0],
&output_loc[0],
&new_sha1[0],
new_size,
2,
sha1s.data(),
patches.data(),
nullptr);
ASSERT_EQ(0, ap_result);
ASSERT_TRUE(file_cmp(output_loc, new_file));
ap_result = applypatch(&old_file[0],
&output_loc[0],
&new_sha1[0],
new_size,
2,
sha1s.data(),
patches.data(),
nullptr);
ASSERT_EQ(0, ap_result);
ASSERT_TRUE(file_cmp(output_loc, new_file));
}
TEST_F(ApplyPatchDoubleCacheTest, ApplyDoubleCorruptedInNewLocation) {
mangle_file(old_file);
mangle_file(cache_file);
std::vector<char*> sha1s;
sha1s.push_back(&bad_sha1_a[0]);
sha1s.push_back(&old_sha1[0]);
int ap_result = applypatch(&old_file[0],
&output_loc[0],
&new_sha1[0],
new_size,
2,
sha1s.data(),
patches.data(),
nullptr);
ASSERT_NE(0, ap_result);
ASSERT_FALSE(file_cmp(output_loc, new_file));
ap_result = applypatch(&old_file[0],
&output_loc[0],
&new_sha1[0],
new_size,
2,
sha1s.data(),
patches.data(),
nullptr);
ASSERT_NE(0, ap_result);
ASSERT_FALSE(file_cmp(output_loc, new_file));
}
+178
View File
@@ -0,0 +1,178 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agree to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <errno.h>
#include <fcntl.h>
#include <gtest/gtest.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <memory>
#include <string>
#include <vector>
#include <openssl/sha.h>
#include <android-base/stringprintf.h>
#include "common.h"
#include "common/test_constants.h"
#include "minzip/SysUtil.h"
#include "ui.h"
#include "verifier.h"
static const char* DATA_PATH = getenv("ANDROID_DATA");
static const char* TESTDATA_PATH = "/recovery/testdata/";
RecoveryUI* ui = NULL;
class MockUI : public RecoveryUI {
void Init() { }
void SetStage(int, int) { }
void SetLocale(const char*) { }
void SetBackground(Icon icon) { }
void SetSystemUpdateText(bool security_update) { }
void SetProgressType(ProgressType determinate) { }
void ShowProgress(float portion, float seconds) { }
void SetProgress(float fraction) { }
void ShowText(bool visible) { }
bool IsTextVisible() { return false; }
bool WasTextEverVisible() { return false; }
void Print(const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
}
void PrintOnScreenOnly(const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
}
void ShowFile(const char*) { }
void StartMenu(const char* const * headers, const char* const * items,
int initial_selection) { }
int SelectMenu(int sel) { return 0; }
void EndMenu() { }
};
void
ui_print(const char* format, ...) {
va_list ap;
va_start(ap, format);
vfprintf(stdout, format, ap);
va_end(ap);
}
class VerifierTest : public testing::TestWithParam<std::vector<std::string>> {
public:
MemMapping memmap;
std::vector<Certificate> certs;
virtual void SetUp() {
std::vector<std::string> args = GetParam();
std::string package =
android::base::StringPrintf("%s%s%s%s", DATA_PATH, NATIVE_TEST_PATH,
TESTDATA_PATH, args[0].c_str());
if (sysMapFile(package.c_str(), &memmap) != 0) {
FAIL() << "Failed to mmap " << package << ": " << strerror(errno)
<< "\n";
}
for (auto it = ++(args.cbegin()); it != args.cend(); ++it) {
if (it->substr(it->length() - 3, it->length()) == "256") {
if (certs.empty()) {
FAIL() << "May only specify -sha256 after key type\n";
}
certs.back().hash_len = SHA256_DIGEST_LENGTH;
} else {
std::string public_key_file = android::base::StringPrintf(
"%s%s%stest_key_%s.txt", DATA_PATH, NATIVE_TEST_PATH,
TESTDATA_PATH, it->c_str());
ASSERT_TRUE(load_keys(public_key_file.c_str(), certs));
certs.back().hash_len = SHA_DIGEST_LENGTH;
}
}
if (certs.empty()) {
std::string public_key_file = android::base::StringPrintf(
"%s%s%stest_key_e3.txt", DATA_PATH, NATIVE_TEST_PATH,
TESTDATA_PATH);
ASSERT_TRUE(load_keys(public_key_file.c_str(), certs));
certs.back().hash_len = SHA_DIGEST_LENGTH;
}
}
static void SetUpTestCase() {
ui = new MockUI();
}
};
class VerifierSuccessTest : public VerifierTest {
};
class VerifierFailureTest : public VerifierTest {
};
TEST_P(VerifierSuccessTest, VerifySucceed) {
ASSERT_EQ(verify_file(memmap.addr, memmap.length, certs), VERIFY_SUCCESS);
}
TEST_P(VerifierFailureTest, VerifyFailure) {
ASSERT_EQ(verify_file(memmap.addr, memmap.length, certs), VERIFY_FAILURE);
}
INSTANTIATE_TEST_CASE_P(SingleKeySuccess, VerifierSuccessTest,
::testing::Values(
std::vector<std::string>({"otasigned.zip", "e3"}),
std::vector<std::string>({"otasigned_f4.zip", "f4"}),
std::vector<std::string>({"otasigned_sha256.zip", "e3", "sha256"}),
std::vector<std::string>({"otasigned_f4_sha256.zip", "f4", "sha256"}),
std::vector<std::string>({"otasigned_ecdsa_sha256.zip", "ec", "sha256"})));
INSTANTIATE_TEST_CASE_P(MultiKeySuccess, VerifierSuccessTest,
::testing::Values(
std::vector<std::string>({"otasigned.zip", "f4", "e3"}),
std::vector<std::string>({"otasigned_f4.zip", "ec", "f4"}),
std::vector<std::string>({"otasigned_sha256.zip", "ec", "e3", "e3", "sha256"}),
std::vector<std::string>({"otasigned_f4_sha256.zip", "ec", "sha256", "e3", "f4", "sha256"}),
std::vector<std::string>({"otasigned_ecdsa_sha256.zip", "f4", "sha256", "e3", "ec", "sha256"})));
INSTANTIATE_TEST_CASE_P(WrongKey, VerifierFailureTest,
::testing::Values(
std::vector<std::string>({"otasigned.zip", "f4"}),
std::vector<std::string>({"otasigned_f4.zip", "e3"}),
std::vector<std::string>({"otasigned_ecdsa_sha256.zip", "e3", "sha256"})));
INSTANTIATE_TEST_CASE_P(WrongHash, VerifierFailureTest,
::testing::Values(
std::vector<std::string>({"otasigned.zip", "e3", "sha256"}),
std::vector<std::string>({"otasigned_f4.zip", "f4", "sha256"}),
std::vector<std::string>({"otasigned_sha256.zip"}),
std::vector<std::string>({"otasigned_f4_sha256.zip", "f4"}),
std::vector<std::string>({"otasigned_ecdsa_sha256.zip"})));
INSTANTIATE_TEST_CASE_P(BadPackage, VerifierFailureTest,
::testing::Values(
std::vector<std::string>({"random.zip"}),
std::vector<std::string>({"fake-eocd.zip"}),
std::vector<std::string>({"alter-metadata.zip"}),
std::vector<std::string>({"alter-footer.zip"})));
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
View File
+1
View File
@@ -0,0 +1 @@
{64,0xc926ad21,{1795090719,2141396315,950055447,2581568430,4268923165,1920809988,546586521,3498997798,1776797858,3740060814,1805317999,1429410244,129622599,1422441418,1783893377,1222374759,2563319927,323993566,28517732,609753416,1826472888,215237850,4261642700,4049082591,3228462402,774857746,154822455,2497198897,2758199418,3019015328,2794777644,87251430,2534927978,120774784,571297800,3695899472,2479925187,3811625450,3401832990,2394869647,3267246207,950095497,555058928,414729973,1136544882,3044590084,465547824,4058146728,2731796054,1689838846,3890756939,1048029507,895090649,247140249,178744550,3547885223,3165179243,109881576,3944604415,1044303212,3772373029,2985150306,3737520932,3599964420},{3437017481,3784475129,2800224972,3086222688,251333580,2131931323,512774938,325948880,2657486437,2102694287,3820568226,792812816,1026422502,2053275343,2800889200,3113586810,165549746,4273519969,4065247892,1902789247,772932719,3941848426,3652744109,216871947,3164400649,1942378755,3996765851,1055777370,964047799,629391717,2232744317,3910558992,191868569,2758883837,3682816752,2997714732,2702529250,3570700455,3776873832,3924067546,3555689545,2758825434,1323144535,61311905,1997411085,376844204,213777604,4077323584,9135381,1625809335,2804742137,2952293945,1117190829,4237312782,1825108855,3013147971,1111251351,2568837572,1684324211,2520978805,367251975,810756730,2353784344,1175080310}}
+1
View File
@@ -0,0 +1 @@
v5 {32,{36,250,86,214,202,22,20,147,198,120,2,28,76,190,78,23,106,35,24,96,86,22,186,69,132,93,192,232,0,213,14,103},{222,154,23,13,125,130,22,76,146,185,140,159,138,255,105,143,32,16,27,72,175,145,141,121,233,184,77,24,217,141,132,181}}
+1
View File
@@ -0,0 +1 @@
v2 {64,0xc9bd1f21,{293133087,3210546773,865313125,250921607,3158780490,943703457,1242806226,2986289859,2942743769,2457906415,2719374299,1783459420,149579627,3081531591,3440738617,2788543742,2758457512,1146764939,3699497403,2446203424,1744968926,1159130537,2370028300,3978231572,3392699980,1487782451,1180150567,2841334302,3753960204,961373345,3333628321,748825784,2978557276,1566596926,1613056060,2600292737,1847226629,50398611,1890374404,2878700735,2286201787,1401186359,619285059,731930817,2340993166,1156490245,2992241729,151498140,318782170,3480838990,2100383433,4223552555,3628927011,4247846280,1759029513,4215632601,2719154626,3490334597,1751299340,3487864726,3668753795,4217506054,3748782284,3150295088},{1772626313,445326068,3477676155,1758201194,2986784722,491035581,3922936562,702212696,2979856666,3324974564,2488428922,3056318590,1626954946,664714029,398585816,3964097931,3356701905,2298377729,2040082097,3025491477,539143308,3348777868,2995302452,3602465520,212480763,2691021393,1307177300,704008044,2031136606,1054106474,3838318865,2441343869,1477566916,700949900,2534790355,3353533667,336163563,4106790558,2701448228,1571536379,1103842411,3623110423,1635278839,1577828979,910322800,715583630,138128831,1017877531,2289162787,447994798,1897243165,4121561445,4150719842,2131821093,2262395396,3305771534,980753571,3256525190,3128121808,1072869975,3507939515,4229109952,118381341,2209831334}}

Some files were not shown because too many files have changed in this diff Show More