Merge up to AOSP marshmallow-release
In order to maintain compatibility with older trees, we now have minadbd.old and minui.old. I had to use a TARGET_GLOBAL_CFLAG to handle ifdef issues in minui/minui.d because healthd includes minui/minui.h and there was no other alternative to make minui.h compatible with older trees without having to modify healthd rules which is outside of TWRP. Note that the new minui does not currently have support for qcom overlay graphics. Support for this graphics mode will likely be added in a later patch set. If you are building in a 6.0 tree and have a device that needs qcom overlay graphics, be warned, as off mode charging may not work properly. A dead battery in this case could potentially brick your device if it is unable to charge as healthd handles charging duties. Update rules for building toolbox and add rules for making toybox Use permissive.sh in init.rc which will follow symlinks so we do not have to worry about what binary is supplying the setenforce functionality (toolbox, toybox, or busybox). Fix a few warnings in the main recovery binary source code. Fix a few includes that were missing that prevented compiling in 6.0 Change-Id: Ia67aa2107d260883da5e365475a19bea538e8b97
This commit is contained in:
+37
-13
@@ -88,14 +88,25 @@ LOCAL_CFLAGS += -Wno-unused-parameter
|
||||
# libm \
|
||||
# libc
|
||||
|
||||
LOCAL_C_INCLUDES += \
|
||||
system/vold \
|
||||
system/extras/ext4_utils \
|
||||
system/core/adb \
|
||||
|
||||
LOCAL_C_INCLUDES += bionic external/stlport/stlport external/openssl/include $(LOCAL_PATH)/libmincrypt/includes
|
||||
|
||||
LOCAL_STATIC_LIBRARIES :=
|
||||
LOCAL_SHARED_LIBRARIES :=
|
||||
|
||||
LOCAL_STATIC_LIBRARIES += libguitwrp
|
||||
LOCAL_SHARED_LIBRARIES += libz libc libstlport libcutils libstdc++ libtar libblkid libminuitwrp libminadbd libmtdutils libminzip libaosprecovery
|
||||
LOCAL_SHARED_LIBRARIES += libgccdemangle libcrecovery
|
||||
LOCAL_SHARED_LIBRARIES += libz libc libcutils libstdc++ libtar libblkid libminuitwrp libminadbd libmtdutils libminzip libaosprecovery
|
||||
LOCAL_SHARED_LIBRARIES += libcrecovery
|
||||
|
||||
ifneq ($(wildcard external/stlport/Android.mk),)
|
||||
LOCAL_SHARED_LIBRARIES += libstlport
|
||||
else
|
||||
LOCAL_SHARED_LIBRARIES += libc++
|
||||
endif
|
||||
|
||||
ifneq ($(wildcard system/core/libsparse/Android.mk),)
|
||||
LOCAL_SHARED_LIBRARIES += libsparse
|
||||
@@ -113,7 +124,7 @@ ifeq ($(TARGET_USERIMAGES_USE_EXT4), true)
|
||||
LOCAL_C_INCLUDES += system/extras/ext4_utils
|
||||
LOCAL_SHARED_LIBRARIES += libext4_utils
|
||||
ifneq ($(wildcard external/lz4/Android.mk),)
|
||||
LOCAL_STATIC_LIBRARIES += liblz4-static
|
||||
#LOCAL_STATIC_LIBRARIES += liblz4-static
|
||||
endif
|
||||
endif
|
||||
ifneq ($(wildcard external/libselinux/Android.mk),)
|
||||
@@ -138,14 +149,10 @@ ifeq ($(TWHAVE_SELINUX), true)
|
||||
endif
|
||||
endif
|
||||
|
||||
# This binary is in the recovery ramdisk, which is otherwise a copy of root.
|
||||
# It gets copied there in config/Makefile. LOCAL_MODULE_TAGS suppresses
|
||||
# a (redundant) copy of the binary in /system/bin for user builds.
|
||||
# TODO: Build the ramdisk image in a more principled way.
|
||||
LOCAL_MODULE_TAGS := eng
|
||||
LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
|
||||
|
||||
#ifeq ($(TARGET_RECOVERY_UI_LIB),)
|
||||
LOCAL_SRC_FILES += default_device.cpp
|
||||
# LOCAL_SRC_FILES += default_device.cpp
|
||||
#else
|
||||
# LOCAL_STATIC_LIBRARIES += $(TARGET_RECOVERY_UI_LIB)
|
||||
#endif
|
||||
@@ -271,6 +278,7 @@ endif
|
||||
ifeq ($(TW_INCLUDE_CRYPTO), true)
|
||||
LOCAL_CFLAGS += -DTW_INCLUDE_CRYPTO
|
||||
LOCAL_SHARED_LIBRARIES += libcryptfslollipop
|
||||
LOCAL_C_INCLUDES += external/boringssl/src/include
|
||||
endif
|
||||
ifeq ($(TW_USE_MODEL_HARDWARE_ID_FOR_DEVICE_ID), true)
|
||||
LOCAL_CFLAGS += -DTW_USE_MODEL_HARDWARE_ID_FOR_DEVICE_ID
|
||||
@@ -311,6 +319,9 @@ endif
|
||||
ifneq ($(TARGET_RECOVERY_INITRC),)
|
||||
TW_EXCLUDE_DEFAULT_USB_INIT := true
|
||||
endif
|
||||
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -gt 22; echo $$?),0)
|
||||
LOCAL_CFLAGS += -DTW_USE_NEW_MINADBD
|
||||
endif
|
||||
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES := \
|
||||
dump_image \
|
||||
@@ -339,6 +350,10 @@ else
|
||||
endif
|
||||
ifneq ($(TW_USE_TOOLBOX), true)
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES += busybox_symlinks
|
||||
else
|
||||
ifneq ($(wildcard external/toybox/Android.mk),)
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES += toybox_symlinks
|
||||
endif
|
||||
endif
|
||||
ifneq ($(TW_NO_EXFAT), true)
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES += mkexfatfs
|
||||
@@ -483,9 +498,7 @@ endif
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
commands_recovery_local_path := $(LOCAL_PATH)
|
||||
include $(LOCAL_PATH)/minui/Android.mk \
|
||||
$(LOCAL_PATH)/minadbd/Android.mk \
|
||||
$(LOCAL_PATH)/tests/Android.mk \
|
||||
include $(LOCAL_PATH)/tests/Android.mk \
|
||||
$(LOCAL_PATH)/tools/Android.mk \
|
||||
$(LOCAL_PATH)/edify/Android.mk \
|
||||
$(LOCAL_PATH)/updater/Android.mk \
|
||||
@@ -495,6 +508,15 @@ ifeq ($(wildcard system/core/uncrypt/Android.mk),)
|
||||
include $(commands_recovery_local_path)/uncrypt/Android.mk
|
||||
endif
|
||||
|
||||
ifeq ($(shell test $(PLATFORM_SDK_VERSION) -gt 22; echo $$?),0)
|
||||
include $(commands_recovery_local_path)/minadbd/Android.mk \
|
||||
$(commands_recovery_local_path)/minui/Android.mk
|
||||
else
|
||||
TARGET_GLOBAL_CFLAGS += -DTW_USE_OLD_MINUI_H
|
||||
include $(commands_recovery_local_path)/minadbd.old/Android.mk \
|
||||
$(commands_recovery_local_path)/minui.old/Android.mk
|
||||
endif
|
||||
|
||||
#includes for TWRP
|
||||
include $(commands_recovery_local_path)/injecttwrp/Android.mk \
|
||||
$(commands_recovery_local_path)/htcdumlock/Android.mk \
|
||||
@@ -516,7 +538,9 @@ include $(commands_recovery_local_path)/injecttwrp/Android.mk \
|
||||
$(commands_recovery_local_path)/mtp/Android.mk \
|
||||
$(commands_recovery_local_path)/minzip/Android.mk \
|
||||
$(commands_recovery_local_path)/dosfstools/Android.mk \
|
||||
$(commands_recovery_local_path)/etc/Android.mk
|
||||
$(commands_recovery_local_path)/etc/Android.mk \
|
||||
$(commands_recovery_local_path)/toybox/Android.mk \
|
||||
$(commands_recovery_local_path)/libpixelflinger/Android.mk
|
||||
|
||||
ifeq ($(TW_INCLUDE_CRYPTO), true)
|
||||
include $(commands_recovery_local_path)/crypto/lollipop/Android.mk
|
||||
|
||||
@@ -1,13 +1,4 @@
|
||||
**Team Win Recovery Project (TWRP)**
|
||||
|
||||
The goal of this branch is to rebase TWRP onto AOSP while maintaining as much of the original AOSP code as possible. This goal should allow us to apply updates to the AOSP code going forward with little to no extra work. With this goal in mind, we will carefully consider any changes needed to the AOSP code before allowing them. In most cases, instead of changing the AOSP code, we'll create our own functions instead. The only changes that should be made to AOSP code should be those affecting startup of the recovery and some of the make files.
|
||||
|
||||
If there are changes that need to be merged from AOSP, we will pull the change directly from AOSP instead of creating a new patch in order to prevent merge conflicts with AOSP.
|
||||
|
||||
This branch is under final testing and will be used shortly for public builds, but has not officially been released.
|
||||
|
||||
You can find a compiling guide [here](http://forum.xda-developers.com/showthread.php?t=1943625 "Guide").
|
||||
|
||||
[More information about the project.](http://www.teamw.in/project/twrp2 "More Information")
|
||||
|
||||
If you have code changes to submit those should be pushed to our gerrit instance. A guide can be found [here](http://teamw.in/twrp2-gerrit "Gerrit Guide").
|
||||
|
||||
+7
-5
@@ -29,10 +29,8 @@
|
||||
#include "ui.h"
|
||||
#include "cutils/properties.h"
|
||||
#include "adb_install.h"
|
||||
extern "C" {
|
||||
#include "minadbd/fuse_adb_provider.h"
|
||||
#include "fuse_sideload.h"
|
||||
}
|
||||
|
||||
static RecoveryUI* ui = NULL;
|
||||
|
||||
@@ -47,7 +45,8 @@ set_usb_driver(bool enabled) {
|
||||
printf("failed to open driver control: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
if (write(fd, enabled ? "1" : "0", 1) < 0) {
|
||||
|
||||
if (TEMP_FAILURE_RETRY(write(fd, enabled ? "1" : "0", 1)) == -1) {
|
||||
/*
|
||||
ui->Print("failed to set driver control: %s\n", strerror(errno));
|
||||
*/
|
||||
@@ -67,12 +66,15 @@ stop_adbd() {
|
||||
set_usb_driver(false);
|
||||
}
|
||||
|
||||
bool is_ro_debuggable() {
|
||||
char value[PROPERTY_VALUE_MAX+1];
|
||||
return (property_get("ro.debuggable", value, NULL) == 1 && value[0] == '1');
|
||||
}
|
||||
|
||||
void
|
||||
maybe_restart_adbd() {
|
||||
char value[PROPERTY_VALUE_MAX+1];
|
||||
int len = property_get("ro.debuggable", value, NULL);
|
||||
if (len == 1 && value[0] == '1') {
|
||||
if (is_ro_debuggable()) {
|
||||
printf("Restarting adbd...\n");
|
||||
set_usb_driver(true);
|
||||
property_set("ctl.start", "adbd");
|
||||
|
||||
+28
-25
@@ -453,20 +453,19 @@ int WriteToPartition(unsigned char* data, size_t len,
|
||||
int attempt;
|
||||
|
||||
for (attempt = 0; attempt < 2; ++attempt) {
|
||||
lseek(fd, start, SEEK_SET);
|
||||
if (TEMP_FAILURE_RETRY(lseek(fd, start, SEEK_SET)) == -1) {
|
||||
printf("failed seek on %s: %s\n",
|
||||
partition, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
while (start < len) {
|
||||
size_t to_write = len - start;
|
||||
if (to_write > 1<<20) to_write = 1<<20;
|
||||
|
||||
ssize_t written = write(fd, data+start, to_write);
|
||||
if (written < 0) {
|
||||
if (errno == EINTR) {
|
||||
written = 0;
|
||||
} else {
|
||||
printf("failed write writing to %s (%s)\n",
|
||||
partition, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
ssize_t written = TEMP_FAILURE_RETRY(write(fd, data+start, to_write));
|
||||
if (written == -1) {
|
||||
printf("failed write writing to %s: %s\n", partition, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
start += written;
|
||||
}
|
||||
@@ -491,13 +490,20 @@ int WriteToPartition(unsigned char* data, size_t len,
|
||||
// won't just be reading the cache.
|
||||
sync();
|
||||
int dc = open("/proc/sys/vm/drop_caches", O_WRONLY);
|
||||
write(dc, "3\n", 2);
|
||||
if (TEMP_FAILURE_RETRY(write(dc, "3\n", 2)) == -1) {
|
||||
printf("write to /proc/sys/vm/drop_caches failed: %s\n", strerror(errno));
|
||||
} else {
|
||||
printf(" caches dropped\n");
|
||||
}
|
||||
close(dc);
|
||||
sleep(1);
|
||||
printf(" caches dropped\n");
|
||||
|
||||
// verify
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
if (TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_SET)) == -1) {
|
||||
printf("failed to seek back to beginning of %s: %s\n",
|
||||
partition, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
unsigned char buffer[4096];
|
||||
start = len;
|
||||
size_t p;
|
||||
@@ -507,15 +513,12 @@ int WriteToPartition(unsigned char* data, size_t len,
|
||||
|
||||
size_t so_far = 0;
|
||||
while (so_far < to_read) {
|
||||
ssize_t read_count = read(fd, buffer+so_far, to_read-so_far);
|
||||
if (read_count < 0) {
|
||||
if (errno == EINTR) {
|
||||
read_count = 0;
|
||||
} else {
|
||||
printf("verify read error %s at %zu: %s\n",
|
||||
partition, p, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
ssize_t read_count =
|
||||
TEMP_FAILURE_RETRY(read(fd, buffer+so_far, to_read-so_far));
|
||||
if (read_count == -1) {
|
||||
printf("verify read error %s at %zu: %s\n",
|
||||
partition, p, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if ((size_t)read_count < to_read) {
|
||||
printf("short verify read %s at %zu: %zd %zu %s\n",
|
||||
@@ -656,8 +659,8 @@ ssize_t FileSink(const unsigned char* data, ssize_t len, void* token) {
|
||||
ssize_t done = 0;
|
||||
ssize_t wrote;
|
||||
while (done < (ssize_t) len) {
|
||||
wrote = write(fd, data+done, len-done);
|
||||
if (wrote <= 0) {
|
||||
wrote = TEMP_FAILURE_RETRY(write(fd, data+done, len-done));
|
||||
if (wrote == -1) {
|
||||
printf("error writing %d bytes: %s\n", (int)(len-done), strerror(errno));
|
||||
return done;
|
||||
}
|
||||
@@ -690,7 +693,7 @@ size_t FreeSpaceForFile(const char* filename) {
|
||||
printf("failed to statfs %s: %s\n", filename, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
return sf.f_bsize * sf.f_bfree;
|
||||
return sf.f_bsize * sf.f_bavail;
|
||||
}
|
||||
|
||||
int CacheSizeCheck(size_t bytes) {
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
@@ -408,6 +408,7 @@ unsigned char* ReadImage(const char* filename,
|
||||
p[2] == 0x08 && // deflate compression
|
||||
p[3] == 0x00) { // no header flags
|
||||
// 'pos' is the offset of the start of a gzip chunk.
|
||||
size_t chunk_offset = pos;
|
||||
|
||||
*num_chunks += 3;
|
||||
*chunks = realloc(*chunks, *num_chunks * sizeof(ImageChunk));
|
||||
@@ -453,6 +454,14 @@ unsigned char* ReadImage(const char* filename,
|
||||
strm.avail_out = allocated - curr->len;
|
||||
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;
|
||||
}
|
||||
curr->len = allocated - strm.avail_out;
|
||||
if (strm.avail_out == 0) {
|
||||
allocated *= 2;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <malloc.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ extern "C" {
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// fake Volume struct that allows us to use the AOSP code easily
|
||||
struct Volume
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#ifndef RECOVERY_COMMON_H
|
||||
#define RECOVERY_COMMON_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
@@ -24,13 +25,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static long tmplog_offset = 0;
|
||||
|
||||
#define ui_print(...) printf(__VA_ARGS__)
|
||||
#define ui_print_overwrite(...) printf(__VA_ARGS__)
|
||||
|
||||
// TODO: restore ui_print for LOGE
|
||||
#define LOGE(...) printf("E:" __VA_ARGS__)
|
||||
#define LOGE(...) fprintf(stdout, "E:" __VA_ARGS__)
|
||||
#define LOGW(...) fprintf(stdout, "W:" __VA_ARGS__)
|
||||
#define LOGI(...) fprintf(stdout, "I:" __VA_ARGS__)
|
||||
|
||||
@@ -45,12 +40,15 @@ static long tmplog_offset = 0;
|
||||
#define STRINGIFY(x) #x
|
||||
#define EXPAND(x) STRINGIFY(x)
|
||||
|
||||
extern bool modified_flash;
|
||||
//typedef struct fstab_rec Volume;
|
||||
|
||||
// fopen a file, mounting volumes and making parent dirs as necessary.
|
||||
FILE* fopen_path(const char *path, const char *mode);
|
||||
|
||||
//void ui_print(const char* format, ...);
|
||||
void ui_print(const char* format, ...);
|
||||
|
||||
bool is_ro_debuggable();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
+25
-15
@@ -15,28 +15,38 @@ ifeq ($(TARGET_HW_DISK_ENCRYPTION),true)
|
||||
LOCAL_CFLAGS += -DCONFIG_HW_DISK_ENCRYPTION
|
||||
endif
|
||||
|
||||
ifneq ($(wildcard hardware/libhardware/include/hardware/keymaster0.h),)
|
||||
LOCAL_CFLAGS += -DTW_CRYPTO_HAVE_KEYMASTERX
|
||||
LOCAL_C_INCLUDES += external/boringssl/src/include
|
||||
endif
|
||||
|
||||
LOCAL_WHOLE_STATIC_LIBRARIES += libscrypttwrp_static
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
|
||||
|
||||
#include $(CLEAR_VARS)
|
||||
#LOCAL_MODULE := twrpdec
|
||||
#LOCAL_MODULE_TAGS := eng optional
|
||||
#LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
|
||||
#LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
|
||||
#LOCAL_SRC_FILES := main.c cryptfs.c
|
||||
#LOCAL_SHARED_LIBRARIES := libcrypto libhardware libcutils libc
|
||||
#LOCAL_C_INCLUDES := external/openssl/include $(commands_recovery_local_path)/crypto/scrypt/lib/crypto
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := twrpdec
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_MODULE_CLASS := RECOVERY_EXECUTABLES
|
||||
LOCAL_MODULE_PATH := $(TARGET_RECOVERY_ROOT_OUT)/sbin
|
||||
LOCAL_SRC_FILES := main.c cryptfs.c
|
||||
LOCAL_SHARED_LIBRARIES := libcrypto libhardware libcutils libc
|
||||
LOCAL_C_INCLUDES := external/openssl/include $(commands_recovery_local_path)/crypto/scrypt/lib/crypto
|
||||
|
||||
#ifeq ($(TARGET_HW_DISK_ENCRYPTION),true)
|
||||
# LOCAL_C_INCLUDES += device/qcom/common/cryptfs_hw
|
||||
# LOCAL_SHARED_LIBRARIES += libcryptfs_hw
|
||||
# LOCAL_CFLAGS += -DCONFIG_HW_DISK_ENCRYPTION
|
||||
#endif
|
||||
ifeq ($(TARGET_HW_DISK_ENCRYPTION),true)
|
||||
LOCAL_C_INCLUDES += device/qcom/common/cryptfs_hw
|
||||
LOCAL_SHARED_LIBRARIES += libcryptfs_hw
|
||||
LOCAL_CFLAGS += -DCONFIG_HW_DISK_ENCRYPTION
|
||||
endif
|
||||
|
||||
#LOCAL_WHOLE_STATIC_LIBRARIES += libscrypttwrp_static
|
||||
#include $(BUILD_EXECUTABLE)
|
||||
ifneq ($(wildcard hardware/libhardware/include/hardware/keymaster0.h),)
|
||||
LOCAL_CFLAGS += -DTW_CRYPTO_HAVE_KEYMASTERX
|
||||
LOCAL_C_INCLUDES += external/boringssl/src/include
|
||||
endif
|
||||
|
||||
LOCAL_WHOLE_STATIC_LIBRARIES += libscrypttwrp_static
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
endif
|
||||
|
||||
+338
-17
@@ -43,7 +43,16 @@
|
||||
#include "cryptfs.h"
|
||||
#include "cutils/properties.h"
|
||||
#include "crypto_scrypt.h"
|
||||
|
||||
#ifndef TW_CRYPTO_HAVE_KEYMASTERX
|
||||
#include <hardware/keymaster.h>
|
||||
#else
|
||||
#include <stdbool.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <hardware/keymaster0.h>
|
||||
#include <hardware/keymaster1.h>
|
||||
#endif
|
||||
|
||||
#ifndef min /* already defined by windows.h */
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
@@ -76,6 +85,7 @@
|
||||
#define RSA_KEY_SIZE 2048
|
||||
#define RSA_KEY_SIZE_BYTES (RSA_KEY_SIZE / 8)
|
||||
#define RSA_EXPONENT 0x10001
|
||||
#define KEYMASTER_CRYPTFS_RATE_LIMIT 1 // Maximum one try per second
|
||||
|
||||
#define RETRY_MOUNT_ATTEMPTS 10
|
||||
#define RETRY_MOUNT_DELAY_SECONDS 1
|
||||
@@ -97,6 +107,7 @@ void set_partition_data(const char* block_device, const char* key_location, cons
|
||||
strcpy(file_system, fs);
|
||||
}
|
||||
|
||||
#ifndef TW_CRYPTO_HAVE_KEYMASTERX
|
||||
static int keymaster_init(keymaster_device_t **keymaster_dev)
|
||||
{
|
||||
int rc;
|
||||
@@ -279,6 +290,308 @@ static int keymaster_sign_object(struct crypt_mnt_ftr *ftr,
|
||||
keymaster_close(keymaster_dev);
|
||||
return rc;
|
||||
}
|
||||
#else //#ifndef TW_CRYPTO_HAVE_KEYMASTERX
|
||||
static int keymaster_init(keymaster0_device_t **keymaster0_dev,
|
||||
keymaster1_device_t **keymaster1_dev)
|
||||
{
|
||||
int rc;
|
||||
|
||||
const hw_module_t* mod;
|
||||
rc = hw_get_module_by_class(KEYSTORE_HARDWARE_MODULE_ID, NULL, &mod);
|
||||
if (rc) {
|
||||
printf("could not find any keystore module\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
printf("keymaster module name is %s\n", mod->name);
|
||||
printf("keymaster version is %d\n", mod->module_api_version);
|
||||
|
||||
*keymaster0_dev = NULL;
|
||||
*keymaster1_dev = NULL;
|
||||
if (mod->module_api_version == KEYMASTER_MODULE_API_VERSION_1_0) {
|
||||
printf("Found keymaster1 module, using keymaster1 API.\n");
|
||||
rc = keymaster1_open(mod, keymaster1_dev);
|
||||
} else {
|
||||
printf("Found keymaster0 module, using keymaster0 API.\n");
|
||||
rc = keymaster0_open(mod, keymaster0_dev);
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
printf("could not open keymaster device in %s (%s)\n",
|
||||
KEYSTORE_HARDWARE_MODULE_ID, strerror(-rc));
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
*keymaster0_dev = NULL;
|
||||
*keymaster1_dev = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Should we use keymaster? */
|
||||
static int keymaster_check_compatibility()
|
||||
{
|
||||
keymaster0_device_t *keymaster0_dev = 0;
|
||||
keymaster1_device_t *keymaster1_dev = 0;
|
||||
int rc = 0;
|
||||
|
||||
if (keymaster_init(&keymaster0_dev, &keymaster1_dev)) {
|
||||
printf("Failed to init keymaster\n");
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (keymaster1_dev) {
|
||||
rc = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
// TODO(swillden): Check to see if there's any reason to require v0.3. I think v0.1 and v0.2
|
||||
// should work.
|
||||
if (keymaster0_dev->common.module->module_api_version
|
||||
< KEYMASTER_MODULE_API_VERSION_0_3) {
|
||||
rc = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!(keymaster0_dev->flags & KEYMASTER_SOFTWARE_ONLY) &&
|
||||
(keymaster0_dev->flags & KEYMASTER_BLOBS_ARE_STANDALONE)) {
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
out:
|
||||
if (keymaster1_dev) {
|
||||
keymaster1_close(keymaster1_dev);
|
||||
}
|
||||
if (keymaster0_dev) {
|
||||
keymaster0_close(keymaster0_dev);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Create a new keymaster key and store it in this footer */
|
||||
static int keymaster_create_key(struct crypt_mnt_ftr *ftr)
|
||||
{
|
||||
uint8_t* key = 0;
|
||||
keymaster0_device_t *keymaster0_dev = 0;
|
||||
keymaster1_device_t *keymaster1_dev = 0;
|
||||
|
||||
if (keymaster_init(&keymaster0_dev, &keymaster1_dev)) {
|
||||
printf("Failed to init keymaster\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int rc = 0;
|
||||
size_t key_size = 0;
|
||||
if (keymaster1_dev) {
|
||||
keymaster_key_param_t params[] = {
|
||||
/* Algorithm & size specifications. Stick with RSA for now. Switch to AES later. */
|
||||
keymaster_param_enum(KM_TAG_ALGORITHM, KM_ALGORITHM_RSA),
|
||||
keymaster_param_int(KM_TAG_KEY_SIZE, RSA_KEY_SIZE),
|
||||
keymaster_param_long(KM_TAG_RSA_PUBLIC_EXPONENT, RSA_EXPONENT),
|
||||
|
||||
/* The only allowed purpose for this key is signing. */
|
||||
keymaster_param_enum(KM_TAG_PURPOSE, KM_PURPOSE_SIGN),
|
||||
|
||||
/* Padding & digest specifications. */
|
||||
keymaster_param_enum(KM_TAG_PADDING, KM_PAD_NONE),
|
||||
keymaster_param_enum(KM_TAG_DIGEST, KM_DIGEST_NONE),
|
||||
|
||||
/* Require that the key be usable in standalone mode. File system isn't available. */
|
||||
keymaster_param_enum(KM_TAG_BLOB_USAGE_REQUIREMENTS, KM_BLOB_STANDALONE),
|
||||
|
||||
/* No auth requirements, because cryptfs is not yet integrated with gatekeeper. */
|
||||
keymaster_param_bool(KM_TAG_NO_AUTH_REQUIRED),
|
||||
|
||||
/* Rate-limit key usage attempts, to rate-limit brute force */
|
||||
keymaster_param_int(KM_TAG_MIN_SECONDS_BETWEEN_OPS, KEYMASTER_CRYPTFS_RATE_LIMIT),
|
||||
};
|
||||
keymaster_key_param_set_t param_set = { params, sizeof(params)/sizeof(*params) };
|
||||
keymaster_key_blob_t key_blob;
|
||||
keymaster_error_t error = keymaster1_dev->generate_key(keymaster1_dev, ¶m_set,
|
||||
&key_blob,
|
||||
NULL /* characteristics */);
|
||||
if (error != KM_ERROR_OK) {
|
||||
printf("Failed to generate keymaster1 key, error %d\n", error);
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
key = (uint8_t*)key_blob.key_material;
|
||||
key_size = key_blob.key_material_size;
|
||||
}
|
||||
else if (keymaster0_dev) {
|
||||
keymaster_rsa_keygen_params_t params;
|
||||
memset(¶ms, '\0', sizeof(params));
|
||||
params.public_exponent = RSA_EXPONENT;
|
||||
params.modulus_size = RSA_KEY_SIZE;
|
||||
|
||||
if (keymaster0_dev->generate_keypair(keymaster0_dev, TYPE_RSA, ¶ms,
|
||||
&key, &key_size)) {
|
||||
printf("Failed to generate keypair\n");
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
printf("Cryptfs bug: keymaster_init succeeded but didn't initialize a device\n");
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (key_size > KEYMASTER_BLOB_SIZE) {
|
||||
printf("Keymaster key too large for crypto footer\n");
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(ftr->keymaster_blob, key, key_size);
|
||||
ftr->keymaster_blob_size = key_size;
|
||||
|
||||
out:
|
||||
if (keymaster0_dev)
|
||||
keymaster0_close(keymaster0_dev);
|
||||
if (keymaster1_dev)
|
||||
keymaster1_close(keymaster1_dev);
|
||||
free(key);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* This signs the given object using the keymaster key. */
|
||||
static int keymaster_sign_object(struct crypt_mnt_ftr *ftr,
|
||||
const unsigned char *object,
|
||||
const size_t object_size,
|
||||
unsigned char **signature,
|
||||
size_t *signature_size)
|
||||
{
|
||||
int rc = 0;
|
||||
keymaster0_device_t *keymaster0_dev = 0;
|
||||
keymaster1_device_t *keymaster1_dev = 0;
|
||||
if (keymaster_init(&keymaster0_dev, &keymaster1_dev)) {
|
||||
printf("Failed to init keymaster\n");
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
unsigned char to_sign[RSA_KEY_SIZE_BYTES];
|
||||
size_t to_sign_size = sizeof(to_sign);
|
||||
memset(to_sign, 0, RSA_KEY_SIZE_BYTES);
|
||||
|
||||
// To sign a message with RSA, the message must satisfy two
|
||||
// constraints:
|
||||
//
|
||||
// 1. The message, when interpreted as a big-endian numeric value, must
|
||||
// be strictly less than the public modulus of the RSA key. Note
|
||||
// that because the most significant bit of the public modulus is
|
||||
// guaranteed to be 1 (else it's an (n-1)-bit key, not an n-bit
|
||||
// key), an n-bit message with most significant bit 0 always
|
||||
// satisfies this requirement.
|
||||
//
|
||||
// 2. The message must have the same length in bits as the public
|
||||
// modulus of the RSA key. This requirement isn't mathematically
|
||||
// necessary, but is necessary to ensure consistency in
|
||||
// implementations.
|
||||
switch (ftr->kdf_type) {
|
||||
case KDF_SCRYPT_KEYMASTER:
|
||||
// This ensures the most significant byte of the signed message
|
||||
// is zero. We could have zero-padded to the left instead, but
|
||||
// this approach is slightly more robust against changes in
|
||||
// object size. However, it's still broken (but not unusably
|
||||
// so) because we really should be using a proper deterministic
|
||||
// RSA padding function, such as PKCS1.
|
||||
memcpy(to_sign + 1, object, min(RSA_KEY_SIZE_BYTES - 1, object_size));
|
||||
printf("Signing safely-padded object\n");
|
||||
break;
|
||||
default:
|
||||
printf("Unknown KDF type %d\n", ftr->kdf_type);
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (keymaster0_dev) {
|
||||
keymaster_rsa_sign_params_t params;
|
||||
params.digest_type = DIGEST_NONE;
|
||||
params.padding_type = PADDING_NONE;
|
||||
|
||||
rc = keymaster0_dev->sign_data(keymaster0_dev,
|
||||
¶ms,
|
||||
ftr->keymaster_blob,
|
||||
ftr->keymaster_blob_size,
|
||||
to_sign,
|
||||
to_sign_size,
|
||||
signature,
|
||||
signature_size);
|
||||
goto out;
|
||||
} else if (keymaster1_dev) {
|
||||
keymaster_key_blob_t key = { ftr->keymaster_blob, ftr->keymaster_blob_size };
|
||||
keymaster_key_param_t params[] = {
|
||||
keymaster_param_enum(KM_TAG_PADDING, KM_PAD_NONE),
|
||||
keymaster_param_enum(KM_TAG_DIGEST, KM_DIGEST_NONE),
|
||||
};
|
||||
keymaster_key_param_set_t param_set = { params, sizeof(params)/sizeof(*params) };
|
||||
keymaster_operation_handle_t op_handle;
|
||||
keymaster_error_t error = keymaster1_dev->begin(keymaster1_dev, KM_PURPOSE_SIGN, &key,
|
||||
¶m_set, NULL /* out_params */,
|
||||
&op_handle);
|
||||
if (error == KM_ERROR_KEY_RATE_LIMIT_EXCEEDED) {
|
||||
// Key usage has been rate-limited. Wait a bit and try again.
|
||||
sleep(KEYMASTER_CRYPTFS_RATE_LIMIT);
|
||||
error = keymaster1_dev->begin(keymaster1_dev, KM_PURPOSE_SIGN, &key,
|
||||
¶m_set, NULL /* out_params */,
|
||||
&op_handle);
|
||||
}
|
||||
if (error != KM_ERROR_OK) {
|
||||
printf("Error starting keymaster signature transaction: %d\n", error);
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
keymaster_blob_t input = { to_sign, to_sign_size };
|
||||
size_t input_consumed;
|
||||
error = keymaster1_dev->update(keymaster1_dev, op_handle, NULL /* in_params */,
|
||||
&input, &input_consumed, NULL /* out_params */,
|
||||
NULL /* output */);
|
||||
if (error != KM_ERROR_OK) {
|
||||
printf("Error sending data to keymaster signature transaction: %d\n", error);
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
if (input_consumed != to_sign_size) {
|
||||
// This should never happen. If it does, it's a bug in the keymaster implementation.
|
||||
printf("Keymaster update() did not consume all data.\n");
|
||||
keymaster1_dev->abort(keymaster1_dev, op_handle);
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
keymaster_blob_t tmp_sig;
|
||||
error = keymaster1_dev->finish(keymaster1_dev, op_handle, NULL /* in_params */,
|
||||
NULL /* verify signature */, NULL /* out_params */,
|
||||
&tmp_sig);
|
||||
if (error != KM_ERROR_OK) {
|
||||
printf("Error finishing keymaster signature transaction: %d\n", error);
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*signature = (uint8_t*)tmp_sig.data;
|
||||
*signature_size = tmp_sig.data_length;
|
||||
} else {
|
||||
printf("Cryptfs bug: keymaster_init succeded but didn't initialize a device.\n");
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
if (keymaster1_dev)
|
||||
keymaster1_close(keymaster1_dev);
|
||||
if (keymaster0_dev)
|
||||
keymaster0_close(keymaster0_dev);
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif //#ifndef TW_CRYPTO_HAVE_KEYMASTERX
|
||||
|
||||
/* Store password when userdata is successfully decrypted and mounted.
|
||||
* Cleared by cryptfs_clear_password
|
||||
@@ -352,7 +665,7 @@ static void get_device_scrypt_params(struct crypt_mnt_ftr *ftr) {
|
||||
* taken.
|
||||
*/
|
||||
if ((i != 3) || (token != NULL)) {
|
||||
printf("bad scrypt parameters '%s' should be like '12:8:1'; using defaults", paramstr);
|
||||
printf("bad scrypt parameters '%s' should be like '12:8:1'; using defaults\n", paramstr);
|
||||
memcpy(params, default_params, sizeof(params));
|
||||
}
|
||||
}
|
||||
@@ -526,13 +839,13 @@ static unsigned char* convert_hex_ascii_to_key(const char* master_key_ascii,
|
||||
|
||||
size_t size = strlen (master_key_ascii);
|
||||
if (size % 2) {
|
||||
printf("Trying to convert ascii string of odd length");
|
||||
printf("Trying to convert ascii string of odd length\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned char* master_key = (unsigned char*) malloc(size / 2);
|
||||
if (master_key == 0) {
|
||||
printf("Cannot allocate");
|
||||
printf("Cannot allocate\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -541,7 +854,7 @@ static unsigned char* convert_hex_ascii_to_key(const char* master_key_ascii,
|
||||
int low_nibble = hexdigit (master_key_ascii[i + 1]);
|
||||
|
||||
if(high_nibble < 0 || low_nibble < 0) {
|
||||
printf("Invalid hex string");
|
||||
printf("Invalid hex string\n");
|
||||
free (master_key);
|
||||
return NULL;
|
||||
}
|
||||
@@ -818,7 +1131,7 @@ errout:
|
||||
static int pbkdf2(const char *passwd, const unsigned char *salt,
|
||||
unsigned char *ikey, void *params UNUSED)
|
||||
{
|
||||
printf("Using pbkdf2 for cryptfs KDF");
|
||||
printf("Using pbkdf2 for cryptfs KDF\n");
|
||||
|
||||
/* Turn the password into a key and IV that can decrypt the master key */
|
||||
unsigned int keysize;
|
||||
@@ -922,25 +1235,25 @@ static int encrypt_master_key(const char *passwd, const unsigned char *salt,
|
||||
case KDF_SCRYPT_KEYMASTER_BADLY_PADDED:
|
||||
case KDF_SCRYPT_KEYMASTER:
|
||||
if (keymaster_create_key(crypt_ftr)) {
|
||||
printf("keymaster_create_key failed");
|
||||
printf("keymaster_create_key failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (scrypt_keymaster(passwd, salt, ikey, crypt_ftr)) {
|
||||
printf("scrypt failed");
|
||||
printf("scrypt failed\n");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case KDF_SCRYPT:
|
||||
if (scrypt(passwd, salt, ikey, crypt_ftr)) {
|
||||
printf("scrypt failed");
|
||||
printf("scrypt failed\n");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("Invalid kdf_type");
|
||||
printf("Invalid kdf_type\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -957,7 +1270,11 @@ static int encrypt_master_key(const char *passwd, const unsigned char *salt,
|
||||
printf("EVP_EncryptUpdate failed\n");
|
||||
return -1;
|
||||
}
|
||||
#ifndef TW_CRYPTO_HAVE_KEYMASTERX
|
||||
if (! EVP_EncryptFinal(&e_ctx, encrypted_master_key + encrypted_len, &final_len)) {
|
||||
#else
|
||||
if (! EVP_EncryptFinal_ex(&e_ctx, encrypted_master_key + encrypted_len, &final_len)) {
|
||||
#endif
|
||||
printf("EVP_EncryptFinal failed\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -982,7 +1299,7 @@ static int encrypt_master_key(const char *passwd, const unsigned char *salt,
|
||||
sizeof(crypt_ftr->scrypted_intermediate_key));
|
||||
|
||||
if (rc) {
|
||||
printf("encrypt_master_key: crypto_scrypt failed");
|
||||
printf("encrypt_master_key: crypto_scrypt failed\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1002,7 +1319,7 @@ static int decrypt_master_key_aux(char *passwd, unsigned char *salt,
|
||||
/* Turn the password into an intermediate key and IV that can decrypt the
|
||||
master key */
|
||||
if (kdf(passwd, salt, ikey, kdf_params)) {
|
||||
printf("kdf failed");
|
||||
printf("kdf failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1016,7 +1333,11 @@ static int decrypt_master_key_aux(char *passwd, unsigned char *salt,
|
||||
encrypted_master_key, KEY_LEN_BYTES)) {
|
||||
return -1;
|
||||
}
|
||||
#ifndef TW_CRYPTO_HAVE_KEYMASTERX
|
||||
if (! EVP_DecryptFinal(&d_ctx, decrypted_master_key + decrypted_len, &final_len)) {
|
||||
#else
|
||||
if (! EVP_DecryptFinal_ex(&d_ctx, decrypted_master_key + decrypted_len, &final_len)) {
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1066,7 +1387,7 @@ static int decrypt_master_key(char *passwd, unsigned char *decrypted_master_key,
|
||||
decrypted_master_key, kdf, kdf_params,
|
||||
intermediate_key, intermediate_key_size);
|
||||
if (ret != 0) {
|
||||
printf("failure decrypting master key");
|
||||
printf("failure decrypting master key\n");
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -1396,7 +1717,7 @@ int cryptfs_check_passwd(char *passwd)
|
||||
// cryptfs_changepw also adjusts so pass original
|
||||
// Note that adjust_passwd only recognises patterns
|
||||
// so we can safely use CRYPT_TYPE_PATTERN
|
||||
printf("TWRP NOT Updating pattern to new format");
|
||||
printf("TWRP NOT Updating pattern to new format\n");
|
||||
//cryptfs_changepw(CRYPT_TYPE_PATTERN, passwd);
|
||||
} else if (hex_passwd) {
|
||||
//printf("trying hex_passwd '%s'\n", hex_passwd);
|
||||
@@ -1445,17 +1766,17 @@ int cryptfs_verify_passwd(char *passwd)
|
||||
|
||||
property_get("ro.crypto.state", encrypted_state, "");
|
||||
if (strcmp(encrypted_state, "encrypted") ) {
|
||||
printf("device not encrypted, aborting");
|
||||
printf("device not encrypted, aborting\n");
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (!master_key_saved) {
|
||||
printf("encrypted fs not yet mounted, aborting");
|
||||
printf("encrypted fs not yet mounted, aborting\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!saved_mount_point) {
|
||||
printf("encrypted fs failed to save mount point, aborting");
|
||||
printf("encrypted fs failed to save mount point, aborting\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1515,7 +1836,7 @@ static int cryptfs_init_crypt_mnt_ftr(struct crypt_mnt_ftr *ftr)
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("keymaster_check_compatibility failed");
|
||||
printf("keymaster_check_compatibility failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,13 +23,10 @@
|
||||
#include "cryptfs.h"
|
||||
#include "cutils/properties.h"
|
||||
#include "crypto_scrypt.h"
|
||||
#include <hardware/keymaster.h>
|
||||
|
||||
int main() {
|
||||
printf("blah\n");
|
||||
set_partition_data("/dev/block/mmcblk0p28", "/dev/block/mmcblk0p27", "ext4");
|
||||
printf("blah2\n");
|
||||
int ret = cryptfs_check_passwd("30303030");
|
||||
//int ret = cryptfs_check_passwd("0000");
|
||||
set_partition_data("/dev/block/platform/sdhci-tegra.3/by-name/UDA", "/dev/block/platform/sdhci-tegra.3/by-name/MD1", "f2fs");
|
||||
//int ret = cryptfs_check_passwd("30303030");
|
||||
int ret = cryptfs_check_passwd("0000");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
local_c_flags := -DUSE_OPENSSL_PBKDF2
|
||||
|
||||
local_c_includes := $(log_c_includes) external/openssl/include
|
||||
local_c_includes := $(log_c_includes) external/openssl/include external/boringssl/src/include
|
||||
|
||||
local_additional_dependencies := $(LOCAL_PATH)/android-config.mk $(LOCAL_PATH)/Scrypt.mk
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include <map>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "variables.h"
|
||||
#include "data.hpp"
|
||||
@@ -76,7 +77,11 @@ int DataManager::mInitialized = 0;
|
||||
|
||||
extern bool datamedia;
|
||||
|
||||
#ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
|
||||
pthread_mutex_t DataManager::m_valuesLock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
|
||||
#else
|
||||
pthread_mutex_t DataManager::m_valuesLock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
|
||||
#endif
|
||||
|
||||
// Device ID functions
|
||||
void DataManager::sanitize_device_id(char* device_id) {
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <map>
|
||||
#include <pthread.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
+1
-66
@@ -14,74 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <linux/input.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "device.h"
|
||||
#include "screen_ui.h"
|
||||
|
||||
static const char* HEADERS[] = { "Volume up/down to move highlight;",
|
||||
"enter button to select.",
|
||||
"",
|
||||
NULL };
|
||||
|
||||
static const char* ITEMS[] = {"reboot system now",
|
||||
"apply update from ADB",
|
||||
"wipe data/factory reset",
|
||||
"wipe cache partition",
|
||||
"reboot to bootloader",
|
||||
"power down",
|
||||
"view recovery logs",
|
||||
NULL };
|
||||
|
||||
class DefaultDevice : public Device {
|
||||
public:
|
||||
DefaultDevice() :
|
||||
ui(new ScreenRecoveryUI) {
|
||||
}
|
||||
|
||||
RecoveryUI* GetUI() { return ui; }
|
||||
|
||||
int HandleMenuKey(int key, int visible) {
|
||||
if (visible) {
|
||||
switch (key) {
|
||||
case KEY_DOWN:
|
||||
case KEY_VOLUMEDOWN:
|
||||
return kHighlightDown;
|
||||
|
||||
case KEY_UP:
|
||||
case KEY_VOLUMEUP:
|
||||
return kHighlightUp;
|
||||
|
||||
case KEY_ENTER:
|
||||
case KEY_POWER:
|
||||
return kInvokeItem;
|
||||
}
|
||||
}
|
||||
|
||||
return kNoAction;
|
||||
}
|
||||
|
||||
BuiltinAction InvokeMenuItem(int menu_position) {
|
||||
switch (menu_position) {
|
||||
case 0: return REBOOT;
|
||||
case 1: return APPLY_ADB_SIDELOAD;
|
||||
case 2: return WIPE_DATA;
|
||||
case 3: return WIPE_CACHE;
|
||||
case 4: return REBOOT_BOOTLOADER;
|
||||
case 5: return SHUTDOWN;
|
||||
case 6: return READ_RECOVERY_LASTLOG;
|
||||
default: return NO_ACTION;
|
||||
}
|
||||
}
|
||||
|
||||
const char* const* GetMenuHeaders() { return HEADERS; }
|
||||
const char* const* GetMenuItems() { return ITEMS; }
|
||||
|
||||
private:
|
||||
RecoveryUI* ui;
|
||||
};
|
||||
|
||||
Device* make_device() {
|
||||
return new DefaultDevice();
|
||||
return new Device(new ScreenRecoveryUI);
|
||||
}
|
||||
|
||||
+74
@@ -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.
|
||||
*/
|
||||
|
||||
#include "device.h"
|
||||
|
||||
static const char* MENU_ITEMS[] = {
|
||||
"Reboot system now",
|
||||
"Reboot to bootloader",
|
||||
"Apply update from ADB",
|
||||
"Apply update from SD card",
|
||||
"Wipe data/factory reset",
|
||||
"Wipe cache partition",
|
||||
"Mount /system",
|
||||
"View recovery logs",
|
||||
"Power off",
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* const* Device::GetMenuItems() {
|
||||
return MENU_ITEMS;
|
||||
}
|
||||
|
||||
Device::BuiltinAction Device::InvokeMenuItem(int menu_position) {
|
||||
switch (menu_position) {
|
||||
case 0: return REBOOT;
|
||||
case 1: return REBOOT_BOOTLOADER;
|
||||
case 2: return APPLY_ADB_SIDELOAD;
|
||||
case 3: return APPLY_SDCARD;
|
||||
case 4: return WIPE_DATA;
|
||||
case 5: return WIPE_CACHE;
|
||||
case 6: return MOUNT_SYSTEM;
|
||||
case 7: return VIEW_RECOVERY_LOGS;
|
||||
case 8: return SHUTDOWN;
|
||||
default: return NO_ACTION;
|
||||
}
|
||||
}
|
||||
|
||||
int Device::HandleMenuKey(int key, int visible) {
|
||||
if (!visible) {
|
||||
return kNoAction;
|
||||
}
|
||||
|
||||
switch (key) {
|
||||
case KEY_DOWN:
|
||||
case KEY_VOLUMEDOWN:
|
||||
return kHighlightDown;
|
||||
|
||||
case KEY_UP:
|
||||
case KEY_VOLUMEUP:
|
||||
return kHighlightUp;
|
||||
|
||||
case KEY_ENTER:
|
||||
case KEY_POWER:
|
||||
return kInvokeItem;
|
||||
|
||||
default:
|
||||
// If you have all of the above buttons, any other buttons
|
||||
// are ignored. Otherwise, any button cycles the highlight.
|
||||
return ui_->HasThreeButtons() ? kNoAction : kHighlightDown;
|
||||
}
|
||||
}
|
||||
@@ -21,29 +21,20 @@
|
||||
|
||||
class Device {
|
||||
public:
|
||||
Device(RecoveryUI* ui) : ui_(ui) { }
|
||||
virtual ~Device() { }
|
||||
|
||||
// Called to obtain the UI object that should be used to display
|
||||
// the recovery user interface for this device. You should not
|
||||
// have called Init() on the UI object already, the caller will do
|
||||
// that after this method returns.
|
||||
virtual RecoveryUI* GetUI() = 0;
|
||||
virtual RecoveryUI* GetUI() { return ui_; }
|
||||
|
||||
// Called when recovery starts up (after the UI has been obtained
|
||||
// and initialized and after the arguments have been parsed, but
|
||||
// before anything else).
|
||||
virtual void StartRecovery() { };
|
||||
|
||||
// enum KeyAction { NONE, TOGGLE, REBOOT };
|
||||
|
||||
// // Called in the input thread when a new key (key_code) is
|
||||
// // pressed. *key_pressed is an array of KEY_MAX+1 bytes
|
||||
// // indicating which other keys are already pressed. Return a
|
||||
// // KeyAction to indicate action should be taken immediately.
|
||||
// // These actions happen when recovery is not waiting for input
|
||||
// // (eg, in the midst of installing a package).
|
||||
// virtual KeyAction CheckImmediateKeyAction(volatile char* key_pressed, int key_code) = 0;
|
||||
|
||||
// Called from the main thread when recovery is at the main menu
|
||||
// and waiting for input, and a key is pressed. (Note that "at"
|
||||
// the main menu does not necessarily mean the menu is visible;
|
||||
@@ -63,12 +54,26 @@ class Device {
|
||||
// - invoke the highlighted item (kInvokeItem)
|
||||
// - do nothing (kNoAction)
|
||||
// - invoke a specific action (a menu position: any non-negative number)
|
||||
virtual int HandleMenuKey(int key, int visible) = 0;
|
||||
virtual int HandleMenuKey(int key, int visible);
|
||||
|
||||
enum BuiltinAction { NO_ACTION, REBOOT, APPLY_EXT,
|
||||
APPLY_CACHE, // APPLY_CACHE is deprecated; has no effect
|
||||
APPLY_ADB_SIDELOAD, WIPE_DATA, WIPE_CACHE,
|
||||
REBOOT_BOOTLOADER, SHUTDOWN, READ_RECOVERY_LASTLOG };
|
||||
enum BuiltinAction {
|
||||
NO_ACTION = 0,
|
||||
REBOOT = 1,
|
||||
APPLY_SDCARD = 2,
|
||||
// APPLY_CACHE was 3.
|
||||
APPLY_ADB_SIDELOAD = 4,
|
||||
WIPE_DATA = 5,
|
||||
WIPE_CACHE = 6,
|
||||
REBOOT_BOOTLOADER = 7,
|
||||
SHUTDOWN = 8,
|
||||
VIEW_RECOVERY_LOGS = 9,
|
||||
MOUNT_SYSTEM = 10,
|
||||
};
|
||||
|
||||
// Return the list of menu items (an array of strings,
|
||||
// NULL-terminated). The menu_position passed to InvokeMenuItem
|
||||
// will correspond to the indexes into this array.
|
||||
virtual const char* const* GetMenuItems();
|
||||
|
||||
// Perform a recovery action selected from the menu.
|
||||
// 'menu_position' will be the item number of the selected menu
|
||||
@@ -79,31 +84,26 @@ class Device {
|
||||
// builtin actions, you can just return the corresponding enum
|
||||
// value. If it is an action specific to your device, you
|
||||
// actually perform it here and return NO_ACTION.
|
||||
virtual BuiltinAction InvokeMenuItem(int menu_position) = 0;
|
||||
virtual BuiltinAction InvokeMenuItem(int menu_position);
|
||||
|
||||
static const int kNoAction = -1;
|
||||
static const int kHighlightUp = -2;
|
||||
static const int kHighlightDown = -3;
|
||||
static const int kInvokeItem = -4;
|
||||
|
||||
// Called when we do a wipe data/factory reset operation (either via a
|
||||
// reboot from the main system with the --wipe_data flag, or when the
|
||||
// user boots into recovery manually and selects the option from the
|
||||
// menu.) Can perform whatever device-specific wiping actions are
|
||||
// needed. Return 0 on success. The userdata and cache partitions
|
||||
// are erased AFTER this returns (whether it returns success or not).
|
||||
virtual int WipeData() { return 0; }
|
||||
// Called before and after we do a wipe data/factory reset operation,
|
||||
// either via a reboot from the main system with the --wipe_data flag,
|
||||
// or when the user boots into recovery image manually and selects the
|
||||
// option from the menu, to perform whatever device-specific wiping
|
||||
// actions are needed.
|
||||
// Return true on success; returning false from PreWipeData will prevent
|
||||
// the regular wipe, and returning false from PostWipeData will cause
|
||||
// the wipe to be considered a failure.
|
||||
virtual bool PreWipeData() { return true; }
|
||||
virtual bool PostWipeData() { return true; }
|
||||
|
||||
// Return the headers (an array of strings, one per line,
|
||||
// NULL-terminated) for the main menu. Typically these tell users
|
||||
// what to push to move the selection and invoke the selected
|
||||
// item.
|
||||
virtual const char* const* GetMenuHeaders() = 0;
|
||||
|
||||
// Return the list of menu items (an array of strings,
|
||||
// NULL-terminated). The menu_position passed to InvokeMenuItem
|
||||
// will correspond to the indexes into this array.
|
||||
virtual const char* const* GetMenuItems() = 0;
|
||||
private:
|
||||
RecoveryUI* ui_;
|
||||
};
|
||||
|
||||
// The device-specific library must define this function (or the
|
||||
|
||||
+1
-1
@@ -24,6 +24,6 @@ void MD5Transform(uint32_t buf[4], uint32_t const in[16]);
|
||||
/*
|
||||
* This is needed to make RSAREF happy on some MS-DOS compilers.
|
||||
*/
|
||||
typedef struct MD5Context MD5_CTX;
|
||||
//typedef struct MD5Context MD5_CTX;
|
||||
|
||||
#endif /* !MD5_H */
|
||||
|
||||
+4
-3
@@ -7,9 +7,10 @@ edify_src_files := \
|
||||
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++.
|
||||
edify_cflags := -x 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
|
||||
|
||||
#
|
||||
# Build the host-side command line tool
|
||||
|
||||
+1
-2
@@ -25,13 +25,12 @@ extern int yyparse(Expr** root, int* error_count);
|
||||
|
||||
int expect(const char* expr_str, const char* expected, int* errors) {
|
||||
Expr* e;
|
||||
int error;
|
||||
char* result;
|
||||
|
||||
printf(".");
|
||||
|
||||
int error_count = parse_string(expr_str, &e, &error_count);
|
||||
if (error > 0 || error_count > 0) {
|
||||
if (error_count > 0) {
|
||||
printf("error parsing \"%s\" (%d errors)\n",
|
||||
expr_str, error_count);
|
||||
++*errors;
|
||||
|
||||
+1
-8
@@ -2,17 +2,10 @@ import /init.recovery.usb.rc
|
||||
import /init.recovery.${ro.hardware}.rc
|
||||
|
||||
on early-init
|
||||
# Apply strict SELinux checking of PROT_EXEC on mmap/mprotect calls.
|
||||
write /sys/fs/selinux/checkreqprot 0
|
||||
|
||||
# Set the security context for the init process.
|
||||
# This should occur before anything else (e.g. ueventd) is started.
|
||||
setcon u:r:init:s0
|
||||
|
||||
start ueventd
|
||||
start healthd
|
||||
|
||||
service set_permissive /sbin/toolbox setenforce 0
|
||||
service set_permissive /sbin/permissive.sh
|
||||
oneshot
|
||||
seclabel u:r:recovery:s0
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <dirent.h>
|
||||
#include <stdlib.h>
|
||||
#include "find_file.hpp"
|
||||
#include "twrp-functions.hpp"
|
||||
#include "twcommon.h"
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "flashutils/flashutils.h"
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/mount.h>
|
||||
@@ -35,19 +36,17 @@ 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;
|
||||
|
||||
if (lseek(fd->fd, block * fd->block_size, SEEK_SET) < 0) {
|
||||
printf("seek on sdcard failed: %s\n", strerror(errno));
|
||||
off64_t offset = ((off64_t) block) * fd->block_size;
|
||||
if (TEMP_FAILURE_RETRY(lseek64(fd->fd, offset, SEEK_SET)) == -1) {
|
||||
fprintf(stderr, "seek on sdcard failed: %s\n", strerror(errno));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
while (fetch_size > 0) {
|
||||
ssize_t r = read(fd->fd, buffer, fetch_size);
|
||||
if (r < 0) {
|
||||
if (r != -EINTR) {
|
||||
printf("read on sdcard failed: %s\n", strerror(errno));
|
||||
return -EIO;
|
||||
}
|
||||
r = 0;
|
||||
ssize_t r = TEMP_FAILURE_RETRY(read(fd->fd, buffer, fetch_size));
|
||||
if (r == -1) {
|
||||
fprintf(stderr, "read on sdcard failed: %s\n", strerror(errno));
|
||||
return -EIO;
|
||||
}
|
||||
fetch_size -= r;
|
||||
buffer += r;
|
||||
|
||||
@@ -17,7 +17,13 @@
|
||||
#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
|
||||
|
||||
#endif
|
||||
|
||||
+38
-14
@@ -53,6 +53,7 @@
|
||||
#include <string.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statfs.h>
|
||||
@@ -105,27 +106,52 @@ static void fuse_reply(struct fuse_data* fd, __u64 unique, const void *data, siz
|
||||
|
||||
vec[0].iov_base = &hdr;
|
||||
vec[0].iov_len = sizeof(hdr);
|
||||
vec[1].iov_base = data;
|
||||
vec[1].iov_base = /* const_cast */(void*)(data);
|
||||
vec[1].iov_len = len;
|
||||
|
||||
res = writev(fd->ffd, vec, 2);
|
||||
if (res < 0) {
|
||||
printf("*** REPLY FAILED *** %d\n", errno);
|
||||
printf("*** REPLY FAILED *** %s\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
static int handle_init(void* data, struct fuse_data* fd, const struct fuse_in_header* hdr) {
|
||||
const struct fuse_init_in* req = data;
|
||||
struct fuse_init_out out;
|
||||
size_t fuse_struct_size;
|
||||
|
||||
|
||||
/* Kernel 2.6.16 is the first stable kernel with struct fuse_init_out
|
||||
* defined (fuse version 7.6). The structure is the same from 7.6 through
|
||||
* 7.22. Beginning with 7.23, the structure increased in size and added
|
||||
* new parameters.
|
||||
*/
|
||||
if (req->major != FUSE_KERNEL_VERSION || req->minor < 6) {
|
||||
printf("Fuse kernel version mismatch: Kernel version %d.%d, Expected at least %d.6",
|
||||
req->major, req->minor, FUSE_KERNEL_VERSION);
|
||||
return -1;
|
||||
}
|
||||
|
||||
out.minor = MIN(req->minor, FUSE_KERNEL_MINOR_VERSION);
|
||||
fuse_struct_size = sizeof(out);
|
||||
#if defined(FUSE_COMPAT_22_INIT_OUT_SIZE)
|
||||
/* FUSE_KERNEL_VERSION >= 23. */
|
||||
|
||||
/* If the kernel only works on minor revs older than or equal to 22,
|
||||
* then use the older structure size since this code only uses the 7.22
|
||||
* version of the structure. */
|
||||
if (req->minor <= 22) {
|
||||
fuse_struct_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
|
||||
}
|
||||
#endif
|
||||
|
||||
out.major = FUSE_KERNEL_VERSION;
|
||||
out.minor = FUSE_KERNEL_MINOR_VERSION;
|
||||
out.max_readahead = req->max_readahead;
|
||||
out.flags = 0;
|
||||
out.max_background = 32;
|
||||
out.congestion_threshold = 32;
|
||||
out.max_write = 4096;
|
||||
fuse_reply(fd, hdr->unique, &out, sizeof(out));
|
||||
fuse_reply(fd, hdr->unique, &out, fuse_struct_size);
|
||||
|
||||
return NO_STATUS;
|
||||
}
|
||||
@@ -404,7 +430,7 @@ int run_fuse_sideload(struct provider_vtab* vtab, void* cookie,
|
||||
|
||||
char opts[256];
|
||||
snprintf(opts, sizeof(opts),
|
||||
("fd=%d,user_id=%d,group_id=%d,max_read=%zu,"
|
||||
("fd=%d,user_id=%d,group_id=%d,max_read=%u,"
|
||||
"allow_other,rootmode=040000"),
|
||||
fd.ffd, fd.uid, fd.gid, block_size);
|
||||
|
||||
@@ -416,14 +442,12 @@ int run_fuse_sideload(struct provider_vtab* vtab, void* cookie,
|
||||
}
|
||||
uint8_t request_buffer[sizeof(struct fuse_in_header) + PATH_MAX*8];
|
||||
for (;;) {
|
||||
ssize_t len = read(fd.ffd, request_buffer, sizeof(request_buffer));
|
||||
if (len < 0) {
|
||||
if (errno != EINTR) {
|
||||
perror("read request");
|
||||
if (errno == ENODEV) {
|
||||
result = -1;
|
||||
break;
|
||||
}
|
||||
ssize_t len = TEMP_FAILURE_RETRY(read(fd.ffd, request_buffer, sizeof(request_buffer)));
|
||||
if (len == -1) {
|
||||
perror("read request");
|
||||
if (errno == ENODEV) {
|
||||
result = -1;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -482,7 +506,7 @@ int run_fuse_sideload(struct provider_vtab* vtab, void* cookie,
|
||||
outhdr.len = sizeof(outhdr);
|
||||
outhdr.error = result;
|
||||
outhdr.unique = hdr->unique;
|
||||
write(fd.ffd, &outhdr, sizeof(outhdr));
|
||||
TEMP_FAILURE_RETRY(write(fd.ffd, &outhdr, sizeof(outhdr)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,10 @@
|
||||
#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"
|
||||
@@ -35,4 +39,6 @@ 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
@@ -71,7 +71,7 @@ ifeq ($(TW_ROUND_SCREEN), true)
|
||||
LOCAL_CFLAGS += -DTW_ROUND_SCREEN
|
||||
endif
|
||||
|
||||
LOCAL_C_INCLUDES += bionic external/stlport/stlport
|
||||
LOCAL_C_INCLUDES += bionic external/stlport/stlport system/core/libpixelflinger/include
|
||||
LOCAL_CFLAGS += -DTWRES=\"$(TWRES_PATH)\"
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
@@ -49,7 +49,6 @@ extern "C" {
|
||||
#include "../variables.h"
|
||||
#include "../twinstall.h"
|
||||
#include "cutils/properties.h"
|
||||
#include "../minadbd/adb.h"
|
||||
#include "../adb_install.h"
|
||||
#include "../set_metadata.h"
|
||||
};
|
||||
|
||||
+21
-6
@@ -18,6 +18,7 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
@@ -47,7 +48,7 @@ static const float DEFAULT_IMAGE_PROGRESS_FRACTION = 0.1;
|
||||
|
||||
// If the package contains an update binary, extract it and run it.
|
||||
static int
|
||||
try_update_binary(const char *path, ZipArchive *zip, int* wipe_cache) {
|
||||
try_update_binary(const char* path, ZipArchive* zip, bool* wipe_cache) {
|
||||
const ZipEntry* binary_entry =
|
||||
mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME);
|
||||
if (binary_entry == NULL) {
|
||||
@@ -87,7 +88,7 @@ try_update_binary(const char *path, ZipArchive *zip, int* wipe_cache) {
|
||||
// fill up the next <frac> part of of the progress bar
|
||||
// over <secs> seconds. If <secs> is zero, use
|
||||
// set_progress commands to manually control the
|
||||
// progress of this segment of the bar
|
||||
// progress of this segment of the bar.
|
||||
//
|
||||
// set_progress <frac>
|
||||
// <frac> should be between 0.0 and 1.0; sets the
|
||||
@@ -106,6 +107,18 @@ try_update_binary(const char *path, ZipArchive *zip, int* wipe_cache) {
|
||||
// ui_print <string>
|
||||
// display <string> on the screen.
|
||||
//
|
||||
// wipe_cache
|
||||
// a wipe of cache will be performed following a successful
|
||||
// installation.
|
||||
//
|
||||
// clear_display
|
||||
// turn off the text display.
|
||||
//
|
||||
// enable_reboot
|
||||
// packages can explicitly request that they want the user
|
||||
// to be able to reboot during installation (useful for
|
||||
// debugging packages that don't exit).
|
||||
//
|
||||
// - the name of the package zip file.
|
||||
//
|
||||
|
||||
@@ -128,7 +141,7 @@ try_update_binary(const char *path, ZipArchive *zip, int* wipe_cache) {
|
||||
}
|
||||
close(pipefd[1]);
|
||||
|
||||
*wipe_cache = 0;
|
||||
*wipe_cache = false;
|
||||
|
||||
char buffer[1024];
|
||||
FILE* from_child = fdopen(pipefd[0], "r");
|
||||
@@ -157,7 +170,7 @@ try_update_binary(const char *path, ZipArchive *zip, int* wipe_cache) {
|
||||
}
|
||||
fflush(stdout);
|
||||
} else if (strcmp(command, "wipe_cache") == 0) {
|
||||
*wipe_cache = 1;
|
||||
*wipe_cache = true;
|
||||
} else if (strcmp(command, "clear_display") == 0) {
|
||||
ui->SetBackground(RecoveryUI::NONE);
|
||||
} else if (strcmp(command, "enable_reboot") == 0) {
|
||||
@@ -182,7 +195,7 @@ try_update_binary(const char *path, ZipArchive *zip, int* wipe_cache) {
|
||||
}
|
||||
|
||||
static int
|
||||
really_install_package(const char *path, int* wipe_cache, bool needs_mount)
|
||||
really_install_package(const char *path, bool* wipe_cache, bool needs_mount)
|
||||
{
|
||||
ui->SetBackground(RecoveryUI::INSTALLING_UPDATE);
|
||||
ui->Print("Finding update package...\n");
|
||||
@@ -252,9 +265,11 @@ really_install_package(const char *path, int* wipe_cache, bool needs_mount)
|
||||
}
|
||||
|
||||
int
|
||||
install_package(const char* path, int* wipe_cache, const char* install_file,
|
||||
install_package(const char* path, bool* wipe_cache, const char* install_file,
|
||||
bool needs_mount)
|
||||
{
|
||||
modified_flash = true;
|
||||
|
||||
FILE* install_log = fopen_path(install_file, "w");
|
||||
if (install_log) {
|
||||
fputs(path, install_log);
|
||||
|
||||
@@ -28,7 +28,7 @@ enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT, INSTALL_NONE };
|
||||
// Install the package specified by root_path. If INSTALL_SUCCESS is
|
||||
// returned and *wipe_cache is true on exit, caller should wipe the
|
||||
// cache partition.
|
||||
int install_package(const char *root_path, int* wipe_cache,
|
||||
int install_package(const char* root_path, bool* wipe_cache,
|
||||
const char* install_file, bool needs_mount);
|
||||
RSAPublicKey* load_keys(const char* filename, int* numKeys);
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ static inline int fwrite_all(const void *ptr, size_t size,
|
||||
} else if (errno != EINTR && errno != EAGAIN)
|
||||
return -1;
|
||||
if (errno == EAGAIN) /* Try later, *sigh* */
|
||||
xusleep(250000);
|
||||
usleep(250000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <libgen.h>
|
||||
|
||||
#include "nls.h"
|
||||
#include "c.h"
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
#include "fileutils.h"
|
||||
#include "pathnames.h"
|
||||
|
||||
#ifndef _PATH_TMP
|
||||
#define _PATH_TMP "/tmp/"
|
||||
#endif
|
||||
|
||||
/* Create open temporary file in safe way. Please notice that the
|
||||
* file permissions are -rw------- by default. */
|
||||
int xmkstemp(char **tmpname, char *dir)
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
* Written by Karel Zak <kzak@redhat.com>
|
||||
*/
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <libgen.h>
|
||||
|
||||
#include "c.h"
|
||||
#include "at.h"
|
||||
@@ -13,6 +15,9 @@
|
||||
#include "fileutils.h"
|
||||
#include "all-io.h"
|
||||
|
||||
#define STRINGIFY(x) #x
|
||||
#define EXPAND(x) STRINGIFY(x)
|
||||
|
||||
char *sysfs_devno_attribute_path(dev_t devno, char *buf,
|
||||
size_t bufsiz, const char *attr)
|
||||
{
|
||||
@@ -436,7 +441,7 @@ int sysfs_write_string(struct sysfs_cxt *cxt, const char *attr, const char *str)
|
||||
|
||||
int sysfs_write_u64(struct sysfs_cxt *cxt, const char *attr, uint64_t num)
|
||||
{
|
||||
char buf[sizeof(stringify_value(ULLONG_MAX))];
|
||||
char buf[sizeof(STRINGIFY(ULLONG_MAX))];
|
||||
int fd, rc = 0, len, errsv;
|
||||
|
||||
fd = sysfs_open(cxt, attr, O_WRONLY|O_CLOEXEC);
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
LOCAL_PATH:= system/core/libpixelflinger
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
#
|
||||
# C/C++ and ARMv5 objects
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
ifneq ($(wildcard system/core/libpixelflinger/codeflinger/x86/X86Assembler.cpp),)
|
||||
ifeq ($(TARGET_ARCH),x86)
|
||||
TW_HAVE_X86_ACCELERATED_PIXELFLINGER := true
|
||||
endif
|
||||
endif
|
||||
|
||||
PIXELFLINGER_SRC_FILES += \
|
||||
codeflinger/CodeCache.cpp \
|
||||
codeflinger/tinyutils/SharedBuffer.cpp \
|
||||
codeflinger/tinyutils/VectorImpl.cpp \
|
||||
format.cpp \
|
||||
clear.cpp \
|
||||
raster.cpp \
|
||||
buffer.cpp
|
||||
|
||||
ifneq ($(TW_HAVE_X86_ACCELERATED_PIXELFLINGER),true)
|
||||
PIXELFLINGER_SRC_FILES += \
|
||||
codeflinger/ARMAssemblerInterface.cpp \
|
||||
codeflinger/ARMAssemblerProxy.cpp \
|
||||
codeflinger/GGLAssembler.cpp \
|
||||
codeflinger/load_store.cpp \
|
||||
codeflinger/blending.cpp \
|
||||
codeflinger/texturing.cpp \
|
||||
fixed.cpp.arm \
|
||||
picker.cpp.arm \
|
||||
pixelflinger.cpp.arm \
|
||||
trap.cpp.arm \
|
||||
scanline.cpp.arm
|
||||
else
|
||||
PIXELFLINGER_SRC_FILES_x86 := \
|
||||
codeflinger/x86/X86Assembler.cpp \
|
||||
codeflinger/x86/GGLX86Assembler.cpp \
|
||||
codeflinger/x86/load_store.cpp \
|
||||
codeflinger/x86/blending.cpp \
|
||||
codeflinger/x86/texturing.cpp \
|
||||
fixed.cpp \
|
||||
picker.cpp \
|
||||
pixelflinger.cpp \
|
||||
trap.cpp \
|
||||
scanline.cpp
|
||||
|
||||
PIXELFLINGER_C_INCLUDES_x86 := \
|
||||
external/libenc
|
||||
|
||||
endif
|
||||
|
||||
PIXELFLINGER_CFLAGS := -fstrict-aliasing -fomit-frame-pointer
|
||||
|
||||
PIXELFLINGER_SRC_FILES_arm := \
|
||||
codeflinger/ARMAssembler.cpp \
|
||||
codeflinger/disassem.c \
|
||||
col32cb16blend.S \
|
||||
t32cb16blend.S \
|
||||
|
||||
ifeq ($(ARCH_ARM_HAVE_NEON),true)
|
||||
PIXELFLINGER_SRC_FILES_arm += col32cb16blend_neon.S
|
||||
PIXELFLINGER_CFLAGS_arm += -D__ARM_HAVE_NEON
|
||||
endif
|
||||
|
||||
PIXELFLINGER_SRC_FILES_arm64 := \
|
||||
codeflinger/Arm64Assembler.cpp \
|
||||
codeflinger/Arm64Disassembler.cpp \
|
||||
arch-arm64/col32cb16blend.S \
|
||||
arch-arm64/t32cb16blend.S \
|
||||
|
||||
ifndef ARCH_MIPS_REV6
|
||||
PIXELFLINGER_SRC_FILES_mips := \
|
||||
codeflinger/MIPSAssembler.cpp \
|
||||
codeflinger/mips_disassem.c \
|
||||
arch-mips/t32cb16blend.S \
|
||||
|
||||
endif
|
||||
|
||||
#
|
||||
# Static library version
|
||||
#
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE:= libpixelflinger_twrp
|
||||
LOCAL_SRC_FILES := $(PIXELFLINGER_SRC_FILES)
|
||||
LOCAL_SRC_FILES_arm := $(PIXELFLINGER_SRC_FILES_arm)
|
||||
LOCAL_SRC_FILES_arm64 := $(PIXELFLINGER_SRC_FILES_arm64)
|
||||
LOCAL_SRC_FILES_x86 := $(PIXELFLINGER_SRC_FILES_x86)
|
||||
LOCAL_SRC_FILES_mips := $(PIXELFLINGER_SRC_FILES_mips)
|
||||
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
|
||||
LOCAL_C_INCLUDES += $(LOCAL_EXPORT_C_INCLUDE_DIRS)
|
||||
LOCAL_CFLAGS := $(PIXELFLINGER_CFLAGS)
|
||||
LOCAL_C_INCLUDES_x86 := $(PIXELFLINGER_C_INCLUDES_x86)
|
||||
ifeq ($(TW_HAVE_X86_ACCELERATED_PIXELFLINGER),true)
|
||||
LOCAL_WHOLE_STATIC_LIBRARIES += libenc
|
||||
LOCAL_C_INCLUDES += external/libenc
|
||||
endif
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <utime.h>
|
||||
#include <string.h>
|
||||
|
||||
#define DEBUG
|
||||
#ifdef STDC_HEADERS
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
# Copyright 2005 The Android Open Source Project
|
||||
#
|
||||
# Android.mk for adb
|
||||
#
|
||||
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
|
||||
# minadbd library
|
||||
# =========================================================
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
adb.c \
|
||||
fdevent.c \
|
||||
fuse_adb_provider.c \
|
||||
transport.c \
|
||||
transport_usb.c \
|
||||
sockets.c \
|
||||
services.c \
|
||||
usb_linux_client.c \
|
||||
utils.c
|
||||
|
||||
LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter
|
||||
LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
|
||||
LOCAL_MODULE_TAGS := eng
|
||||
LOCAL_MODULE := libminadbd
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../
|
||||
LOCAL_SHARED_LIBRARIES := libfusesideload libcutils libc
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
@@ -0,0 +1,39 @@
|
||||
The contents of this directory are copied from system/core/adb, with
|
||||
the following changes:
|
||||
|
||||
adb.c
|
||||
- much support for host mode and non-linux OS's stripped out; this
|
||||
version only runs as adbd on the device.
|
||||
- always setuid/setgid's itself to the shell user
|
||||
- only uses USB transport
|
||||
- references to JDWP removed
|
||||
- main() removed
|
||||
- all ADB_HOST and win32 code removed
|
||||
- removed listeners, logging code, background server (for host)
|
||||
|
||||
adb.h
|
||||
- minor changes to match adb.c changes
|
||||
|
||||
sockets.c
|
||||
- references to JDWP removed
|
||||
- ADB_HOST code removed
|
||||
|
||||
services.c
|
||||
- all services except echo_service (which is commented out) removed
|
||||
- all host mode support removed
|
||||
- sideload_service() added; this is the only service supported. It
|
||||
receives a single blob of data, writes it to a fixed filename, and
|
||||
makes the process exit.
|
||||
|
||||
Android.mk
|
||||
- only builds in adbd mode; builds as static library instead of a
|
||||
standalone executable.
|
||||
|
||||
sysdeps.h
|
||||
- changes adb_creat() to use O_NOFOLLOW
|
||||
|
||||
transport.c
|
||||
- removed ADB_HOST code
|
||||
|
||||
transport_usb.c
|
||||
- removed ADB_HOST code
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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 __FUSE_ADB_PROVIDER_H
|
||||
#define __FUSE_ADB_PROVIDER_H
|
||||
|
||||
int run_adb_fuse(int sfd, uint64_t file_size, uint32_t block_size);
|
||||
|
||||
#endif
|
||||
+27
-19
@@ -1,30 +1,38 @@
|
||||
# Copyright 2005 The Android Open Source Project
|
||||
#
|
||||
# Android.mk for adb
|
||||
#
|
||||
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
|
||||
# minadbd library
|
||||
# =========================================================
|
||||
minadbd_cflags := \
|
||||
-Wall -Werror \
|
||||
-Wno-unused-parameter \
|
||||
-Wno-missing-field-initializers \
|
||||
-DADB_HOST=0 \
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
adb.c \
|
||||
fdevent.c \
|
||||
fuse_adb_provider.c \
|
||||
transport.c \
|
||||
transport_usb.c \
|
||||
sockets.c \
|
||||
services.c \
|
||||
usb_linux_client.c \
|
||||
utils.c
|
||||
adb_main.cpp \
|
||||
fuse_adb_provider.cpp \
|
||||
services.cpp \
|
||||
../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 := eng
|
||||
LOCAL_MODULE := libminadbd
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../
|
||||
LOCAL_SHARED_LIBRARIES := libfusesideload libcutils libc
|
||||
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
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_CLANG := true
|
||||
LOCAL_MODULE := minadbd_test
|
||||
LOCAL_SRC_FILES := fuse_adb_provider_test.cpp
|
||||
LOCAL_CFLAGS := $(minadbd_cflags)
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH) system/core/adb
|
||||
LOCAL_STATIC_LIBRARIES := libminadbd
|
||||
LOCAL_SHARED_LIBRARIES := liblog libbase libcutils
|
||||
|
||||
include $(BUILD_NATIVE_TEST)
|
||||
|
||||
+3
-34
@@ -1,39 +1,8 @@
|
||||
The contents of this directory are copied from system/core/adb, with
|
||||
the following changes:
|
||||
minadbd is now mostly built from libadbd. The fuse features are unique to
|
||||
minadbd, and services.c has been modified as follows:
|
||||
|
||||
adb.c
|
||||
- much support for host mode and non-linux OS's stripped out; this
|
||||
version only runs as adbd on the device.
|
||||
- always setuid/setgid's itself to the shell user
|
||||
- only uses USB transport
|
||||
- references to JDWP removed
|
||||
- main() removed
|
||||
- all ADB_HOST and win32 code removed
|
||||
- removed listeners, logging code, background server (for host)
|
||||
|
||||
adb.h
|
||||
- minor changes to match adb.c changes
|
||||
|
||||
sockets.c
|
||||
- references to JDWP removed
|
||||
- ADB_HOST code removed
|
||||
|
||||
services.c
|
||||
- all services except echo_service (which is commented out) removed
|
||||
- all services removed
|
||||
- all host mode support removed
|
||||
- sideload_service() added; this is the only service supported. It
|
||||
receives a single blob of data, writes it to a fixed filename, and
|
||||
makes the process exit.
|
||||
|
||||
Android.mk
|
||||
- only builds in adbd mode; builds as static library instead of a
|
||||
standalone executable.
|
||||
|
||||
sysdeps.h
|
||||
- changes adb_creat() to use O_NOFOLLOW
|
||||
|
||||
transport.c
|
||||
- removed ADB_HOST code
|
||||
|
||||
transport_usb.c
|
||||
- removed ADB_HOST code
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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 <signal.h>
|
||||
#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);
|
||||
|
||||
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.
|
||||
auth_required = false;
|
||||
|
||||
init_transport_registration();
|
||||
usb_init();
|
||||
|
||||
D("Event loop starting\n");
|
||||
fdevent_loop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "sysdeps.h"
|
||||
|
||||
#include "adb.h"
|
||||
#include "adb_io.h"
|
||||
#include "fuse_adb_provider.h"
|
||||
#include "fuse_sideload.h"
|
||||
|
||||
int read_block_adb(void* data, uint32_t block, uint8_t* buffer, uint32_t fetch_size) {
|
||||
adb_data* ad = reinterpret_cast<adb_data*>(data);
|
||||
|
||||
if (!WriteFdFmt(ad->sfd, "%08u", block)) {
|
||||
fprintf(stderr, "failed to write to adb host: %s\n", strerror(errno));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (!ReadFdExactly(ad->sfd, buffer, fetch_size)) {
|
||||
fprintf(stderr, "failed to read from adb host: %s\n", strerror(errno));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void close_adb(void* data) {
|
||||
adb_data* ad = reinterpret_cast<adb_data*>(data);
|
||||
WriteFdExactly(ad->sfd, "DONEDONE");
|
||||
}
|
||||
|
||||
int run_adb_fuse(int sfd, uint64_t file_size, uint32_t block_size) {
|
||||
adb_data ad;
|
||||
ad.sfd = sfd;
|
||||
ad.file_size = file_size;
|
||||
ad.block_size = block_size;
|
||||
|
||||
provider_vtab vtab;
|
||||
vtab.read_block = read_block_adb;
|
||||
vtab.close = close_adb;
|
||||
|
||||
return run_fuse_sideload(&vtab, &ad, file_size, block_size);
|
||||
}
|
||||
@@ -17,6 +17,16 @@
|
||||
#ifndef __FUSE_ADB_PROVIDER_H
|
||||
#define __FUSE_ADB_PROVIDER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct adb_data {
|
||||
int sfd; // file descriptor for the adb channel
|
||||
|
||||
uint64_t file_size;
|
||||
uint32_t block_size;
|
||||
};
|
||||
|
||||
int read_block_adb(void* cookie, uint32_t block, uint8_t* buffer, uint32_t fetch_size);
|
||||
int run_adb_fuse(int sfd, uint64_t file_size, uint32_t block_size);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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 "fuse_adb_provider.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "adb_io.h"
|
||||
|
||||
TEST(fuse_adb_provider, read_block_adb) {
|
||||
adb_data data = {};
|
||||
int sockets[2];
|
||||
|
||||
ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, sockets));
|
||||
data.sfd = sockets[0];
|
||||
|
||||
int host_socket = sockets[1];
|
||||
fcntl(host_socket, F_SETFL, O_NONBLOCK);
|
||||
|
||||
const char expected_data[] = "foobar";
|
||||
char block_data[sizeof(expected_data)] = {};
|
||||
|
||||
// If we write the result of read_block_adb's request before the request is
|
||||
// actually made we can avoid needing an extra thread for this test.
|
||||
ASSERT_TRUE(WriteFdExactly(host_socket, expected_data,
|
||||
strlen(expected_data)));
|
||||
|
||||
uint32_t block = 1234U;
|
||||
const char expected_block[] = "00001234";
|
||||
ASSERT_EQ(0, read_block_adb(reinterpret_cast<void*>(&data), block,
|
||||
reinterpret_cast<uint8_t*>(block_data),
|
||||
sizeof(expected_data) - 1));
|
||||
|
||||
// Check that read_block_adb requested the right block.
|
||||
char block_req[sizeof(expected_block)] = {};
|
||||
ASSERT_TRUE(ReadFdExactly(host_socket, block_req, 8));
|
||||
ASSERT_EQ(0, block_req[8]);
|
||||
ASSERT_EQ(8U, strlen(block_req));
|
||||
ASSERT_STREQ(expected_block, block_req);
|
||||
|
||||
// Check that read_block_adb returned the right data.
|
||||
ASSERT_EQ(0, block_req[8]);
|
||||
ASSERT_STREQ(expected_data, block_data);
|
||||
|
||||
// Check that nothing else was written to the socket.
|
||||
char tmp;
|
||||
errno = 0;
|
||||
ASSERT_EQ(-1, read(host_socket, &tmp, 1));
|
||||
ASSERT_EQ(EWOULDBLOCK, errno);
|
||||
|
||||
close(sockets[0]);
|
||||
close(sockets[1]);
|
||||
}
|
||||
|
||||
TEST(fuse_adb_provider, read_block_adb_fail_write) {
|
||||
adb_data data = {};
|
||||
int sockets[2];
|
||||
|
||||
ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, sockets));
|
||||
data.sfd = sockets[0];
|
||||
|
||||
ASSERT_EQ(0, close(sockets[1]));
|
||||
|
||||
char buf[1];
|
||||
ASSERT_EQ(-EIO, read_block_adb(reinterpret_cast<void*>(&data), 0,
|
||||
reinterpret_cast<uint8_t*>(buf), 1));
|
||||
|
||||
close(sockets[0]);
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (C) 2007 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 <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sysdeps.h"
|
||||
|
||||
#define TRACE_TAG TRACE_SERVICES
|
||||
#include "adb.h"
|
||||
#include "fdevent.h"
|
||||
#include "fuse_adb_provider.h"
|
||||
|
||||
typedef struct stinfo stinfo;
|
||||
|
||||
struct stinfo {
|
||||
void (*func)(int fd, void *cookie);
|
||||
int fd;
|
||||
void *cookie;
|
||||
};
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
printf("sideload-host file size %d block size %d\n", file_size, block_size);
|
||||
|
||||
int result = run_adb_fuse(sfd, file_size, block_size);
|
||||
|
||||
printf("sideload_host finished\n");
|
||||
sleep(1);
|
||||
exit(result == 0 ? 0 : 1);
|
||||
}
|
||||
|
||||
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");
|
||||
return -1;
|
||||
}
|
||||
|
||||
stinfo* sti = reinterpret_cast<stinfo*>(malloc(sizeof(stinfo)));
|
||||
if(sti == 0) fatal("cannot allocate stinfo");
|
||||
sti->func = func;
|
||||
sti->cookie = cookie;
|
||||
sti->fd = s[1];
|
||||
|
||||
adb_thread_t t;
|
||||
if (adb_thread_create( &t, service_bootstrap_func, sti)){
|
||||
free(sti);
|
||||
adb_close(s[0]);
|
||||
adb_close(s[1]);
|
||||
printf("cannot create service thread\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
D("service thread started, %d:%d\n",s[0], s[1]);
|
||||
return s[0];
|
||||
}
|
||||
|
||||
int service_to_fd(const char* name) {
|
||||
int ret = -1;
|
||||
|
||||
if (!strncmp(name, "sideload:", 9)) {
|
||||
// this exit status causes recovery to print a special error
|
||||
// message saying to use a newer adb (that supports
|
||||
// sideload-host).
|
||||
exit(3);
|
||||
} else if (!strncmp(name, "sideload-host:", 14)) {
|
||||
ret = create_service_thread(sideload_host_service, (void*)(name + 14));
|
||||
}
|
||||
if (ret >= 0) {
|
||||
close_on_exec(ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := graphics_overlay.c events.c resources.c
|
||||
ifneq ($(BOARD_CUSTOM_GRAPHICS),)
|
||||
LOCAL_SRC_FILES += $(BOARD_CUSTOM_GRAPHICS)
|
||||
else
|
||||
LOCAL_SRC_FILES += graphics.c
|
||||
endif
|
||||
|
||||
LOCAL_C_INCLUDES +=\
|
||||
external/libpng \
|
||||
external/zlib \
|
||||
system/core/include/pixelflinger
|
||||
|
||||
ifeq ($(TW_TARGET_USES_QCOM_BSP), true)
|
||||
LOCAL_CFLAGS += -DMSM_BSP
|
||||
ifeq ($(TARGET_PREBUILT_KERNEL),)
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
|
||||
LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
|
||||
else
|
||||
ifeq ($(TARGET_CUSTOM_KERNEL_HEADERS),)
|
||||
LOCAL_C_INCLUDES += $(commands_recovery_local_path)/minui/include
|
||||
else
|
||||
LOCAL_C_INCLUDES += $(TARGET_CUSTOM_KERNEL_HEADERS)
|
||||
endif
|
||||
endif
|
||||
else
|
||||
LOCAL_C_INCLUDES += $(commands_recovery_local_path)/minui/include
|
||||
endif
|
||||
|
||||
ifeq ($(TW_NEW_ION_HEAP), true)
|
||||
LOCAL_CFLAGS += -DNEW_ION_HEAP
|
||||
endif
|
||||
|
||||
LOCAL_STATIC_LIBRARY := libpng
|
||||
LOCAL_WHOLE_STATIC_LIBRARIES := libpixelflinger_static
|
||||
LOCAL_MODULE := libminui
|
||||
|
||||
# This used to compare against values in double-quotes (which are just
|
||||
# ordinary characters in this context). Strip double-quotes from the
|
||||
# value so that either will work.
|
||||
|
||||
ifeq ($(subst ",,$(TARGET_RECOVERY_PIXEL_FORMAT)),RGBX_8888)
|
||||
LOCAL_CFLAGS += -DRECOVERY_RGBX
|
||||
endif
|
||||
ifeq ($(subst ",,$(TARGET_RECOVERY_PIXEL_FORMAT)),BGRA_8888)
|
||||
LOCAL_CFLAGS += -DRECOVERY_BGRA
|
||||
endif
|
||||
|
||||
ifneq ($(TARGET_RECOVERY_OVERSCAN_PERCENT),)
|
||||
LOCAL_CFLAGS += -DOVERSCAN_PERCENT=$(TARGET_RECOVERY_OVERSCAN_PERCENT)
|
||||
else
|
||||
LOCAL_CFLAGS += -DOVERSCAN_PERCENT=0
|
||||
endif
|
||||
|
||||
ifneq ($(TW_BRIGHTNESS_PATH),)
|
||||
LOCAL_CFLAGS += -DTW_BRIGHTNESS_PATH=\"$(TW_BRIGHTNESS_PATH)\"
|
||||
endif
|
||||
ifneq ($(TW_MAX_BRIGHTNESS),)
|
||||
LOCAL_CFLAGS += -DTW_MAX_BRIGHTNESS=$(TW_MAX_BRIGHTNESS)
|
||||
else
|
||||
LOCAL_CFLAGS += -DTW_MAX_BRIGHTNESS=255
|
||||
endif
|
||||
ifneq ($(TW_NO_SCREEN_BLANK),)
|
||||
LOCAL_CFLAGS += -DTW_NO_SCREEN_BLANK
|
||||
endif
|
||||
ifneq ($(BOARD_USE_CUSTOM_RECOVERY_FONT),)
|
||||
LOCAL_CFLAGS += -DBOARD_USE_CUSTOM_RECOVERY_FONT=$(BOARD_USE_CUSTOM_RECOVERY_FONT)
|
||||
endif
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := graphics_overlay.c events.c resources.c
|
||||
ifneq ($(BOARD_CUSTOM_GRAPHICS),)
|
||||
LOCAL_SRC_FILES += $(BOARD_CUSTOM_GRAPHICS)
|
||||
else
|
||||
LOCAL_SRC_FILES += graphics.c
|
||||
endif
|
||||
|
||||
ifeq ($(TW_TARGET_USES_QCOM_BSP), true)
|
||||
LOCAL_CFLAGS += -DMSM_BSP
|
||||
ifeq ($(TARGET_PREBUILT_KERNEL),)
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
|
||||
LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
|
||||
else
|
||||
ifeq ($(TARGET_CUSTOM_KERNEL_HEADERS),)
|
||||
LOCAL_C_INCLUDES += $(commands_recovery_local_path)/minui/include
|
||||
else
|
||||
LOCAL_C_INCLUDES += $(TARGET_CUSTOM_KERNEL_HEADERS)
|
||||
endif
|
||||
endif
|
||||
else
|
||||
LOCAL_C_INCLUDES += $(commands_recovery_local_path)/minui/include
|
||||
endif
|
||||
|
||||
LOCAL_C_INCLUDES +=\
|
||||
external/libpng\
|
||||
external/zlib
|
||||
|
||||
LOCAL_MODULE := libminui
|
||||
|
||||
LOCAL_ARM_MODE:= arm
|
||||
LOCAL_SHARED_LIBRARIES := libpng libpixelflinger
|
||||
# This used to compare against values in double-quotes (which are just
|
||||
# ordinary characters in this context). Strip double-quotes from the
|
||||
# value so that either will work.
|
||||
|
||||
ifeq ($(subst ",,$(TARGET_RECOVERY_PIXEL_FORMAT)),RGBX_8888)
|
||||
LOCAL_CFLAGS += -DRECOVERY_RGBX
|
||||
endif
|
||||
ifeq ($(subst ",,$(TARGET_RECOVERY_PIXEL_FORMAT)),BGRA_8888)
|
||||
LOCAL_CFLAGS += -DRECOVERY_BGRA
|
||||
endif
|
||||
|
||||
ifneq ($(TARGET_RECOVERY_OVERSCAN_PERCENT),)
|
||||
LOCAL_CFLAGS += -DOVERSCAN_PERCENT=$(TARGET_RECOVERY_OVERSCAN_PERCENT)
|
||||
else
|
||||
LOCAL_CFLAGS += -DOVERSCAN_PERCENT=0
|
||||
endif
|
||||
|
||||
ifneq ($(TW_BRIGHTNESS_PATH),)
|
||||
LOCAL_CFLAGS += -DTW_BRIGHTNESS_PATH=\"$(TW_BRIGHTNESS_PATH)\"
|
||||
endif
|
||||
ifneq ($(TW_MAX_BRIGHTNESS),)
|
||||
LOCAL_CFLAGS += -DTW_MAX_BRIGHTNESS=$(TW_MAX_BRIGHTNESS)
|
||||
else
|
||||
LOCAL_CFLAGS += -DTW_MAX_BRIGHTNESS=255
|
||||
endif
|
||||
ifneq ($(TW_NO_SCREEN_BLANK),)
|
||||
LOCAL_CFLAGS += -DTW_NO_SCREEN_BLANK
|
||||
endif
|
||||
ifneq ($(BOARD_USE_CUSTOM_RECOVERY_FONT),)
|
||||
LOCAL_CFLAGS += -DBOARD_USE_CUSTOM_RECOVERY_FONT=$(BOARD_USE_CUSTOM_RECOVERY_FONT)
|
||||
endif
|
||||
|
||||
LOCAL_CFLAGS += -DFASTMMI_FEATURE
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
@@ -0,0 +1,214 @@
|
||||
struct {
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
unsigned cwidth;
|
||||
unsigned cheight;
|
||||
unsigned char rundata[];
|
||||
} font = {
|
||||
.width = 960,
|
||||
.height = 18,
|
||||
.cwidth = 10,
|
||||
.cheight = 18,
|
||||
.rundata = {
|
||||
0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x55,0x82,0x06,0x82,0x02,0x82,0x10,0x82,
|
||||
0x11,0x83,0x08,0x82,0x0a,0x82,0x04,0x82,0x46,0x82,0x08,0x82,0x07,0x84,0x06,
|
||||
0x84,0x0a,0x81,0x03,0x88,0x04,0x84,0x04,0x88,0x04,0x84,0x06,0x84,0x1e,0x81,
|
||||
0x0e,0x81,0x0a,0x84,0x06,0x84,0x07,0x82,0x05,0x85,0x07,0x84,0x04,0x86,0x04,
|
||||
0x88,0x02,0x88,0x04,0x84,0x04,0x82,0x04,0x82,0x02,0x88,0x05,0x86,0x01,0x82,
|
||||
0x04,0x82,0x02,0x82,0x08,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x04,0x84,0x04,
|
||||
0x86,0x06,0x84,0x04,0x86,0x06,0x84,0x04,0x88,0x02,0x82,0x04,0x82,0x02,0x82,
|
||||
0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,
|
||||
0x88,0x03,0x86,0x0e,0x86,0x06,0x82,0x11,0x82,0x10,0x82,0x18,0x82,0x0f,0x84,
|
||||
0x0d,0x82,0x1c,0x82,0x09,0x84,0x7f,0x16,0x84,0x05,0x82,0x05,0x84,0x07,0x83,
|
||||
0x02,0x82,0x19,0x82,0x06,0x82,0x02,0x82,0x06,0x82,0x01,0x82,0x03,0x86,0x04,
|
||||
0x83,0x02,0x82,0x03,0x82,0x01,0x82,0x07,0x82,0x09,0x82,0x06,0x82,0x3e,0x82,
|
||||
0x04,0x84,0x06,0x83,0x06,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x08,0x82,0x03,
|
||||
0x82,0x09,0x82,0x02,0x82,0x09,0x82,0x03,0x82,0x02,0x82,0x04,0x82,0x02,0x82,
|
||||
0x1c,0x82,0x0e,0x82,0x08,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x05,0x84,0x04,
|
||||
0x82,0x02,0x82,0x05,0x82,0x02,0x82,0x03,0x82,0x03,0x82,0x03,0x82,0x08,0x82,
|
||||
0x09,0x82,0x02,0x82,0x03,0x82,0x04,0x82,0x05,0x82,0x0a,0x82,0x03,0x82,0x04,
|
||||
0x82,0x02,0x82,0x08,0x82,0x04,0x82,0x02,0x83,0x03,0x82,0x03,0x82,0x02,0x82,
|
||||
0x03,0x82,0x03,0x82,0x04,0x82,0x02,0x82,0x03,0x82,0x03,0x82,0x04,0x82,0x02,
|
||||
0x82,0x06,0x82,0x05,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,
|
||||
0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x08,0x82,0x03,0x82,0x08,0x82,0x0c,
|
||||
0x82,0x05,0x84,0x11,0x82,0x0f,0x82,0x18,0x82,0x0e,0x82,0x02,0x82,0x0c,0x82,
|
||||
0x1c,0x82,0x0b,0x82,0x7f,0x15,0x82,0x08,0x82,0x08,0x82,0x05,0x82,0x01,0x82,
|
||||
0x01,0x82,0x19,0x82,0x06,0x82,0x02,0x82,0x06,0x82,0x01,0x82,0x02,0x82,0x01,
|
||||
0x82,0x01,0x82,0x02,0x82,0x01,0x82,0x01,0x82,0x03,0x82,0x01,0x82,0x07,0x82,
|
||||
0x08,0x82,0x08,0x82,0x3d,0x82,0x03,0x82,0x02,0x82,0x04,0x84,0x05,0x82,0x04,
|
||||
0x82,0x02,0x82,0x04,0x82,0x06,0x83,0x03,0x82,0x08,0x82,0x04,0x81,0x09,0x82,
|
||||
0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x1a,0x82,0x10,0x82,0x06,0x82,0x04,
|
||||
0x82,0x02,0x82,0x04,0x82,0x03,0x82,0x02,0x82,0x03,0x82,0x03,0x82,0x03,0x82,
|
||||
0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x08,0x82,0x08,0x82,0x04,0x82,0x02,
|
||||
0x82,0x04,0x82,0x05,0x82,0x0a,0x82,0x03,0x82,0x03,0x82,0x03,0x82,0x08,0x83,
|
||||
0x02,0x83,0x02,0x83,0x03,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,
|
||||
0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x05,0x82,0x05,0x82,
|
||||
0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x03,0x82,0x02,0x82,0x04,
|
||||
0x82,0x02,0x82,0x09,0x82,0x03,0x82,0x08,0x82,0x0c,0x82,0x04,0x82,0x02,0x82,
|
||||
0x11,0x82,0x0e,0x82,0x18,0x82,0x0e,0x82,0x02,0x82,0x0c,0x82,0x0b,0x82,0x0b,
|
||||
0x82,0x02,0x82,0x0b,0x82,0x4d,0x82,0x45,0x82,0x08,0x82,0x08,0x82,0x05,0x82,
|
||||
0x02,0x83,0x1a,0x82,0x07,0x81,0x02,0x81,0x07,0x82,0x01,0x82,0x02,0x82,0x01,
|
||||
0x82,0x05,0x82,0x01,0x84,0x04,0x82,0x01,0x82,0x07,0x82,0x08,0x82,0x08,0x82,
|
||||
0x06,0x82,0x02,0x82,0x06,0x82,0x28,0x82,0x04,0x82,0x02,0x82,0x03,0x82,0x01,
|
||||
0x82,0x05,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x05,0x84,0x03,0x82,0x08,0x82,
|
||||
0x0d,0x82,0x03,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x19,0x82,0x12,0x82,0x05,
|
||||
0x82,0x04,0x82,0x02,0x82,0x02,0x84,0x03,0x82,0x02,0x82,0x03,0x82,0x03,0x82,
|
||||
0x03,0x82,0x08,0x82,0x04,0x82,0x02,0x82,0x08,0x82,0x08,0x82,0x08,0x82,0x04,
|
||||
0x82,0x05,0x82,0x0a,0x82,0x03,0x82,0x03,0x82,0x03,0x82,0x08,0x83,0x02,0x83,
|
||||
0x02,0x84,0x02,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,
|
||||
0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x0b,0x82,0x05,0x82,0x04,0x82,0x02,0x82,
|
||||
0x04,0x82,0x02,0x82,0x04,0x82,0x03,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x08,
|
||||
0x82,0x04,0x82,0x09,0x82,0x0b,0x82,0x03,0x82,0x04,0x82,0x20,0x82,0x18,0x82,
|
||||
0x0e,0x82,0x10,0x82,0x0b,0x82,0x0b,0x82,0x02,0x82,0x0b,0x82,0x4d,0x82,0x45,
|
||||
0x82,0x08,0x82,0x08,0x82,0x26,0x82,0x10,0x88,0x01,0x82,0x01,0x82,0x06,0x83,
|
||||
0x01,0x82,0x04,0x84,0x08,0x81,0x08,0x82,0x0a,0x82,0x05,0x82,0x02,0x82,0x06,
|
||||
0x82,0x28,0x82,0x03,0x82,0x04,0x82,0x05,0x82,0x0b,0x82,0x08,0x82,0x04,0x82,
|
||||
0x01,0x82,0x03,0x82,0x08,0x82,0x0d,0x82,0x03,0x82,0x04,0x82,0x02,0x82,0x04,
|
||||
0x82,0x18,0x82,0x06,0x88,0x06,0x82,0x04,0x82,0x04,0x82,0x02,0x82,0x01,0x85,
|
||||
0x02,0x82,0x04,0x82,0x02,0x82,0x03,0x82,0x03,0x82,0x08,0x82,0x04,0x82,0x02,
|
||||
0x82,0x08,0x82,0x08,0x82,0x08,0x82,0x04,0x82,0x05,0x82,0x0a,0x82,0x03,0x82,
|
||||
0x02,0x82,0x04,0x82,0x08,0x88,0x02,0x84,0x02,0x82,0x02,0x82,0x04,0x82,0x02,
|
||||
0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x0b,0x82,
|
||||
0x05,0x82,0x04,0x82,0x03,0x82,0x02,0x82,0x03,0x82,0x04,0x82,0x04,0x84,0x06,
|
||||
0x84,0x08,0x82,0x05,0x82,0x09,0x82,0x0b,0x82,0x2b,0x82,0x18,0x82,0x0e,0x82,
|
||||
0x10,0x82,0x1c,0x82,0x0b,0x82,0x4d,0x82,0x45,0x82,0x08,0x82,0x08,0x82,0x26,
|
||||
0x82,0x11,0x82,0x01,0x82,0x03,0x82,0x01,0x82,0x09,0x82,0x06,0x82,0x12,0x82,
|
||||
0x0a,0x82,0x06,0x84,0x07,0x82,0x27,0x82,0x04,0x82,0x04,0x82,0x05,0x82,0x0b,
|
||||
0x82,0x07,0x82,0x04,0x82,0x02,0x82,0x03,0x82,0x01,0x83,0x04,0x82,0x01,0x83,
|
||||
0x08,0x82,0x05,0x82,0x02,0x82,0x03,0x82,0x04,0x82,0x05,0x83,0x07,0x83,0x05,
|
||||
0x82,0x16,0x82,0x08,0x82,0x03,0x82,0x01,0x82,0x01,0x82,0x02,0x82,0x04,0x82,
|
||||
0x02,0x82,0x02,0x82,0x04,0x82,0x08,0x82,0x04,0x82,0x02,0x82,0x08,0x82,0x08,
|
||||
0x82,0x08,0x82,0x04,0x82,0x05,0x82,0x0a,0x82,0x03,0x82,0x02,0x82,0x04,0x82,
|
||||
0x08,0x82,0x01,0x82,0x01,0x82,0x02,0x82,0x01,0x82,0x01,0x82,0x02,0x82,0x04,
|
||||
0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x03,0x82,
|
||||
0x0a,0x82,0x05,0x82,0x04,0x82,0x03,0x82,0x02,0x82,0x03,0x82,0x01,0x82,0x01,
|
||||
0x82,0x04,0x84,0x06,0x84,0x08,0x82,0x05,0x82,0x0a,0x82,0x0a,0x82,0x23,0x85,
|
||||
0x03,0x82,0x01,0x83,0x06,0x85,0x05,0x83,0x01,0x82,0x04,0x84,0x04,0x86,0x05,
|
||||
0x85,0x01,0x81,0x02,0x82,0x01,0x83,0x05,0x84,0x09,0x84,0x02,0x82,0x03,0x82,
|
||||
0x06,0x82,0x05,0x81,0x01,0x82,0x01,0x82,0x03,0x82,0x01,0x83,0x06,0x84,0x04,
|
||||
0x82,0x01,0x83,0x06,0x83,0x01,0x82,0x02,0x82,0x01,0x84,0x04,0x86,0x03,0x86,
|
||||
0x04,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,
|
||||
0x82,0x02,0x82,0x04,0x82,0x03,0x87,0x05,0x82,0x08,0x82,0x08,0x82,0x26,0x82,
|
||||
0x11,0x82,0x01,0x82,0x04,0x86,0x07,0x82,0x05,0x83,0x12,0x82,0x0a,0x82,0x04,
|
||||
0x88,0x02,0x88,0x0c,0x88,0x10,0x82,0x04,0x82,0x04,0x82,0x05,0x82,0x0a,0x82,
|
||||
0x06,0x83,0x04,0x82,0x03,0x82,0x03,0x83,0x02,0x82,0x03,0x83,0x02,0x82,0x07,
|
||||
0x82,0x06,0x84,0x05,0x82,0x02,0x83,0x05,0x83,0x07,0x83,0x04,0x82,0x18,0x82,
|
||||
0x06,0x82,0x04,0x82,0x01,0x82,0x01,0x82,0x02,0x82,0x04,0x82,0x02,0x86,0x04,
|
||||
0x82,0x08,0x82,0x04,0x82,0x02,0x86,0x04,0x86,0x04,0x82,0x02,0x84,0x02,0x88,
|
||||
0x05,0x82,0x0a,0x82,0x03,0x85,0x05,0x82,0x08,0x82,0x01,0x82,0x01,0x82,0x02,
|
||||
0x82,0x01,0x82,0x01,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x03,0x82,0x03,0x82,
|
||||
0x04,0x82,0x02,0x82,0x03,0x82,0x05,0x84,0x07,0x82,0x05,0x82,0x04,0x82,0x03,
|
||||
0x82,0x02,0x82,0x03,0x82,0x01,0x82,0x01,0x82,0x05,0x82,0x08,0x82,0x08,0x82,
|
||||
0x06,0x82,0x0a,0x82,0x0a,0x82,0x22,0x82,0x03,0x82,0x02,0x83,0x02,0x82,0x04,
|
||||
0x82,0x03,0x82,0x03,0x82,0x02,0x83,0x03,0x82,0x02,0x82,0x05,0x82,0x06,0x82,
|
||||
0x03,0x83,0x02,0x83,0x02,0x82,0x06,0x82,0x0b,0x82,0x02,0x82,0x02,0x82,0x07,
|
||||
0x82,0x05,0x88,0x02,0x83,0x02,0x82,0x04,0x82,0x02,0x82,0x03,0x83,0x02,0x82,
|
||||
0x04,0x82,0x02,0x83,0x03,0x83,0x02,0x82,0x02,0x82,0x04,0x82,0x04,0x82,0x06,
|
||||
0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x03,0x82,0x02,0x82,
|
||||
0x03,0x82,0x04,0x82,0x08,0x82,0x02,0x84,0x09,0x82,0x09,0x84,0x23,0x82,0x11,
|
||||
0x82,0x01,0x82,0x06,0x82,0x01,0x82,0x05,0x82,0x05,0x82,0x01,0x82,0x11,0x82,
|
||||
0x0a,0x82,0x06,0x84,0x07,0x82,0x26,0x82,0x05,0x82,0x04,0x82,0x05,0x82,0x08,
|
||||
0x83,0x09,0x82,0x03,0x82,0x03,0x82,0x09,0x82,0x02,0x82,0x04,0x82,0x05,0x82,
|
||||
0x06,0x82,0x02,0x82,0x05,0x83,0x01,0x82,0x17,0x82,0x16,0x82,0x06,0x82,0x05,
|
||||
0x82,0x01,0x82,0x01,0x82,0x02,0x88,0x02,0x82,0x03,0x82,0x03,0x82,0x08,0x82,
|
||||
0x04,0x82,0x02,0x82,0x08,0x82,0x08,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x05,
|
||||
0x82,0x0a,0x82,0x03,0x82,0x02,0x82,0x04,0x82,0x08,0x82,0x01,0x82,0x01,0x82,
|
||||
0x02,0x82,0x02,0x84,0x02,0x82,0x04,0x82,0x02,0x86,0x04,0x82,0x04,0x82,0x02,
|
||||
0x86,0x09,0x82,0x06,0x82,0x05,0x82,0x04,0x82,0x04,0x84,0x04,0x82,0x01,0x82,
|
||||
0x01,0x82,0x04,0x84,0x07,0x82,0x07,0x82,0x07,0x82,0x0b,0x82,0x09,0x82,0x27,
|
||||
0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x08,0x82,0x04,0x82,0x02,0x82,0x04,0x82,
|
||||
0x04,0x82,0x06,0x82,0x03,0x82,0x03,0x82,0x04,0x82,0x05,0x82,0x0b,0x82,0x02,
|
||||
0x82,0x01,0x82,0x08,0x82,0x05,0x82,0x01,0x82,0x01,0x82,0x02,0x82,0x04,0x82,
|
||||
0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x03,0x82,0x07,
|
||||
0x82,0x0a,0x82,0x06,0x82,0x04,0x82,0x03,0x82,0x02,0x82,0x03,0x82,0x04,0x82,
|
||||
0x04,0x84,0x04,0x82,0x04,0x82,0x07,0x82,0x06,0x82,0x08,0x82,0x08,0x82,0x26,
|
||||
0x82,0x0f,0x88,0x05,0x82,0x01,0x82,0x05,0x82,0x05,0x82,0x02,0x82,0x01,0x82,
|
||||
0x0d,0x82,0x0a,0x82,0x05,0x82,0x02,0x82,0x06,0x82,0x26,0x82,0x05,0x82,0x04,
|
||||
0x82,0x05,0x82,0x07,0x82,0x0c,0x82,0x02,0x88,0x08,0x82,0x02,0x82,0x04,0x82,
|
||||
0x05,0x82,0x05,0x82,0x04,0x82,0x08,0x82,0x18,0x82,0x14,0x82,0x07,0x82,0x05,
|
||||
0x82,0x01,0x84,0x03,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x08,0x82,
|
||||
0x04,0x82,0x02,0x82,0x08,0x82,0x08,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x05,
|
||||
0x82,0x0a,0x82,0x03,0x82,0x02,0x82,0x04,0x82,0x08,0x82,0x01,0x82,0x01,0x82,
|
||||
0x02,0x82,0x02,0x84,0x02,0x82,0x04,0x82,0x02,0x82,0x08,0x82,0x04,0x82,0x02,
|
||||
0x82,0x02,0x82,0x0a,0x82,0x05,0x82,0x05,0x82,0x04,0x82,0x04,0x84,0x04,0x82,
|
||||
0x01,0x82,0x01,0x82,0x04,0x84,0x07,0x82,0x07,0x82,0x07,0x82,0x0b,0x82,0x09,
|
||||
0x82,0x22,0x87,0x02,0x82,0x04,0x82,0x02,0x82,0x08,0x82,0x04,0x82,0x02,0x88,
|
||||
0x04,0x82,0x06,0x82,0x03,0x82,0x03,0x82,0x04,0x82,0x05,0x82,0x0b,0x82,0x02,
|
||||
0x84,0x09,0x82,0x05,0x82,0x01,0x82,0x01,0x82,0x02,0x82,0x04,0x82,0x02,0x82,
|
||||
0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x03,0x82,0x08,0x86,0x05,
|
||||
0x82,0x06,0x82,0x04,0x82,0x03,0x82,0x02,0x82,0x03,0x82,0x01,0x82,0x01,0x82,
|
||||
0x05,0x82,0x05,0x82,0x04,0x82,0x06,0x82,0x07,0x82,0x08,0x82,0x08,0x82,0x26,
|
||||
0x82,0x10,0x82,0x01,0x82,0x07,0x82,0x01,0x82,0x04,0x82,0x01,0x83,0x02,0x82,
|
||||
0x03,0x83,0x0f,0x82,0x08,0x82,0x06,0x82,0x02,0x82,0x06,0x82,0x25,0x82,0x07,
|
||||
0x82,0x02,0x82,0x06,0x82,0x06,0x82,0x07,0x82,0x04,0x82,0x07,0x82,0x09,0x82,
|
||||
0x02,0x82,0x04,0x82,0x04,0x82,0x06,0x82,0x04,0x82,0x08,0x82,0x19,0x82,0x05,
|
||||
0x88,0x05,0x82,0x08,0x82,0x05,0x82,0x02,0x82,0x04,0x82,0x04,0x82,0x02,0x82,
|
||||
0x04,0x82,0x02,0x82,0x08,0x82,0x04,0x82,0x02,0x82,0x08,0x82,0x08,0x82,0x04,
|
||||
0x82,0x02,0x82,0x04,0x82,0x05,0x82,0x05,0x82,0x03,0x82,0x03,0x82,0x03,0x82,
|
||||
0x03,0x82,0x08,0x82,0x04,0x82,0x02,0x82,0x03,0x83,0x02,0x82,0x04,0x82,0x02,
|
||||
0x82,0x08,0x82,0x01,0x82,0x01,0x82,0x02,0x82,0x03,0x82,0x09,0x82,0x05,0x82,
|
||||
0x05,0x82,0x04,0x82,0x04,0x84,0x04,0x83,0x02,0x83,0x03,0x82,0x02,0x82,0x06,
|
||||
0x82,0x06,0x82,0x08,0x82,0x0c,0x82,0x08,0x82,0x21,0x82,0x04,0x82,0x02,0x82,
|
||||
0x04,0x82,0x02,0x82,0x08,0x82,0x04,0x82,0x02,0x82,0x0a,0x82,0x06,0x82,0x03,
|
||||
0x82,0x03,0x82,0x04,0x82,0x05,0x82,0x0b,0x82,0x02,0x85,0x08,0x82,0x05,0x82,
|
||||
0x01,0x82,0x01,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,
|
||||
0x82,0x02,0x82,0x04,0x82,0x03,0x82,0x0d,0x82,0x04,0x82,0x06,0x82,0x04,0x82,
|
||||
0x04,0x84,0x04,0x82,0x01,0x82,0x01,0x82,0x05,0x82,0x05,0x82,0x04,0x82,0x05,
|
||||
0x82,0x08,0x82,0x08,0x82,0x08,0x82,0x38,0x82,0x01,0x82,0x04,0x82,0x01,0x82,
|
||||
0x01,0x82,0x04,0x84,0x01,0x82,0x01,0x82,0x03,0x82,0x10,0x82,0x08,0x82,0x30,
|
||||
0x83,0x06,0x82,0x07,0x82,0x02,0x82,0x06,0x82,0x05,0x82,0x08,0x82,0x04,0x82,
|
||||
0x07,0x82,0x03,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x04,0x82,0x06,0x82,0x04,
|
||||
0x82,0x03,0x81,0x04,0x82,0x1a,0x82,0x10,0x82,0x10,0x82,0x08,0x82,0x04,0x82,
|
||||
0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x08,
|
||||
0x82,0x08,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x05,0x82,0x05,0x82,0x03,0x82,
|
||||
0x03,0x82,0x03,0x82,0x03,0x82,0x08,0x82,0x04,0x82,0x02,0x82,0x03,0x83,0x02,
|
||||
0x82,0x04,0x82,0x02,0x82,0x08,0x82,0x02,0x84,0x02,0x82,0x03,0x82,0x03,0x82,
|
||||
0x04,0x82,0x05,0x82,0x05,0x82,0x04,0x82,0x05,0x82,0x05,0x83,0x02,0x83,0x03,
|
||||
0x82,0x02,0x82,0x06,0x82,0x05,0x82,0x09,0x82,0x0c,0x82,0x08,0x82,0x21,0x82,
|
||||
0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x08,0x82,0x04,0x82,0x02,0x82,0x0a,
|
||||
0x82,0x07,0x85,0x04,0x82,0x04,0x82,0x05,0x82,0x0b,0x82,0x02,0x82,0x02,0x82,
|
||||
0x07,0x82,0x05,0x82,0x01,0x82,0x01,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,
|
||||
0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x03,0x82,0x0d,0x82,0x04,0x82,
|
||||
0x06,0x82,0x04,0x82,0x04,0x84,0x04,0x82,0x01,0x82,0x01,0x82,0x04,0x84,0x04,
|
||||
0x82,0x04,0x82,0x04,0x82,0x09,0x82,0x08,0x82,0x08,0x82,0x26,0x82,0x10,0x82,
|
||||
0x01,0x82,0x05,0x86,0x04,0x82,0x01,0x82,0x01,0x82,0x01,0x83,0x01,0x84,0x10,
|
||||
0x82,0x06,0x82,0x1d,0x83,0x11,0x83,0x05,0x82,0x09,0x84,0x07,0x82,0x05,0x82,
|
||||
0x09,0x82,0x02,0x82,0x08,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x04,
|
||||
0x82,0x08,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x06,0x83,0x07,0x83,0x09,0x82,
|
||||
0x0e,0x82,0x0a,0x82,0x06,0x82,0x03,0x82,0x02,0x82,0x04,0x82,0x02,0x82,0x03,
|
||||
0x82,0x04,0x82,0x02,0x82,0x03,0x82,0x03,0x82,0x03,0x82,0x08,0x82,0x09,0x82,
|
||||
0x02,0x83,0x02,0x82,0x04,0x82,0x05,0x82,0x06,0x82,0x01,0x82,0x04,0x82,0x04,
|
||||
0x82,0x02,0x82,0x08,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x03,0x82,0x02,0x82,
|
||||
0x03,0x82,0x09,0x82,0x02,0x82,0x03,0x82,0x04,0x82,0x03,0x82,0x02,0x82,0x06,
|
||||
0x82,0x06,0x82,0x02,0x82,0x06,0x82,0x05,0x82,0x04,0x82,0x02,0x82,0x04,0x82,
|
||||
0x05,0x82,0x05,0x82,0x09,0x82,0x0d,0x82,0x07,0x82,0x21,0x82,0x04,0x82,0x02,
|
||||
0x83,0x02,0x82,0x04,0x82,0x03,0x82,0x03,0x82,0x02,0x83,0x03,0x82,0x03,0x82,
|
||||
0x04,0x82,0x06,0x82,0x08,0x82,0x04,0x82,0x05,0x82,0x0b,0x82,0x02,0x82,0x03,
|
||||
0x82,0x06,0x82,0x05,0x82,0x01,0x82,0x01,0x82,0x02,0x82,0x04,0x82,0x03,0x82,
|
||||
0x02,0x82,0x03,0x83,0x02,0x82,0x04,0x82,0x02,0x83,0x03,0x82,0x07,0x82,0x04,
|
||||
0x82,0x04,0x82,0x02,0x82,0x03,0x82,0x02,0x83,0x05,0x82,0x05,0x88,0x03,0x82,
|
||||
0x02,0x82,0x04,0x82,0x02,0x83,0x03,0x82,0x0a,0x82,0x08,0x82,0x08,0x82,0x26,
|
||||
0x82,0x1c,0x82,0x06,0x82,0x02,0x83,0x03,0x84,0x02,0x82,0x10,0x82,0x04,0x82,
|
||||
0x1e,0x83,0x11,0x83,0x05,0x82,0x0a,0x82,0x05,0x88,0x02,0x88,0x04,0x84,0x09,
|
||||
0x82,0x05,0x84,0x06,0x84,0x05,0x82,0x09,0x84,0x06,0x84,0x07,0x83,0x07,0x83,
|
||||
0x0a,0x81,0x0e,0x81,0x0b,0x82,0x07,0x85,0x03,0x82,0x04,0x82,0x02,0x86,0x06,
|
||||
0x84,0x04,0x86,0x04,0x88,0x02,0x82,0x0a,0x84,0x01,0x81,0x02,0x82,0x04,0x82,
|
||||
0x02,0x88,0x04,0x83,0x05,0x82,0x04,0x82,0x02,0x88,0x02,0x82,0x04,0x82,0x02,
|
||||
0x82,0x04,0x82,0x04,0x84,0x04,0x82,0x0a,0x85,0x03,0x82,0x04,0x82,0x04,0x84,
|
||||
0x07,0x82,0x07,0x84,0x07,0x82,0x05,0x82,0x04,0x82,0x02,0x82,0x04,0x82,0x05,
|
||||
0x82,0x05,0x88,0x03,0x86,0x09,0x82,0x03,0x86,0x22,0x85,0x01,0x81,0x02,0x82,
|
||||
0x01,0x83,0x06,0x85,0x05,0x83,0x01,0x82,0x04,0x85,0x05,0x82,0x07,0x86,0x03,
|
||||
0x82,0x04,0x82,0x02,0x88,0x08,0x82,0x02,0x82,0x04,0x82,0x02,0x88,0x02,0x82,
|
||||
0x01,0x82,0x01,0x82,0x02,0x82,0x04,0x82,0x04,0x84,0x04,0x82,0x01,0x83,0x06,
|
||||
0x83,0x01,0x82,0x03,0x82,0x08,0x86,0x06,0x84,0x05,0x83,0x01,0x82,0x05,0x82,
|
||||
0x06,0x82,0x02,0x82,0x03,0x82,0x04,0x82,0x04,0x83,0x01,0x82,0x03,0x87,0x06,
|
||||
0x84,0x05,0x82,0x05,0x84,0x7f,0x15,0x83,0x7f,0x14,0x83,0x7f,0x5e,0x82,0x7f,
|
||||
0x05,0x89,0x47,0x82,0x04,0x82,0x17,0x82,0x03,0x82,0x34,0x82,0x0e,0x82,0x4e,
|
||||
0x82,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x0a,0x82,0x04,0x82,0x17,0x82,0x03,0x82,
|
||||
0x34,0x82,0x0e,0x82,0x48,0x82,0x04,0x82,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x0a,
|
||||
0x82,0x04,0x82,0x17,0x82,0x03,0x82,0x34,0x82,0x0e,0x82,0x49,0x82,0x02,0x82,
|
||||
0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x0c,0x86,0x19,0x85,0x35,0x82,0x0e,0x82,0x4a,
|
||||
0x84,0x3f,
|
||||
0x00,
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Copyright (C) 2007 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 _MINUI_H_
|
||||
#define _MINUI_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void* gr_surface;
|
||||
typedef unsigned short gr_pixel;
|
||||
|
||||
int gr_init(void);
|
||||
void gr_exit(void);
|
||||
|
||||
int gr_fb_width(void);
|
||||
int gr_fb_height(void);
|
||||
gr_pixel *gr_fb_data(void);
|
||||
void gr_flip(void);
|
||||
void gr_fb_blank(bool blank);
|
||||
|
||||
void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a);
|
||||
void gr_fill(int x1, int y1, int x2, int y2);
|
||||
|
||||
// system/core/charger uses different gr_print signatures in diferent
|
||||
// Android versions, either with or without int bold.
|
||||
int gr_text(int x, int y, const char *s, ...);
|
||||
int gr_text_impl(int x, int y, const char *s, int bold);
|
||||
|
||||
void gr_texticon(int x, int y, gr_surface icon);
|
||||
int gr_measure(const char *s);
|
||||
void gr_font_size(int *x, int *y);
|
||||
void gr_get_memory_surface(gr_surface);
|
||||
|
||||
void gr_blit(gr_surface source, int sx, int sy, int w, int h, int dx, int dy);
|
||||
unsigned int gr_get_width(gr_surface surface);
|
||||
unsigned int gr_get_height(gr_surface surface);
|
||||
|
||||
// input event structure, include <linux/input.h> for the definition.
|
||||
// see http://www.mjmwired.net/kernel/Documentation/input/ for info.
|
||||
struct input_event;
|
||||
|
||||
typedef int (*ev_callback)(int fd, uint32_t epevents, void *data);
|
||||
typedef int (*ev_set_key_callback)(int code, int value, void *data);
|
||||
|
||||
int ev_init(ev_callback input_cb, void *data);
|
||||
void ev_exit(void);
|
||||
int ev_add_fd(int fd, ev_callback cb, void *data);
|
||||
int ev_sync_key_state(ev_set_key_callback set_key_cb, void *data);
|
||||
|
||||
/* timeout has the same semantics as for poll
|
||||
* 0 : don't block
|
||||
* < 0 : block forever
|
||||
* > 0 : block for 'timeout' milliseconds
|
||||
*/
|
||||
int ev_wait(int timeout);
|
||||
|
||||
int ev_get_input(int fd, uint32_t epevents, struct input_event *ev);
|
||||
void ev_dispatch(void);
|
||||
int ev_get_epollfd(void);
|
||||
|
||||
// Resources
|
||||
|
||||
// Returns 0 if no error, else negative.
|
||||
int res_create_surface(const char* name, gr_surface* pSurface);
|
||||
|
||||
// Load an array of display surfaces from a single PNG image. The PNG
|
||||
// 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, gr_surface** pSurface);
|
||||
|
||||
int res_create_localized_surface(const char* name, gr_surface* pSurface);
|
||||
void res_free_surface(gr_surface surface);
|
||||
static inline int res_create_display_surface(const char* name, gr_surface* pSurface) {
|
||||
return res_create_surface(name, pSurface);
|
||||
}
|
||||
|
||||
// These are new graphics functions from 5.0 that were not available in
|
||||
// 4.4 that are required by charger and healthd
|
||||
void gr_clear();
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,54 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char *argv)
|
||||
{
|
||||
unsigned n;
|
||||
unsigned char *x;
|
||||
unsigned m;
|
||||
unsigned run_val;
|
||||
unsigned run_count;
|
||||
|
||||
n = gimp_image.width * gimp_image.height;
|
||||
m = 0;
|
||||
x = gimp_image.pixel_data;
|
||||
|
||||
printf("struct {\n");
|
||||
printf(" unsigned width;\n");
|
||||
printf(" unsigned height;\n");
|
||||
printf(" unsigned cwidth;\n");
|
||||
printf(" unsigned cheight;\n");
|
||||
printf(" unsigned char rundata[];\n");
|
||||
printf("} font = {\n");
|
||||
printf(" .width = %d,\n .height = %d,\n .cwidth = %d,\n .cheight = %d,\n", gimp_image.width, gimp_image.height,
|
||||
gimp_image.width / 96, gimp_image.height);
|
||||
printf(" .rundata = {\n");
|
||||
|
||||
run_val = (*x ? 0 : 255);
|
||||
run_count = 1;
|
||||
n--;
|
||||
x+=3;
|
||||
|
||||
while(n-- > 0) {
|
||||
unsigned val = (*x ? 0 : 255);
|
||||
x+=3;
|
||||
if((val == run_val) && (run_count < 127)) {
|
||||
run_count++;
|
||||
} else {
|
||||
eject:
|
||||
printf("0x%02x,",run_count | (run_val ? 0x80 : 0x00));
|
||||
run_val = val;
|
||||
run_count = 1;
|
||||
m += 5;
|
||||
if(m >= 75) {
|
||||
printf("\n");
|
||||
m = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("0x%02x,",run_count | (run_val ? 0x80 : 0x00));
|
||||
printf("\n0x00,");
|
||||
printf("\n");
|
||||
printf(" }\n};\n");
|
||||
return 0;
|
||||
}
|
||||
+20
-81
@@ -1,17 +1,13 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := graphics_overlay.c events.c resources.c
|
||||
ifneq ($(BOARD_CUSTOM_GRAPHICS),)
|
||||
LOCAL_SRC_FILES += $(BOARD_CUSTOM_GRAPHICS)
|
||||
else
|
||||
LOCAL_SRC_FILES += graphics.c
|
||||
endif
|
||||
|
||||
LOCAL_C_INCLUDES +=\
|
||||
external/libpng \
|
||||
external/zlib \
|
||||
system/core/include/pixelflinger
|
||||
LOCAL_SRC_FILES := \
|
||||
events.cpp \
|
||||
graphics.cpp \
|
||||
graphics_adf.cpp \
|
||||
graphics_drm.cpp \
|
||||
graphics_fbdev.cpp \
|
||||
resources.cpp \
|
||||
|
||||
ifeq ($(TW_TARGET_USES_QCOM_BSP), true)
|
||||
LOCAL_CFLAGS += -DMSM_BSP
|
||||
@@ -33,14 +29,21 @@ ifeq ($(TW_NEW_ION_HEAP), true)
|
||||
LOCAL_CFLAGS += -DNEW_ION_HEAP
|
||||
endif
|
||||
|
||||
LOCAL_STATIC_LIBRARY := libpng
|
||||
LOCAL_WHOLE_STATIC_LIBRARIES := libpixelflinger_static
|
||||
LOCAL_WHOLE_STATIC_LIBRARIES += libadf
|
||||
LOCAL_WHOLE_STATIC_LIBRARIES += libdrm
|
||||
LOCAL_STATIC_LIBRARIES += libpng
|
||||
|
||||
LOCAL_MODULE := libminui
|
||||
|
||||
LOCAL_CLANG := true
|
||||
|
||||
# This used to compare against values in double-quotes (which are just
|
||||
# ordinary characters in this context). Strip double-quotes from the
|
||||
# value so that either will work.
|
||||
|
||||
ifeq ($(subst ",,$(TARGET_RECOVERY_PIXEL_FORMAT)),ABGR_8888)
|
||||
LOCAL_CFLAGS += -DRECOVERY_ABGR
|
||||
endif
|
||||
ifeq ($(subst ",,$(TARGET_RECOVERY_PIXEL_FORMAT)),RGBX_8888)
|
||||
LOCAL_CFLAGS += -DRECOVERY_RGBX
|
||||
endif
|
||||
@@ -65,76 +68,12 @@ endif
|
||||
ifneq ($(TW_NO_SCREEN_BLANK),)
|
||||
LOCAL_CFLAGS += -DTW_NO_SCREEN_BLANK
|
||||
endif
|
||||
ifneq ($(BOARD_USE_CUSTOM_RECOVERY_FONT),)
|
||||
LOCAL_CFLAGS += -DBOARD_USE_CUSTOM_RECOVERY_FONT=$(BOARD_USE_CUSTOM_RECOVERY_FONT)
|
||||
endif
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
# Used by OEMs for factory test images.
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := graphics_overlay.c events.c resources.c
|
||||
ifneq ($(BOARD_CUSTOM_GRAPHICS),)
|
||||
LOCAL_SRC_FILES += $(BOARD_CUSTOM_GRAPHICS)
|
||||
else
|
||||
LOCAL_SRC_FILES += graphics.c
|
||||
endif
|
||||
|
||||
ifeq ($(TW_TARGET_USES_QCOM_BSP), true)
|
||||
LOCAL_CFLAGS += -DMSM_BSP
|
||||
ifeq ($(TARGET_PREBUILT_KERNEL),)
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
|
||||
LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
|
||||
else
|
||||
ifeq ($(TARGET_CUSTOM_KERNEL_HEADERS),)
|
||||
LOCAL_C_INCLUDES += $(commands_recovery_local_path)/minui/include
|
||||
else
|
||||
LOCAL_C_INCLUDES += $(TARGET_CUSTOM_KERNEL_HEADERS)
|
||||
endif
|
||||
endif
|
||||
else
|
||||
LOCAL_C_INCLUDES += $(commands_recovery_local_path)/minui/include
|
||||
endif
|
||||
|
||||
LOCAL_C_INCLUDES +=\
|
||||
external/libpng\
|
||||
external/zlib
|
||||
|
||||
LOCAL_MODULE := libminui
|
||||
|
||||
LOCAL_ARM_MODE:= arm
|
||||
LOCAL_SHARED_LIBRARIES := libpng libpixelflinger
|
||||
# This used to compare against values in double-quotes (which are just
|
||||
# ordinary characters in this context). Strip double-quotes from the
|
||||
# value so that either will work.
|
||||
|
||||
ifeq ($(subst ",,$(TARGET_RECOVERY_PIXEL_FORMAT)),RGBX_8888)
|
||||
LOCAL_CFLAGS += -DRECOVERY_RGBX
|
||||
endif
|
||||
ifeq ($(subst ",,$(TARGET_RECOVERY_PIXEL_FORMAT)),BGRA_8888)
|
||||
LOCAL_CFLAGS += -DRECOVERY_BGRA
|
||||
endif
|
||||
|
||||
ifneq ($(TARGET_RECOVERY_OVERSCAN_PERCENT),)
|
||||
LOCAL_CFLAGS += -DOVERSCAN_PERCENT=$(TARGET_RECOVERY_OVERSCAN_PERCENT)
|
||||
else
|
||||
LOCAL_CFLAGS += -DOVERSCAN_PERCENT=0
|
||||
endif
|
||||
|
||||
ifneq ($(TW_BRIGHTNESS_PATH),)
|
||||
LOCAL_CFLAGS += -DTW_BRIGHTNESS_PATH=\"$(TW_BRIGHTNESS_PATH)\"
|
||||
endif
|
||||
ifneq ($(TW_MAX_BRIGHTNESS),)
|
||||
LOCAL_CFLAGS += -DTW_MAX_BRIGHTNESS=$(TW_MAX_BRIGHTNESS)
|
||||
else
|
||||
LOCAL_CFLAGS += -DTW_MAX_BRIGHTNESS=255
|
||||
endif
|
||||
ifneq ($(TW_NO_SCREEN_BLANK),)
|
||||
LOCAL_CFLAGS += -DTW_NO_SCREEN_BLANK
|
||||
endif
|
||||
ifneq ($(BOARD_USE_CUSTOM_RECOVERY_FONT),)
|
||||
LOCAL_CFLAGS += -DBOARD_USE_CUSTOM_RECOVERY_FONT=$(BOARD_USE_CUSTOM_RECOVERY_FONT)
|
||||
endif
|
||||
|
||||
LOCAL_CFLAGS += -DFASTMMI_FEATURE
|
||||
|
||||
LOCAL_WHOLE_STATIC_LIBRARIES += libminui
|
||||
LOCAL_SHARED_LIBRARIES := libpng
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Copyright (C) 2007 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 <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <linux/input.h>
|
||||
|
||||
#include "minui.h"
|
||||
|
||||
#define MAX_DEVICES 16
|
||||
#define MAX_MISC_FDS 16
|
||||
|
||||
#define BITS_PER_LONG (sizeof(unsigned long) * 8)
|
||||
#define BITS_TO_LONGS(x) (((x) + BITS_PER_LONG - 1) / BITS_PER_LONG)
|
||||
|
||||
struct fd_info {
|
||||
int fd;
|
||||
ev_callback cb;
|
||||
void* data;
|
||||
};
|
||||
|
||||
static int g_epoll_fd;
|
||||
static epoll_event polledevents[MAX_DEVICES + MAX_MISC_FDS];
|
||||
static int npolledevents;
|
||||
|
||||
static fd_info ev_fdinfo[MAX_DEVICES + MAX_MISC_FDS];
|
||||
|
||||
static unsigned ev_count = 0;
|
||||
static unsigned ev_dev_count = 0;
|
||||
static unsigned ev_misc_count = 0;
|
||||
|
||||
static bool test_bit(size_t bit, unsigned long* array) {
|
||||
return (array[bit/BITS_PER_LONG] & (1UL << (bit % BITS_PER_LONG))) != 0;
|
||||
}
|
||||
|
||||
int ev_init(ev_callback input_cb, void* data) {
|
||||
bool epollctlfail = false;
|
||||
|
||||
g_epoll_fd = epoll_create(MAX_DEVICES + MAX_MISC_FDS);
|
||||
if (g_epoll_fd == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
DIR* dir = opendir("/dev/input");
|
||||
if (dir != NULL) {
|
||||
dirent* de;
|
||||
while ((de = readdir(dir))) {
|
||||
unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)];
|
||||
|
||||
// fprintf(stderr,"/dev/input/%s\n", de->d_name);
|
||||
if (strncmp(de->d_name, "event", 5)) continue;
|
||||
int fd = openat(dirfd(dir), de->d_name, O_RDONLY);
|
||||
if (fd == -1) continue;
|
||||
|
||||
// Read the evbits of the input device.
|
||||
if (ioctl(fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1) {
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
// We assume that only EV_KEY, EV_REL, and EV_SW event types are ever needed.
|
||||
if (!test_bit(EV_KEY, ev_bits) && !test_bit(EV_REL, ev_bits) && !test_bit(EV_SW, ev_bits)) {
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
epoll_event ev;
|
||||
ev.events = EPOLLIN | EPOLLWAKEUP;
|
||||
ev.data.ptr = &ev_fdinfo[ev_count];
|
||||
if (epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {
|
||||
close(fd);
|
||||
epollctlfail = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
ev_fdinfo[ev_count].fd = fd;
|
||||
ev_fdinfo[ev_count].cb = input_cb;
|
||||
ev_fdinfo[ev_count].data = data;
|
||||
ev_count++;
|
||||
ev_dev_count++;
|
||||
if (ev_dev_count == MAX_DEVICES) break;
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
if (epollctlfail && !ev_count) {
|
||||
close(g_epoll_fd);
|
||||
g_epoll_fd = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ev_get_epollfd(void) {
|
||||
return g_epoll_fd;
|
||||
}
|
||||
|
||||
int ev_add_fd(int fd, ev_callback cb, void* data) {
|
||||
if (ev_misc_count == MAX_MISC_FDS || cb == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
epoll_event ev;
|
||||
ev.events = EPOLLIN | EPOLLWAKEUP;
|
||||
ev.data.ptr = (void *)&ev_fdinfo[ev_count];
|
||||
int ret = epoll_ctl(g_epoll_fd, EPOLL_CTL_ADD, fd, &ev);
|
||||
if (!ret) {
|
||||
ev_fdinfo[ev_count].fd = fd;
|
||||
ev_fdinfo[ev_count].cb = cb;
|
||||
ev_fdinfo[ev_count].data = data;
|
||||
ev_count++;
|
||||
ev_misc_count++;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ev_exit(void) {
|
||||
while (ev_count > 0) {
|
||||
close(ev_fdinfo[--ev_count].fd);
|
||||
}
|
||||
ev_misc_count = 0;
|
||||
ev_dev_count = 0;
|
||||
close(g_epoll_fd);
|
||||
}
|
||||
|
||||
int ev_wait(int timeout) {
|
||||
npolledevents = epoll_wait(g_epoll_fd, polledevents, ev_count, timeout);
|
||||
if (npolledevents <= 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ev_dispatch(void) {
|
||||
for (int n = 0; n < npolledevents; n++) {
|
||||
fd_info* fdi = reinterpret_cast<fd_info*>(polledevents[n].data.ptr);
|
||||
ev_callback cb = fdi->cb;
|
||||
if (cb) {
|
||||
cb(fdi->fd, polledevents[n].events, fdi->data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ev_get_input(int fd, uint32_t epevents, input_event* ev) {
|
||||
if (epevents & EPOLLIN) {
|
||||
ssize_t r = TEMP_FAILURE_RETRY(read(fd, ev, sizeof(*ev)));
|
||||
if (r == sizeof(*ev)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ev_sync_key_state(ev_set_key_callback set_key_cb, void* data) {
|
||||
unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)];
|
||||
unsigned long key_bits[BITS_TO_LONGS(KEY_MAX)];
|
||||
|
||||
for (size_t i = 0; i < ev_dev_count; ++i) {
|
||||
memset(ev_bits, 0, sizeof(ev_bits));
|
||||
memset(key_bits, 0, sizeof(key_bits));
|
||||
|
||||
if (ioctl(ev_fdinfo[i].fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1) {
|
||||
continue;
|
||||
}
|
||||
if (!test_bit(EV_KEY, ev_bits)) {
|
||||
continue;
|
||||
}
|
||||
if (ioctl(ev_fdinfo[i].fd, EVIOCGKEY(sizeof(key_bits)), key_bits) == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int code = 0; code <= KEY_MAX; code++) {
|
||||
if (test_bit(code, key_bits)) {
|
||||
set_key_cb(code, 1, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ev_iterate_available_keys(std::function<void(int)> f) {
|
||||
unsigned long ev_bits[BITS_TO_LONGS(EV_MAX)];
|
||||
unsigned long key_bits[BITS_TO_LONGS(KEY_MAX)];
|
||||
|
||||
for (size_t i = 0; i < ev_dev_count; ++i) {
|
||||
memset(ev_bits, 0, sizeof(ev_bits));
|
||||
memset(key_bits, 0, sizeof(key_bits));
|
||||
|
||||
// Does this device even have keys?
|
||||
if (ioctl(ev_fdinfo[i].fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits) == -1) {
|
||||
continue;
|
||||
}
|
||||
if (!test_bit(EV_KEY, ev_bits)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int rc = ioctl(ev_fdinfo[i].fd, EVIOCGBIT(EV_KEY, KEY_MAX), key_bits);
|
||||
if (rc == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int key_code = 0; key_code <= KEY_MAX; ++key_code) {
|
||||
if (test_bit(key_code, key_bits)) {
|
||||
f(key_code);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -3,7 +3,7 @@ struct {
|
||||
unsigned height;
|
||||
unsigned cwidth;
|
||||
unsigned cheight;
|
||||
unsigned char rundata[];
|
||||
unsigned char rundata[2973];
|
||||
} font = {
|
||||
.width = 960,
|
||||
.height = 18,
|
||||
|
||||
@@ -0,0 +1,411 @@
|
||||
/*
|
||||
* Copyright (C) 2007 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 <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/kd.h>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "font_10x18.h"
|
||||
#include "minui.h"
|
||||
#include "graphics.h"
|
||||
|
||||
struct GRFont {
|
||||
GRSurface* texture;
|
||||
int cwidth;
|
||||
int cheight;
|
||||
};
|
||||
|
||||
static GRFont* gr_font = NULL;
|
||||
static minui_backend* gr_backend = NULL;
|
||||
|
||||
static int overscan_percent = OVERSCAN_PERCENT;
|
||||
static int overscan_offset_x = 0;
|
||||
static int overscan_offset_y = 0;
|
||||
|
||||
static unsigned char gr_current_r = 255;
|
||||
static unsigned char gr_current_g = 255;
|
||||
static unsigned char gr_current_b = 255;
|
||||
static unsigned char gr_current_a = 255;
|
||||
|
||||
static GRSurface* gr_draw = NULL;
|
||||
|
||||
static bool outside(int x, int y)
|
||||
{
|
||||
return x < 0 || x >= gr_draw->width || y < 0 || y >= gr_draw->height;
|
||||
}
|
||||
|
||||
int gr_measure(const char *s)
|
||||
{
|
||||
return gr_font->cwidth * strlen(s);
|
||||
}
|
||||
|
||||
void gr_font_size(int *x, int *y)
|
||||
{
|
||||
*x = gr_font->cwidth;
|
||||
*y = gr_font->cheight;
|
||||
}
|
||||
|
||||
static void text_blend(unsigned char* src_p, int src_row_bytes,
|
||||
unsigned char* dst_p, int dst_row_bytes,
|
||||
int width, int height)
|
||||
{
|
||||
for (int j = 0; j < height; ++j) {
|
||||
unsigned char* sx = src_p;
|
||||
unsigned char* px = dst_p;
|
||||
for (int i = 0; i < width; ++i) {
|
||||
unsigned char a = *sx++;
|
||||
if (gr_current_a < 255) a = ((int)a * gr_current_a) / 255;
|
||||
if (a == 255) {
|
||||
*px++ = gr_current_r;
|
||||
*px++ = gr_current_g;
|
||||
*px++ = gr_current_b;
|
||||
px++;
|
||||
} else if (a > 0) {
|
||||
*px = (*px * (255-a) + gr_current_r * a) / 255;
|
||||
++px;
|
||||
*px = (*px * (255-a) + gr_current_g * a) / 255;
|
||||
++px;
|
||||
*px = (*px * (255-a) + gr_current_b * a) / 255;
|
||||
++px;
|
||||
++px;
|
||||
} else {
|
||||
px += 4;
|
||||
}
|
||||
}
|
||||
src_p += src_row_bytes;
|
||||
dst_p += dst_row_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
void gr_text(int x, int y, const char *s, bool bold)
|
||||
{
|
||||
GRFont* font = gr_font;
|
||||
|
||||
if (!font->texture || gr_current_a == 0) return;
|
||||
|
||||
bold = bold && (font->texture->height != font->cheight);
|
||||
|
||||
x += overscan_offset_x;
|
||||
y += overscan_offset_y;
|
||||
|
||||
unsigned char ch;
|
||||
while ((ch = *s++)) {
|
||||
if (outside(x, y) || outside(x+font->cwidth-1, y+font->cheight-1)) break;
|
||||
|
||||
if (ch < ' ' || ch > '~') {
|
||||
ch = '?';
|
||||
}
|
||||
|
||||
unsigned char* src_p = font->texture->data + ((ch - ' ') * font->cwidth) +
|
||||
(bold ? font->cheight * font->texture->row_bytes : 0);
|
||||
unsigned char* dst_p = gr_draw->data + y*gr_draw->row_bytes + x*gr_draw->pixel_bytes;
|
||||
|
||||
text_blend(src_p, font->texture->row_bytes,
|
||||
dst_p, gr_draw->row_bytes,
|
||||
font->cwidth, font->cheight);
|
||||
|
||||
x += font->cwidth;
|
||||
}
|
||||
}
|
||||
|
||||
void gr_texticon(int x, int y, GRSurface* icon) {
|
||||
if (icon == NULL) return;
|
||||
|
||||
if (icon->pixel_bytes != 1) {
|
||||
printf("gr_texticon: source has wrong format\n");
|
||||
return;
|
||||
}
|
||||
|
||||
x += overscan_offset_x;
|
||||
y += overscan_offset_y;
|
||||
|
||||
if (outside(x, y) || outside(x+icon->width-1, y+icon->height-1)) return;
|
||||
|
||||
unsigned char* src_p = icon->data;
|
||||
unsigned char* dst_p = gr_draw->data + y*gr_draw->row_bytes + x*gr_draw->pixel_bytes;
|
||||
|
||||
text_blend(src_p, icon->row_bytes,
|
||||
dst_p, gr_draw->row_bytes,
|
||||
icon->width, icon->height);
|
||||
}
|
||||
|
||||
void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
|
||||
{
|
||||
#if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA)
|
||||
gr_current_r = b;
|
||||
gr_current_g = g;
|
||||
gr_current_b = r;
|
||||
gr_current_a = a;
|
||||
#else
|
||||
gr_current_r = r;
|
||||
gr_current_g = g;
|
||||
gr_current_b = b;
|
||||
gr_current_a = a;
|
||||
#endif
|
||||
}
|
||||
|
||||
void gr_clear()
|
||||
{
|
||||
if (gr_current_r == gr_current_g && gr_current_r == gr_current_b) {
|
||||
memset(gr_draw->data, gr_current_r, gr_draw->height * gr_draw->row_bytes);
|
||||
} else {
|
||||
unsigned char* px = gr_draw->data;
|
||||
for (int y = 0; y < gr_draw->height; ++y) {
|
||||
for (int x = 0; x < gr_draw->width; ++x) {
|
||||
*px++ = gr_current_r;
|
||||
*px++ = gr_current_g;
|
||||
*px++ = gr_current_b;
|
||||
px++;
|
||||
}
|
||||
px += gr_draw->row_bytes - (gr_draw->width * gr_draw->pixel_bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gr_fill(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
x1 += overscan_offset_x;
|
||||
y1 += overscan_offset_y;
|
||||
|
||||
x2 += overscan_offset_x;
|
||||
y2 += overscan_offset_y;
|
||||
|
||||
if (outside(x1, y1) || outside(x2-1, y2-1)) return;
|
||||
|
||||
unsigned char* p = gr_draw->data + y1 * gr_draw->row_bytes + x1 * gr_draw->pixel_bytes;
|
||||
if (gr_current_a == 255) {
|
||||
int x, y;
|
||||
for (y = y1; y < y2; ++y) {
|
||||
unsigned char* px = p;
|
||||
for (x = x1; x < x2; ++x) {
|
||||
*px++ = gr_current_r;
|
||||
*px++ = gr_current_g;
|
||||
*px++ = gr_current_b;
|
||||
px++;
|
||||
}
|
||||
p += gr_draw->row_bytes;
|
||||
}
|
||||
} else if (gr_current_a > 0) {
|
||||
int x, y;
|
||||
for (y = y1; y < y2; ++y) {
|
||||
unsigned char* px = p;
|
||||
for (x = x1; x < x2; ++x) {
|
||||
*px = (*px * (255-gr_current_a) + gr_current_r * gr_current_a) / 255;
|
||||
++px;
|
||||
*px = (*px * (255-gr_current_a) + gr_current_g * gr_current_a) / 255;
|
||||
++px;
|
||||
*px = (*px * (255-gr_current_a) + gr_current_b * gr_current_a) / 255;
|
||||
++px;
|
||||
++px;
|
||||
}
|
||||
p += gr_draw->row_bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gr_blit(GRSurface* source, int sx, int sy, int w, int h, int dx, int dy) {
|
||||
if (source == NULL) return;
|
||||
|
||||
if (gr_draw->pixel_bytes != source->pixel_bytes) {
|
||||
printf("gr_blit: source has wrong format\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dx += overscan_offset_x;
|
||||
dy += overscan_offset_y;
|
||||
|
||||
if (outside(dx, dy) || outside(dx+w-1, dy+h-1)) return;
|
||||
|
||||
unsigned char* src_p = source->data + sy*source->row_bytes + sx*source->pixel_bytes;
|
||||
unsigned char* dst_p = gr_draw->data + dy*gr_draw->row_bytes + dx*gr_draw->pixel_bytes;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < h; ++i) {
|
||||
memcpy(dst_p, src_p, w * source->pixel_bytes);
|
||||
src_p += source->row_bytes;
|
||||
dst_p += gr_draw->row_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int gr_get_width(GRSurface* surface) {
|
||||
if (surface == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return surface->width;
|
||||
}
|
||||
|
||||
unsigned int gr_get_height(GRSurface* surface) {
|
||||
if (surface == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return surface->height;
|
||||
}
|
||||
|
||||
static void gr_init_font(void)
|
||||
{
|
||||
gr_font = reinterpret_cast<GRFont*>(calloc(sizeof(*gr_font), 1));
|
||||
|
||||
int res = res_create_alpha_surface("font", &(gr_font->texture));
|
||||
if (res == 0) {
|
||||
// The font image should be a 96x2 array of character images. The
|
||||
// columns are the printable ASCII characters 0x20 - 0x7f. The
|
||||
// top row is regular text; the bottom row is bold.
|
||||
gr_font->cwidth = gr_font->texture->width / 96;
|
||||
gr_font->cheight = gr_font->texture->height / 2;
|
||||
} else {
|
||||
printf("failed to read font: res=%d\n", res);
|
||||
|
||||
// fall back to the compiled-in font.
|
||||
gr_font->texture = reinterpret_cast<GRSurface*>(malloc(sizeof(*gr_font->texture)));
|
||||
gr_font->texture->width = font.width;
|
||||
gr_font->texture->height = font.height;
|
||||
gr_font->texture->row_bytes = font.width;
|
||||
gr_font->texture->pixel_bytes = 1;
|
||||
|
||||
unsigned char* bits = reinterpret_cast<unsigned char*>(malloc(font.width * font.height));
|
||||
gr_font->texture->data = reinterpret_cast<unsigned char*>(bits);
|
||||
|
||||
unsigned char data;
|
||||
unsigned char* in = font.rundata;
|
||||
while((data = *in++)) {
|
||||
memset(bits, (data & 0x80) ? 255 : 0, data & 0x7f);
|
||||
bits += (data & 0x7f);
|
||||
}
|
||||
|
||||
gr_font->cwidth = font.cwidth;
|
||||
gr_font->cheight = font.cheight;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Exercises many of the gr_*() functions; useful for testing.
|
||||
static void gr_test() {
|
||||
GRSurface** images;
|
||||
int frames;
|
||||
int result = res_create_multi_surface("icon_installing", &frames, &images);
|
||||
if (result < 0) {
|
||||
printf("create surface %d\n", result);
|
||||
gr_exit();
|
||||
return;
|
||||
}
|
||||
|
||||
time_t start = time(NULL);
|
||||
int x;
|
||||
for (x = 0; x <= 1200; ++x) {
|
||||
if (x < 400) {
|
||||
gr_color(0, 0, 0, 255);
|
||||
} else {
|
||||
gr_color(0, (x-400)%128, 0, 255);
|
||||
}
|
||||
gr_clear();
|
||||
|
||||
gr_color(255, 0, 0, 255);
|
||||
GRSurface* frame = images[x%frames];
|
||||
gr_blit(frame, 0, 0, frame->width, frame->height, x, 0);
|
||||
|
||||
gr_color(255, 0, 0, 128);
|
||||
gr_fill(400, 150, 600, 350);
|
||||
|
||||
gr_color(255, 255, 255, 255);
|
||||
gr_text(500, 225, "hello, world!", 0);
|
||||
gr_color(255, 255, 0, 128);
|
||||
gr_text(300+x, 275, "pack my box with five dozen liquor jugs", 1);
|
||||
|
||||
gr_color(0, 0, 255, 128);
|
||||
gr_fill(gr_draw->width - 200 - x, 300, gr_draw->width - x, 500);
|
||||
|
||||
gr_draw = gr_backend->flip(gr_backend);
|
||||
}
|
||||
printf("getting end time\n");
|
||||
time_t end = time(NULL);
|
||||
printf("got end time\n");
|
||||
printf("start %ld end %ld\n", (long)start, (long)end);
|
||||
if (end > start) {
|
||||
printf("%.2f fps\n", ((double)x) / (end-start));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void gr_flip() {
|
||||
gr_draw = gr_backend->flip(gr_backend);
|
||||
}
|
||||
|
||||
int gr_init(void)
|
||||
{
|
||||
gr_init_font();
|
||||
|
||||
gr_backend = open_adf();
|
||||
if (gr_backend) {
|
||||
gr_draw = gr_backend->init(gr_backend);
|
||||
if (!gr_draw) {
|
||||
gr_backend->exit(gr_backend);
|
||||
}
|
||||
}
|
||||
|
||||
if (!gr_draw) {
|
||||
gr_backend = open_drm();
|
||||
gr_draw = gr_backend->init(gr_backend);
|
||||
}
|
||||
|
||||
if (!gr_draw) {
|
||||
gr_backend = open_fbdev();
|
||||
gr_draw = gr_backend->init(gr_backend);
|
||||
if (gr_draw == NULL) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
overscan_offset_x = gr_draw->width * overscan_percent / 100;
|
||||
overscan_offset_y = gr_draw->height * overscan_percent / 100;
|
||||
|
||||
gr_flip();
|
||||
gr_flip();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void gr_exit(void)
|
||||
{
|
||||
gr_backend->exit(gr_backend);
|
||||
}
|
||||
|
||||
int gr_fb_width(void)
|
||||
{
|
||||
return gr_draw->width - 2*overscan_offset_x;
|
||||
}
|
||||
|
||||
int gr_fb_height(void)
|
||||
{
|
||||
return gr_draw->height - 2*overscan_offset_y;
|
||||
}
|
||||
|
||||
void gr_fb_blank(bool blank)
|
||||
{
|
||||
gr_backend->blank(gr_backend, blank);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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 _GRAPHICS_H_
|
||||
#define _GRAPHICS_H_
|
||||
|
||||
#include "minui.h"
|
||||
|
||||
// TODO: lose the function pointers.
|
||||
struct minui_backend {
|
||||
// Initializes the backend and returns a GRSurface* to draw into.
|
||||
GRSurface* (*init)(minui_backend*);
|
||||
|
||||
// Causes the current drawing surface (returned by the most recent
|
||||
// call to flip() or init()) to be displayed, and returns a new
|
||||
// drawing surface.
|
||||
GRSurface* (*flip)(minui_backend*);
|
||||
|
||||
// Blank (or unblank) the screen.
|
||||
void (*blank)(minui_backend*, bool);
|
||||
|
||||
// Device cleanup when drawing is done.
|
||||
void (*exit)(minui_backend*);
|
||||
};
|
||||
|
||||
minui_backend* open_fbdev();
|
||||
minui_backend* open_adf();
|
||||
minui_backend* open_drm();
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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 <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <adf/adf.h>
|
||||
|
||||
#include "graphics.h"
|
||||
|
||||
struct adf_surface_pdata {
|
||||
GRSurface base;
|
||||
int fd;
|
||||
__u32 offset;
|
||||
__u32 pitch;
|
||||
};
|
||||
|
||||
struct adf_pdata {
|
||||
minui_backend base;
|
||||
int intf_fd;
|
||||
adf_id_t eng_id;
|
||||
__u32 format;
|
||||
|
||||
unsigned int current_surface;
|
||||
unsigned int n_surfaces;
|
||||
adf_surface_pdata surfaces[2];
|
||||
};
|
||||
|
||||
static GRSurface* adf_flip(minui_backend *backend);
|
||||
static void adf_blank(minui_backend *backend, bool blank);
|
||||
|
||||
static int adf_surface_init(adf_pdata *pdata, drm_mode_modeinfo *mode, adf_surface_pdata *surf) {
|
||||
memset(surf, 0, sizeof(*surf));
|
||||
|
||||
surf->fd = adf_interface_simple_buffer_alloc(pdata->intf_fd, mode->hdisplay,
|
||||
mode->vdisplay, pdata->format, &surf->offset, &surf->pitch);
|
||||
if (surf->fd < 0)
|
||||
return surf->fd;
|
||||
|
||||
surf->base.width = mode->hdisplay;
|
||||
surf->base.height = mode->vdisplay;
|
||||
surf->base.row_bytes = surf->pitch;
|
||||
surf->base.pixel_bytes = (pdata->format == DRM_FORMAT_RGB565) ? 2 : 4;
|
||||
|
||||
surf->base.data = reinterpret_cast<uint8_t*>(mmap(NULL,
|
||||
surf->pitch * surf->base.height, PROT_WRITE,
|
||||
MAP_SHARED, surf->fd, surf->offset));
|
||||
if (surf->base.data == MAP_FAILED) {
|
||||
close(surf->fd);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adf_interface_init(adf_pdata *pdata)
|
||||
{
|
||||
adf_interface_data intf_data;
|
||||
int ret = 0;
|
||||
int err;
|
||||
|
||||
err = adf_get_interface_data(pdata->intf_fd, &intf_data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = adf_surface_init(pdata, &intf_data.current_mode, &pdata->surfaces[0]);
|
||||
if (err < 0) {
|
||||
fprintf(stderr, "allocating surface 0 failed: %s\n", strerror(-err));
|
||||
ret = err;
|
||||
goto done;
|
||||
}
|
||||
|
||||
err = adf_surface_init(pdata, &intf_data.current_mode,
|
||||
&pdata->surfaces[1]);
|
||||
if (err < 0) {
|
||||
fprintf(stderr, "allocating surface 1 failed: %s\n", strerror(-err));
|
||||
memset(&pdata->surfaces[1], 0, sizeof(pdata->surfaces[1]));
|
||||
pdata->n_surfaces = 1;
|
||||
} else {
|
||||
pdata->n_surfaces = 2;
|
||||
}
|
||||
|
||||
done:
|
||||
adf_free_interface_data(&intf_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int adf_device_init(adf_pdata *pdata, adf_device *dev)
|
||||
{
|
||||
adf_id_t intf_id;
|
||||
int intf_fd;
|
||||
int err;
|
||||
|
||||
err = adf_find_simple_post_configuration(dev, &pdata->format, 1, &intf_id,
|
||||
&pdata->eng_id);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = adf_device_attach(dev, pdata->eng_id, intf_id);
|
||||
if (err < 0 && err != -EALREADY)
|
||||
return err;
|
||||
|
||||
pdata->intf_fd = adf_interface_open(dev, intf_id, O_RDWR);
|
||||
if (pdata->intf_fd < 0)
|
||||
return pdata->intf_fd;
|
||||
|
||||
err = adf_interface_init(pdata);
|
||||
if (err < 0) {
|
||||
close(pdata->intf_fd);
|
||||
pdata->intf_fd = -1;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static GRSurface* adf_init(minui_backend *backend)
|
||||
{
|
||||
adf_pdata *pdata = (adf_pdata *)backend;
|
||||
adf_id_t *dev_ids = NULL;
|
||||
ssize_t n_dev_ids, i;
|
||||
GRSurface* ret;
|
||||
|
||||
#if defined(RECOVERY_ABGR)
|
||||
pdata->format = DRM_FORMAT_ABGR8888;
|
||||
#elif defined(RECOVERY_BGRA)
|
||||
pdata->format = DRM_FORMAT_BGRA8888;
|
||||
#elif defined(RECOVERY_RGBX)
|
||||
pdata->format = DRM_FORMAT_RGBX8888;
|
||||
#else
|
||||
pdata->format = DRM_FORMAT_RGB565;
|
||||
#endif
|
||||
|
||||
n_dev_ids = adf_devices(&dev_ids);
|
||||
if (n_dev_ids == 0) {
|
||||
return NULL;
|
||||
} else if (n_dev_ids < 0) {
|
||||
fprintf(stderr, "enumerating adf devices failed: %s\n",
|
||||
strerror(-n_dev_ids));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pdata->intf_fd = -1;
|
||||
|
||||
for (i = 0; i < n_dev_ids && pdata->intf_fd < 0; i++) {
|
||||
adf_device dev;
|
||||
|
||||
int err = adf_device_open(dev_ids[i], O_RDWR, &dev);
|
||||
if (err < 0) {
|
||||
fprintf(stderr, "opening adf device %u failed: %s\n", dev_ids[i],
|
||||
strerror(-err));
|
||||
continue;
|
||||
}
|
||||
|
||||
err = adf_device_init(pdata, &dev);
|
||||
if (err < 0)
|
||||
fprintf(stderr, "initializing adf device %u failed: %s\n",
|
||||
dev_ids[i], strerror(-err));
|
||||
|
||||
adf_device_close(&dev);
|
||||
}
|
||||
|
||||
free(dev_ids);
|
||||
|
||||
if (pdata->intf_fd < 0)
|
||||
return NULL;
|
||||
|
||||
ret = adf_flip(backend);
|
||||
|
||||
adf_blank(backend, true);
|
||||
adf_blank(backend, false);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GRSurface* adf_flip(minui_backend *backend)
|
||||
{
|
||||
adf_pdata *pdata = (adf_pdata *)backend;
|
||||
adf_surface_pdata *surf = &pdata->surfaces[pdata->current_surface];
|
||||
|
||||
int fence_fd = adf_interface_simple_post(pdata->intf_fd, pdata->eng_id,
|
||||
surf->base.width, surf->base.height, pdata->format, surf->fd,
|
||||
surf->offset, surf->pitch, -1);
|
||||
if (fence_fd >= 0)
|
||||
close(fence_fd);
|
||||
|
||||
pdata->current_surface = (pdata->current_surface + 1) % pdata->n_surfaces;
|
||||
return &pdata->surfaces[pdata->current_surface].base;
|
||||
}
|
||||
|
||||
static void adf_blank(minui_backend *backend, bool blank)
|
||||
{
|
||||
adf_pdata *pdata = (adf_pdata *)backend;
|
||||
adf_interface_blank(pdata->intf_fd,
|
||||
blank ? DRM_MODE_DPMS_OFF : DRM_MODE_DPMS_ON);
|
||||
}
|
||||
|
||||
static void adf_surface_destroy(adf_surface_pdata *surf)
|
||||
{
|
||||
munmap(surf->base.data, surf->pitch * surf->base.height);
|
||||
close(surf->fd);
|
||||
}
|
||||
|
||||
static void adf_exit(minui_backend *backend)
|
||||
{
|
||||
adf_pdata *pdata = (adf_pdata *)backend;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < pdata->n_surfaces; i++)
|
||||
adf_surface_destroy(&pdata->surfaces[i]);
|
||||
if (pdata->intf_fd >= 0)
|
||||
close(pdata->intf_fd);
|
||||
free(pdata);
|
||||
}
|
||||
|
||||
minui_backend *open_adf()
|
||||
{
|
||||
adf_pdata* pdata = reinterpret_cast<adf_pdata*>(calloc(1, sizeof(*pdata)));
|
||||
if (!pdata) {
|
||||
perror("allocating adf backend failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pdata->base.init = adf_init;
|
||||
pdata->base.flip = adf_flip;
|
||||
pdata->base.blank = adf_blank;
|
||||
pdata->base.exit = adf_exit;
|
||||
return &pdata->base;
|
||||
}
|
||||
@@ -0,0 +1,476 @@
|
||||
/*
|
||||
* 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 <drm_fourcc.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <xf86drm.h>
|
||||
#include <xf86drmMode.h>
|
||||
|
||||
#include "minui.h"
|
||||
#include "graphics.h"
|
||||
|
||||
#define ARRAY_SIZE(A) (sizeof(A)/sizeof(*(A)))
|
||||
|
||||
struct drm_surface {
|
||||
GRSurface base;
|
||||
uint32_t fb_id;
|
||||
uint32_t handle;
|
||||
};
|
||||
|
||||
static drm_surface *drm_surfaces[2];
|
||||
static int current_buffer;
|
||||
|
||||
static drmModeCrtc *main_monitor_crtc;
|
||||
static drmModeConnector *main_monitor_connector;
|
||||
|
||||
static int drm_fd = -1;
|
||||
|
||||
static void drm_disable_crtc(int drm_fd, drmModeCrtc *crtc) {
|
||||
if (crtc) {
|
||||
drmModeSetCrtc(drm_fd, crtc->crtc_id,
|
||||
0, // fb_id
|
||||
0, 0, // x,y
|
||||
NULL, // connectors
|
||||
0, // connector_count
|
||||
NULL); // mode
|
||||
}
|
||||
}
|
||||
|
||||
static void drm_enable_crtc(int drm_fd, drmModeCrtc *crtc,
|
||||
struct drm_surface *surface) {
|
||||
int32_t ret;
|
||||
|
||||
ret = drmModeSetCrtc(drm_fd, crtc->crtc_id,
|
||||
surface->fb_id,
|
||||
0, 0, // x,y
|
||||
&main_monitor_connector->connector_id,
|
||||
1, // connector_count
|
||||
&main_monitor_crtc->mode);
|
||||
|
||||
if (ret)
|
||||
printf("drmModeSetCrtc failed ret=%d\n", ret);
|
||||
}
|
||||
|
||||
static void drm_blank(minui_backend* backend __unused, bool blank) {
|
||||
if (blank)
|
||||
drm_disable_crtc(drm_fd, main_monitor_crtc);
|
||||
else
|
||||
drm_enable_crtc(drm_fd, main_monitor_crtc,
|
||||
drm_surfaces[current_buffer]);
|
||||
}
|
||||
|
||||
static void drm_destroy_surface(struct drm_surface *surface) {
|
||||
struct drm_gem_close gem_close;
|
||||
int ret;
|
||||
|
||||
if(!surface)
|
||||
return;
|
||||
|
||||
if (surface->base.data)
|
||||
munmap(surface->base.data,
|
||||
surface->base.row_bytes * surface->base.height);
|
||||
|
||||
if (surface->fb_id) {
|
||||
ret = drmModeRmFB(drm_fd, surface->fb_id);
|
||||
if (ret)
|
||||
printf("drmModeRmFB failed ret=%d\n", ret);
|
||||
}
|
||||
|
||||
if (surface->handle) {
|
||||
memset(&gem_close, 0, sizeof(gem_close));
|
||||
gem_close.handle = surface->handle;
|
||||
|
||||
ret = drmIoctl(drm_fd, DRM_IOCTL_GEM_CLOSE, &gem_close);
|
||||
if (ret)
|
||||
printf("DRM_IOCTL_GEM_CLOSE failed ret=%d\n", ret);
|
||||
}
|
||||
|
||||
free(surface);
|
||||
}
|
||||
|
||||
static int drm_format_to_bpp(uint32_t format) {
|
||||
switch(format) {
|
||||
case DRM_FORMAT_ABGR8888:
|
||||
case DRM_FORMAT_BGRA8888:
|
||||
case DRM_FORMAT_RGBX8888:
|
||||
case DRM_FORMAT_BGRX8888:
|
||||
case DRM_FORMAT_XBGR8888:
|
||||
case DRM_FORMAT_XRGB8888:
|
||||
return 32;
|
||||
case DRM_FORMAT_RGB565:
|
||||
return 16;
|
||||
default:
|
||||
printf("Unknown format %d\n", format);
|
||||
return 32;
|
||||
}
|
||||
}
|
||||
|
||||
static drm_surface *drm_create_surface(int width, int height) {
|
||||
struct drm_surface *surface;
|
||||
struct drm_mode_create_dumb create_dumb;
|
||||
uint32_t format;
|
||||
int ret;
|
||||
|
||||
surface = (struct drm_surface*)calloc(1, sizeof(*surface));
|
||||
if (!surface) {
|
||||
printf("Can't allocate memory\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if defined(RECOVERY_ABGR)
|
||||
format = DRM_FORMAT_RGBA8888;
|
||||
#elif defined(RECOVERY_BGRA)
|
||||
format = DRM_FORMAT_ARGB8888;
|
||||
#elif defined(RECOVERY_RGBX)
|
||||
format = DRM_FORMAT_XBGR8888;
|
||||
#else
|
||||
format = DRM_FORMAT_RGB565;
|
||||
#endif
|
||||
|
||||
memset(&create_dumb, 0, sizeof(create_dumb));
|
||||
create_dumb.height = height;
|
||||
create_dumb.width = width;
|
||||
create_dumb.bpp = drm_format_to_bpp(format);
|
||||
create_dumb.flags = 0;
|
||||
|
||||
ret = drmIoctl(drm_fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_dumb);
|
||||
if (ret) {
|
||||
printf("DRM_IOCTL_MODE_CREATE_DUMB failed ret=%d\n",ret);
|
||||
drm_destroy_surface(surface);
|
||||
return NULL;
|
||||
}
|
||||
surface->handle = create_dumb.handle;
|
||||
|
||||
uint32_t handles[4], pitches[4], offsets[4];
|
||||
|
||||
handles[0] = surface->handle;
|
||||
pitches[0] = create_dumb.pitch;
|
||||
offsets[0] = 0;
|
||||
|
||||
ret = drmModeAddFB2(drm_fd, width, height,
|
||||
format, handles, pitches, offsets,
|
||||
&(surface->fb_id), 0);
|
||||
if (ret) {
|
||||
printf("drmModeAddFB2 failed ret=%d\n", ret);
|
||||
drm_destroy_surface(surface);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct drm_mode_map_dumb map_dumb;
|
||||
memset(&map_dumb, 0, sizeof(map_dumb));
|
||||
map_dumb.handle = create_dumb.handle;
|
||||
ret = drmIoctl(drm_fd, DRM_IOCTL_MODE_MAP_DUMB, &map_dumb);
|
||||
if (ret) {
|
||||
printf("DRM_IOCTL_MODE_MAP_DUMB failed ret=%d\n",ret);
|
||||
drm_destroy_surface(surface);
|
||||
return NULL;;
|
||||
}
|
||||
|
||||
surface->base.height = height;
|
||||
surface->base.width = width;
|
||||
surface->base.row_bytes = create_dumb.pitch;
|
||||
surface->base.pixel_bytes = create_dumb.bpp / 8;
|
||||
surface->base.data = (unsigned char*)
|
||||
mmap(NULL,
|
||||
surface->base.height * surface->base.row_bytes,
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED,
|
||||
drm_fd, map_dumb.offset);
|
||||
if (surface->base.data == MAP_FAILED) {
|
||||
perror("mmap() failed");
|
||||
drm_destroy_surface(surface);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
static drmModeCrtc *find_crtc_for_connector(int fd,
|
||||
drmModeRes *resources,
|
||||
drmModeConnector *connector) {
|
||||
int i, j;
|
||||
drmModeEncoder *encoder;
|
||||
int32_t crtc;
|
||||
|
||||
/*
|
||||
* Find the encoder. If we already have one, just use it.
|
||||
*/
|
||||
if (connector->encoder_id)
|
||||
encoder = drmModeGetEncoder(fd, connector->encoder_id);
|
||||
else
|
||||
encoder = NULL;
|
||||
|
||||
if (encoder && encoder->crtc_id) {
|
||||
crtc = encoder->crtc_id;
|
||||
drmModeFreeEncoder(encoder);
|
||||
return drmModeGetCrtc(fd, crtc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Didn't find anything, try to find a crtc and encoder combo.
|
||||
*/
|
||||
crtc = -1;
|
||||
for (i = 0; i < connector->count_encoders; i++) {
|
||||
encoder = drmModeGetEncoder(fd, connector->encoders[i]);
|
||||
|
||||
if (encoder) {
|
||||
for (j = 0; j < resources->count_crtcs; j++) {
|
||||
if (!(encoder->possible_crtcs & (1 << j)))
|
||||
continue;
|
||||
crtc = resources->crtcs[j];
|
||||
break;
|
||||
}
|
||||
if (crtc >= 0) {
|
||||
drmModeFreeEncoder(encoder);
|
||||
return drmModeGetCrtc(fd, crtc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static drmModeConnector *find_used_connector_by_type(int fd,
|
||||
drmModeRes *resources,
|
||||
unsigned type) {
|
||||
int i;
|
||||
for (i = 0; i < resources->count_connectors; i++) {
|
||||
drmModeConnector *connector;
|
||||
|
||||
connector = drmModeGetConnector(fd, resources->connectors[i]);
|
||||
if (connector) {
|
||||
if ((connector->connector_type == type) &&
|
||||
(connector->connection == DRM_MODE_CONNECTED) &&
|
||||
(connector->count_modes > 0))
|
||||
return connector;
|
||||
|
||||
drmModeFreeConnector(connector);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static drmModeConnector *find_first_connected_connector(int fd,
|
||||
drmModeRes *resources) {
|
||||
int i;
|
||||
for (i = 0; i < resources->count_connectors; i++) {
|
||||
drmModeConnector *connector;
|
||||
|
||||
connector = drmModeGetConnector(fd, resources->connectors[i]);
|
||||
if (connector) {
|
||||
if ((connector->count_modes > 0) &&
|
||||
(connector->connection == DRM_MODE_CONNECTED))
|
||||
return connector;
|
||||
|
||||
drmModeFreeConnector(connector);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static drmModeConnector *find_main_monitor(int fd, drmModeRes *resources,
|
||||
uint32_t *mode_index) {
|
||||
unsigned i = 0;
|
||||
int modes;
|
||||
/* Look for LVDS/eDP/DSI connectors. Those are the main screens. */
|
||||
unsigned kConnectorPriority[] = {
|
||||
DRM_MODE_CONNECTOR_LVDS,
|
||||
DRM_MODE_CONNECTOR_eDP,
|
||||
DRM_MODE_CONNECTOR_DSI,
|
||||
};
|
||||
|
||||
drmModeConnector *main_monitor_connector = NULL;
|
||||
do {
|
||||
main_monitor_connector = find_used_connector_by_type(fd,
|
||||
resources,
|
||||
kConnectorPriority[i]);
|
||||
i++;
|
||||
} while (!main_monitor_connector && i < ARRAY_SIZE(kConnectorPriority));
|
||||
|
||||
/* If we didn't find a connector, grab the first one that is connected. */
|
||||
if (!main_monitor_connector)
|
||||
main_monitor_connector =
|
||||
find_first_connected_connector(fd, resources);
|
||||
|
||||
/* If we still didn't find a connector, give up and return. */
|
||||
if (!main_monitor_connector)
|
||||
return NULL;
|
||||
|
||||
*mode_index = 0;
|
||||
for (modes = 0; modes < main_monitor_connector->count_modes; modes++) {
|
||||
if (main_monitor_connector->modes[modes].type &
|
||||
DRM_MODE_TYPE_PREFERRED) {
|
||||
*mode_index = modes;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return main_monitor_connector;
|
||||
}
|
||||
|
||||
static void disable_non_main_crtcs(int fd,
|
||||
drmModeRes *resources,
|
||||
drmModeCrtc* main_crtc) {
|
||||
int i;
|
||||
drmModeCrtc* crtc;
|
||||
|
||||
for (i = 0; i < resources->count_connectors; i++) {
|
||||
drmModeConnector *connector;
|
||||
|
||||
connector = drmModeGetConnector(fd, resources->connectors[i]);
|
||||
crtc = find_crtc_for_connector(fd, resources, connector);
|
||||
if (crtc->crtc_id != main_crtc->crtc_id)
|
||||
drm_disable_crtc(fd, crtc);
|
||||
drmModeFreeCrtc(crtc);
|
||||
}
|
||||
}
|
||||
|
||||
static GRSurface* drm_init(minui_backend* backend __unused) {
|
||||
drmModeRes *res = NULL;
|
||||
uint32_t selected_mode;
|
||||
char *dev_name;
|
||||
int width, height;
|
||||
int ret, i;
|
||||
|
||||
/* Consider DRM devices in order. */
|
||||
for (i = 0; i < DRM_MAX_MINOR; i++) {
|
||||
uint64_t cap = 0;
|
||||
|
||||
ret = asprintf(&dev_name, DRM_DEV_NAME, DRM_DIR_NAME, i);
|
||||
if (ret < 0)
|
||||
continue;
|
||||
|
||||
drm_fd = open(dev_name, O_RDWR, 0);
|
||||
free(dev_name);
|
||||
if (drm_fd < 0)
|
||||
continue;
|
||||
|
||||
/* We need dumb buffers. */
|
||||
ret = drmGetCap(drm_fd, DRM_CAP_DUMB_BUFFER, &cap);
|
||||
if (ret || cap == 0) {
|
||||
close(drm_fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
res = drmModeGetResources(drm_fd);
|
||||
if (!res) {
|
||||
close(drm_fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Use this device if it has at least one connected monitor. */
|
||||
if (res->count_crtcs > 0 && res->count_connectors > 0)
|
||||
if (find_first_connected_connector(drm_fd, res))
|
||||
break;
|
||||
|
||||
drmModeFreeResources(res);
|
||||
close(drm_fd);
|
||||
res = NULL;
|
||||
}
|
||||
|
||||
if (drm_fd < 0 || res == NULL) {
|
||||
perror("cannot find/open a drm device");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
main_monitor_connector = find_main_monitor(drm_fd,
|
||||
res, &selected_mode);
|
||||
|
||||
if (!main_monitor_connector) {
|
||||
printf("main_monitor_connector not found\n");
|
||||
drmModeFreeResources(res);
|
||||
close(drm_fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
main_monitor_crtc = find_crtc_for_connector(drm_fd, res,
|
||||
main_monitor_connector);
|
||||
|
||||
if (!main_monitor_crtc) {
|
||||
printf("main_monitor_crtc not found\n");
|
||||
drmModeFreeResources(res);
|
||||
close(drm_fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
disable_non_main_crtcs(drm_fd,
|
||||
res, main_monitor_crtc);
|
||||
|
||||
main_monitor_crtc->mode = main_monitor_connector->modes[selected_mode];
|
||||
|
||||
width = main_monitor_crtc->mode.hdisplay;
|
||||
height = main_monitor_crtc->mode.vdisplay;
|
||||
|
||||
drmModeFreeResources(res);
|
||||
|
||||
drm_surfaces[0] = drm_create_surface(width, height);
|
||||
drm_surfaces[1] = drm_create_surface(width, height);
|
||||
if (!drm_surfaces[0] || !drm_surfaces[1]) {
|
||||
drm_destroy_surface(drm_surfaces[0]);
|
||||
drm_destroy_surface(drm_surfaces[1]);
|
||||
drmModeFreeResources(res);
|
||||
close(drm_fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
current_buffer = 0;
|
||||
|
||||
drm_enable_crtc(drm_fd, main_monitor_crtc, drm_surfaces[1]);
|
||||
|
||||
return &(drm_surfaces[0]->base);
|
||||
}
|
||||
|
||||
static GRSurface* drm_flip(minui_backend* backend __unused) {
|
||||
int ret;
|
||||
|
||||
ret = drmModePageFlip(drm_fd, main_monitor_crtc->crtc_id,
|
||||
drm_surfaces[current_buffer]->fb_id, 0, NULL);
|
||||
if (ret < 0) {
|
||||
printf("drmModePageFlip failed ret=%d\n", ret);
|
||||
return NULL;
|
||||
}
|
||||
current_buffer = 1 - current_buffer;
|
||||
return &(drm_surfaces[current_buffer]->base);
|
||||
}
|
||||
|
||||
static void drm_exit(minui_backend* backend __unused) {
|
||||
drm_disable_crtc(drm_fd, main_monitor_crtc);
|
||||
drm_destroy_surface(drm_surfaces[0]);
|
||||
drm_destroy_surface(drm_surfaces[1]);
|
||||
drmModeFreeCrtc(main_monitor_crtc);
|
||||
drmModeFreeConnector(main_monitor_connector);
|
||||
close(drm_fd);
|
||||
drm_fd = -1;
|
||||
}
|
||||
|
||||
static minui_backend drm_backend = {
|
||||
.init = drm_init,
|
||||
.flip = drm_flip,
|
||||
.blank = drm_blank,
|
||||
.exit = drm_exit,
|
||||
};
|
||||
|
||||
minui_backend* open_drm() {
|
||||
return &drm_backend;
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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 <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/kd.h>
|
||||
|
||||
#include "minui.h"
|
||||
#include "graphics.h"
|
||||
|
||||
static GRSurface* fbdev_init(minui_backend*);
|
||||
static GRSurface* fbdev_flip(minui_backend*);
|
||||
static void fbdev_blank(minui_backend*, bool);
|
||||
static void fbdev_exit(minui_backend*);
|
||||
|
||||
static GRSurface gr_framebuffer[2];
|
||||
static bool double_buffered;
|
||||
static GRSurface* gr_draw = NULL;
|
||||
static int displayed_buffer;
|
||||
|
||||
static fb_var_screeninfo vi;
|
||||
static int fb_fd = -1;
|
||||
|
||||
static minui_backend my_backend = {
|
||||
.init = fbdev_init,
|
||||
.flip = fbdev_flip,
|
||||
.blank = fbdev_blank,
|
||||
.exit = fbdev_exit,
|
||||
};
|
||||
|
||||
minui_backend* open_fbdev() {
|
||||
return &my_backend;
|
||||
}
|
||||
|
||||
static void fbdev_blank(minui_backend* backend __unused, bool blank)
|
||||
{
|
||||
#if defined(TW_NO_SCREEN_BLANK) && defined(TW_BRIGHTNESS_PATH) && defined(TW_MAX_BRIGHTNESS)
|
||||
int fd;
|
||||
char brightness[4];
|
||||
snprintf(brightness, 4, "%03d", TW_MAX_BRIGHTNESS/2);
|
||||
|
||||
fd = open(TW_BRIGHTNESS_PATH, O_RDWR);
|
||||
if (fd < 0) {
|
||||
perror("cannot open LCD backlight");
|
||||
return;
|
||||
}
|
||||
write(fd, blank ? "000" : brightness, 3);
|
||||
close(fd);
|
||||
#else
|
||||
int ret;
|
||||
|
||||
ret = ioctl(fb_fd, FBIOBLANK, blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK);
|
||||
if (ret < 0)
|
||||
perror("ioctl(): blank");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void set_displayed_framebuffer(unsigned n)
|
||||
{
|
||||
if (n > 1 || !double_buffered) return;
|
||||
|
||||
vi.yres_virtual = gr_framebuffer[0].height * 2;
|
||||
vi.yoffset = n * gr_framebuffer[0].height;
|
||||
vi.bits_per_pixel = gr_framebuffer[0].pixel_bytes * 8;
|
||||
if (ioctl(fb_fd, FBIOPUT_VSCREENINFO, &vi) < 0) {
|
||||
perror("active fb swap failed");
|
||||
}
|
||||
displayed_buffer = n;
|
||||
}
|
||||
|
||||
static GRSurface* fbdev_init(minui_backend* backend) {
|
||||
int fd = open("/dev/graphics/fb0", O_RDWR);
|
||||
if (fd == -1) {
|
||||
perror("cannot open fb0");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fb_fix_screeninfo fi;
|
||||
if (ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) {
|
||||
perror("failed to get fb0 info");
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ioctl(fd, FBIOGET_VSCREENINFO, &vi) < 0) {
|
||||
perror("failed to get fb0 info");
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// We print this out for informational purposes only, but
|
||||
// throughout we assume that the framebuffer device uses an RGBX
|
||||
// pixel format. This is the case for every development device I
|
||||
// have access to. For some of those devices (eg, hammerhead aka
|
||||
// Nexus 5), FBIOGET_VSCREENINFO *reports* that it wants a
|
||||
// different format (XBGR) but actually produces the correct
|
||||
// results on the display when you write RGBX.
|
||||
//
|
||||
// If you have a device that actually *needs* another pixel format
|
||||
// (ie, BGRX, or 565), patches welcome...
|
||||
|
||||
printf("fb0 reports (possibly inaccurate):\n"
|
||||
" vi.bits_per_pixel = %d\n"
|
||||
" vi.red.offset = %3d .length = %3d\n"
|
||||
" vi.green.offset = %3d .length = %3d\n"
|
||||
" vi.blue.offset = %3d .length = %3d\n",
|
||||
vi.bits_per_pixel,
|
||||
vi.red.offset, vi.red.length,
|
||||
vi.green.offset, vi.green.length,
|
||||
vi.blue.offset, vi.blue.length);
|
||||
|
||||
void* bits = mmap(0, fi.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (bits == MAP_FAILED) {
|
||||
perror("failed to mmap framebuffer");
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(bits, 0, fi.smem_len);
|
||||
|
||||
gr_framebuffer[0].width = vi.xres;
|
||||
gr_framebuffer[0].height = vi.yres;
|
||||
gr_framebuffer[0].row_bytes = fi.line_length;
|
||||
gr_framebuffer[0].pixel_bytes = vi.bits_per_pixel / 8;
|
||||
gr_framebuffer[0].data = reinterpret_cast<uint8_t*>(bits);
|
||||
memset(gr_framebuffer[0].data, 0, gr_framebuffer[0].height * gr_framebuffer[0].row_bytes);
|
||||
|
||||
/* check if we can use double buffering */
|
||||
if (vi.yres * fi.line_length * 2 <= fi.smem_len) {
|
||||
double_buffered = true;
|
||||
|
||||
memcpy(gr_framebuffer+1, gr_framebuffer, sizeof(GRSurface));
|
||||
gr_framebuffer[1].data = gr_framebuffer[0].data +
|
||||
gr_framebuffer[0].height * gr_framebuffer[0].row_bytes;
|
||||
|
||||
gr_draw = gr_framebuffer+1;
|
||||
|
||||
} else {
|
||||
double_buffered = false;
|
||||
|
||||
// Without double-buffering, we allocate RAM for a buffer to
|
||||
// draw in, and then "flipping" the buffer consists of a
|
||||
// memcpy from the buffer we allocated to the framebuffer.
|
||||
|
||||
gr_draw = (GRSurface*) malloc(sizeof(GRSurface));
|
||||
memcpy(gr_draw, gr_framebuffer, sizeof(GRSurface));
|
||||
gr_draw->data = (unsigned char*) malloc(gr_draw->height * gr_draw->row_bytes);
|
||||
if (!gr_draw->data) {
|
||||
perror("failed to allocate in-memory surface");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
memset(gr_draw->data, 0, gr_draw->height * gr_draw->row_bytes);
|
||||
fb_fd = fd;
|
||||
set_displayed_framebuffer(0);
|
||||
|
||||
printf("framebuffer: %d (%d x %d)\n", fb_fd, gr_draw->width, gr_draw->height);
|
||||
|
||||
fbdev_blank(backend, true);
|
||||
fbdev_blank(backend, false);
|
||||
|
||||
return gr_draw;
|
||||
}
|
||||
|
||||
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.
|
||||
gr_draw = gr_framebuffer + displayed_buffer;
|
||||
set_displayed_framebuffer(1-displayed_buffer);
|
||||
} else {
|
||||
// Copy from the in-memory surface to the framebuffer.
|
||||
memcpy(gr_framebuffer[0].data, gr_draw->data,
|
||||
gr_draw->height * gr_draw->row_bytes);
|
||||
}
|
||||
return gr_draw;
|
||||
}
|
||||
|
||||
static void fbdev_exit(minui_backend* backend __unused) {
|
||||
close(fb_fd);
|
||||
fb_fd = -1;
|
||||
|
||||
if (!double_buffered && gr_draw) {
|
||||
free(gr_draw->data);
|
||||
free(gr_draw);
|
||||
}
|
||||
gr_draw = NULL;
|
||||
}
|
||||
+112
-1
@@ -17,6 +17,116 @@
|
||||
#ifndef _MINUI_H_
|
||||
#define _MINUI_H_
|
||||
|
||||
#ifndef TW_USE_OLD_MINUI_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
//
|
||||
// Graphics.
|
||||
//
|
||||
|
||||
struct GRSurface {
|
||||
int width;
|
||||
int height;
|
||||
int row_bytes;
|
||||
int pixel_bytes;
|
||||
unsigned char* data;
|
||||
};
|
||||
|
||||
int gr_init();
|
||||
void gr_exit();
|
||||
|
||||
int gr_fb_width();
|
||||
int gr_fb_height();
|
||||
|
||||
void gr_flip();
|
||||
void gr_fb_blank(bool blank);
|
||||
|
||||
void gr_clear(); // clear entire surface to current color
|
||||
void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a);
|
||||
void gr_fill(int x1, int y1, int x2, int y2);
|
||||
void gr_text(int x, int y, const char *s, bool bold);
|
||||
void gr_texticon(int x, int y, GRSurface* icon);
|
||||
int gr_measure(const char *s);
|
||||
void gr_font_size(int *x, int *y);
|
||||
|
||||
void gr_blit(GRSurface* source, int sx, int sy, int w, int h, int dx, int dy);
|
||||
unsigned int gr_get_width(GRSurface* surface);
|
||||
unsigned int gr_get_height(GRSurface* surface);
|
||||
|
||||
//
|
||||
// Input events.
|
||||
//
|
||||
|
||||
struct input_event;
|
||||
|
||||
// TODO: move these over to std::function.
|
||||
typedef int (*ev_callback)(int fd, uint32_t epevents, void* data);
|
||||
typedef int (*ev_set_key_callback)(int code, int value, void* data);
|
||||
|
||||
int ev_init(ev_callback input_cb, void* data);
|
||||
void ev_exit();
|
||||
int ev_add_fd(int fd, ev_callback cb, void* data);
|
||||
void ev_iterate_available_keys(std::function<void(int)> f);
|
||||
int ev_sync_key_state(ev_set_key_callback set_key_cb, void* data);
|
||||
|
||||
// 'timeout' has the same semantics as poll(2).
|
||||
// 0 : don't block
|
||||
// < 0 : block forever
|
||||
// > 0 : block for 'timeout' milliseconds
|
||||
int ev_wait(int timeout);
|
||||
|
||||
int ev_get_input(int fd, uint32_t epevents, input_event* ev);
|
||||
void ev_dispatch();
|
||||
int ev_get_epollfd();
|
||||
|
||||
//
|
||||
// Resources
|
||||
//
|
||||
|
||||
// res_create_*_surface() functions return 0 if no error, else
|
||||
// negative.
|
||||
//
|
||||
// A "display" surface is one that is intended to be drawn to the
|
||||
// screen with gr_blit(). An "alpha" surface is a grayscale image
|
||||
// interpreted as an alpha mask used to render text in the current
|
||||
// color (with gr_text() or gr_texticon()).
|
||||
//
|
||||
// All these functions load PNG images from "/res/images/${name}.png".
|
||||
|
||||
// Load a single display surface from a PNG image.
|
||||
int res_create_display_surface(const char* name, GRSurface** pSurface);
|
||||
|
||||
// Load an array of display surfaces from a single PNG image. The PNG
|
||||
// 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);
|
||||
|
||||
// Load a single alpha surface from a grayscale PNG image.
|
||||
int res_create_alpha_surface(const char* name, GRSurface** pSurface);
|
||||
|
||||
// Load part of a grayscale PNG image that is the first match for the
|
||||
// given locale. The image is expected to be a composite of multiple
|
||||
// translations of the same text, with special added rows that encode
|
||||
// the subimages' size and intended locale in the pixel data. See
|
||||
// development/tools/recovery_l10n for an app that will generate these
|
||||
// specialized images from Android resources.
|
||||
int res_create_localized_alpha_surface(const char* name, const char* locale,
|
||||
GRSurface** pSurface);
|
||||
|
||||
// Free a surface allocated by any of the res_create_*_surface()
|
||||
// functions.
|
||||
void res_free_surface(GRSurface* surface);
|
||||
|
||||
#else //ifndef TW_USE_OLD_MINUI_H
|
||||
|
||||
// This the old minui.old/minui.h for compatibility with building TWRP
|
||||
// in pre 6.0 trees.
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -102,4 +212,5 @@ void gr_clear();
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif // ifndef TW_USE_OLD_MINUI_H
|
||||
#endif // ifndef _MINUI_H_
|
||||
|
||||
@@ -0,0 +1,459 @@
|
||||
/*
|
||||
* Copyright (C) 2007 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/kd.h>
|
||||
|
||||
#include <png.h>
|
||||
|
||||
#include "minui.h"
|
||||
|
||||
extern char* locale;
|
||||
|
||||
#define SURFACE_DATA_ALIGNMENT 8
|
||||
|
||||
static GRSurface* malloc_surface(size_t data_size) {
|
||||
size_t size = sizeof(GRSurface) + data_size + SURFACE_DATA_ALIGNMENT;
|
||||
unsigned char* temp = reinterpret_cast<unsigned char*>(malloc(size));
|
||||
if (temp == NULL) return NULL;
|
||||
GRSurface* surface = reinterpret_cast<GRSurface*>(temp);
|
||||
surface->data = temp + sizeof(GRSurface) +
|
||||
(SURFACE_DATA_ALIGNMENT - (sizeof(GRSurface) % SURFACE_DATA_ALIGNMENT));
|
||||
return surface;
|
||||
}
|
||||
|
||||
static int open_png(const char* name, png_structp* png_ptr, png_infop* info_ptr,
|
||||
png_uint_32* width, png_uint_32* height, png_byte* channels) {
|
||||
char resPath[256];
|
||||
unsigned char header[8];
|
||||
int result = 0;
|
||||
int color_type, bit_depth;
|
||||
size_t bytesRead;
|
||||
|
||||
snprintf(resPath, sizeof(resPath)-1, "/res/images/%s.png", name);
|
||||
resPath[sizeof(resPath)-1] = '\0';
|
||||
FILE* fp = fopen(resPath, "rb");
|
||||
if (fp == NULL) {
|
||||
result = -1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
bytesRead = fread(header, 1, sizeof(header), fp);
|
||||
if (bytesRead != sizeof(header)) {
|
||||
result = -2;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (png_sig_cmp(header, 0, sizeof(header))) {
|
||||
result = -3;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
*png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
if (!*png_ptr) {
|
||||
result = -4;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
*info_ptr = png_create_info_struct(*png_ptr);
|
||||
if (!*info_ptr) {
|
||||
result = -5;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (setjmp(png_jmpbuf(*png_ptr))) {
|
||||
result = -6;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
png_init_io(*png_ptr, fp);
|
||||
png_set_sig_bytes(*png_ptr, sizeof(header));
|
||||
png_read_info(*png_ptr, *info_ptr);
|
||||
|
||||
png_get_IHDR(*png_ptr, *info_ptr, width, height, &bit_depth,
|
||||
&color_type, NULL, NULL, NULL);
|
||||
|
||||
*channels = png_get_channels(*png_ptr, *info_ptr);
|
||||
|
||||
if (bit_depth == 8 && *channels == 3 && color_type == PNG_COLOR_TYPE_RGB) {
|
||||
// 8-bit RGB images: great, nothing to do.
|
||||
} else if (bit_depth <= 8 && *channels == 1 && color_type == PNG_COLOR_TYPE_GRAY) {
|
||||
// 1-, 2-, 4-, or 8-bit gray images: expand to 8-bit gray.
|
||||
png_set_expand_gray_1_2_4_to_8(*png_ptr);
|
||||
} else if (bit_depth <= 8 && *channels == 1 && color_type == PNG_COLOR_TYPE_PALETTE) {
|
||||
// paletted images: expand to 8-bit RGB. Note that we DON'T
|
||||
// currently expand the tRNS chunk (if any) to an alpha
|
||||
// channel, because minui doesn't support alpha channels in
|
||||
// general.
|
||||
png_set_palette_to_rgb(*png_ptr);
|
||||
*channels = 3;
|
||||
} else {
|
||||
fprintf(stderr, "minui doesn't support PNG depth %d channels %d color_type %d\n",
|
||||
bit_depth, *channels, color_type);
|
||||
result = -7;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
exit:
|
||||
if (result < 0) {
|
||||
png_destroy_read_struct(png_ptr, info_ptr, NULL);
|
||||
}
|
||||
if (fp != NULL) {
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// "display" surfaces are transformed into the framebuffer's required
|
||||
// pixel format (currently only RGBX is supported) at load time, so
|
||||
// gr_blit() can be nothing more than a memcpy() for each row. The
|
||||
// next two functions are the only ones that know anything about the
|
||||
// framebuffer pixel format; they need to be modified if the
|
||||
// framebuffer format changes (but nothing else should).
|
||||
|
||||
// Allocate and return a GRSurface* sufficient for storing an image of
|
||||
// the indicated size in the framebuffer pixel format.
|
||||
static GRSurface* init_display_surface(png_uint_32 width, png_uint_32 height) {
|
||||
GRSurface* surface = malloc_surface(width * height * 4);
|
||||
if (surface == NULL) return NULL;
|
||||
|
||||
surface->width = width;
|
||||
surface->height = height;
|
||||
surface->row_bytes = width * 4;
|
||||
surface->pixel_bytes = 4;
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
// Copy 'input_row' to 'output_row', transforming it to the
|
||||
// framebuffer pixel format. The input format depends on the value of
|
||||
// 'channels':
|
||||
//
|
||||
// 1 - input is 8-bit grayscale
|
||||
// 3 - input is 24-bit RGB
|
||||
// 4 - input is 32-bit RGBA/RGBX
|
||||
//
|
||||
// 'width' is the number of pixels in the row.
|
||||
static void transform_rgb_to_draw(unsigned char* input_row,
|
||||
unsigned char* output_row,
|
||||
int channels, int width) {
|
||||
int x;
|
||||
unsigned char* ip = input_row;
|
||||
unsigned char* op = output_row;
|
||||
|
||||
switch (channels) {
|
||||
case 1:
|
||||
// expand gray level to RGBX
|
||||
for (x = 0; x < width; ++x) {
|
||||
*op++ = *ip;
|
||||
*op++ = *ip;
|
||||
*op++ = *ip;
|
||||
*op++ = 0xff;
|
||||
ip++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// expand RGBA to RGBX
|
||||
for (x = 0; x < width; ++x) {
|
||||
*op++ = *ip++;
|
||||
*op++ = *ip++;
|
||||
*op++ = *ip++;
|
||||
*op++ = 0xff;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
// copy RGBA to RGBX
|
||||
memcpy(output_row, input_row, width*4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int res_create_display_surface(const char* name, 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;
|
||||
unsigned char* p_row;
|
||||
unsigned int y;
|
||||
|
||||
*pSurface = NULL;
|
||||
|
||||
result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels);
|
||||
if (result < 0) return result;
|
||||
|
||||
surface = init_display_surface(width, height);
|
||||
if (surface == NULL) {
|
||||
result = -8;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
#if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA)
|
||||
png_set_bgr(png_ptr);
|
||||
#endif
|
||||
|
||||
p_row = reinterpret_cast<unsigned char*>(malloc(width * 4));
|
||||
for (y = 0; y < height; ++y) {
|
||||
png_read_row(png_ptr, p_row, NULL);
|
||||
transform_rgb_to_draw(p_row, surface->data + y * surface->row_bytes, channels, width);
|
||||
}
|
||||
free(p_row);
|
||||
|
||||
*pSurface = surface;
|
||||
|
||||
exit:
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
if (result < 0 && surface != NULL) free(surface);
|
||||
return result;
|
||||
}
|
||||
|
||||
int res_create_multi_display_surface(const char* name, int* frames, 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;
|
||||
unsigned int y;
|
||||
|
||||
*pSurface = NULL;
|
||||
*frames = -1;
|
||||
|
||||
result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels);
|
||||
if (result < 0) return result;
|
||||
|
||||
*frames = 1;
|
||||
if (png_get_text(png_ptr, info_ptr, &text, &num_text)) {
|
||||
for (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;
|
||||
}
|
||||
}
|
||||
printf(" found frames = %d\n", *frames);
|
||||
}
|
||||
|
||||
if (height % *frames != 0) {
|
||||
printf("bad height (%d) for frame count (%d)\n", height, *frames);
|
||||
result = -9;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
surface = reinterpret_cast<GRSurface**>(malloc(*frames * sizeof(GRSurface*)));
|
||||
if (surface == NULL) {
|
||||
result = -8;
|
||||
goto exit;
|
||||
}
|
||||
for (i = 0; i < *frames; ++i) {
|
||||
surface[i] = init_display_surface(width, height / *frames);
|
||||
if (surface[i] == NULL) {
|
||||
result = -8;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA)
|
||||
png_set_bgr(png_ptr);
|
||||
#endif
|
||||
|
||||
p_row = reinterpret_cast<unsigned char*>(malloc(width * 4));
|
||||
for (y = 0; y < height; ++y) {
|
||||
png_read_row(png_ptr, p_row, NULL);
|
||||
int frame = y % *frames;
|
||||
unsigned char* out_row = surface[frame]->data +
|
||||
(y / *frames) * surface[frame]->row_bytes;
|
||||
transform_rgb_to_draw(p_row, out_row, channels, width);
|
||||
}
|
||||
free(p_row);
|
||||
|
||||
*pSurface = reinterpret_cast<GRSurface**>(surface);
|
||||
|
||||
exit:
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
|
||||
if (result < 0) {
|
||||
if (surface) {
|
||||
for (i = 0; i < *frames; ++i) {
|
||||
if (surface[i]) free(surface[i]);
|
||||
}
|
||||
free(surface);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int res_create_alpha_surface(const char* name, 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;
|
||||
|
||||
*pSurface = NULL;
|
||||
|
||||
result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels);
|
||||
if (result < 0) return result;
|
||||
|
||||
if (channels != 1) {
|
||||
result = -7;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
surface = malloc_surface(width * height);
|
||||
if (surface == NULL) {
|
||||
result = -8;
|
||||
goto exit;
|
||||
}
|
||||
surface->width = width;
|
||||
surface->height = height;
|
||||
surface->row_bytes = width;
|
||||
surface->pixel_bytes = 1;
|
||||
|
||||
#if defined(RECOVERY_ABGR) || defined(RECOVERY_BGRA)
|
||||
png_set_bgr(png_ptr);
|
||||
#endif
|
||||
|
||||
unsigned char* p_row;
|
||||
unsigned int y;
|
||||
for (y = 0; y < height; ++y) {
|
||||
p_row = surface->data + y * surface->row_bytes;
|
||||
png_read_row(png_ptr, p_row, NULL);
|
||||
}
|
||||
|
||||
*pSurface = surface;
|
||||
|
||||
exit:
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
if (result < 0 && surface != NULL) free(surface);
|
||||
return result;
|
||||
}
|
||||
|
||||
static int matches_locale(const char* loc, const char* locale) {
|
||||
if (locale == NULL) return 0;
|
||||
|
||||
if (strcmp(loc, locale) == 0) return 1;
|
||||
|
||||
// if loc does *not* have an underscore, and it matches the start
|
||||
// of locale, and the next character in locale *is* an underscore,
|
||||
// that's a match. For instance, loc == "en" matches locale ==
|
||||
// "en_US".
|
||||
|
||||
int i;
|
||||
for (i = 0; loc[i] != 0 && loc[i] != '_'; ++i);
|
||||
if (loc[i] == '_') return 0;
|
||||
|
||||
return (strncmp(locale, loc, i) == 0 && locale[i] == '_');
|
||||
}
|
||||
|
||||
int res_create_localized_alpha_surface(const char* name,
|
||||
const char* locale,
|
||||
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;
|
||||
unsigned char* row;
|
||||
png_uint_32 y;
|
||||
|
||||
*pSurface = NULL;
|
||||
|
||||
if (locale == NULL) {
|
||||
surface = malloc_surface(0);
|
||||
surface->width = 0;
|
||||
surface->height = 0;
|
||||
surface->row_bytes = 0;
|
||||
surface->pixel_bytes = 1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
result = open_png(name, &png_ptr, &info_ptr, &width, &height, &channels);
|
||||
if (result < 0) return result;
|
||||
|
||||
if (channels != 1) {
|
||||
result = -7;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
row = reinterpret_cast<unsigned char*>(malloc(width));
|
||||
for (y = 0; y < height; ++y) {
|
||||
png_read_row(png_ptr, row, NULL);
|
||||
int w = (row[1] << 8) | row[0];
|
||||
int h = (row[3] << 8) | row[2];
|
||||
int len = row[4];
|
||||
char* loc = (char*)row+5;
|
||||
|
||||
if (y+1+h >= height || matches_locale(loc, locale)) {
|
||||
printf(" %20s: %s (%d x %d @ %d)\n", name, loc, w, h, y);
|
||||
|
||||
surface = malloc_surface(w*h);
|
||||
if (surface == NULL) {
|
||||
result = -8;
|
||||
goto exit;
|
||||
}
|
||||
surface->width = w;
|
||||
surface->height = h;
|
||||
surface->row_bytes = w;
|
||||
surface->pixel_bytes = 1;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < h; ++i, ++y) {
|
||||
png_read_row(png_ptr, row, NULL);
|
||||
memcpy(surface->data + i*w, row, w);
|
||||
}
|
||||
|
||||
*pSurface = reinterpret_cast<GRSurface*>(surface);
|
||||
break;
|
||||
} else {
|
||||
int i;
|
||||
for (i = 0; i < h; ++i, ++y) {
|
||||
png_read_row(png_ptr, row, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||
if (result < 0 && surface != NULL) free(surface);
|
||||
return result;
|
||||
}
|
||||
|
||||
void res_free_surface(GRSurface* surface) {
|
||||
free(surface);
|
||||
}
|
||||
@@ -154,7 +154,7 @@ endif
|
||||
|
||||
LOCAL_CFLAGS += -DTWRES=\"$(TWRES_PATH)\"
|
||||
LOCAL_SHARED_LIBRARIES += libz libc libcutils libjpeg libpng
|
||||
LOCAL_STATIC_LIBRARIES += libpixelflinger_static
|
||||
LOCAL_STATIC_LIBRARIES += libpixelflinger_twrp
|
||||
LOCAL_MODULE_TAGS := eng
|
||||
LOCAL_MODULE := libminuitwrp
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#include "../common.h"
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <linux/fb.h>
|
||||
#include <linux/kd.h>
|
||||
|
||||
+2
-2
@@ -85,7 +85,7 @@ dirCreateHierarchy(const char *path, int mode,
|
||||
c--;
|
||||
}
|
||||
if (c == cpath) {
|
||||
//xxx test this path
|
||||
//xxx test this path
|
||||
/* No directory component. Act like the path was empty.
|
||||
*/
|
||||
errno = ENOENT;
|
||||
@@ -206,7 +206,7 @@ dirUnlinkHierarchy(const char *path)
|
||||
/* recurse over components */
|
||||
errno = 0;
|
||||
while ((de = readdir(dir)) != NULL) {
|
||||
//TODO: don't blow the stack
|
||||
//TODO: don't blow the stack
|
||||
char dn[PATH_MAX];
|
||||
if (!strcmp(de->d_name, "..") || !strcmp(de->d_name, ".")) {
|
||||
continue;
|
||||
|
||||
@@ -140,7 +140,6 @@ static bool resizeHash(HashTable* pHashTable, int newSize)
|
||||
int i;
|
||||
|
||||
assert(countTombStones(pHashTable) == pHashTable->numDeadEntries);
|
||||
//LOGI("before: dead=%d\n", pHashTable->numDeadEntries);
|
||||
|
||||
pNewEntries = (HashEntry*) calloc(newSize, sizeof(HashTable));
|
||||
if (pNewEntries == NULL)
|
||||
@@ -196,7 +195,6 @@ void* mzHashTableLookup(HashTable* pHashTable, unsigned int itemHash, void* item
|
||||
(*cmpFunc)(pEntry->data, item) == 0)
|
||||
{
|
||||
/* match */
|
||||
//LOGD("+++ match on entry %d\n", pEntry - pHashTable->pEntries);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -206,8 +204,6 @@ void* mzHashTableLookup(HashTable* pHashTable, unsigned int itemHash, void* item
|
||||
break; /* edge case - single-entry table */
|
||||
pEntry = pHashTable->pEntries;
|
||||
}
|
||||
|
||||
//LOGI("+++ look probing %d...\n", pEntry - pHashTable->pEntries);
|
||||
}
|
||||
|
||||
if (pEntry->data == NULL) {
|
||||
@@ -228,10 +224,6 @@ void* mzHashTableLookup(HashTable* pHashTable, unsigned int itemHash, void* item
|
||||
abort();
|
||||
}
|
||||
/* note "pEntry" is now invalid */
|
||||
} else {
|
||||
//LOGW("okay %d/%d/%d\n",
|
||||
// pHashTable->numEntries, pHashTable->tableSize,
|
||||
// (pHashTable->tableSize * LOAD_NUMER) / LOAD_DENOM);
|
||||
}
|
||||
|
||||
/* full table is bad -- search for nonexistent never halts */
|
||||
@@ -264,7 +256,6 @@ bool mzHashTableRemove(HashTable* pHashTable, unsigned int itemHash, void* item)
|
||||
pEnd = &pHashTable->pEntries[pHashTable->tableSize];
|
||||
while (pEntry->data != NULL) {
|
||||
if (pEntry->data == item) {
|
||||
//LOGI("+++ stepping on entry %d\n", pEntry - pHashTable->pEntries);
|
||||
pEntry->data = HASH_TOMBSTONE;
|
||||
pHashTable->numEntries--;
|
||||
pHashTable->numDeadEntries++;
|
||||
@@ -277,8 +268,6 @@ bool mzHashTableRemove(HashTable* pHashTable, unsigned int itemHash, void* item)
|
||||
break; /* edge case - single-entry table */
|
||||
pEntry = pHashTable->pEntries;
|
||||
}
|
||||
|
||||
//LOGI("+++ del probing %d...\n", pEntry - pHashTable->pEntries);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
+6
-4
@@ -27,11 +27,13 @@ static int getFileStartAndLength(int fd, off_t *start_, size_t *length_)
|
||||
assert(start_ != NULL);
|
||||
assert(length_ != NULL);
|
||||
|
||||
start = lseek(fd, 0L, SEEK_CUR);
|
||||
end = lseek(fd, 0L, SEEK_END);
|
||||
(void) lseek(fd, start, SEEK_SET);
|
||||
// TODO: isn't start always 0 for the single call site? just use fstat instead?
|
||||
|
||||
if (start == (off_t) -1 || end == (off_t) -1) {
|
||||
start = TEMP_FAILURE_RETRY(lseek(fd, 0L, SEEK_CUR));
|
||||
end = TEMP_FAILURE_RETRY(lseek(fd, 0L, SEEK_END));
|
||||
|
||||
if (TEMP_FAILURE_RETRY(lseek(fd, start, SEEK_SET)) == -1 ||
|
||||
start == (off_t) -1 || end == (off_t) -1) {
|
||||
LOGE("could not determine length of file\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
+75
-162
@@ -327,10 +327,6 @@ static bool parseZipArchive(ZipArchive* pArchive)
|
||||
#else
|
||||
pEntry = &pArchive->pEntries[i];
|
||||
#endif
|
||||
|
||||
//LOGI("%d: localHdr=%d fnl=%d el=%d cl=%d\n",
|
||||
// i, localHdrOffset, fileNameLen, extraLen, commentLen);
|
||||
|
||||
pEntry->fileNameLen = fileNameLen;
|
||||
pEntry->fileName = fileName;
|
||||
|
||||
@@ -488,7 +484,7 @@ const ZipEntry* mzFindZipEntry(const ZipArchive* pArchive,
|
||||
/*
|
||||
* Return true if the entry is a symbolic link.
|
||||
*/
|
||||
bool mzIsZipEntrySymlink(const ZipEntry* pEntry)
|
||||
static bool mzIsZipEntrySymlink(const ZipEntry* pEntry)
|
||||
{
|
||||
if ((pEntry->versionMadeBy & 0xff00) == CENVEM_UNIX) {
|
||||
return S_ISLNK(pEntry->externalFileAttributes >> 16);
|
||||
@@ -632,30 +628,6 @@ static bool crcProcessFunction(const unsigned char *data, int dataLen,
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the CRC on this entry; return true if it is correct.
|
||||
* May do other internal checks as well.
|
||||
*/
|
||||
bool mzIsZipEntryIntact(const ZipArchive *pArchive, const ZipEntry *pEntry)
|
||||
{
|
||||
unsigned long crc;
|
||||
bool ret;
|
||||
|
||||
crc = crc32(0L, Z_NULL, 0);
|
||||
ret = mzProcessZipEntryContents(pArchive, pEntry, crcProcessFunction,
|
||||
(void *)&crc);
|
||||
if (!ret) {
|
||||
LOGE("Can't calculate CRC for entry\n");
|
||||
return false;
|
||||
}
|
||||
if (crc != (unsigned long)pEntry->crc32) {
|
||||
LOGW("CRC for entry %.*s (0x%08lx) != expected (0x%08lx)\n",
|
||||
pEntry->fileNameLen, pEntry->fileName, crc, pEntry->crc32);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char *buf;
|
||||
int bufLen;
|
||||
@@ -703,13 +675,11 @@ static bool writeProcessFunction(const unsigned char *data, int dataLen,
|
||||
}
|
||||
ssize_t soFar = 0;
|
||||
while (true) {
|
||||
ssize_t n = write(fd, data+soFar, dataLen-soFar);
|
||||
ssize_t n = TEMP_FAILURE_RETRY(write(fd, data+soFar, dataLen-soFar));
|
||||
if (n <= 0) {
|
||||
LOGE("Error writing %zd bytes from zip file from %p: %s\n",
|
||||
dataLen-soFar, data+soFar, strerror(errno));
|
||||
if (errno != EINTR) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
} else if (n > 0) {
|
||||
soFar += n;
|
||||
if (soFar == dataLen) return true;
|
||||
@@ -737,23 +707,6 @@ bool mzExtractZipEntryToFile(const ZipArchive *pArchive,
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Obtain a pointer to the in-memory representation of a stored entry.
|
||||
*/
|
||||
bool mzGetStoredEntry(const ZipArchive *pArchive,
|
||||
const ZipEntry *pEntry, unsigned char **addr, size_t *length)
|
||||
{
|
||||
if (pEntry->compression != STORED) {
|
||||
LOGE("Can't getStoredEntry for '%s'; not stored\n",
|
||||
pEntry->fileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
*addr = pArchive->addr + pEntry->offset;
|
||||
*length = pEntry->uncompLen;
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
unsigned char* buffer;
|
||||
long len;
|
||||
@@ -873,7 +826,7 @@ static const char *targetEntryPath(MzPathHelper *helper, ZipEntry *pEntry)
|
||||
*/
|
||||
bool mzExtractRecursive(const ZipArchive *pArchive,
|
||||
const char *zipDir, const char *targetDir,
|
||||
int flags, const struct utimbuf *timestamp,
|
||||
const struct utimbuf *timestamp,
|
||||
void (*callback)(const char *fn, void *), void *cookie,
|
||||
struct selabel_handle *sehnd)
|
||||
{
|
||||
@@ -923,8 +876,8 @@ bool mzExtractRecursive(const ZipArchive *pArchive,
|
||||
|
||||
/* Walk through the entries and extract anything whose path begins
|
||||
* with zpath.
|
||||
//TODO: since the entries are sorted, binary search for the first match
|
||||
// and stop after the first non-match.
|
||||
//TODO: since the entries are sorted, binary search for the first match
|
||||
// and stop after the first non-match.
|
||||
*/
|
||||
unsigned int i;
|
||||
bool seenMatch = false;
|
||||
@@ -933,10 +886,10 @@ bool mzExtractRecursive(const ZipArchive *pArchive,
|
||||
for (i = 0; i < pArchive->numEntries; i++) {
|
||||
ZipEntry *pEntry = pArchive->pEntries + i;
|
||||
if (pEntry->fileNameLen < zipDirLen) {
|
||||
//TODO: look out for a single empty directory entry that matches zpath, but
|
||||
// missing the trailing slash. Most zip files seem to include
|
||||
// the trailing slash, but I think it's legal to leave it off.
|
||||
// e.g., zpath "a/b/", entry "a/b", with no children of the entry.
|
||||
//TODO: look out for a single empty directory entry that matches zpath, but
|
||||
// missing the trailing slash. Most zip files seem to include
|
||||
// the trailing slash, but I think it's legal to leave it off.
|
||||
// e.g., zpath "a/b/", entry "a/b", with no children of the entry.
|
||||
/* No chance of matching.
|
||||
*/
|
||||
#if SORT_ENTRIES
|
||||
@@ -977,30 +930,19 @@ bool mzExtractRecursive(const ZipArchive *pArchive,
|
||||
break;
|
||||
}
|
||||
|
||||
/* With DRY_RUN set, invoke the callback but don't do anything else.
|
||||
*/
|
||||
if (flags & MZ_EXTRACT_DRY_RUN) {
|
||||
if (callback != NULL) callback(targetFile, cookie);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Create the file or directory.
|
||||
*/
|
||||
#define UNZIP_DIRMODE 0755
|
||||
#define UNZIP_FILEMODE 0644
|
||||
if (pEntry->fileName[pEntry->fileNameLen-1] == '/') {
|
||||
if (!(flags & MZ_EXTRACT_FILES_ONLY)) {
|
||||
int ret = dirCreateHierarchy(
|
||||
targetFile, UNZIP_DIRMODE, timestamp, false, sehnd);
|
||||
if (ret != 0) {
|
||||
LOGE("Can't create containing directory for \"%s\": %s\n",
|
||||
targetFile, strerror(errno));
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
LOGD("Extracted dir \"%s\"\n", targetFile);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Create the file or directory. We ignore directory entries
|
||||
* because we recursively create paths to each file entry we encounter
|
||||
* in the zip archive anyway.
|
||||
*
|
||||
* NOTE: A "directory entry" in a zip archive is just a zero length
|
||||
* entry that ends in a "/". They're not mandatory and many tools get
|
||||
* rid of them. We need to process them only if we want to preserve
|
||||
* empty directories from the archive.
|
||||
*/
|
||||
if (pEntry->fileName[pEntry->fileNameLen-1] != '/') {
|
||||
/* This is not a directory. First, make sure that
|
||||
* the containing directory exists.
|
||||
*/
|
||||
@@ -1013,91 +955,62 @@ bool mzExtractRecursive(const ZipArchive *pArchive,
|
||||
break;
|
||||
}
|
||||
|
||||
/* With FILES_ONLY set, we need to ignore metadata entirely,
|
||||
* so treat symlinks as regular files.
|
||||
/*
|
||||
* The entry is a regular file or a symlink. Open the target for writing.
|
||||
*
|
||||
* TODO: This behavior for symlinks seems rather bizarre. For a
|
||||
* symlink foo/bar/baz -> foo/tar/taz, we will create a file called
|
||||
* "foo/bar/baz" whose contents are the literal "foo/tar/taz". We
|
||||
* warn about this for now and preserve older behavior.
|
||||
*/
|
||||
if (!(flags & MZ_EXTRACT_FILES_ONLY) && mzIsZipEntrySymlink(pEntry)) {
|
||||
/* The entry is a symbolic link.
|
||||
* The relative target of the symlink is in the
|
||||
* data section of this entry.
|
||||
*/
|
||||
if (pEntry->uncompLen == 0) {
|
||||
LOGE("Symlink entry \"%s\" has no target\n",
|
||||
targetFile);
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
char *linkTarget = malloc(pEntry->uncompLen + 1);
|
||||
if (linkTarget == NULL) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
ok = mzReadZipEntry(pArchive, pEntry, linkTarget,
|
||||
pEntry->uncompLen);
|
||||
if (!ok) {
|
||||
LOGE("Can't read symlink target for \"%s\"\n",
|
||||
targetFile);
|
||||
free(linkTarget);
|
||||
break;
|
||||
}
|
||||
linkTarget[pEntry->uncompLen] = '\0';
|
||||
|
||||
/* Make the link.
|
||||
*/
|
||||
ret = symlink(linkTarget, targetFile);
|
||||
if (ret != 0) {
|
||||
LOGE("Can't symlink \"%s\" to \"%s\": %s\n",
|
||||
targetFile, linkTarget, strerror(errno));
|
||||
free(linkTarget);
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
LOGD("Extracted symlink \"%s\" -> \"%s\"\n",
|
||||
targetFile, linkTarget);
|
||||
free(linkTarget);
|
||||
} else {
|
||||
/* The entry is a regular file.
|
||||
* Open the target for writing.
|
||||
*/
|
||||
|
||||
char *secontext = NULL;
|
||||
|
||||
if (sehnd) {
|
||||
selabel_lookup(sehnd, &secontext, targetFile, UNZIP_FILEMODE);
|
||||
setfscreatecon(secontext);
|
||||
}
|
||||
|
||||
int fd = creat(targetFile, UNZIP_FILEMODE);
|
||||
|
||||
if (secontext) {
|
||||
freecon(secontext);
|
||||
setfscreatecon(NULL);
|
||||
}
|
||||
|
||||
if (fd < 0) {
|
||||
LOGE("Can't create target file \"%s\": %s\n",
|
||||
targetFile, strerror(errno));
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
bool ok = mzExtractZipEntryToFile(pArchive, pEntry, fd);
|
||||
close(fd);
|
||||
if (!ok) {
|
||||
LOGE("Error extracting \"%s\"\n", targetFile);
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (timestamp != NULL && utime(targetFile, timestamp)) {
|
||||
LOGE("Error touching \"%s\"\n", targetFile);
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
LOGV("Extracted file \"%s\"\n", targetFile);
|
||||
++extractCount;
|
||||
if (mzIsZipEntrySymlink(pEntry)) {
|
||||
LOGE("Symlink entry \"%.*s\" will be output as a regular file.",
|
||||
pEntry->fileNameLen, pEntry->fileName);
|
||||
}
|
||||
|
||||
char *secontext = NULL;
|
||||
|
||||
if (sehnd) {
|
||||
selabel_lookup(sehnd, &secontext, targetFile, UNZIP_FILEMODE);
|
||||
setfscreatecon(secontext);
|
||||
}
|
||||
|
||||
int fd = open(targetFile, O_CREAT|O_WRONLY|O_TRUNC|O_SYNC,
|
||||
UNZIP_FILEMODE);
|
||||
|
||||
if (secontext) {
|
||||
freecon(secontext);
|
||||
setfscreatecon(NULL);
|
||||
}
|
||||
|
||||
if (fd < 0) {
|
||||
LOGE("Can't create target file \"%s\": %s\n",
|
||||
targetFile, strerror(errno));
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
bool ok = mzExtractZipEntryToFile(pArchive, pEntry, fd);
|
||||
if (ok) {
|
||||
ok = (fsync(fd) == 0);
|
||||
}
|
||||
if (close(fd) != 0) {
|
||||
ok = false;
|
||||
}
|
||||
if (!ok) {
|
||||
LOGE("Error extracting \"%s\"\n", targetFile);
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (timestamp != NULL && utime(targetFile, timestamp)) {
|
||||
LOGE("Error touching \"%s\"\n", targetFile);
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
LOGV("Extracted file \"%s\"\n", targetFile);
|
||||
++extractCount;
|
||||
}
|
||||
|
||||
if (callback != NULL) callback(targetFile, cookie);
|
||||
|
||||
+5
-69
@@ -85,56 +85,12 @@ void mzCloseZipArchive(ZipArchive* pArchive);
|
||||
const ZipEntry* mzFindZipEntry(const ZipArchive* pArchive,
|
||||
const char* entryName);
|
||||
|
||||
/*
|
||||
* Get the number of entries in the Zip archive.
|
||||
*/
|
||||
INLINE unsigned int mzZipEntryCount(const ZipArchive* pArchive) {
|
||||
return pArchive->numEntries;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get an entry by index. Returns NULL if the index is out-of-bounds.
|
||||
*/
|
||||
INLINE const ZipEntry*
|
||||
mzGetZipEntryAt(const ZipArchive* pArchive, unsigned int index)
|
||||
{
|
||||
if (index < pArchive->numEntries) {
|
||||
return pArchive->pEntries + index;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the index number of an entry in the archive.
|
||||
*/
|
||||
INLINE unsigned int
|
||||
mzGetZipEntryIndex(const ZipArchive *pArchive, const ZipEntry *pEntry) {
|
||||
return pEntry - pArchive->pEntries;
|
||||
}
|
||||
|
||||
/*
|
||||
* Simple accessors.
|
||||
*/
|
||||
INLINE UnterminatedString mzGetZipEntryFileName(const ZipEntry* pEntry) {
|
||||
UnterminatedString ret;
|
||||
ret.str = pEntry->fileName;
|
||||
ret.len = pEntry->fileNameLen;
|
||||
return ret;
|
||||
}
|
||||
INLINE long mzGetZipEntryOffset(const ZipEntry* pEntry) {
|
||||
return pEntry->offset;
|
||||
}
|
||||
INLINE long mzGetZipEntryUncompLen(const ZipEntry* pEntry) {
|
||||
return pEntry->uncompLen;
|
||||
}
|
||||
INLINE long mzGetZipEntryModTime(const ZipEntry* pEntry) {
|
||||
return pEntry->modTime;
|
||||
}
|
||||
INLINE long mzGetZipEntryCrc32(const ZipEntry* pEntry) {
|
||||
return pEntry->crc32;
|
||||
}
|
||||
bool mzIsZipEntrySymlink(const ZipEntry* pEntry);
|
||||
|
||||
|
||||
/*
|
||||
* Type definition for the callback function used by
|
||||
@@ -163,12 +119,6 @@ bool mzProcessZipEntryContents(const ZipArchive *pArchive,
|
||||
bool mzReadZipEntry(const ZipArchive* pArchive, const ZipEntry* pEntry,
|
||||
char* buf, int bufLen);
|
||||
|
||||
/*
|
||||
* Check the CRC on this entry; return true if it is correct.
|
||||
* May do other internal checks as well.
|
||||
*/
|
||||
bool mzIsZipEntryIntact(const ZipArchive *pArchive, const ZipEntry *pEntry);
|
||||
|
||||
/*
|
||||
* Inflate and write an entry to a file.
|
||||
*/
|
||||
@@ -183,20 +133,12 @@ bool mzExtractZipEntryToBuffer(const ZipArchive *pArchive,
|
||||
const ZipEntry *pEntry, unsigned char* buffer);
|
||||
|
||||
/*
|
||||
* Return a pointer and length for a given entry. The returned region
|
||||
* should be valid until pArchive is closed, and should be treated as
|
||||
* read-only.
|
||||
*
|
||||
* Only makes sense for entries which are stored (ie, not compressed).
|
||||
* No guarantees are made regarding alignment of the returned pointer.
|
||||
*/
|
||||
bool mzGetStoredEntry(const ZipArchive *pArchive,
|
||||
const ZipEntry* pEntry, unsigned char **addr, size_t *length);
|
||||
|
||||
/*
|
||||
* Inflate all entries under zipDir to the directory specified by
|
||||
* Inflate all files under zipDir to the directory specified by
|
||||
* targetDir, which must exist and be a writable directory.
|
||||
*
|
||||
* Directory entries and symlinks are not extracted.
|
||||
*
|
||||
*
|
||||
* The immediate children of zipDir will become the immediate
|
||||
* children of targetDir; e.g., if the archive contains the entries
|
||||
*
|
||||
@@ -211,21 +153,15 @@ bool mzGetStoredEntry(const ZipArchive *pArchive,
|
||||
* /tmp/two
|
||||
* /tmp/d/three
|
||||
*
|
||||
* flags is zero or more of the following:
|
||||
*
|
||||
* MZ_EXTRACT_FILES_ONLY - only unpack files, not directories or symlinks
|
||||
* MZ_EXTRACT_DRY_RUN - don't do anything, but do invoke the callback
|
||||
*
|
||||
* If timestamp is non-NULL, file timestamps will be set accordingly.
|
||||
*
|
||||
* If callback is non-NULL, it will be invoked with each unpacked file.
|
||||
*
|
||||
* Returns true on success, false on failure.
|
||||
*/
|
||||
enum { MZ_EXTRACT_FILES_ONLY = 1, MZ_EXTRACT_DRY_RUN = 2 };
|
||||
bool mzExtractRecursive(const ZipArchive *pArchive,
|
||||
const char *zipDir, const char *targetDir,
|
||||
int flags, const struct utimbuf *timestamp,
|
||||
const struct utimbuf *timestamp,
|
||||
void (*callback)(const char *fn, void*), void *cookie,
|
||||
struct selabel_handle *sehnd);
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ int main(int argc, char **argv) {
|
||||
if (fd < 0) die("error opening %s", argv[2]);
|
||||
|
||||
char header[HEADER_SIZE];
|
||||
int headerlen = read(fd, header, sizeof(header));
|
||||
int headerlen = TEMP_FAILURE_RETRY(read(fd, header, sizeof(header)));
|
||||
if (headerlen <= 0) die("error reading %s header", argv[2]);
|
||||
|
||||
MtdReadContext *in = mtd_read_partition(partition);
|
||||
@@ -104,7 +104,7 @@ int main(int argc, char **argv) {
|
||||
if (wrote != headerlen) die("error writing %s", argv[1]);
|
||||
|
||||
int len;
|
||||
while ((len = read(fd, buf, sizeof(buf))) > 0) {
|
||||
while ((len = TEMP_FAILURE_RETRY(read(fd, buf, sizeof(buf)))) > 0) {
|
||||
wrote = mtd_write_data(out, buf, len);
|
||||
if (wrote != len) die("error writing %s", argv[1]);
|
||||
}
|
||||
@@ -125,13 +125,13 @@ int main(int argc, char **argv) {
|
||||
if (mtd_partition_info(partition, NULL, &block_size, NULL))
|
||||
die("error getting %s block size", argv[1]);
|
||||
|
||||
if (lseek(fd, headerlen, SEEK_SET) != headerlen)
|
||||
if (TEMP_FAILURE_RETRY(lseek(fd, headerlen, SEEK_SET)) != headerlen)
|
||||
die("error rewinding %s", argv[2]);
|
||||
|
||||
int left = block_size - headerlen;
|
||||
while (left < 0) left += block_size;
|
||||
while (left > 0) {
|
||||
len = read(fd, buf, left > (int)sizeof(buf) ? (int)sizeof(buf) : left);
|
||||
len = TEMP_FAILURE_RETRY(read(fd, buf, left > (int)sizeof(buf) ? (int)sizeof(buf) : left));
|
||||
if (len <= 0) die("error reading %s", argv[2]);
|
||||
if (mtd_write_data(out, buf, len) != len)
|
||||
die("error writing %s", argv[1]);
|
||||
|
||||
+14
-75
@@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <mntent.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -59,10 +60,8 @@ free_volume_internals(const MountedVolume *volume, int zero)
|
||||
int
|
||||
scan_mounted_volumes()
|
||||
{
|
||||
char buf[2048];
|
||||
const char *bufp;
|
||||
int fd;
|
||||
ssize_t nbytes;
|
||||
FILE* fp;
|
||||
struct mntent* mentry;
|
||||
|
||||
if (g_mounts_state.volumes == NULL) {
|
||||
const int numv = 32;
|
||||
@@ -84,80 +83,20 @@ scan_mounted_volumes()
|
||||
}
|
||||
g_mounts_state.volume_count = 0;
|
||||
|
||||
/* Open and read the file contents.
|
||||
*/
|
||||
fd = open(PROC_MOUNTS_FILENAME, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
goto bail;
|
||||
/* Open and read mount table entries. */
|
||||
fp = setmntent(PROC_MOUNTS_FILENAME, "r");
|
||||
if (fp == NULL) {
|
||||
return -1;
|
||||
}
|
||||
nbytes = read(fd, buf, sizeof(buf) - 1);
|
||||
close(fd);
|
||||
if (nbytes < 0) {
|
||||
goto bail;
|
||||
while ((mentry = getmntent(fp)) != NULL) {
|
||||
MountedVolume* v = &g_mounts_state.volumes[g_mounts_state.volume_count++];
|
||||
v->device = strdup(mentry->mnt_fsname);
|
||||
v->mount_point = strdup(mentry->mnt_dir);
|
||||
v->filesystem = strdup(mentry->mnt_type);
|
||||
v->flags = strdup(mentry->mnt_opts);
|
||||
}
|
||||
buf[nbytes] = '\0';
|
||||
|
||||
/* Parse the contents of the file, which looks like:
|
||||
*
|
||||
* # cat /proc/mounts
|
||||
* rootfs / rootfs rw 0 0
|
||||
* /dev/pts /dev/pts devpts rw 0 0
|
||||
* /proc /proc proc rw 0 0
|
||||
* /sys /sys sysfs rw 0 0
|
||||
* /dev/block/mtdblock4 /system yaffs2 rw,nodev,noatime,nodiratime 0 0
|
||||
* /dev/block/mtdblock5 /data yaffs2 rw,nodev,noatime,nodiratime 0 0
|
||||
* /dev/block/mmcblk0p1 /sdcard vfat rw,sync,dirsync,fmask=0000,dmask=0000,codepage=cp437,iocharset=iso8859-1,utf8 0 0
|
||||
*
|
||||
* The zeroes at the end are dummy placeholder fields to make the
|
||||
* output match Linux's /etc/mtab, but don't represent anything here.
|
||||
*/
|
||||
bufp = buf;
|
||||
while (nbytes > 0) {
|
||||
char device[64];
|
||||
char mount_point[64];
|
||||
char filesystem[64];
|
||||
char flags[128];
|
||||
int matches;
|
||||
|
||||
/* %as is a gnu extension that malloc()s a string for each field.
|
||||
*/
|
||||
matches = sscanf(bufp, "%63s %63s %63s %127s",
|
||||
device, mount_point, filesystem, flags);
|
||||
|
||||
if (matches == 4) {
|
||||
device[sizeof(device)-1] = '\0';
|
||||
mount_point[sizeof(mount_point)-1] = '\0';
|
||||
filesystem[sizeof(filesystem)-1] = '\0';
|
||||
flags[sizeof(flags)-1] = '\0';
|
||||
|
||||
MountedVolume *v =
|
||||
&g_mounts_state.volumes[g_mounts_state.volume_count++];
|
||||
v->device = strdup(device);
|
||||
v->mount_point = strdup(mount_point);
|
||||
v->filesystem = strdup(filesystem);
|
||||
v->flags = strdup(flags);
|
||||
} else {
|
||||
printf("matches was %d on <<%.40s>>\n", matches, bufp);
|
||||
}
|
||||
|
||||
/* Eat the line.
|
||||
*/
|
||||
while (nbytes > 0 && *bufp != '\n') {
|
||||
bufp++;
|
||||
nbytes--;
|
||||
}
|
||||
if (nbytes > 0) {
|
||||
bufp++;
|
||||
nbytes--;
|
||||
}
|
||||
}
|
||||
|
||||
endmntent(fp);
|
||||
return 0;
|
||||
|
||||
bail:
|
||||
//TODO: free the strings we've allocated.
|
||||
g_mounts_state.volume_count = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
const MountedVolume *
|
||||
|
||||
+26
-21
@@ -105,7 +105,7 @@ mtd_scan_partitions()
|
||||
if (fd < 0) {
|
||||
goto bail;
|
||||
}
|
||||
nbytes = read(fd, buf, sizeof(buf) - 1);
|
||||
nbytes = TEMP_FAILURE_RETRY(read(fd, buf, sizeof(buf) - 1));
|
||||
close(fd);
|
||||
if (nbytes < 0) {
|
||||
goto bail;
|
||||
@@ -276,12 +276,6 @@ MtdReadContext *mtd_read_partition(const MtdPartition *partition)
|
||||
return ctx;
|
||||
}
|
||||
|
||||
// Seeks to a location in the partition. Don't mix with reads of
|
||||
// anything other than whole blocks; unpredictable things will result.
|
||||
void mtd_read_skip_to(const MtdReadContext* ctx, size_t offset) {
|
||||
lseek64(ctx->fd, offset, SEEK_SET);
|
||||
}
|
||||
|
||||
static int read_block(const MtdPartition *partition, int fd, char *data)
|
||||
{
|
||||
struct mtd_ecc_stats before, after;
|
||||
@@ -290,13 +284,18 @@ static int read_block(const MtdPartition *partition, int fd, char *data)
|
||||
return -1;
|
||||
}
|
||||
|
||||
loff_t pos = lseek64(fd, 0, SEEK_CUR);
|
||||
loff_t pos = TEMP_FAILURE_RETRY(lseek64(fd, 0, SEEK_CUR));
|
||||
if (pos == -1) {
|
||||
printf("mtd: read_block: couldn't SEEK_CUR: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t size = partition->erase_size;
|
||||
int mgbb;
|
||||
|
||||
while (pos + size <= (int) partition->size) {
|
||||
if (lseek64(fd, pos, SEEK_SET) != pos || read(fd, data, size) != size) {
|
||||
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));
|
||||
} else if (ioctl(fd, ECCGETSTATS, &after)) {
|
||||
@@ -310,8 +309,8 @@ static int read_block(const MtdPartition *partition, int fd, char *data)
|
||||
memcpy(&before, &after, sizeof(struct mtd_ecc_stats));
|
||||
} else if ((mgbb = ioctl(fd, MEMGETBADBLOCK, &pos))) {
|
||||
fprintf(stderr,
|
||||
"mtd: MEMGETBADBLOCK returned %d at 0x%08llx (errno=%d)\n",
|
||||
mgbb, pos, errno);
|
||||
"mtd: MEMGETBADBLOCK returned %d at 0x%08llx: %s\n",
|
||||
mgbb, pos, strerror(errno));
|
||||
} else {
|
||||
return 0; // Success!
|
||||
}
|
||||
@@ -406,8 +405,11 @@ static int write_block(MtdWriteContext *ctx, const char *data)
|
||||
const MtdPartition *partition = ctx->partition;
|
||||
int fd = ctx->fd;
|
||||
|
||||
off_t pos = lseek(fd, 0, SEEK_CUR);
|
||||
if (pos == (off_t) -1) return 1;
|
||||
off_t pos = TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_CUR));
|
||||
if (pos == (off_t) -1) {
|
||||
printf("mtd: write_block: couldn't SEEK_CUR: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t size = partition->erase_size;
|
||||
while (pos + size <= (int) partition->size) {
|
||||
@@ -416,8 +418,8 @@ static int write_block(MtdWriteContext *ctx, const char *data)
|
||||
if (ret != 0 && !(ret == -1 && errno == EOPNOTSUPP)) {
|
||||
add_bad_block_offset(ctx, pos);
|
||||
fprintf(stderr,
|
||||
"mtd: not writing bad block at 0x%08lx (ret %d errno %d)\n",
|
||||
pos, ret, errno);
|
||||
"mtd: not writing bad block at 0x%08lx (ret %d): %s\n",
|
||||
pos, ret, strerror(errno));
|
||||
pos += partition->erase_size;
|
||||
continue; // Don't try to erase known factory-bad blocks.
|
||||
}
|
||||
@@ -440,15 +442,15 @@ static int write_block(MtdWriteContext *ctx, const char *data)
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if (lseek(fd, pos, SEEK_SET) != pos ||
|
||||
write(fd, data, size) != size) {
|
||||
if (TEMP_FAILURE_RETRY(lseek(fd, pos, SEEK_SET)) != pos ||
|
||||
TEMP_FAILURE_RETRY(write(fd, data, size)) != size) {
|
||||
printf("mtd: write error at 0x%08lx (%s)\n",
|
||||
pos, strerror(errno));
|
||||
}
|
||||
|
||||
char verify[size];
|
||||
if (lseek(fd, pos, SEEK_SET) != pos ||
|
||||
read(fd, verify, size) != size) {
|
||||
if (TEMP_FAILURE_RETRY(lseek(fd, pos, SEEK_SET)) != pos ||
|
||||
TEMP_FAILURE_RETRY(read(fd, verify, size)) != size) {
|
||||
printf("mtd: re-read error at 0x%08lx (%s)\n",
|
||||
pos, strerror(errno));
|
||||
continue;
|
||||
@@ -522,8 +524,11 @@ off_t mtd_erase_blocks(MtdWriteContext *ctx, int blocks)
|
||||
ctx->stored = 0;
|
||||
}
|
||||
|
||||
off_t pos = lseek(ctx->fd, 0, SEEK_CUR);
|
||||
if ((off_t) pos == (off_t) -1) return pos;
|
||||
off_t pos = TEMP_FAILURE_RETRY(lseek(ctx->fd, 0, SEEK_CUR));
|
||||
if ((off_t) pos == (off_t) -1) {
|
||||
printf("mtd_erase_blocks: couldn't SEEK_CUR: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
const int total = (ctx->partition->size - pos) / ctx->partition->erase_size;
|
||||
if (blocks < 0) blocks = total;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user