diff options
73 files changed, 3476 insertions, 991 deletions
@@ -1344,29 +1344,29 @@ int adb_main(int is_daemon, int server_port) " unchanged.\n"); } + /* add extra groups: + ** AID_ADB to access the USB driver + ** AID_LOG to read system logs (adb logcat) + ** AID_INPUT to diagnose input issues (getevent) + ** AID_INET to diagnose network issues (netcfg, ping) + ** AID_GRAPHICS to access the frame buffer + ** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump) + ** AID_SDCARD_R to allow reading from the SD card + ** AID_SDCARD_RW to allow writing to the SD card + ** AID_NET_BW_STATS to read out qtaguid statistics + */ + gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_GRAPHICS, + AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW, + AID_NET_BW_STATS }; + if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) { + exit(1); + } + /* don't listen on a port (default 5037) if running in secure mode */ /* don't run as root if we are running in secure mode */ if (should_drop_privileges()) { drop_capabilities_bounding_set_if_needed(); - /* add extra groups: - ** AID_ADB to access the USB driver - ** AID_LOG to read system logs (adb logcat) - ** AID_INPUT to diagnose input issues (getevent) - ** AID_INET to diagnose network issues (netcfg, ping) - ** AID_GRAPHICS to access the frame buffer - ** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump) - ** AID_SDCARD_R to allow reading from the SD card - ** AID_SDCARD_RW to allow writing to the SD card - ** AID_NET_BW_STATS to read out qtaguid statistics - */ - gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_GRAPHICS, - AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW, - AID_NET_BW_STATS }; - if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) { - exit(1); - } - /* then switch user and group to "shell" */ if (setgid(AID_SHELL) != 0) { exit(1); diff --git a/adb/framebuffer_service.c b/adb/framebuffer_service.c index fa7fd98dc..8cbe8403c 100644 --- a/adb/framebuffer_service.c +++ b/adb/framebuffer_service.c @@ -61,7 +61,7 @@ void framebuffer_service(int fd, void *cookie) int w, h, f; int fds[2]; - if (pipe(fds) < 0) goto pipefail; + if (pipe2(fds, O_CLOEXEC) < 0) goto pipefail; pid_t pid = fork(); if (pid < 0) goto done; diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c index c7e0ad539..957e5db1c 100755 --- a/adb/usb_vendors.c +++ b/adb/usb_vendors.c @@ -74,6 +74,8 @@ #define VENDOR_ID_GIGABYTE 0x0414 // Gigaset's USB Vendor ID #define VENDOR_ID_GIGASET 0x1E85 +// GIONEE's USB Vendor ID +#define VENDOR_ID_GIONEE 0x271D // Google's USB Vendor ID #define VENDOR_ID_GOOGLE 0x18d1 // Haier's USB Vendor ID @@ -82,6 +84,8 @@ #define VENDOR_ID_HARRIS 0x19A5 // Hisense's USB Vendor ID #define VENDOR_ID_HISENSE 0x109b +// Honeywell's USB Vendor ID +#define VENDOR_ID_HONEYWELL 0x0c2e // HP's USB Vendor ID #define VENDOR_ID_HP 0x03f0 // HTC's USB Vendor ID @@ -158,6 +162,8 @@ #define VENDOR_ID_SHARP 0x04dd // SK Telesys's USB Vendor ID #define VENDOR_ID_SK_TELESYS 0x1F53 +// Smartisan's USB Vendor ID +#define VENDOR_ID_SMARTISAN 0x29a9 // Sony's USB Vendor ID #define VENDOR_ID_SONY 0x054C // Sony Ericsson's USB Vendor ID @@ -210,10 +216,12 @@ int builtInVendorIds[] = { VENDOR_ID_GARMIN_ASUS, VENDOR_ID_GIGABYTE, VENDOR_ID_GIGASET, + VENDOR_ID_GIONEE, VENDOR_ID_GOOGLE, VENDOR_ID_HAIER, VENDOR_ID_HARRIS, VENDOR_ID_HISENSE, + VENDOR_ID_HONEYWELL, VENDOR_ID_HP, VENDOR_ID_HTC, VENDOR_ID_HUAWEI, @@ -252,6 +260,7 @@ int builtInVendorIds[] = { VENDOR_ID_SAMSUNG, VENDOR_ID_SHARP, VENDOR_ID_SK_TELESYS, + VENDOR_ID_SMARTISAN, VENDOR_ID_SONY, VENDOR_ID_SONY_ERICSSON, VENDOR_ID_T_AND_A, diff --git a/charger/charger.c b/charger/charger.c index e3cadb1dd..15add87d0 100644 --- a/charger/charger.c +++ b/charger/charger.c @@ -40,6 +40,7 @@ #include <cutils/list.h> #include <cutils/misc.h> #include <cutils/uevent.h> +#include <cutils/properties.h> #ifdef CHARGER_ENABLE_SUSPEND #include <suspend/autosuspend.h> @@ -830,8 +831,16 @@ static void process_key(struct charger *charger, int code, int64_t now) if (key->down) { int64_t reboot_timeout = key->timestamp + POWER_ON_KEY_TIME; if (now >= reboot_timeout) { - LOGI("[%lld] rebooting\n", now); - android_reboot(ANDROID_RB_RESTART, 0, 0); + /* We do not currently support booting from charger mode on + all devices. Check the property and continue booting or reboot + accordingly. */ + if (property_get_bool("ro.enable_boot_charger_mode", false)) { + LOGI("[%lld] booting from charger mode\n", now); + property_set("sys.boot_from_charger_mode", "1"); + } else { + LOGI("[%lld] rebooting\n", now); + android_reboot(ANDROID_RB_RESTART, 0, 0); + } } else { /* if the key is pressed but timeout hasn't expired, * make sure we wake up at the right-ish time to check diff --git a/debuggerd/arm/machine.cpp b/debuggerd/arm/machine.cpp index fd2f69b60..839d47a8c 100644 --- a/debuggerd/arm/machine.cpp +++ b/debuggerd/arm/machine.cpp @@ -40,57 +40,55 @@ // If configured to do so, dump memory around *all* registers // for the crashing thread. -void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) { +void dump_memory_and_code(log_t* log, pid_t tid) { struct pt_regs regs; if (ptrace(PTRACE_GETREGS, tid, 0, ®s)) { return; } - if (IS_AT_FAULT(scope_flags) && DUMP_MEMORY_FOR_ALL_REGISTERS) { - static const char REG_NAMES[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp"; + static const char REG_NAMES[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp"; - for (int reg = 0; reg < 14; reg++) { - // this may not be a valid way to access, but it'll do for now - uintptr_t addr = regs.uregs[reg]; + for (int reg = 0; reg < 14; reg++) { + // this may not be a valid way to access, but it'll do for now + uintptr_t addr = regs.uregs[reg]; - // Don't bother if it looks like a small int or ~= null, or if - // it's in the kernel area. - if (addr < 4096 || addr >= 0xc0000000) { - continue; - } - - _LOG(log, scope_flags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]); - dump_memory(log, tid, addr, scope_flags | SCOPE_SENSITIVE); + // Don't bother if it looks like a small int or ~= null, or if + // it's in the kernel area. + if (addr < 4096 || addr >= 0xc0000000) { + continue; } + + _LOG(log, logtype::MEMORY, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]); + dump_memory(log, tid, addr); } // explicitly allow upload of code dump logging - _LOG(log, scope_flags, "\ncode around pc:\n"); - dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_pc), scope_flags); + _LOG(log, logtype::MEMORY, "\ncode around pc:\n"); + dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_pc)); if (regs.ARM_pc != regs.ARM_lr) { - _LOG(log, scope_flags, "\ncode around lr:\n"); - dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_lr), scope_flags); + _LOG(log, logtype::MEMORY, "\ncode around lr:\n"); + dump_memory(log, tid, static_cast<uintptr_t>(regs.ARM_lr)); } } -void dump_registers(log_t* log, pid_t tid, int scope_flags) { +void dump_registers(log_t* log, pid_t tid) { struct pt_regs r; if (ptrace(PTRACE_GETREGS, tid, 0, &r)) { - _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno)); + _LOG(log, logtype::REGISTERS, "cannot get registers: %s\n", strerror(errno)); return; } - _LOG(log, scope_flags, " r0 %08x r1 %08x r2 %08x r3 %08x\n", + _LOG(log, logtype::REGISTERS, " r0 %08x r1 %08x r2 %08x r3 %08x\n", static_cast<uint32_t>(r.ARM_r0), static_cast<uint32_t>(r.ARM_r1), static_cast<uint32_t>(r.ARM_r2), static_cast<uint32_t>(r.ARM_r3)); - _LOG(log, scope_flags, " r4 %08x r5 %08x r6 %08x r7 %08x\n", + _LOG(log, logtype::REGISTERS, " r4 %08x r5 %08x r6 %08x r7 %08x\n", static_cast<uint32_t>(r.ARM_r4), static_cast<uint32_t>(r.ARM_r5), static_cast<uint32_t>(r.ARM_r6), static_cast<uint32_t>(r.ARM_r7)); - _LOG(log, scope_flags, " r8 %08x r9 %08x sl %08x fp %08x\n", + _LOG(log, logtype::REGISTERS, " r8 %08x r9 %08x sl %08x fp %08x\n", static_cast<uint32_t>(r.ARM_r8), static_cast<uint32_t>(r.ARM_r9), static_cast<uint32_t>(r.ARM_r10), static_cast<uint32_t>(r.ARM_fp)); - _LOG(log, scope_flags, " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n", + _LOG(log, logtype::REGISTERS, " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n", static_cast<uint32_t>(r.ARM_ip), static_cast<uint32_t>(r.ARM_sp), static_cast<uint32_t>(r.ARM_lr), static_cast<uint32_t>(r.ARM_pc), static_cast<uint32_t>(r.ARM_cpsr)); @@ -100,14 +98,14 @@ void dump_registers(log_t* log, pid_t tid, int scope_flags) { int i; if (ptrace(PTRACE_GETVFPREGS, tid, 0, &vfp_regs)) { - _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno)); + _LOG(log, logtype::REGISTERS, "cannot get registers: %s\n", strerror(errno)); return; } for (i = 0; i < NUM_VFP_REGS; i += 2) { - _LOG(log, scope_flags, " d%-2d %016llx d%-2d %016llx\n", + _LOG(log, logtype::REGISTERS, " d%-2d %016llx d%-2d %016llx\n", i, vfp_regs.fpregs[i], i+1, vfp_regs.fpregs[i+1]); } - _LOG(log, scope_flags, " scr %08lx\n", vfp_regs.fpscr); + _LOG(log, logtype::REGISTERS, " scr %08lx\n", vfp_regs.fpscr); #endif } diff --git a/debuggerd/arm64/machine.cpp b/debuggerd/arm64/machine.cpp index 2413d5e5a..48308c3e7 100644 --- a/debuggerd/arm64/machine.cpp +++ b/debuggerd/arm64/machine.cpp @@ -37,68 +37,66 @@ * If configured to do so, dump memory around *all* registers * for the crashing thread. */ -void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) { +void dump_memory_and_code(log_t* log, pid_t tid) { struct user_pt_regs regs; struct iovec io; io.iov_base = ®s; io.iov_len = sizeof(regs); if (ptrace(PTRACE_GETREGSET, tid, (void*)NT_PRSTATUS, &io) == -1) { - _LOG(log, scope_flags, "%s: ptrace failed to get registers: %s\n", + _LOG(log, logtype::ERROR, "%s: ptrace failed to get registers: %s\n", __func__, strerror(errno)); return; } - if (IS_AT_FAULT(scope_flags) && DUMP_MEMORY_FOR_ALL_REGISTERS) { - for (int reg = 0; reg < 31; reg++) { - uintptr_t addr = regs.regs[reg]; + for (int reg = 0; reg < 31; reg++) { + uintptr_t addr = regs.regs[reg]; - /* - * Don't bother if it looks like a small int or ~= null, or if - * it's in the kernel area. - */ - if (addr < 4096 || addr >= (1UL<<63)) { - continue; - } - - _LOG(log, scope_flags | SCOPE_SENSITIVE, "\nmemory near x%d:\n", reg); - dump_memory(log, tid, addr, scope_flags | SCOPE_SENSITIVE); + /* + * Don't bother if it looks like a small int or ~= null, or if + * it's in the kernel area. + */ + if (addr < 4096 || addr >= (1UL<<63)) { + continue; } + + _LOG(log, logtype::MEMORY, "\nmemory near x%d:\n", reg); + dump_memory(log, tid, addr); } - _LOG(log, scope_flags, "\ncode around pc:\n"); - dump_memory(log, tid, (uintptr_t)regs.pc, scope_flags); + _LOG(log, logtype::MEMORY, "\ncode around pc:\n"); + dump_memory(log, tid, (uintptr_t)regs.pc); if (regs.pc != regs.sp) { - _LOG(log, scope_flags, "\ncode around sp:\n"); - dump_memory(log, tid, (uintptr_t)regs.sp, scope_flags); + _LOG(log, logtype::MEMORY, "\ncode around sp:\n"); + dump_memory(log, tid, (uintptr_t)regs.sp); } } -void dump_registers(log_t* log, pid_t tid, int scope_flags) -{ +void dump_registers(log_t* log, pid_t tid) { struct user_pt_regs r; struct iovec io; io.iov_base = &r; io.iov_len = sizeof(r); if (ptrace(PTRACE_GETREGSET, tid, (void*) NT_PRSTATUS, (void*) &io) == -1) { - _LOG(log, scope_flags, "ptrace error: %s\n", strerror(errno)); + _LOG(log, logtype::ERROR, "ptrace error: %s\n", strerror(errno)); return; } for (int i = 0; i < 28; i += 4) { - _LOG(log, scope_flags, " x%-2d %016lx x%-2d %016lx x%-2d %016lx x%-2d %016lx\n", + _LOG(log, logtype::REGISTERS, + " x%-2d %016lx x%-2d %016lx x%-2d %016lx x%-2d %016lx\n", i, (uint64_t)r.regs[i], i+1, (uint64_t)r.regs[i+1], i+2, (uint64_t)r.regs[i+2], i+3, (uint64_t)r.regs[i+3]); } - _LOG(log, scope_flags, " x28 %016lx x29 %016lx x30 %016lx\n", + _LOG(log, logtype::REGISTERS, " x28 %016lx x29 %016lx x30 %016lx\n", (uint64_t)r.regs[28], (uint64_t)r.regs[29], (uint64_t)r.regs[30]); - _LOG(log, scope_flags, " sp %016lx pc %016lx\n", + _LOG(log, logtype::REGISTERS, " sp %016lx pc %016lx\n", (uint64_t)r.sp, (uint64_t)r.pc); @@ -107,12 +105,12 @@ void dump_registers(log_t* log, pid_t tid, int scope_flags) io.iov_len = sizeof(f); if (ptrace(PTRACE_GETREGSET, tid, (void*) NT_PRFPREG, (void*) &io) == -1) { - _LOG(log, scope_flags, "ptrace error: %s\n", strerror(errno)); + _LOG(log, logtype::ERROR, "ptrace error: %s\n", strerror(errno)); return; } for (int i = 0; i < 32; i += 4) { - _LOG(log, scope_flags, " v%-2d %016lx v%-2d %016lx v%-2d %016lx v%-2d %016lx\n", + _LOG(log, logtype::REGISTERS, " v%-2d %016lx v%-2d %016lx v%-2d %016lx v%-2d %016lx\n", i, (uint64_t)f.vregs[i], i+1, (uint64_t)f.vregs[i+1], i+2, (uint64_t)f.vregs[i+2], diff --git a/debuggerd/backtrace.cpp b/debuggerd/backtrace.cpp index d3883485c..c4a2143cf 100644 --- a/debuggerd/backtrace.cpp +++ b/debuggerd/backtrace.cpp @@ -30,6 +30,7 @@ #include <UniquePtr.h> #include "backtrace.h" + #include "utility.h" static void dump_process_header(log_t* log, pid_t pid) { @@ -48,16 +49,17 @@ static void dump_process_header(log_t* log, pid_t pid) { struct tm tm; localtime_r(&t, &tm); char timestr[64]; + _LOG(log, logtype::BACKTRACE, "\n\nABI: '%s'\n", ABI_STRING); strftime(timestr, sizeof(timestr), "%F %T", &tm); - _LOG(log, SCOPE_AT_FAULT, "\n\n----- pid %d at %s -----\n", pid, timestr); + _LOG(log, logtype::BACKTRACE, "\n----- pid %d at %s -----\n", pid, timestr); if (procname) { - _LOG(log, SCOPE_AT_FAULT, "Cmd line: %s\n", procname); + _LOG(log, logtype::BACKTRACE, "Cmd line: %s\n", procname); } } static void dump_process_footer(log_t* log, pid_t pid) { - _LOG(log, SCOPE_AT_FAULT, "\n----- end %d -----\n", pid); + _LOG(log, logtype::BACKTRACE, "\n----- end %d -----\n", pid); } static void dump_thread( @@ -79,10 +81,10 @@ static void dump_thread( } } - _LOG(log, SCOPE_AT_FAULT, "\n\"%s\" sysTid=%d\n", threadname ? threadname : "<unknown>", tid); + _LOG(log, logtype::BACKTRACE, "\n\"%s\" sysTid=%d\n", threadname ? threadname : "<unknown>", tid); if (!attached && ptrace(PTRACE_ATTACH, tid, 0, 0) < 0) { - _LOG(log, SCOPE_AT_FAULT, "Could not attach to thread: %s\n", strerror(errno)); + _LOG(log, logtype::BACKTRACE, "Could not attach to thread: %s\n", strerror(errno)); return; } @@ -90,11 +92,11 @@ static void dump_thread( UniquePtr<Backtrace> backtrace(Backtrace::Create(tid, BACKTRACE_CURRENT_THREAD)); if (backtrace->Unwind(0)) { - dump_backtrace_to_log(backtrace.get(), log, SCOPE_AT_FAULT, " "); + dump_backtrace_to_log(backtrace.get(), log, " "); } if (!attached && ptrace(PTRACE_DETACH, tid, 0, 0) != 0) { - LOG("ptrace detach from %d failed: %s\n", tid, strerror(errno)); + _LOG(log, logtype::ERROR, "ptrace detach from %d failed: %s\n", tid, strerror(errno)); *detach_failed = true; } } @@ -104,7 +106,6 @@ void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed, log_t log; log.tfd = fd; log.amfd = amfd; - log.quiet = true; dump_process_header(&log, pid); dump_thread(&log, tid, true, detach_failed, total_sleep_time_usec); @@ -133,9 +134,8 @@ void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed, dump_process_footer(&log, pid); } -void dump_backtrace_to_log(Backtrace* backtrace, log_t* log, - int scope_flags, const char* prefix) { +void dump_backtrace_to_log(Backtrace* backtrace, log_t* log, const char* prefix) { for (size_t i = 0; i < backtrace->NumFrames(); i++) { - _LOG(log, scope_flags, "%s%s\n", prefix, backtrace->FormatFrameData(i).c_str()); + _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, backtrace->FormatFrameData(i).c_str()); } } diff --git a/debuggerd/backtrace.h b/debuggerd/backtrace.h index 2ec8afb40..da14cd466 100644 --- a/debuggerd/backtrace.h +++ b/debuggerd/backtrace.h @@ -29,7 +29,6 @@ void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed, int* total_sleep_time_usec); /* Dumps the backtrace in the backtrace data structure to the log. */ -void dump_backtrace_to_log(Backtrace* backtrace, log_t* log, - int scope_flags, const char* prefix); +void dump_backtrace_to_log(Backtrace* backtrace, log_t* log, const char* prefix); #endif // _DEBUGGERD_BACKTRACE_H diff --git a/debuggerd/crasher.c b/debuggerd/crasher.c index 4721da9cf..e11d9af7f 100644 --- a/debuggerd/crasher.c +++ b/debuggerd/crasher.c @@ -110,12 +110,19 @@ static void abuse_heap() { free((void*) buf); // GCC is smart enough to warn about this, but we're doing it deliberately. } +static void sigsegv_non_null() { + int* a = (int *)(&do_action); + *a = 42; +} + static int do_action(const char* arg) { fprintf(stderr,"crasher: init pid=%d tid=%d\n", getpid(), gettid()); if (!strncmp(arg, "thread-", strlen("thread-"))) { return do_action_on_thread(arg + strlen("thread-")); + } else if (!strcmp(arg, "SIGSEGV-non-null")) { + sigsegv_non_null(); } else if (!strcmp(arg, "smash-stack")) { return smash_stack(42); } else if (!strcmp(arg, "stack-overflow")) { @@ -166,7 +173,8 @@ static int do_action(const char* arg) fprintf(stderr, " LOG_ALWAYS_FATAL call LOG_ALWAYS_FATAL\n"); fprintf(stderr, " LOG_ALWAYS_FATAL_IF call LOG_ALWAYS_FATAL\n"); fprintf(stderr, " SIGPIPE cause a SIGPIPE\n"); - fprintf(stderr, " SIGSEGV cause a SIGSEGV (synonym: crash)\n"); + fprintf(stderr, " SIGSEGV cause a SIGSEGV at address 0x0 (synonym: crash)\n"); + fprintf(stderr, " SIGSEGV-non-null cause a SIGSEGV at a non-zero address\n"); fprintf(stderr, " SIGTRAP cause a SIGTRAP\n"); fprintf(stderr, "prefix any of the above with 'thread-' to not run\n"); fprintf(stderr, "on the process' main thread.\n"); diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp index 3726c3872..fc13977b0 100644 --- a/debuggerd/debuggerd.cpp +++ b/debuggerd/debuggerd.cpp @@ -30,7 +30,6 @@ #include <sys/stat.h> #include <sys/poll.h> -#include <log/logd.h> #include <log/logger.h> #include <cutils/sockets.h> @@ -62,34 +61,24 @@ static void wait_for_user_action(pid_t pid) { char exe[PATH_MAX]; int count; if ((count = readlink(path, exe, sizeof(exe) - 1)) == -1) { - LOG("readlink('%s') failed: %s", path, strerror(errno)); + ALOGE("readlink('%s') failed: %s", path, strerror(errno)); strlcpy(exe, "unknown", sizeof(exe)); } else { exe[count] = '\0'; } - // Turn "/system/bin/app_process" into "app_process". - // gdbserver doesn't cope with full paths (though we should fix that - // and remove this). - char* name = strrchr(exe, '/'); - if (name == NULL) { - name = exe; // No '/' found. - } else { - ++name; // Skip the '/'. - } - // Explain how to attach the debugger. - LOG( "********************************************************\n" - "* Process %d has been suspended while crashing.\n" - "* To attach gdbserver for a gdb connection on port 5039\n" - "* and start gdbclient:\n" - "*\n" - "* gdbclient %s :5039 %d\n" - "*\n" - "* Wait for gdb to start, then press the VOLUME DOWN key\n" - "* to let the process continue crashing.\n" - "********************************************************\n", - pid, name, pid); + ALOGI("********************************************************\n" + "* Process %d has been suspended while crashing.\n" + "* To attach gdbserver for a gdb connection on port 5039\n" + "* and start gdbclient:\n" + "*\n" + "* gdbclient %s :5039 %d\n" + "*\n" + "* Wait for gdb to start, then press the VOLUME DOWN key\n" + "* to let the process continue crashing.\n" + "********************************************************\n", + pid, exe, pid); // Wait for VOLUME DOWN. if (init_getevent() == 0) { @@ -104,7 +93,7 @@ static void wait_for_user_action(pid_t pid) { uninit_getevent(); } - LOG("debuggerd resuming process %d", pid); + ALOGI("debuggerd resuming process %d", pid); } static int get_process_info(pid_t tid, pid_t* out_pid, uid_t* out_uid, uid_t* out_gid) { @@ -140,11 +129,11 @@ static int read_request(int fd, debugger_request_t* out_request) { socklen_t len = sizeof(cr); int status = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &len); if (status != 0) { - LOG("cannot get credentials\n"); + ALOGE("cannot get credentials\n"); return -1; } - XLOG("reading tid\n"); + ALOGV("reading tid\n"); fcntl(fd, F_SETFL, O_NONBLOCK); pollfd pollfds[1]; @@ -153,7 +142,7 @@ static int read_request(int fd, debugger_request_t* out_request) { pollfds[0].revents = 0; status = TEMP_FAILURE_RETRY(poll(pollfds, 1, 3000)); if (status != 1) { - LOG("timed out reading tid (from pid=%d uid=%d)\n", cr.pid, cr.uid); + ALOGE("timed out reading tid (from pid=%d uid=%d)\n", cr.pid, cr.uid); return -1; } @@ -161,14 +150,11 @@ static int read_request(int fd, debugger_request_t* out_request) { memset(&msg, 0, sizeof(msg)); status = TEMP_FAILURE_RETRY(read(fd, &msg, sizeof(msg))); if (status < 0) { - LOG("read failure? %s (pid=%d uid=%d)\n", strerror(errno), cr.pid, cr.uid); + ALOGE("read failure? %s (pid=%d uid=%d)\n", strerror(errno), cr.pid, cr.uid); return -1; } - if (status == sizeof(debugger_msg_t)) { - XLOG("crash request of size %d abort_msg_address=0x%" PRIPTR "\n", - status, msg.abort_msg_address); - } else { - LOG("invalid crash request of size %d (from pid=%d uid=%d)\n", status, cr.pid, cr.uid); + if (status != sizeof(debugger_msg_t)) { + ALOGE("invalid crash request of size %d (from pid=%d uid=%d)\n", status, cr.pid, cr.uid); return -1; } @@ -186,7 +172,7 @@ static int read_request(int fd, debugger_request_t* out_request) { struct stat s; snprintf(buf, sizeof buf, "/proc/%d/task/%d", out_request->pid, out_request->tid); if (stat(buf, &s)) { - LOG("tid %d does not exist in pid %d. ignoring debug request\n", + ALOGE("tid %d does not exist in pid %d. ignoring debug request\n", out_request->tid, out_request->pid); return -1; } @@ -197,7 +183,7 @@ static int read_request(int fd, debugger_request_t* out_request) { status = get_process_info(out_request->tid, &out_request->pid, &out_request->uid, &out_request->gid); if (status < 0) { - LOG("tid %d does not exist. ignoring explicit dump request\n", out_request->tid); + ALOGE("tid %d does not exist. ignoring explicit dump request\n", out_request->tid); return -1; } } else { @@ -218,13 +204,13 @@ static bool should_attach_gdb(debugger_request_t* request) { } static void handle_request(int fd) { - XLOG("handle_request(%d)\n", fd); + ALOGV("handle_request(%d)\n", fd); debugger_request_t request; memset(&request, 0, sizeof(request)); int status = read_request(fd, &request); if (!status) { - XLOG("BOOM: pid=%d uid=%d gid=%d tid=%d\n", + ALOGV("BOOM: pid=%d uid=%d gid=%d tid=%d\n", request.pid, request.uid, request.gid, request.tid); // At this point, the thread that made the request is blocked in @@ -238,12 +224,12 @@ static void handle_request(int fd) { // See details in bionic/libc/linker/debugger.c, in function // debugger_signal_handler(). if (ptrace(PTRACE_ATTACH, request.tid, 0, 0)) { - LOG("ptrace attach failed: %s\n", strerror(errno)); + ALOGE("ptrace attach failed: %s\n", strerror(errno)); } else { bool detach_failed = false; bool attach_gdb = should_attach_gdb(&request); if (TEMP_FAILURE_RETRY(write(fd, "\0", 1)) != 1) { - LOG("failed responding to client: %s\n", strerror(errno)); + ALOGE("failed responding to client: %s\n", strerror(errno)); } else { char* tombstone_path = NULL; @@ -262,20 +248,20 @@ static void handle_request(int fd) { switch (signal) { case SIGSTOP: if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) { - XLOG("stopped -- dumping to tombstone\n"); + ALOGV("stopped -- dumping to tombstone\n"); tombstone_path = engrave_tombstone(request.pid, request.tid, signal, request.original_si_code, - request.abort_msg_address, true, true, + request.abort_msg_address, true, &detach_failed, &total_sleep_time_usec); } else if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE) { - XLOG("stopped -- dumping to fd\n"); + ALOGV("stopped -- dumping to fd\n"); dump_backtrace(fd, -1, request.pid, request.tid, &detach_failed, &total_sleep_time_usec); } else { - XLOG("stopped -- continuing\n"); + ALOGV("stopped -- continuing\n"); status = ptrace(PTRACE_CONT, request.tid, 0, 0); if (status) { - LOG("ptrace continue failed: %s\n", strerror(errno)); + ALOGE("ptrace continue failed: %s\n", strerror(errno)); } continue; // loop again } @@ -291,7 +277,7 @@ static void handle_request(int fd) { case SIGSTKFLT: #endif case SIGTRAP: - XLOG("stopped -- fatal signal\n"); + ALOGV("stopped -- fatal signal\n"); // Send a SIGSTOP to the process to make all of // the non-signaled threads stop moving. Without // this we get a lot of "ptrace detach failed: @@ -301,13 +287,12 @@ static void handle_request(int fd) { // makes the process less reliable, apparently... tombstone_path = engrave_tombstone(request.pid, request.tid, signal, request.original_si_code, - request.abort_msg_address, !attach_gdb, false, + request.abort_msg_address, !attach_gdb, &detach_failed, &total_sleep_time_usec); break; default: - XLOG("stopped -- unexpected signal\n"); - LOG("process stopped due to unexpected signal %d\n", signal); + ALOGE("process stopped due to unexpected signal %d\n", signal); break; } break; @@ -323,14 +308,14 @@ static void handle_request(int fd) { free(tombstone_path); } - XLOG("detaching\n"); + ALOGV("detaching\n"); if (attach_gdb) { // stop the process so we can debug kill(request.pid, SIGSTOP); // detach so we can attach gdbserver if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) { - LOG("ptrace detach from %d failed: %s\n", request.tid, strerror(errno)); + ALOGE("ptrace detach from %d failed: %s\n", request.tid, strerror(errno)); detach_failed = true; } @@ -342,7 +327,7 @@ static void handle_request(int fd) { } else { // just detach if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) { - LOG("ptrace detach from %d failed: %s\n", request.tid, strerror(errno)); + ALOGE("ptrace detach from %d failed: %s\n", request.tid, strerror(errno)); detach_failed = true; } } @@ -354,7 +339,7 @@ static void handle_request(int fd) { // actual parent won't receive a death notification via wait(2). At this point // there's not much we can do about that. if (detach_failed) { - LOG("debuggerd committing suicide to free the zombie!\n"); + ALOGE("debuggerd committing suicide to free the zombie!\n"); kill(getpid(), SIGKILL); } } @@ -400,16 +385,16 @@ static int do_server() { return 1; fcntl(s, F_SETFD, FD_CLOEXEC); - LOG("debuggerd: " __DATE__ " " __TIME__ "\n"); + ALOGI("debuggerd: " __DATE__ " " __TIME__ "\n"); for (;;) { sockaddr addr; socklen_t alen = sizeof(addr); - XLOG("waiting for connection\n"); + ALOGV("waiting for connection\n"); int fd = accept(s, &addr, &alen); if (fd < 0) { - XLOG("accept failed: %s\n", strerror(errno)); + ALOGV("accept failed: %s\n", strerror(errno)); continue; } diff --git a/debuggerd/machine.h b/debuggerd/machine.h index 2f1e2011b..fca9fbed8 100644 --- a/debuggerd/machine.h +++ b/debuggerd/machine.h @@ -21,7 +21,7 @@ #include "utility.h" -void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags); -void dump_registers(log_t* log, pid_t tid, int scope_flags); +void dump_memory_and_code(log_t* log, pid_t tid); +void dump_registers(log_t* log, pid_t tid); #endif // _DEBUGGERD_MACHINE_H diff --git a/debuggerd/mips/machine.cpp b/debuggerd/mips/machine.cpp index 5c82d4dbe..97834c7fd 100644 --- a/debuggerd/mips/machine.cpp +++ b/debuggerd/mips/machine.cpp @@ -27,9 +27,6 @@ #include "../utility.h" #include "../machine.h" -// enable to dump memory pointed to by every register -#define DUMP_MEMORY_FOR_ALL_REGISTERS 1 - #define R(x) (static_cast<unsigned int>(x)) // The MIPS uapi ptrace.h has the wrong definition for pt_regs. PTRACE_GETREGS @@ -46,72 +43,70 @@ struct pt_regs_mips_t { // If configured to do so, dump memory around *all* registers // for the crashing thread. -void dump_memory_and_code(log_t* log, pid_t tid, int scope_flags) { +void dump_memory_and_code(log_t* log, pid_t tid) { pt_regs_mips_t r; if (ptrace(PTRACE_GETREGS, tid, 0, &r)) { return; } - if (IS_AT_FAULT(scope_flags) && DUMP_MEMORY_FOR_ALL_REGISTERS) { - static const char REG_NAMES[] = "$0atv0v1a0a1a2a3t0t1t2t3t4t5t6t7s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra"; - - for (int reg = 0; reg < 32; reg++) { - // skip uninteresting registers - if (reg == 0 // $0 - || reg == 26 // $k0 - || reg == 27 // $k1 - || reg == 31 // $ra (done below) - ) - continue; + static const char REG_NAMES[] = "$0atv0v1a0a1a2a3t0t1t2t3t4t5t6t7s0s1s2s3s4s5s6s7t8t9k0k1gpsps8ra"; - uintptr_t addr = R(r.regs[reg]); + for (int reg = 0; reg < 32; reg++) { + // skip uninteresting registers + if (reg == 0 // $0 + || reg == 26 // $k0 + || reg == 27 // $k1 + || reg == 31 // $ra (done below) + ) + continue; - // Don't bother if it looks like a small int or ~= null, or if - // it's in the kernel area. - if (addr < 4096 || addr >= 0x80000000) { - continue; - } + uintptr_t addr = R(r.regs[reg]); - _LOG(log, scope_flags | SCOPE_SENSITIVE, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]); - dump_memory(log, tid, addr, scope_flags | SCOPE_SENSITIVE); + // Don't bother if it looks like a small int or ~= null, or if + // it's in the kernel area. + if (addr < 4096 || addr >= 0x80000000) { + continue; } + + _LOG(log, logtype::MEMORY, "\nmemory near %.2s:\n", ®_NAMES[reg * 2]); + dump_memory(log, tid, addr); } unsigned int pc = R(r.cp0_epc); unsigned int ra = R(r.regs[31]); - _LOG(log, scope_flags, "\ncode around pc:\n"); - dump_memory(log, tid, (uintptr_t)pc, scope_flags); + _LOG(log, logtype::MEMORY, "\ncode around pc:\n"); + dump_memory(log, tid, (uintptr_t)pc); if (pc != ra) { - _LOG(log, scope_flags, "\ncode around ra:\n"); - dump_memory(log, tid, (uintptr_t)ra, scope_flags); + _LOG(log, logtype::MEMORY, "\ncode around ra:\n"); + dump_memory(log, tid, (uintptr_t)ra); } } -void dump_registers(log_t* log, pid_t tid, int scope_flags) { +void dump_registers(log_t* log, pid_t tid) { pt_regs_mips_t r; if(ptrace(PTRACE_GETREGS, tid, 0, &r)) { - _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno)); + _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno)); return; } - _LOG(log, scope_flags, " zr %08x at %08x v0 %08x v1 %08x\n", + _LOG(log, logtype::REGISTERS, " zr %08x at %08x v0 %08x v1 %08x\n", R(r.regs[0]), R(r.regs[1]), R(r.regs[2]), R(r.regs[3])); - _LOG(log, scope_flags, " a0 %08x a1 %08x a2 %08x a3 %08x\n", + _LOG(log, logtype::REGISTERS, " a0 %08x a1 %08x a2 %08x a3 %08x\n", R(r.regs[4]), R(r.regs[5]), R(r.regs[6]), R(r.regs[7])); - _LOG(log, scope_flags, " t0 %08x t1 %08x t2 %08x t3 %08x\n", + _LOG(log, logtype::REGISTERS, " t0 %08x t1 %08x t2 %08x t3 %08x\n", R(r.regs[8]), R(r.regs[9]), R(r.regs[10]), R(r.regs[11])); - _LOG(log, scope_flags, " t4 %08x t5 %08x t6 %08x t7 %08x\n", + _LOG(log, logtype::REGISTERS, " t4 %08x t5 %08x t6 %08x t7 %08x\n", R(r.regs[12]), R(r.regs[13]), R(r.regs[14]), R(r.regs[15])); - _LOG(log, scope_flags, " s0 %08x s1 %08x s2 %08x s3 %08x\n", + _LOG(log, logtype::REGISTERS, " s0 %08x s1 %08x s2 %08x s3 %08x\n", R(r.regs[16]), R(r.regs[17]), R(r.regs[18]), R(r.regs[19])); - _LOG(log, scope_flags, " s4 %08x s5 %08x s6 %08x s7 %08x\n", + _LOG(log, logtype::REGISTERS, " s4 %08x s5 %08x s6 %08x s7 %08x\n", R(r.regs[20]), R(r.regs[21]), R(r.regs[22]), R(r.regs[23])); - _LOG(log, scope_flags, " t8 %08x t9 %08x k0 %08x k1 %08x\n", + _LOG(log, logtype::REGISTERS, " t8 %08x t9 %08x k0 %08x k1 %08x\n", R(r.regs[24]), R(r.regs[25]), R(r.regs[26]), R(r.regs[27])); - _LOG(log, scope_flags, " gp %08x sp %08x s8 %08x ra %08x\n", + _LOG(log, logtype::REGISTERS, " gp %08x sp %08x s8 %08x ra %08x\n", R(r.regs[28]), R(r.regs[29]), R(r.regs[30]), R(r.regs[31])); - _LOG(log, scope_flags, " hi %08x lo %08x bva %08x epc %08x\n", + _LOG(log, logtype::REGISTERS, " hi %08x lo %08x bva %08x epc %08x\n", R(r.hi), R(r.lo), R(r.cp0_badvaddr), R(r.cp0_epc)); } diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp index fb5f02a4d..a58d9e588 100755 --- a/debuggerd/tombstone.cpp +++ b/debuggerd/tombstone.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#define LOG_TAG "DEBUG" + #include <dirent.h> #include <errno.h> #include <fcntl.h> @@ -56,21 +58,6 @@ // Must match the path defined in NativeCrashListener.java #define NCRASH_SOCKET_PATH "/data/system/ndebugsocket" -// Figure out the abi based on defined macros. -#if defined(__arm__) -#define ABI_STRING "arm" -#elif defined(__aarch64__) -#define ABI_STRING "arm64" -#elif defined(__mips__) -#define ABI_STRING "mips" -#elif defined(__i386__) -#define ABI_STRING "x86" -#elif defined(__x86_64__) -#define ABI_STRING "x86_64" -#else -#error "Unsupported ABI" -#endif - static bool signal_has_si_addr(int sig) { switch (sig) { case SIGBUS: @@ -179,16 +166,16 @@ static void dump_header_info(log_t* log) { property_get("ro.build.fingerprint", fingerprint, "unknown"); property_get("ro.revision", revision, "unknown"); - _LOG(log, SCOPE_AT_FAULT, "Build fingerprint: '%s'\n", fingerprint); - _LOG(log, SCOPE_AT_FAULT, "Revision: '%s'\n", revision); - _LOG(log, SCOPE_AT_FAULT, "ABI: '%s'\n", ABI_STRING); + _LOG(log, logtype::HEADER, "Build fingerprint: '%s'\n", fingerprint); + _LOG(log, logtype::HEADER, "Revision: '%s'\n", revision); + _LOG(log, logtype::HEADER, "ABI: '%s'\n", ABI_STRING); } static void dump_signal_info(log_t* log, pid_t tid, int signal, int si_code) { siginfo_t si; memset(&si, 0, sizeof(si)); if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si) == -1) { - _LOG(log, SCOPE_AT_FAULT, "cannot get siginfo: %s\n", strerror(errno)); + _LOG(log, logtype::HEADER, "cannot get siginfo: %s\n", strerror(errno)); return; } @@ -202,11 +189,11 @@ static void dump_signal_info(log_t* log, pid_t tid, int signal, int si_code) { snprintf(addr_desc, sizeof(addr_desc), "--------"); } - _LOG(log, SCOPE_AT_FAULT, "signal %d (%s), code %d (%s), fault addr %s\n", + _LOG(log, logtype::HEADER, "signal %d (%s), code %d (%s), fault addr %s\n", signal, get_signame(signal), si.si_code, get_sigcode(signal, si.si_code), addr_desc); } -static void dump_thread_info(log_t* log, pid_t pid, pid_t tid, int scope_flags) { +static void dump_thread_info(log_t* log, pid_t pid, pid_t tid) { char path[64]; char threadnamebuf[1024]; char* threadname = NULL; @@ -224,25 +211,21 @@ static void dump_thread_info(log_t* log, pid_t pid, pid_t tid, int scope_flags) } } - if (IS_AT_FAULT(scope_flags)) { - char procnamebuf[1024]; - char* procname = NULL; - - snprintf(path, sizeof(path), "/proc/%d/cmdline", pid); - if ((fp = fopen(path, "r"))) { - procname = fgets(procnamebuf, sizeof(procnamebuf), fp); - fclose(fp); - } + char procnamebuf[1024]; + char* procname = NULL; - _LOG(log, SCOPE_AT_FAULT, "pid: %d, tid: %d, name: %s >>> %s <<<\n", pid, tid, - threadname ? threadname : "UNKNOWN", procname ? procname : "UNKNOWN"); - } else { - _LOG(log, 0, "pid: %d, tid: %d, name: %s\n", pid, tid, threadname ? threadname : "UNKNOWN"); + snprintf(path, sizeof(path), "/proc/%d/cmdline", pid); + if ((fp = fopen(path, "r"))) { + procname = fgets(procnamebuf, sizeof(procnamebuf), fp); + fclose(fp); } + + _LOG(log, logtype::HEADER, "pid: %d, tid: %d, name: %s >>> %s <<<\n", pid, tid, + threadname ? threadname : "UNKNOWN", procname ? procname : "UNKNOWN"); } static void dump_stack_segment( - Backtrace* backtrace, log_t* log, int scope_flags, uintptr_t* sp, size_t words, int label) { + Backtrace* backtrace, log_t* log, uintptr_t* sp, size_t words, int label) { for (size_t i = 0; i < words; i++) { word_t stack_content; if (!backtrace->ReadWord(*sp, &stack_content)) { @@ -261,27 +244,27 @@ static void dump_stack_segment( if (!func_name.empty()) { if (!i && label >= 0) { if (offset) { - _LOG(log, scope_flags, " #%02d %" PRIPTR " %" PRIPTR " %s (%s+%" PRIuPTR ")\n", + _LOG(log, logtype::STACK, " #%02d %" PRIPTR " %" PRIPTR " %s (%s+%" PRIuPTR ")\n", label, *sp, stack_content, map_name, func_name.c_str(), offset); } else { - _LOG(log, scope_flags, " #%02d %" PRIPTR " %" PRIPTR " %s (%s)\n", + _LOG(log, logtype::STACK, " #%02d %" PRIPTR " %" PRIPTR " %s (%s)\n", label, *sp, stack_content, map_name, func_name.c_str()); } } else { if (offset) { - _LOG(log, scope_flags, " %" PRIPTR " %" PRIPTR " %s (%s+%" PRIuPTR ")\n", + _LOG(log, logtype::STACK, " %" PRIPTR " %" PRIPTR " %s (%s+%" PRIuPTR ")\n", *sp, stack_content, map_name, func_name.c_str(), offset); } else { - _LOG(log, scope_flags, " %" PRIPTR " %" PRIPTR " %s (%s)\n", + _LOG(log, logtype::STACK, " %" PRIPTR " %" PRIPTR " %s (%s)\n", *sp, stack_content, map_name, func_name.c_str()); } } } else { if (!i && label >= 0) { - _LOG(log, scope_flags, " #%02d %" PRIPTR " %" PRIPTR " %s\n", + _LOG(log, logtype::STACK, " #%02d %" PRIPTR " %" PRIPTR " %s\n", label, *sp, stack_content, map_name); } else { - _LOG(log, scope_flags, " %" PRIPTR " %" PRIPTR " %s\n", + _LOG(log, logtype::STACK, " %" PRIPTR " %" PRIPTR " %s\n", *sp, stack_content, map_name); } } @@ -290,7 +273,7 @@ static void dump_stack_segment( } } -static void dump_stack(Backtrace* backtrace, log_t* log, int scope_flags) { +static void dump_stack(Backtrace* backtrace, log_t* log) { size_t first = 0, last; for (size_t i = 0; i < backtrace->NumFrames(); i++) { const backtrace_frame_data_t* frame = backtrace->GetFrame(i); @@ -306,27 +289,22 @@ static void dump_stack(Backtrace* backtrace, log_t* log, int scope_flags) { } first--; - scope_flags |= SCOPE_SENSITIVE; - // Dump a few words before the first frame. word_t sp = backtrace->GetFrame(first)->sp - STACK_WORDS * sizeof(word_t); - dump_stack_segment(backtrace, log, scope_flags, &sp, STACK_WORDS, -1); + dump_stack_segment(backtrace, log, &sp, STACK_WORDS, -1); // Dump a few words from all successive frames. // Only log the first 3 frames, put the rest in the tombstone. for (size_t i = first; i <= last; i++) { const backtrace_frame_data_t* frame = backtrace->GetFrame(i); if (sp != frame->sp) { - _LOG(log, scope_flags, " ........ ........\n"); + _LOG(log, logtype::STACK, " ........ ........\n"); sp = frame->sp; } - if (i - first == 3) { - scope_flags &= (~SCOPE_AT_FAULT); - } if (i == last) { - dump_stack_segment(backtrace, log, scope_flags, &sp, STACK_WORDS, i); + dump_stack_segment(backtrace, log, &sp, STACK_WORDS, i); if (sp < frame->sp + frame->stack_size) { - _LOG(log, scope_flags, " ........ ........\n"); + _LOG(log, logtype::STACK, " ........ ........\n"); } } else { size_t words = frame->stack_size / sizeof(word_t); @@ -335,37 +313,33 @@ static void dump_stack(Backtrace* backtrace, log_t* log, int scope_flags) { } else if (words > STACK_WORDS) { words = STACK_WORDS; } - dump_stack_segment(backtrace, log, scope_flags, &sp, words, i); + dump_stack_segment(backtrace, log, &sp, words, i); } } } -static void dump_backtrace_and_stack(Backtrace* backtrace, log_t* log, int scope_flags) { +static void dump_backtrace_and_stack(Backtrace* backtrace, log_t* log) { if (backtrace->NumFrames()) { - _LOG(log, scope_flags, "\nbacktrace:\n"); - dump_backtrace_to_log(backtrace, log, scope_flags, " "); + _LOG(log, logtype::BACKTRACE, "\nbacktrace:\n"); + dump_backtrace_to_log(backtrace, log, " "); - _LOG(log, scope_flags, "\nstack:\n"); - dump_stack(backtrace, log, scope_flags); + _LOG(log, logtype::STACK, "\nstack:\n"); + dump_stack(backtrace, log); } } -static void dump_map(log_t* log, const backtrace_map_t* map, const char* what, int scope_flags) { - if (map != NULL) { - _LOG(log, scope_flags, " %" PRIPTR "-%" PRIPTR " %c%c%c %s\n", map->start, map->end, +static void dump_map(log_t* log, const backtrace_map_t* map, bool fault_addr) { + _LOG(log, logtype::MAPS, "%s%" PRIPTR "-%" PRIPTR " %c%c%c %s\n", + (fault_addr? "--->" : " "), map->start, map->end, (map->flags & PROT_READ) ? 'r' : '-', (map->flags & PROT_WRITE) ? 'w' : '-', (map->flags & PROT_EXEC) ? 'x' : '-', map->name.c_str()); - } else { - _LOG(log, scope_flags, " (no %s)\n", what); - } } -static void dump_nearby_maps(BacktraceMap* map, log_t* log, pid_t tid, int scope_flags) { - scope_flags |= SCOPE_SENSITIVE; +static void dump_nearby_maps(BacktraceMap* map, log_t* log, pid_t tid) { siginfo_t si; memset(&si, 0, sizeof(si)); if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) { - _LOG(log, scope_flags, "cannot get siginfo for %d: %s\n", tid, strerror(errno)); + _LOG(log, logtype::MAPS, "cannot get siginfo for %d: %s\n", tid, strerror(errno)); return; } if (!signal_has_si_addr(si.si_signo)) { @@ -378,55 +352,44 @@ static void dump_nearby_maps(BacktraceMap* map, log_t* log, pid_t tid, int scope return; } - _LOG(log, scope_flags, "\nmemory map around fault addr %" PRIPTR ":\n", - reinterpret_cast<uintptr_t>(si.si_addr)); + _LOG(log, logtype::MAPS, "\nmemory map: (fault address prefixed with --->)\n"); - // Search for a match, or for a hole where the match would be. The list - // is backward from the file content, so it starts at high addresses. - const backtrace_map_t* cur_map = NULL; - const backtrace_map_t* next_map = NULL; - const backtrace_map_t* prev_map = NULL; + bool found_map = false; for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) { - if (addr >= it->start && addr < it->end) { - cur_map = &*it; - if (it != map->begin()) { - prev_map = &*(it-1); - } - if (++it != map->end()) { - next_map = &*it; - } - break; + bool in_map = addr >= (*it).start && addr < (*it).end; + dump_map(log, &*it, in_map); + if(in_map) { + found_map = true; } } - - // Show the map address in ascending order (like /proc/pid/maps). - dump_map(log, prev_map, "map below", scope_flags); - dump_map(log, cur_map, "map for address", scope_flags); - dump_map(log, next_map, "map above", scope_flags); + if(!found_map) { + _LOG(log, logtype::ERROR, "\nFault address was not in any map!"); + } } static void dump_thread( - Backtrace* backtrace, log_t* log, int scope_flags, int* total_sleep_time_usec) { + Backtrace* backtrace, log_t* log, int* total_sleep_time_usec) { + wait_for_stop(backtrace->Tid(), total_sleep_time_usec); - dump_registers(log, backtrace->Tid(), scope_flags); - dump_backtrace_and_stack(backtrace, log, scope_flags); - if (IS_AT_FAULT(scope_flags)) { - dump_memory_and_code(log, backtrace->Tid(), scope_flags); - dump_nearby_maps(backtrace->GetMap(), log, backtrace->Tid(), scope_flags); - } + dump_registers(log, backtrace->Tid()); + dump_backtrace_and_stack(backtrace, log); + + dump_memory_and_code(log, backtrace->Tid()); + dump_nearby_maps(backtrace->GetMap(), log, backtrace->Tid()); } // Return true if some thread is not detached cleanly static bool dump_sibling_thread_report( log_t* log, pid_t pid, pid_t tid, int* total_sleep_time_usec, BacktraceMap* map) { char task_path[64]; + snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid); DIR* d = opendir(task_path); // Bail early if the task directory cannot be opened if (d == NULL) { - XLOG("Cannot open /proc/%d/task\n", pid); + ALOGE("Cannot open /proc/%d/task\n", pid); return false; } @@ -447,19 +410,23 @@ static bool dump_sibling_thread_report( // Skip this thread if cannot ptrace it if (ptrace(PTRACE_ATTACH, new_tid, 0, 0) < 0) { + _LOG(log, logtype::ERROR, "ptrace attach to %d failed: %s\n", new_tid, strerror(errno)); continue; } - _LOG(log, 0, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n"); - dump_thread_info(log, pid, new_tid, 0); + log->current_tid = new_tid; + _LOG(log, logtype::THREAD, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n"); + dump_thread_info(log, pid, new_tid); UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, new_tid, map)); if (backtrace->Unwind(0)) { - dump_thread(backtrace.get(), log, 0, total_sleep_time_usec); + dump_thread(backtrace.get(), log, total_sleep_time_usec); } + log->current_tid = log->crashed_tid; + if (ptrace(PTRACE_DETACH, new_tid, 0, 0) != 0) { - LOG("ptrace detach from %d failed: %s\n", new_tid, strerror(errno)); + _LOG(log, logtype::ERROR, "ptrace detach from %d failed: %s\n", new_tid, strerror(errno)); detach_failed = true; } } @@ -483,7 +450,7 @@ static void dump_log_file(log_t* log, pid_t pid, const char* filename, android_name_to_log_id(filename), O_RDONLY | O_NONBLOCK, tail, pid); if (!logger_list) { - XLOG("Unable to open %s: %s\n", filename, strerror(errno)); + ALOGE("Unable to open %s: %s\n", filename, strerror(errno)); return; } @@ -500,17 +467,17 @@ static void dump_log_file(log_t* log, pid_t pid, const char* filename, // non-blocking EOF; we're done break; } else { - _LOG(log, 0, "Error while reading log: %s\n", + _LOG(log, logtype::ERROR, "Error while reading log: %s\n", strerror(-actual)); break; } } else if (actual == 0) { - _LOG(log, 0, "Got zero bytes while reading log: %s\n", + _LOG(log, logtype::ERROR, "Got zero bytes while reading log: %s\n", strerror(errno)); break; } - // NOTE: if you XLOG something here, this will spin forever, + // NOTE: if you ALOGV something here, this will spin forever, // because you will be writing as fast as you're reading. Any // high-frequency debug diagnostics should just be written to // the tombstone file. @@ -522,7 +489,7 @@ static void dump_log_file(log_t* log, pid_t pid, const char* filename, } if (first) { - _LOG(log, 0, "--------- %slog %s\n", + _LOG(log, logtype::HEADER, "--------- %slog %s\n", tail ? "tail end of " : "", filename); first = false; } @@ -552,7 +519,7 @@ static void dump_log_file(log_t* log, pid_t pid, const char* filename, AndroidLogEntry e; char buf[512]; android_log_processBinaryLogBuffer(entry, &e, g_eventTagMap, buf, sizeof(buf)); - _LOG(log, 0, "%s.%03d %5d %5d %c %-8s: %s\n", + _LOG(log, logtype::LOGS, "%s.%03d %5d %5d %c %-8s: %s\n", timeBuf, entry->nsec / 1000000, entry->pid, entry->tid, 'I', e.tag, e.message); continue; @@ -579,7 +546,7 @@ static void dump_log_file(log_t* log, pid_t pid, const char* filename, ++nl; } - _LOG(log, 0, "%s.%03d %5d %5d %c %-8s: %s\n", + _LOG(log, logtype::LOGS, "%s.%03d %5d %5d %c %-8s: %s\n", timeBuf, entry->nsec / 1000000, entry->pid, entry->tid, prioChar, tag, msg); @@ -619,7 +586,7 @@ static void dump_abort_message(Backtrace* backtrace, log_t* log, uintptr_t addre } msg[sizeof(msg) - 1] = '\0'; - _LOG(log, SCOPE_AT_FAULT, "Abort message: '%s'\n", msg); + _LOG(log, logtype::HEADER, "Abort message: '%s'\n", msg); } // Dumps all information about the specified pid to the tombstone. @@ -641,10 +608,11 @@ static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, int si_code TEMP_FAILURE_RETRY( write(log->amfd, &datum, 4) ); } - _LOG(log, SCOPE_AT_FAULT, + _LOG(log, logtype::HEADER, "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n"); dump_header_info(log); - dump_thread_info(log, pid, tid, SCOPE_AT_FAULT); + dump_thread_info(log, pid, tid); + if (signal) { dump_signal_info(log, tid, signal, si_code); } @@ -653,7 +621,7 @@ static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, int si_code UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get())); if (backtrace->Unwind(0)) { dump_abort_message(backtrace.get(), log, abort_msg_address); - dump_thread(backtrace.get(), log, SCOPE_AT_FAULT, total_sleep_time_usec); + dump_thread(backtrace.get(), log, total_sleep_time_usec); } if (want_logs) { @@ -715,7 +683,7 @@ static char* find_and_open_tombstone(int* fd) { } if (oldest < 0) { - LOG("Failed to find a valid tombstone, default to using tombstone 0.\n"); + ALOGE("Failed to find a valid tombstone, default to using tombstone 0.\n"); oldest = 0; } @@ -723,7 +691,7 @@ static char* find_and_open_tombstone(int* fd) { snprintf(path, sizeof(path), TOMBSTONE_TEMPLATE, oldest); *fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600); if (*fd < 0) { - LOG("failed to open tombstone file '%s': %s\n", path, strerror(errno)); + ALOGE("failed to open tombstone file '%s': %s\n", path, strerror(errno)); return NULL; } fchown(*fd, AID_SYSTEM, AID_SYSTEM); @@ -761,14 +729,19 @@ static int activity_manager_connect() { } char* engrave_tombstone(pid_t pid, pid_t tid, int signal, int original_si_code, - uintptr_t abort_msg_address, bool dump_sibling_threads, bool quiet, + uintptr_t abort_msg_address, bool dump_sibling_threads, bool* detach_failed, int* total_sleep_time_usec) { + + log_t log; + log.current_tid = tid; + log.crashed_tid = tid; + if ((mkdir(TOMBSTONE_DIR, 0755) == -1) && (errno != EEXIST)) { - LOG("failed to create %s: %s\n", TOMBSTONE_DIR, strerror(errno)); + _LOG(&log, logtype::ERROR, "failed to create %s: %s\n", TOMBSTONE_DIR, strerror(errno)); } if (chown(TOMBSTONE_DIR, AID_SYSTEM, AID_SYSTEM) == -1) { - LOG("failed to change ownership of %s: %s\n", TOMBSTONE_DIR, strerror(errno)); + _LOG(&log, logtype::ERROR, "failed to change ownership of %s: %s\n", TOMBSTONE_DIR, strerror(errno)); } int fd = -1; @@ -776,25 +749,25 @@ char* engrave_tombstone(pid_t pid, pid_t tid, int signal, int original_si_code, if (selinux_android_restorecon(TOMBSTONE_DIR, 0) == 0) { path = find_and_open_tombstone(&fd); } else { - LOG("Failed to restore security context, not writing tombstone.\n"); + _LOG(&log, logtype::ERROR, "Failed to restore security context, not writing tombstone.\n"); } - if (fd < 0 && quiet) { - LOG("Skipping tombstone write, nothing to do.\n"); + if (fd < 0) { + _LOG(&log, logtype::ERROR, "Skipping tombstone write, nothing to do.\n"); *detach_failed = false; return NULL; } - log_t log; log.tfd = fd; // Preserve amfd since it can be modified through the calls below without // being closed. int amfd = activity_manager_connect(); log.amfd = amfd; - log.quiet = quiet; *detach_failed = dump_crash(&log, pid, tid, signal, original_si_code, abort_msg_address, dump_sibling_threads, total_sleep_time_usec); + ALOGI("\nTombstone written to: %s\n", path); + // Either of these file descriptors can be -1, any error is ignored. close(amfd); close(fd); diff --git a/debuggerd/tombstone.h b/debuggerd/tombstone.h index 3574e8459..7e2b2fe60 100644 --- a/debuggerd/tombstone.h +++ b/debuggerd/tombstone.h @@ -25,7 +25,7 @@ * Returns the path of the tombstone, which must be freed using free(). */ char* engrave_tombstone(pid_t pid, pid_t tid, int signal, int original_si_code, uintptr_t abort_msg_address, - bool dump_sibling_threads, bool quiet, - bool* detach_failed, int* total_sleep_time_usec); + bool dump_sibling_threads, bool* detach_failed, + int* total_sleep_time_usec); #endif // _DEBUGGERD_TOMBSTONE_H diff --git a/debuggerd/utility.cpp b/debuggerd/utility.cpp index d4c252f2d..a1633448a 100644 --- a/debuggerd/utility.cpp +++ b/debuggerd/utility.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#define LOG_TAG "DEBUG" + #include "utility.h" #include <errno.h> @@ -25,7 +27,6 @@ #include <backtrace/Backtrace.h> #include <log/log.h> -#include <log/logd.h> const int sleep_time_usec = 50000; // 0.05 seconds const int max_total_sleep_usec = 10000000; // 10 seconds @@ -36,7 +37,7 @@ static int write_to_am(int fd, const char* buf, int len) { int written = TEMP_FAILURE_RETRY(write(fd, buf + len - to_write, to_write)); if (written < 0) { // hard failure - LOG("AM write failure (%d / %s)\n", errno, strerror(errno)); + ALOGE("AM write failure (%d / %s)\n", errno, strerror(errno)); return -1; } to_write -= written; @@ -44,10 +45,22 @@ static int write_to_am(int fd, const char* buf, int len) { return len; } -void _LOG(log_t* log, int scopeFlags, const char* fmt, ...) { - bool want_tfd_write = log && log->tfd >= 0; - bool want_log_write = IS_AT_FAULT(scopeFlags) && (!log || !log->quiet); - bool want_amfd_write = IS_AT_FAULT(scopeFlags) && !IS_SENSITIVE(scopeFlags) && log && log->amfd >= 0; +// Whitelist output desired in the logcat output. +bool is_allowed_in_logcat(enum logtype ltype) { + if ((ltype == ERROR) + || (ltype == HEADER) + || (ltype == REGISTERS) + || (ltype == BACKTRACE)) { + return true; + } + return false; +} + +void _LOG(log_t* log, enum logtype ltype, const char* fmt, ...) { + bool write_to_tombstone = (log->tfd != -1); + bool write_to_logcat = is_allowed_in_logcat(ltype) + && (log->crashed_tid == log->current_tid); + bool write_to_activitymanager = (log->amfd != -1); char buf[512]; va_list ap; @@ -60,13 +73,13 @@ void _LOG(log_t* log, int scopeFlags, const char* fmt, ...) { return; } - if (want_tfd_write) { + if (write_to_tombstone) { TEMP_FAILURE_RETRY(write(log->tfd, buf, len)); } - if (want_log_write) { - __android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_INFO, "DEBUG", buf); - if (want_amfd_write) { + if (write_to_logcat) { + __android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_INFO, LOG_TAG, buf); + if (write_to_activitymanager) { int written = write_to_am(log->amfd, buf, len); if (written <= 0) { // timeout or other failure on write; stop informing the activity manager @@ -83,25 +96,25 @@ int wait_for_signal(pid_t tid, int* total_sleep_time_usec) { if (n < 0) { if (errno == EAGAIN) continue; - LOG("waitpid failed: %s\n", strerror(errno)); + ALOGE("waitpid failed: %s\n", strerror(errno)); return -1; } else if (n > 0) { - XLOG("waitpid: n=%d status=%08x\n", n, status); + ALOGV("waitpid: n=%d status=%08x\n", n, status); if (WIFSTOPPED(status)) { return WSTOPSIG(status); } else { - LOG("unexpected waitpid response: n=%d, status=%08x\n", n, status); + ALOGE("unexpected waitpid response: n=%d, status=%08x\n", n, status); return -1; } } if (*total_sleep_time_usec > max_total_sleep_usec) { - LOG("timed out waiting for tid=%d to die\n", tid); + ALOGE("timed out waiting for tid=%d to die\n", tid); return -1; } // not ready yet - XLOG("not ready yet\n"); + ALOGV("not ready yet\n"); usleep(sleep_time_usec); *total_sleep_time_usec += sleep_time_usec; } @@ -111,7 +124,7 @@ void wait_for_stop(pid_t tid, int* total_sleep_time_usec) { siginfo_t si; while (TEMP_FAILURE_RETRY(ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) < 0 && errno == ESRCH) { if (*total_sleep_time_usec > max_total_sleep_usec) { - LOG("timed out waiting for tid=%d to stop\n", tid); + ALOGE("timed out waiting for tid=%d to stop\n", tid); break; } @@ -126,7 +139,7 @@ void wait_for_stop(pid_t tid, int* total_sleep_time_usec) { #define DUMP_MEMORY_AS_ASCII 0 #endif -void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags) { +void dump_memory(log_t* log, pid_t tid, uintptr_t addr) { char code_buffer[64]; char ascii_buffer[32]; uintptr_t p, end; @@ -190,6 +203,6 @@ void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags) { p += sizeof(long); } *asc_out = '\0'; - _LOG(log, scope_flags, " %s %s\n", code_buffer, ascii_buffer); + _LOG(log, logtype::MEMORY, " %s %s\n", code_buffer, ascii_buffer); } } diff --git a/debuggerd/utility.h b/debuggerd/utility.h index 0f886053f..f2e2d2959 100644 --- a/debuggerd/utility.h +++ b/debuggerd/utility.h @@ -21,48 +21,53 @@ #include <stdbool.h> #include <sys/types.h> +// Figure out the abi based on defined macros. +#if defined(__arm__) +#define ABI_STRING "arm" +#elif defined(__aarch64__) +#define ABI_STRING "arm64" +#elif defined(__mips__) +#define ABI_STRING "mips" +#elif defined(__i386__) +#define ABI_STRING "x86" +#elif defined(__x86_64__) +#define ABI_STRING "x86_64" +#else +#error "Unsupported ABI" +#endif + + typedef struct { /* tombstone file descriptor */ int tfd; /* Activity Manager socket file descriptor */ int amfd; - /* if true, does not log anything to the Android logcat or Activity Manager */ - bool quiet; + // The tid of the thread that crashed. + pid_t crashed_tid; + // The tid of the thread we are currently working with. + pid_t current_tid; } log_t; -/* Log information onto the tombstone. scopeFlags is a bitmask of the flags defined - * here. */ -void _LOG(log_t* log, int scopeFlags, const char *fmt, ...) - __attribute__ ((format(printf, 3, 4))); - -/* The message pertains specifically to the faulting thread / process */ -#define SCOPE_AT_FAULT (1 << 0) -/* The message contains sensitive information such as RAM contents */ -#define SCOPE_SENSITIVE (1 << 1) - -#define IS_AT_FAULT(x) (((x) & SCOPE_AT_FAULT) != 0) -#define IS_SENSITIVE(x) (((x) & SCOPE_SENSITIVE) != 0) +// List of types of logs to simplify the logging decision in _LOG +enum logtype { + ERROR, + HEADER, + THREAD, + REGISTERS, + BACKTRACE, + MAPS, + MEMORY, + STACK, + LOGS +}; -/* Further helpful macros */ -#define LOG(fmt...) _LOG(NULL, SCOPE_AT_FAULT, fmt) - -/* Set to 1 for normal debug traces */ -#if 0 -#define XLOG(fmt...) _LOG(NULL, SCOPE_AT_FAULT, fmt) -#else -#define XLOG(fmt...) do {} while(0) -#endif - -/* Set to 1 for chatty debug traces. Includes all resolved dynamic symbols */ -#if 0 -#define XLOG2(fmt...) _LOG(NULL, SCOPE_AT_FAULT, fmt) -#else -#define XLOG2(fmt...) do {} while(0) -#endif +/* Log information onto the tombstone. */ +void _LOG(log_t* log, logtype ltype, const char *fmt, ...) + __attribute__ ((format(printf, 3, 4))); int wait_for_signal(pid_t tid, int* total_sleep_time_usec); void wait_for_stop(pid_t tid, int* total_sleep_time_usec); -void dump_memory(log_t* log, pid_t tid, uintptr_t addr, int scope_flags); +void dump_memory(log_t* log, pid_t tid, uintptr_t addr); #endif // _DEBUGGERD_UTILITY_H diff --git a/debuggerd/x86/machine.cpp b/debuggerd/x86/machine.cpp index bcc217e83..57330c1e7 100644 --- a/debuggerd/x86/machine.cpp +++ b/debuggerd/x86/machine.cpp @@ -25,21 +25,21 @@ #include "../utility.h" #include "../machine.h" -void dump_memory_and_code(log_t*, pid_t, int) { +void dump_memory_and_code(log_t*, pid_t) { } -void dump_registers(log_t* log, pid_t tid, int scope_flags) { +void dump_registers(log_t* log, pid_t tid) { struct pt_regs r; if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) { - _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno)); + _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno)); return; } - _LOG(log, scope_flags, " eax %08lx ebx %08lx ecx %08lx edx %08lx\n", + _LOG(log, logtype::REGISTERS, " eax %08lx ebx %08lx ecx %08lx edx %08lx\n", r.eax, r.ebx, r.ecx, r.edx); - _LOG(log, scope_flags, " esi %08lx edi %08lx\n", + _LOG(log, logtype::REGISTERS, " esi %08lx edi %08lx\n", r.esi, r.edi); - _LOG(log, scope_flags, " xcs %08x xds %08x xes %08x xfs %08x xss %08x\n", + _LOG(log, logtype::REGISTERS, " xcs %08x xds %08x xes %08x xfs %08x xss %08x\n", r.xcs, r.xds, r.xes, r.xfs, r.xss); - _LOG(log, scope_flags, " eip %08lx ebp %08lx esp %08lx flags %08lx\n", + _LOG(log, logtype::REGISTERS, " eip %08lx ebp %08lx esp %08lx flags %08lx\n", r.eip, r.ebp, r.esp, r.eflags); } diff --git a/debuggerd/x86_64/machine.cpp b/debuggerd/x86_64/machine.cpp index c8c7aa924..af4f35ad7 100755 --- a/debuggerd/x86_64/machine.cpp +++ b/debuggerd/x86_64/machine.cpp @@ -27,25 +27,25 @@ #include "../utility.h" #include "../machine.h" -void dump_memory_and_code(log_t*, pid_t, int) { +void dump_memory_and_code(log_t*, pid_t) { } -void dump_registers(log_t* log, pid_t tid, int scope_flags) { +void dump_registers(log_t* log, pid_t tid) { struct user_regs_struct r; if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) { - _LOG(log, scope_flags, "cannot get registers: %s\n", strerror(errno)); + _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno)); return; } - _LOG(log, scope_flags, " rax %016lx rbx %016lx rcx %016lx rdx %016lx\n", + _LOG(log, logtype::REGISTERS, " rax %016lx rbx %016lx rcx %016lx rdx %016lx\n", r.rax, r.rbx, r.rcx, r.rdx); - _LOG(log, scope_flags, " rsi %016lx rdi %016lx\n", + _LOG(log, logtype::REGISTERS, " rsi %016lx rdi %016lx\n", r.rsi, r.rdi); - _LOG(log, scope_flags, " r8 %016lx r9 %016lx r10 %016lx r11 %016lx\n", + _LOG(log, logtype::REGISTERS, " r8 %016lx r9 %016lx r10 %016lx r11 %016lx\n", r.r8, r.r9, r.r10, r.r11); - _LOG(log, scope_flags, " r12 %016lx r13 %016lx r14 %016lx r15 %016lx\n", + _LOG(log, logtype::REGISTERS, " r12 %016lx r13 %016lx r14 %016lx r15 %016lx\n", r.r12, r.r13, r.r14, r.r15); - _LOG(log, scope_flags, " cs %016lx ss %016lx\n", + _LOG(log, logtype::REGISTERS, " cs %016lx ss %016lx\n", r.cs, r.ss); - _LOG(log, scope_flags, " rip %016lx rbp %016lx rsp %016lx eflags %016lx\n", + _LOG(log, logtype::REGISTERS, " rip %016lx rbp %016lx rsp %016lx eflags %016lx\n", r.rip, r.rbp, r.rsp, r.eflags); } diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c index 9c04c21ea..266d0b5de 100644 --- a/fastboot/fastboot.c +++ b/fastboot/fastboot.c @@ -1216,6 +1216,7 @@ int main(int argc, char **argv) } if (wants_reboot) { fb_queue_reboot(); + fb_queue_wait_for_disconnect(); } else if (wants_reboot_bootloader) { fb_queue_command("reboot-bootloader", "rebooting into bootloader"); fb_queue_wait_for_disconnect(); diff --git a/healthd/healthd.cpp b/healthd/healthd.cpp index 9b84c3e8f..d30e771ea 100644 --- a/healthd/healthd.cpp +++ b/healthd/healthd.cpp @@ -126,7 +126,7 @@ static void uevent_init(void) { KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n"); } -#define UEVENT_MSG_LEN 1024 +#define UEVENT_MSG_LEN 2048 static void uevent_event(void) { char msg[UEVENT_MSG_LEN+2]; char *cp; diff --git a/include/android/log.h b/include/android/log.h index ad36bd223..1c171b7bf 100644 --- a/include/android/log.h +++ b/include/android/log.h @@ -98,11 +98,15 @@ int __android_log_write(int prio, const char *tag, const char *text); */ int __android_log_print(int prio, const char *tag, const char *fmt, ...) #if defined(__GNUC__) +#ifdef __USE_MINGW_ANSI_STDIO #if __USE_MINGW_ANSI_STDIO __attribute__ ((format(gnu_printf, 3, 4))) #else __attribute__ ((format(printf, 3, 4))) #endif +#else + __attribute__ ((format(printf, 3, 4))) +#endif #endif ; @@ -121,11 +125,15 @@ void __android_log_assert(const char *cond, const char *tag, const char *fmt, ...) #if defined(__GNUC__) __attribute__ ((noreturn)) +#ifdef __USE_MINGW_ANSI_STDIO #if __USE_MINGW_ANSI_STDIO __attribute__ ((format(gnu_printf, 3, 4))) #else __attribute__ ((format(printf, 3, 4))) #endif +#else + __attribute__ ((format(printf, 3, 4))) +#endif #endif ; diff --git a/include/cutils/atomic-inline.h b/include/cutils/atomic-inline.h index 4f90ef1d3..007a9053b 100644 --- a/include/cutils/atomic-inline.h +++ b/include/cutils/atomic-inline.h @@ -51,6 +51,8 @@ extern "C" { #include <cutils/atomic-x86.h> #elif defined(__x86_64__) #include <cutils/atomic-x86_64.h> +#elif defined(__mips64) +#include <cutils/atomic-mips64.h> #elif defined(__mips__) #include <cutils/atomic-mips.h> #else diff --git a/include/cutils/atomic-mips.h b/include/cutils/atomic-mips.h index f9d3e253e..1ed833de3 100644 --- a/include/cutils/atomic-mips.h +++ b/include/cutils/atomic-mips.h @@ -117,23 +117,6 @@ android_atomic_release_cas(int32_t old_value, extern ANDROID_ATOMIC_INLINE int32_t -android_atomic_swap(int32_t new_value, volatile int32_t *ptr) -{ - int32_t prev, status; - do { - __asm__ __volatile__ ( - " move %[status], %[new_value]\n" - " ll %[prev], (%[ptr])\n" - " sc %[status], (%[ptr])\n" - : [prev] "=&r" (prev), [status] "=&r" (status) - : [ptr] "r" (ptr), [new_value] "r" (new_value) - ); - } while (__builtin_expect(status == 0, 0)); - android_memory_barrier(); - return prev; -} - -extern ANDROID_ATOMIC_INLINE int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr) { int32_t prev, status; diff --git a/include/cutils/atomic-mips64.h b/include/cutils/atomic-mips64.h new file mode 100644 index 000000000..99bbe3a55 --- /dev/null +++ b/include/cutils/atomic-mips64.h @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_CUTILS_ATOMIC_MIPS64_H +#define ANDROID_CUTILS_ATOMIC_MIPS64_H + +#include <stdint.h> + +#ifndef ANDROID_ATOMIC_INLINE +#define ANDROID_ATOMIC_INLINE inline __attribute__((always_inline)) +#endif + +extern ANDROID_ATOMIC_INLINE void android_compiler_barrier(void) +{ + __asm__ __volatile__ ("" : : : "memory"); +} + +#if ANDROID_SMP == 0 +extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void) +{ + android_compiler_barrier(); +} +extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void) +{ + android_compiler_barrier(); +} +#else +extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void) +{ + __asm__ __volatile__ ("sync" : : : "memory"); +} +extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void) +{ + __asm__ __volatile__ ("sync" : : : "memory"); +} +#endif + +extern ANDROID_ATOMIC_INLINE +int32_t android_atomic_acquire_load(volatile const int32_t *ptr) +{ + int32_t value = *ptr; + android_memory_barrier(); + return value; +} + +extern ANDROID_ATOMIC_INLINE +int64_t android_atomic_acquire_load64(volatile const int64_t *ptr) +{ + int64_t value = *ptr; + android_memory_barrier(); + return value; +} + +extern ANDROID_ATOMIC_INLINE +int32_t android_atomic_release_load(volatile const int32_t *ptr) +{ + android_memory_barrier(); + return *ptr; +} + +extern ANDROID_ATOMIC_INLINE +int64_t android_atomic_release_load64(volatile const int64_t *ptr) +{ + android_memory_barrier(); + return *ptr; +} + +extern ANDROID_ATOMIC_INLINE +void android_atomic_acquire_store(int32_t value, volatile int32_t *ptr) +{ + *ptr = value; + android_memory_barrier(); +} + +extern ANDROID_ATOMIC_INLINE +void android_atomic_acquire_store64(int64_t value, volatile int64_t *ptr) +{ + *ptr = value; + android_memory_barrier(); +} + +extern ANDROID_ATOMIC_INLINE +void android_atomic_release_store(int32_t value, volatile int32_t *ptr) +{ + android_memory_barrier(); + *ptr = value; +} + +extern ANDROID_ATOMIC_INLINE +void android_atomic_release_store64(int64_t value, volatile int64_t *ptr) +{ + android_memory_barrier(); + *ptr = value; +} + +extern ANDROID_ATOMIC_INLINE +int android_atomic_cas(int32_t old_value, int32_t new_value, volatile int32_t *ptr) +{ + int32_t prev, status; + do { + __asm__ __volatile__ ( + " ll %[prev], (%[ptr])\n" + " li %[status], 1\n" + " bne %[prev], %[old], 9f\n" + " move %[status], %[new_value]\n" + " sc %[status], (%[ptr])\n" + "9:\n" + : [prev] "=&r" (prev), [status] "=&r" (status) + : [ptr] "r" (ptr), [old] "r" (old_value), [new_value] "r" (new_value) + ); + } while (__builtin_expect(status == 0, 0)); + return prev != old_value; +} + +extern ANDROID_ATOMIC_INLINE +int64_t android_atomic_cas64(int64_t old_value, int64_t new_value, + volatile int64_t *ptr) +{ + return __sync_val_compare_and_swap(ptr, old_value, new_value) != old_value; +} + +extern ANDROID_ATOMIC_INLINE +int android_atomic_acquire_cas(int32_t old_value, + int32_t new_value, + volatile int32_t *ptr) +{ + int status = android_atomic_cas(old_value, new_value, ptr); + android_memory_barrier(); + return status; +} + +extern ANDROID_ATOMIC_INLINE +int64_t android_atomic_acquire_cas64(int64_t old_value, int64_t new_value, + volatile int64_t *ptr) +{ + int status = android_atomic_cas64(old_value, new_value, ptr); + android_memory_barrier(); + return status; +} + +extern ANDROID_ATOMIC_INLINE +int android_atomic_release_cas(int32_t old_value, + int32_t new_value, + volatile int32_t *ptr) +{ + android_memory_barrier(); + return android_atomic_cas(old_value, new_value, ptr); +} + +extern ANDROID_ATOMIC_INLINE +int64_t android_atomic_release_cas64(int64_t old_value, int64_t new_value, + volatile int64_t *ptr) +{ + android_memory_barrier(); + return android_atomic_cas64(old_value, new_value, ptr); +} + +extern ANDROID_ATOMIC_INLINE +int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr) +{ + int32_t prev, status; + android_memory_barrier(); + do { + __asm__ __volatile__ ( + " ll %[prev], (%[ptr])\n" + " addu %[status], %[prev], %[inc]\n" + " sc %[status], (%[ptr])\n" + : [status] "=&r" (status), [prev] "=&r" (prev) + : [ptr] "r" (ptr), [inc] "Ir" (increment) + ); + } while (__builtin_expect(status == 0, 0)); + return prev; +} + +extern ANDROID_ATOMIC_INLINE int32_t +android_atomic_inc(volatile int32_t *addr) +{ + return android_atomic_add(1, addr); +} + +extern ANDROID_ATOMIC_INLINE int32_t +android_atomic_dec(volatile int32_t *addr) +{ + return android_atomic_add(-1, addr); +} + +extern ANDROID_ATOMIC_INLINE int32_t +android_atomic_and(int32_t value, volatile int32_t *ptr) +{ + int32_t prev, status; + android_memory_barrier(); + do { + __asm__ __volatile__ ( + " ll %[prev], (%[ptr])\n" + " and %[status], %[prev], %[value]\n" + " sc %[status], (%[ptr])\n" + : [prev] "=&r" (prev), [status] "=&r" (status) + : [ptr] "r" (ptr), [value] "Ir" (value) + ); + } while (__builtin_expect(status == 0, 0)); + return prev; +} + +extern ANDROID_ATOMIC_INLINE int32_t +android_atomic_or(int32_t value, volatile int32_t *ptr) +{ + int32_t prev, status; + android_memory_barrier(); + do { + __asm__ __volatile__ ( + " ll %[prev], (%[ptr])\n" + " or %[status], %[prev], %[value]\n" + " sc %[status], (%[ptr])\n" + : [prev] "=&r" (prev), [status] "=&r" (status) + : [ptr] "r" (ptr), [value] "Ir" (value) + ); + } while (__builtin_expect(status == 0, 0)); + return prev; +} + +#endif /* ANDROID_CUTILS_ATOMIC_MIPS_H */ diff --git a/include/cutils/properties.h b/include/cutils/properties.h index 2c70165b0..798db8b36 100644 --- a/include/cutils/properties.h +++ b/include/cutils/properties.h @@ -20,6 +20,7 @@ #include <sys/cdefs.h> #include <stddef.h> #include <sys/system_properties.h> +#include <stdint.h> #ifdef __cplusplus extern "C" { @@ -44,6 +45,64 @@ extern "C" { */ int property_get(const char *key, char *value, const char *default_value); +/* property_get_bool: returns the value of key coerced into a +** boolean. If the property is not set, then the default value is returned. +** +* The following is considered to be true (1): +** "1", "true", "y", "yes", "on" +** +** The following is considered to be false (0): +** "0", "false", "n", "no", "off" +** +** The conversion is whitespace-sensitive (e.g. " off" will not be false). +** +** If no property with this key is set (or the key is NULL) or the boolean +** conversion fails, the default value is returned. +**/ +int8_t property_get_bool(const char *key, int8_t default_value); + +/* property_get_int64: returns the value of key truncated and coerced into a +** int64_t. If the property is not set, then the default value is used. +** +** The numeric conversion is identical to strtoimax with the base inferred: +** - All digits up to the first non-digit characters are read +** - The longest consecutive prefix of digits is converted to a long +** +** Valid strings of digits are: +** - An optional sign character + or - +** - An optional prefix indicating the base (otherwise base 10 is assumed) +** -- 0 prefix is octal +** -- 0x / 0X prefix is hex +** +** Leading/trailing whitespace is ignored. Overflow/underflow will cause +** numeric conversion to fail. +** +** If no property with this key is set (or the key is NULL) or the numeric +** conversion fails, the default value is returned. +**/ +int64_t property_get_int64(const char *key, int64_t default_value); + +/* property_get_int32: returns the value of key truncated and coerced into an +** int32_t. If the property is not set, then the default value is used. +** +** The numeric conversion is identical to strtoimax with the base inferred: +** - All digits up to the first non-digit characters are read +** - The longest consecutive prefix of digits is converted to a long +** +** Valid strings of digits are: +** - An optional sign character + or - +** - An optional prefix indicating the base (otherwise base 10 is assumed) +** -- 0 prefix is octal +** -- 0x / 0X prefix is hex +** +** Leading/trailing whitespace is ignored. Overflow/underflow will cause +** numeric conversion to fail. +** +** If no property with this key is set (or the key is NULL) or the numeric +** conversion fails, the default value is returned. +**/ +int32_t property_get_int32(const char *key, int32_t default_value); + /* property_set: returns 0 on success, < 0 on failure */ int property_set(const char *key, const char *value); diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h index 03b3506de..d8e938ea1 100644 --- a/include/private/android_filesystem_config.h +++ b/include/private/android_filesystem_config.h @@ -244,7 +244,7 @@ static const struct fs_path_config android_files[] = { /* the following five files are INTENTIONALLY set-uid, but they * are NOT included on user builds. */ - { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/su" }, + { 04750, AID_ROOT, AID_SHELL, 0, "system/xbin/su" }, { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/librank" }, { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procrank" }, { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procmem" }, diff --git a/init/builtins.c b/init/builtins.c index d9f7bbe71..0c32b2a7b 100644 --- a/init/builtins.c +++ b/init/builtins.c @@ -877,6 +877,14 @@ int do_load_persist_props(int nargs, char **args) { return -1; } +int do_load_all_props(int nargs, char **args) { + if (nargs == 1) { + load_all_props(); + return 0; + } + return -1; +} + int do_wait(int nargs, char **args) { if (nargs == 2) { diff --git a/init/devices.c b/init/devices.c index 3119e8eca..ea9a4b25d 100644 --- a/init/devices.c +++ b/init/devices.c @@ -15,6 +15,7 @@ */ #include <errno.h> +#include <fnmatch.h> #include <stddef.h> #include <stdio.h> #include <stdlib.h> @@ -77,6 +78,7 @@ struct perms_ { unsigned int uid; unsigned int gid; unsigned short prefix; + unsigned short wildcard; }; struct perm_node { @@ -97,7 +99,8 @@ static list_declare(platform_names); int add_dev_perms(const char *name, const char *attr, mode_t perm, unsigned int uid, unsigned int gid, - unsigned short prefix) { + unsigned short prefix, + unsigned short wildcard) { struct perm_node *node = calloc(1, sizeof(*node)); if (!node) return -ENOMEM; @@ -116,6 +119,7 @@ int add_dev_perms(const char *name, const char *attr, node->dp.uid = uid; node->dp.gid = gid; node->dp.prefix = prefix; + node->dp.wildcard = wildcard; if (attr) list_add_tail(&sys_perms, &node->plist); @@ -140,6 +144,9 @@ void fixup_sys_perms(const char *upath) if (dp->prefix) { if (strncmp(upath, dp->name + 4, strlen(dp->name + 4))) continue; + } else if (dp->wildcard) { + if (fnmatch(dp->name + 4, upath, FNM_PATHNAME) != 0) + continue; } else { if (strcmp(upath, dp->name + 4)) continue; @@ -180,6 +187,9 @@ static mode_t get_device_perm(const char *path, unsigned *uid, unsigned *gid) if (dp->prefix) { if (strncmp(path, dp->name, strlen(dp->name))) continue; + } else if (dp->wildcard) { + if (fnmatch(dp->name, path, FNM_PATHNAME) != 0) + continue; } else { if (strcmp(path, dp->name)) continue; @@ -196,7 +206,8 @@ static mode_t get_device_perm(const char *path, unsigned *uid, unsigned *gid) static void make_device(const char *path, const char *upath UNUSED, - int block, int major, int minor) + int block, int major, int minor, + const char **links) { unsigned uid; unsigned gid; @@ -207,7 +218,7 @@ static void make_device(const char *path, mode = get_device_perm(path, &uid, &gid) | (block ? S_IFBLK : S_IFCHR); if (sehandle) { - selabel_lookup(sehandle, &secontext, path, mode); + selabel_lookup_best_match(sehandle, &secontext, path, links, mode); setfscreatecon(secontext); } @@ -523,7 +534,7 @@ static void handle_device(const char *action, const char *devpath, int i; if(!strcmp(action, "add")) { - make_device(devpath, path, block, major, minor); + make_device(devpath, path, block, major, minor, (const char **)links); if (links) { for (i = 0; links[i]; i++) make_link(devpath, links[i]); diff --git a/init/devices.h b/init/devices.h index a84fa5827..5d0fe8862 100644 --- a/init/devices.h +++ b/init/devices.h @@ -23,6 +23,7 @@ extern void handle_device_fd(); extern void device_init(void); extern int add_dev_perms(const char *name, const char *attr, mode_t perm, unsigned int uid, - unsigned int gid, unsigned short prefix); + unsigned int gid, unsigned short prefix, + unsigned short wildcard); int get_device_fd(); #endif /* _INIT_DEVICES_H */ diff --git a/init/init.c b/init/init.c index c79929bf7..f00107163 100644 --- a/init/init.c +++ b/init/init.c @@ -938,7 +938,7 @@ static int audit_callback(void *data, security_class_t cls __attribute__((unused return 0; } -static int log_callback(int type, const char *fmt, ...) +int log_callback(int type, const char *fmt, ...) { int level; va_list ap; @@ -1051,8 +1051,7 @@ int main(int argc, char **argv) is_charger = !strcmp(bootmode, "charger"); INFO("property init\n"); - if (!is_charger) - property_load_boot_defaults(); + property_load_boot_defaults(); INFO("reading config file\n"); init_parse_config_file("/init.rc"); @@ -1067,28 +1066,19 @@ int main(int argc, char **argv) /* execute all the boot actions to get us started */ action_for_each_trigger("init", action_add_queue_tail); - /* skip mounting filesystems in charger mode */ - if (!is_charger) { - action_for_each_trigger("early-fs", action_add_queue_tail); - action_for_each_trigger("fs", action_add_queue_tail); - action_for_each_trigger("post-fs", action_add_queue_tail); - action_for_each_trigger("post-fs-data", action_add_queue_tail); - } - /* Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random * wasn't ready immediately after wait_for_coldboot_done */ queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng"); - queue_builtin_action(property_service_init_action, "property_service_init"); queue_builtin_action(signal_init_action, "signal_init"); queue_builtin_action(check_startup_action, "check_startup"); + /* Don't mount filesystems or start core system services if in charger mode. */ if (is_charger) { action_for_each_trigger("charger", action_add_queue_tail); } else { - action_for_each_trigger("early-boot", action_add_queue_tail); - action_for_each_trigger("boot", action_add_queue_tail); + action_for_each_trigger("late-init", action_add_queue_tail); } /* run all property triggers based on current state of the properties */ diff --git a/init/init_parser.c b/init/init_parser.c index 78000825d..289e75975 100644 --- a/init/init_parser.c +++ b/init/init_parser.c @@ -120,6 +120,7 @@ static int lookup_keyword(const char *s) case 'l': if (!strcmp(s, "oglevel")) return K_loglevel; if (!strcmp(s, "oad_persist_props")) return K_load_persist_props; + if (!strcmp(s, "oad_all_props")) return K_load_all_props; break; case 'm': if (!strcmp(s, "kdir")) return K_mkdir; diff --git a/init/keywords.h b/init/keywords.h index 6625330c1..2d97e5b99 100644 --- a/init/keywords.h +++ b/init/keywords.h @@ -39,6 +39,7 @@ int do_chown(int nargs, char **args); int do_chmod(int nargs, char **args); int do_loglevel(int nargs, char **args); int do_load_persist_props(int nargs, char **args); +int do_load_all_props(int nargs, char **args); int do_wait(int nargs, char **args); #define __MAKE_KEYWORD_ENUM__ #define KEYWORD(symbol, flags, nargs, func) K_##symbol, @@ -101,6 +102,7 @@ enum { KEYWORD(chmod, COMMAND, 2, do_chmod) KEYWORD(loglevel, COMMAND, 1, do_loglevel) KEYWORD(load_persist_props, COMMAND, 0, do_load_persist_props) + KEYWORD(load_all_props, COMMAND, 0, do_load_all_props) KEYWORD(ioprio, OPTION, 0, 0) #ifdef __MAKE_KEYWORD_ENUM__ KEYWORD_COUNT, diff --git a/init/log.h b/init/log.h index 0ba770fe9..e9cb65a60 100644 --- a/init/log.h +++ b/init/log.h @@ -23,4 +23,6 @@ #define NOTICE(x...) KLOG_NOTICE("init", x) #define INFO(x...) KLOG_INFO("init", x) +extern int log_callback(int type, const char *fmt, ...); + #endif diff --git a/init/property_service.c b/init/property_service.c index fb3bc8d13..d112699e5 100644 --- a/init/property_service.c +++ b/init/property_service.c @@ -55,64 +55,6 @@ static int property_area_inited = 0; static int property_set_fd = -1; -/* White list of permissions for setting property services. */ -struct { - const char *prefix; - unsigned int uid; - unsigned int gid; -} property_perms[] = { - { "net.rmnet0.", AID_RADIO, 0 }, - { "net.gprs.", AID_RADIO, 0 }, - { "net.ppp", AID_RADIO, 0 }, - { "net.qmi", AID_RADIO, 0 }, - { "net.lte", AID_RADIO, 0 }, - { "net.cdma", AID_RADIO, 0 }, - { "ril.", AID_RADIO, 0 }, - { "gsm.", AID_RADIO, 0 }, - { "persist.radio", AID_RADIO, 0 }, - { "net.dns", AID_RADIO, 0 }, - { "sys.usb.config", AID_RADIO, 0 }, - { "net.", AID_SYSTEM, 0 }, - { "dev.", AID_SYSTEM, 0 }, - { "runtime.", AID_SYSTEM, 0 }, - { "hw.", AID_SYSTEM, 0 }, - { "sys.", AID_SYSTEM, 0 }, - { "sys.powerctl", AID_SHELL, 0 }, - { "service.", AID_SYSTEM, 0 }, - { "wlan.", AID_SYSTEM, 0 }, - { "gps.", AID_GPS, 0 }, - { "bluetooth.", AID_BLUETOOTH, 0 }, - { "dhcp.", AID_SYSTEM, 0 }, - { "dhcp.", AID_DHCP, 0 }, - { "debug.", AID_SYSTEM, 0 }, - { "debug.", AID_SHELL, 0 }, - { "log.", AID_SHELL, 0 }, - { "service.adb.root", AID_SHELL, 0 }, - { "service.adb.tcp.port", AID_SHELL, 0 }, - { "persist.logd.size",AID_SYSTEM, 0 }, - { "persist.sys.", AID_SYSTEM, 0 }, - { "persist.service.", AID_SYSTEM, 0 }, - { "persist.security.", AID_SYSTEM, 0 }, - { "persist.gps.", AID_GPS, 0 }, - { "persist.service.bdroid.", AID_BLUETOOTH, 0 }, - { "selinux." , AID_SYSTEM, 0 }, - { NULL, 0, 0 } -}; - -/* - * White list of UID that are allowed to start/stop services. - * Currently there are no user apps that require. - */ -struct { - const char *service; - unsigned int uid; - unsigned int gid; -} control_perms[] = { - { "dumpstate",AID_SHELL, AID_LOG }, - { "ril-daemon",AID_RADIO, AID_RADIO }, - {NULL, 0, 0 } -}; - typedef struct { size_t size; int fd; @@ -194,34 +136,10 @@ static int check_control_mac_perms(const char *name, char *sctx) } /* - * Checks permissions for starting/stoping system services. - * AID_SYSTEM and AID_ROOT are always allowed. - * - * Returns 1 if uid allowed, 0 otherwise. - */ -static int check_control_perms(const char *name, unsigned int uid, unsigned int gid, char *sctx) { - - int i; - if (uid == AID_SYSTEM || uid == AID_ROOT) - return check_control_mac_perms(name, sctx); - - /* Search the ACL */ - for (i = 0; control_perms[i].service; i++) { - if (strcmp(control_perms[i].service, name) == 0) { - if ((uid && control_perms[i].uid == uid) || - (gid && control_perms[i].gid == gid)) { - return check_control_mac_perms(name, sctx); - } - } - } - return 0; -} - -/* * Checks permissions for setting system properties. * Returns 1 if uid allowed, 0 otherwise. */ -static int check_perms(const char *name, unsigned int uid, unsigned int gid, char *sctx) +static int check_perms(const char *name, char *sctx) { int i; unsigned int app_id; @@ -229,26 +147,7 @@ static int check_perms(const char *name, unsigned int uid, unsigned int gid, cha if(!strncmp(name, "ro.", 3)) name +=3; - if (uid == 0) - return check_mac_perms(name, sctx); - - app_id = multiuser_get_app_id(uid); - if (app_id == AID_BLUETOOTH) { - uid = app_id; - } - - for (i = 0; property_perms[i].prefix; i++) { - if (strncmp(property_perms[i].prefix, name, - strlen(property_perms[i].prefix)) == 0) { - if ((uid && property_perms[i].uid == uid) || - (gid && property_perms[i].gid == gid)) { - - return check_mac_perms(name, sctx); - } - } - } - - return 0; + return check_mac_perms(name, sctx); } int __property_get(const char *name, char *value) @@ -406,14 +305,14 @@ void handle_property_set_fd() // Keep the old close-socket-early behavior when handling // ctl.* properties. close(s); - if (check_control_perms(msg.value, cr.uid, cr.gid, source_ctx)) { + if (check_control_mac_perms(msg.value, source_ctx)) { handle_control_message((char*) msg.name + 4, (char*) msg.value); } else { ERROR("sys_prop: Unable to %s service ctl [%s] uid:%d gid:%d pid:%d\n", msg.name + 4, msg.value, cr.uid, cr.gid, cr.pid); } } else { - if (check_perms(msg.name, cr.uid, cr.gid, source_ctx)) { + if (check_perms(msg.name, source_ctx)) { property_set((char*) msg.name, (char*) msg.value); } else { ERROR("sys_prop: permission denied uid:%d name:%s\n", @@ -621,10 +520,8 @@ void load_persist_props(void) load_persistent_properties(); } -void start_property_service(void) +void load_all_props(void) { - int fd; - load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL); load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT, NULL); load_properties_from_file(PROP_PATH_FACTORY, "ro.*"); @@ -633,6 +530,11 @@ void start_property_service(void) /* Read persistent properties after all default values have been loaded. */ load_persistent_properties(); +} + +void start_property_service(void) +{ + int fd; fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0, NULL); if(fd < 0) return; diff --git a/init/property_service.h b/init/property_service.h index 46cbd8ff5..730495e68 100644 --- a/init/property_service.h +++ b/init/property_service.h @@ -24,6 +24,7 @@ extern void handle_property_set_fd(void); extern void property_init(void); extern void property_load_boot_defaults(void); extern void load_persist_props(void); +extern void load_all_props(void); extern void start_property_service(void); void get_property_workspace(int *fd, int *sz); extern int __property_get(const char *name, char *value); diff --git a/init/ueventd.c b/init/ueventd.c index 662196dc1..833e4fd0c 100644 --- a/init/ueventd.c +++ b/init/ueventd.c @@ -21,6 +21,7 @@ #include <stdio.h> #include <ctype.h> #include <signal.h> +#include <selinux/selinux.h> #include <private/android_filesystem_config.h> @@ -76,6 +77,10 @@ int ueventd_main(int argc, char **argv) } #endif + union selinux_callback cb; + cb.func_log = log_callback; + selinux_set_callback(SELINUX_CB_LOG, cb); + INFO("starting ueventd\n"); /* Respect hardware passed in through the kernel cmd line. Here we will look @@ -122,6 +127,7 @@ void set_device_permission(int nargs, char **args) uid_t uid; gid_t gid; int prefix = 0; + int wildcard = 0; char *endptr; int ret; char *tmp = 0; @@ -154,9 +160,13 @@ void set_device_permission(int nargs, char **args) name = tmp; } else { int len = strlen(name); - if (name[len - 1] == '*') { + char *wildcard_chr = strchr(name, '*'); + if ((name[len - 1] == '*') && + (wildcard_chr == (name + len - 1))) { prefix = 1; name[len - 1] = '\0'; + } else if (wildcard_chr) { + wildcard = 1; } } @@ -183,6 +193,6 @@ void set_device_permission(int nargs, char **args) } gid = ret; - add_dev_perms(name, attr, perm, uid, gid, prefix); + add_dev_perms(name, attr, perm, uid, gid, prefix, wildcard); free(tmp); } diff --git a/libbacktrace/Android.build.mk b/libbacktrace/Android.build.mk index 9882e3116..2f5564533 100644 --- a/libbacktrace/Android.build.mk +++ b/libbacktrace/Android.build.mk @@ -18,6 +18,7 @@ include $(CLEAR_VARS) LOCAL_MODULE := $(module) LOCAL_MODULE_TAGS := $(module_tag) +LOCAL_MULTILIB := $($(module)_multilib) LOCAL_ADDITIONAL_DEPENDENCIES := \ $(LOCAL_PATH)/Android.mk \ diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk index 5a0bc7ff6..c321369ba 100755 --- a/libbacktrace/Android.mk +++ b/libbacktrace/Android.mk @@ -113,7 +113,9 @@ build_type := target build_target := SHARED_LIBRARY include $(LOCAL_PATH)/Android.build.mk build_type := host +libbacktrace_libc++_multilib := both include $(LOCAL_PATH)/Android.build.mk +libbacktrace_libc++_multilib := endif #------------------------------------------------------------------------- @@ -186,4 +188,23 @@ LOCAL_SRC_FILES := \ include $(BUILD_HOST_SHARED_LIBRARY) +# Don't build for unbundled branches +ifeq (,$(TARGET_BUILD_APPS)) +#------------------------------------------------------------------------- +# The libbacktrace library (libc++) +#------------------------------------------------------------------------- +include $(CLEAR_VARS) + +LOCAL_MODULE := libbacktrace_libc++ +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := \ + BacktraceMap.cpp \ + +LOCAL_MULTILIB := both + +include $(BUILD_HOST_SHARED_LIBRARY) + +endif # TARGET_BUILD_APPS + endif # HOST_OS-darwin diff --git a/libcutils/Android.mk b/libcutils/Android.mk index 20ad7eadb..933a77bdf 100644 --- a/libcutils/Android.mk +++ b/libcutils/Android.mk @@ -81,6 +81,8 @@ LOCAL_CFLAGS += $(hostSmpFlag) ifneq ($(HOST_OS),windows) LOCAL_CFLAGS += -Werror endif +LOCAL_MULTILIB := both +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk include $(BUILD_HOST_STATIC_LIBRARY) @@ -94,6 +96,7 @@ LOCAL_CFLAGS += $(hostSmpFlag) -m64 ifneq ($(HOST_OS),windows) LOCAL_CFLAGS += -Werror endif +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk include $(BUILD_HOST_STATIC_LIBRARY) # Tests for host @@ -107,6 +110,7 @@ endif LOCAL_SRC_FILES := str_parms.c hashmap.c memory.c LOCAL_STATIC_LIBRARIES := liblog LOCAL_MODULE_TAGS := optional +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk include $(BUILD_HOST_EXECUTABLE) @@ -120,30 +124,40 @@ LOCAL_SRC_FILES := $(commonSources) \ ashmem-dev.c \ debugger.c \ klog.c \ + memory.c \ partition_utils.c \ properties.c \ qtaguid.c \ trace.c \ - uevent.c - -ifeq ($(TARGET_ARCH),arm) - LOCAL_SRC_FILES += arch-arm/memset32.S -else # !arm - ifeq ($(TARGET_ARCH),x86) - LOCAL_CFLAGS += -DHAVE_MEMSET16 -DHAVE_MEMSET32 - LOCAL_SRC_FILES += arch-x86/android_memset16.S arch-x86/android_memset32.S memory.c - else # !x86 - ifeq ($(TARGET_ARCH),mips) - LOCAL_SRC_FILES += arch-mips/android_memset.c - else # !mips - LOCAL_SRC_FILES += memory.c - endif # !mips - endif # !x86 -endif # !arm + uevent.c \ + +LOCAL_SRC_FILES_arm += \ + arch-arm/memset32.S \ + +LOCAL_SRC_FILES_arm64 += \ + arch-arm64/android_memset.S \ + +LOCAL_SRC_FILES_mips += \ + arch-mips/android_memset.c \ + +LOCAL_SRC_FILES_x86 += \ + arch-x86/android_memset16.S \ + arch-x86/android_memset32.S \ + +LOCAL_SRC_FILES_x86_64 += \ + arch-x86_64/android_memset16_SSE2-atom.S \ + arch-x86_64/android_memset32_SSE2-atom.S \ + +LOCAL_CFLAGS_arm += -DHAVE_MEMSET16 -DHAVE_MEMSET32 +LOCAL_CFLAGS_arm64 += -DHAVE_MEMSET16 -DHAVE_MEMSET32 +LOCAL_CFLAGS_mips += -DHAVE_MEMSET16 -DHAVE_MEMSET32 +LOCAL_CFLAGS_x86 += -DHAVE_MEMSET16 -DHAVE_MEMSET32 +LOCAL_CFLAGS_x86_64 += -DHAVE_MEMSET16 -DHAVE_MEMSET32 LOCAL_C_INCLUDES := $(libcutils_c_includes) LOCAL_STATIC_LIBRARIES := liblog LOCAL_CFLAGS += $(targetSmpFlag) -Werror +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) @@ -154,6 +168,7 @@ LOCAL_WHOLE_STATIC_LIBRARIES := libcutils liblog LOCAL_SHARED_LIBRARIES := liblog LOCAL_CFLAGS += $(targetSmpFlag) -Werror LOCAL_C_INCLUDES := $(libcutils_c_includes) +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk include $(BUILD_SHARED_LIBRARY) include $(CLEAR_VARS) @@ -162,6 +177,7 @@ LOCAL_CFLAGS += -DTEST_STR_PARMS -Werror LOCAL_SRC_FILES := str_parms.c hashmap.c memory.c LOCAL_SHARED_LIBRARIES := liblog LOCAL_MODULE_TAGS := optional +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk include $(BUILD_EXECUTABLE) include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/libcutils/arch-arm/memset32.S b/libcutils/arch-arm/memset32.S index 469726563..6efab9f93 100644 --- a/libcutils/arch-arm/memset32.S +++ b/libcutils/arch-arm/memset32.S @@ -51,8 +51,10 @@ android_memset16: android_memset32: .fnstart - .save {lr} + .cfi_startproc str lr, [sp, #-4]! + .cfi_def_cfa_offset 4 + .cfi_rel_offset lr, 0 /* align the destination to a cache-line */ mov r12, r1 @@ -89,5 +91,8 @@ android_memset32: strmih lr, [r0], #2 ldr lr, [sp], #4 + .cfi_def_cfa_offset 0 + .cfi_restore lr bx lr + .cfi_endproc .fnend diff --git a/libcutils/arch-arm64/android_memset.S b/libcutils/arch-arm64/android_memset.S new file mode 100644 index 000000000..9a83a6876 --- /dev/null +++ b/libcutils/arch-arm64/android_memset.S @@ -0,0 +1,211 @@ +/* Copyright (c) 2012, Linaro Limited + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Linaro nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* Assumptions: + * + * ARMv8-a, AArch64 + * Unaligned accesses + * + */ + +/* By default we assume that the DC instruction can be used to zero + data blocks more efficiently. In some circumstances this might be + unsafe, for example in an asymmetric multiprocessor environment with + different DC clear lengths (neither the upper nor lower lengths are + safe to use). */ + +#define dst x0 +#define count x2 +#define tmp1 x3 +#define tmp1w w3 +#define tmp2 x4 +#define tmp2w w4 +#define zva_len_x x5 +#define zva_len w5 +#define zva_bits_x x6 + +#define A_l x1 +#define A_lw w1 +#define tmp3w w9 + +#define ENTRY(f) \ + .text; \ + .globl f; \ + .align 0; \ + .type f, %function; \ + f: \ + .cfi_startproc \ + +#define END(f) \ + .cfi_endproc; \ + .size f, .-f; \ + +ENTRY(android_memset16) + ands A_lw, A_lw, #0xffff + b.eq .Lzero_mem + orr A_lw, A_lw, A_lw, lsl #16 + b .Lexpand_to_64 +END(android_memset16) + +ENTRY(android_memset32) + cmp A_lw, #0 + b.eq .Lzero_mem +.Lexpand_to_64: + orr A_l, A_l, A_l, lsl #32 +.Ltail_maybe_long: + cmp count, #64 + b.ge .Lnot_short +.Ltail_maybe_tiny: + cmp count, #15 + b.le .Ltail15tiny +.Ltail63: + ands tmp1, count, #0x30 + b.eq .Ltail15 + add dst, dst, tmp1 + cmp tmp1w, #0x20 + b.eq 1f + b.lt 2f + stp A_l, A_l, [dst, #-48] +1: + stp A_l, A_l, [dst, #-32] +2: + stp A_l, A_l, [dst, #-16] + +.Ltail15: + and count, count, #15 + add dst, dst, count + stp A_l, A_l, [dst, #-16] /* Repeat some/all of last store. */ + ret + +.Ltail15tiny: + /* Set up to 15 bytes. Does not assume earlier memory + being set. */ + tbz count, #3, 1f + str A_l, [dst], #8 +1: + tbz count, #2, 1f + str A_lw, [dst], #4 +1: + tbz count, #1, 1f + strh A_lw, [dst], #2 +1: + ret + + /* Critical loop. Start at a new cache line boundary. Assuming + * 64 bytes per line, this ensures the entire loop is in one line. */ + .p2align 6 +.Lnot_short: + neg tmp2, dst + ands tmp2, tmp2, #15 + b.eq 2f + /* Bring DST to 128-bit (16-byte) alignment. We know that there's + * more than that to set, so we simply store 16 bytes and advance by + * the amount required to reach alignment. */ + sub count, count, tmp2 + stp A_l, A_l, [dst] + add dst, dst, tmp2 + /* There may be less than 63 bytes to go now. */ + cmp count, #63 + b.le .Ltail63 +2: + sub dst, dst, #16 /* Pre-bias. */ + sub count, count, #64 +1: + stp A_l, A_l, [dst, #16] + stp A_l, A_l, [dst, #32] + stp A_l, A_l, [dst, #48] + stp A_l, A_l, [dst, #64]! + subs count, count, #64 + b.ge 1b + tst count, #0x3f + add dst, dst, #16 + b.ne .Ltail63 + ret + + /* For zeroing memory, check to see if we can use the ZVA feature to + * zero entire 'cache' lines. */ +.Lzero_mem: + mov A_l, #0 + cmp count, #63 + b.le .Ltail_maybe_tiny + neg tmp2, dst + ands tmp2, tmp2, #15 + b.eq 1f + sub count, count, tmp2 + stp A_l, A_l, [dst] + add dst, dst, tmp2 + cmp count, #63 + b.le .Ltail63 +1: + /* For zeroing small amounts of memory, it's not worth setting up + * the line-clear code. */ + cmp count, #128 + b.lt .Lnot_short + mrs tmp1, dczid_el0 + tbnz tmp1, #4, .Lnot_short + mov tmp3w, #4 + and zva_len, tmp1w, #15 /* Safety: other bits reserved. */ + lsl zva_len, tmp3w, zva_len + +.Lzero_by_line: + /* Compute how far we need to go to become suitably aligned. We're + * already at quad-word alignment. */ + cmp count, zva_len_x + b.lt .Lnot_short /* Not enough to reach alignment. */ + sub zva_bits_x, zva_len_x, #1 + neg tmp2, dst + ands tmp2, tmp2, zva_bits_x + b.eq 1f /* Already aligned. */ + /* Not aligned, check that there's enough to copy after alignment. */ + sub tmp1, count, tmp2 + cmp tmp1, #64 + ccmp tmp1, zva_len_x, #8, ge /* NZCV=0b1000 */ + b.lt .Lnot_short + /* We know that there's at least 64 bytes to zero and that it's safe + * to overrun by 64 bytes. */ + mov count, tmp1 +2: + stp A_l, A_l, [dst] + stp A_l, A_l, [dst, #16] + stp A_l, A_l, [dst, #32] + subs tmp2, tmp2, #64 + stp A_l, A_l, [dst, #48] + add dst, dst, #64 + b.ge 2b + /* We've overrun a bit, so adjust dst downwards. */ + add dst, dst, tmp2 +1: + sub count, count, zva_len_x +3: + dc zva, dst + add dst, dst, zva_len_x + subs count, count, zva_len_x + b.ge 3b + ands count, count, zva_bits_x + b.ne .Ltail_maybe_long + ret +END(android_memset32) diff --git a/libcutils/arch-x86_64/android_memset16_SSE2-atom.S b/libcutils/arch-x86_64/android_memset16_SSE2-atom.S new file mode 100644 index 000000000..48a10ed66 --- /dev/null +++ b/libcutils/arch-x86_64/android_memset16_SSE2-atom.S @@ -0,0 +1,564 @@ +/* + * 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. + */ +/* + * Contributed by: Intel Corporation + */ + +#include "cache.h" + +#ifndef L +# define L(label) .L##label +#endif + +#ifndef ALIGN +# define ALIGN(n) .p2align n +#endif + +#ifndef cfi_startproc +# define cfi_startproc .cfi_startproc +#endif + +#ifndef cfi_endproc +# define cfi_endproc .cfi_endproc +#endif + +#ifndef ENTRY +# define ENTRY(name) \ + .type name, @function; \ + .globl name; \ + .p2align 4; \ +name: \ + cfi_startproc +#endif + +#ifndef END +# define END(name) \ + cfi_endproc; \ + .size name, .-name +#endif + +#define JMPTBL(I, B) I - B + +/* Branch to an entry in a jump table. TABLE is a jump table with + relative offsets. INDEX is a register contains the index into the + jump table. SCALE is the scale of INDEX. */ +#define BRANCH_TO_JMPTBL_ENTRY(TABLE, INDEX, SCALE) \ + lea TABLE(%rip), %r11; \ + movslq (%r11, INDEX, SCALE), INDEX; \ + lea (%r11, INDEX), INDEX; \ + jmp *INDEX + + .section .text.sse2,"ax",@progbits + ALIGN (4) +ENTRY (android_memset16) // Address in rdi + shr $1, %rdx // Count in rdx + movzwl %si, %ecx + /* Fill the whole ECX with pattern. */ + shl $16, %esi + or %esi, %ecx // Pattern in ecx + + cmp $32, %rdx + jae L(32wordsormore) + +L(write_less32words): + lea (%rdi, %rdx, 2), %rdi + BRANCH_TO_JMPTBL_ENTRY (L(table_less32words), %rdx, 4) + + .pushsection .rodata.sse2,"a",@progbits + ALIGN (2) +L(table_less32words): + .int JMPTBL (L(write_0words), L(table_less32words)) + .int JMPTBL (L(write_1words), L(table_less32words)) + .int JMPTBL (L(write_2words), L(table_less32words)) + .int JMPTBL (L(write_3words), L(table_less32words)) + .int JMPTBL (L(write_4words), L(table_less32words)) + .int JMPTBL (L(write_5words), L(table_less32words)) + .int JMPTBL (L(write_6words), L(table_less32words)) + .int JMPTBL (L(write_7words), L(table_less32words)) + .int JMPTBL (L(write_8words), L(table_less32words)) + .int JMPTBL (L(write_9words), L(table_less32words)) + .int JMPTBL (L(write_10words), L(table_less32words)) + .int JMPTBL (L(write_11words), L(table_less32words)) + .int JMPTBL (L(write_12words), L(table_less32words)) + .int JMPTBL (L(write_13words), L(table_less32words)) + .int JMPTBL (L(write_14words), L(table_less32words)) + .int JMPTBL (L(write_15words), L(table_less32words)) + .int JMPTBL (L(write_16words), L(table_less32words)) + .int JMPTBL (L(write_17words), L(table_less32words)) + .int JMPTBL (L(write_18words), L(table_less32words)) + .int JMPTBL (L(write_19words), L(table_less32words)) + .int JMPTBL (L(write_20words), L(table_less32words)) + .int JMPTBL (L(write_21words), L(table_less32words)) + .int JMPTBL (L(write_22words), L(table_less32words)) + .int JMPTBL (L(write_23words), L(table_less32words)) + .int JMPTBL (L(write_24words), L(table_less32words)) + .int JMPTBL (L(write_25words), L(table_less32words)) + .int JMPTBL (L(write_26words), L(table_less32words)) + .int JMPTBL (L(write_27words), L(table_less32words)) + .int JMPTBL (L(write_28words), L(table_less32words)) + .int JMPTBL (L(write_29words), L(table_less32words)) + .int JMPTBL (L(write_30words), L(table_less32words)) + .int JMPTBL (L(write_31words), L(table_less32words)) + .popsection + + ALIGN (4) +L(write_28words): + movl %ecx, -56(%rdi) + movl %ecx, -52(%rdi) +L(write_24words): + movl %ecx, -48(%rdi) + movl %ecx, -44(%rdi) +L(write_20words): + movl %ecx, -40(%rdi) + movl %ecx, -36(%rdi) +L(write_16words): + movl %ecx, -32(%rdi) + movl %ecx, -28(%rdi) +L(write_12words): + movl %ecx, -24(%rdi) + movl %ecx, -20(%rdi) +L(write_8words): + movl %ecx, -16(%rdi) + movl %ecx, -12(%rdi) +L(write_4words): + movl %ecx, -8(%rdi) + movl %ecx, -4(%rdi) +L(write_0words): + ret + + ALIGN (4) +L(write_29words): + movl %ecx, -58(%rdi) + movl %ecx, -54(%rdi) +L(write_25words): + movl %ecx, -50(%rdi) + movl %ecx, -46(%rdi) +L(write_21words): + movl %ecx, -42(%rdi) + movl %ecx, -38(%rdi) +L(write_17words): + movl %ecx, -34(%rdi) + movl %ecx, -30(%rdi) +L(write_13words): + movl %ecx, -26(%rdi) + movl %ecx, -22(%rdi) +L(write_9words): + movl %ecx, -18(%rdi) + movl %ecx, -14(%rdi) +L(write_5words): + movl %ecx, -10(%rdi) + movl %ecx, -6(%rdi) +L(write_1words): + mov %cx, -2(%rdi) + ret + + ALIGN (4) +L(write_30words): + movl %ecx, -60(%rdi) + movl %ecx, -56(%rdi) +L(write_26words): + movl %ecx, -52(%rdi) + movl %ecx, -48(%rdi) +L(write_22words): + movl %ecx, -44(%rdi) + movl %ecx, -40(%rdi) +L(write_18words): + movl %ecx, -36(%rdi) + movl %ecx, -32(%rdi) +L(write_14words): + movl %ecx, -28(%rdi) + movl %ecx, -24(%rdi) +L(write_10words): + movl %ecx, -20(%rdi) + movl %ecx, -16(%rdi) +L(write_6words): + movl %ecx, -12(%rdi) + movl %ecx, -8(%rdi) +L(write_2words): + movl %ecx, -4(%rdi) + ret + + ALIGN (4) +L(write_31words): + movl %ecx, -62(%rdi) + movl %ecx, -58(%rdi) +L(write_27words): + movl %ecx, -54(%rdi) + movl %ecx, -50(%rdi) +L(write_23words): + movl %ecx, -46(%rdi) + movl %ecx, -42(%rdi) +L(write_19words): + movl %ecx, -38(%rdi) + movl %ecx, -34(%rdi) +L(write_15words): + movl %ecx, -30(%rdi) + movl %ecx, -26(%rdi) +L(write_11words): + movl %ecx, -22(%rdi) + movl %ecx, -18(%rdi) +L(write_7words): + movl %ecx, -14(%rdi) + movl %ecx, -10(%rdi) +L(write_3words): + movl %ecx, -6(%rdi) + movw %cx, -2(%rdi) + ret + + ALIGN (4) +L(32wordsormore): + shl $1, %rdx + test $0x01, %edi + jz L(aligned2bytes) + mov %ecx, (%rdi) + mov %ecx, -4(%rdi, %rdx) + sub $2, %rdx + add $1, %rdi + rol $8, %ecx +L(aligned2bytes): + /* Fill xmm0 with the pattern. */ + movd %ecx, %xmm0 + pshufd $0, %xmm0, %xmm0 + + testl $0xf, %edi + jz L(aligned_16) +/* RDX > 32 and RDI is not 16 byte aligned. */ + movdqu %xmm0, (%rdi) + mov %rdi, %rsi + and $-16, %rdi + add $16, %rdi + sub %rdi, %rsi + add %rsi, %rdx + + ALIGN (4) +L(aligned_16): + cmp $128, %rdx + jge L(128bytesormore) + +L(aligned_16_less128bytes): + add %rdx, %rdi + shr $1, %rdx + BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4) + + ALIGN (4) +L(128bytesormore): + cmp $SHARED_CACHE_SIZE, %rdx + jg L(128bytesormore_nt) + +L(128bytesormore_normal): + sub $128, %rdx + movdqa %xmm0, (%rdi) + movdqa %xmm0, 0x10(%rdi) + movdqa %xmm0, 0x20(%rdi) + movdqa %xmm0, 0x30(%rdi) + movdqa %xmm0, 0x40(%rdi) + movdqa %xmm0, 0x50(%rdi) + movdqa %xmm0, 0x60(%rdi) + movdqa %xmm0, 0x70(%rdi) + lea 128(%rdi), %rdi + cmp $128, %rdx + jl L(128bytesless_normal) + + sub $128, %rdx + movdqa %xmm0, (%rdi) + movdqa %xmm0, 0x10(%rdi) + movdqa %xmm0, 0x20(%rdi) + movdqa %xmm0, 0x30(%rdi) + movdqa %xmm0, 0x40(%rdi) + movdqa %xmm0, 0x50(%rdi) + movdqa %xmm0, 0x60(%rdi) + movdqa %xmm0, 0x70(%rdi) + lea 128(%rdi), %rdi + cmp $128, %rdx + jl L(128bytesless_normal) + + sub $128, %rdx + movdqa %xmm0, (%rdi) + movdqa %xmm0, 0x10(%rdi) + movdqa %xmm0, 0x20(%rdi) + movdqa %xmm0, 0x30(%rdi) + movdqa %xmm0, 0x40(%rdi) + movdqa %xmm0, 0x50(%rdi) + movdqa %xmm0, 0x60(%rdi) + movdqa %xmm0, 0x70(%rdi) + lea 128(%rdi), %rdi + cmp $128, %rdx + jl L(128bytesless_normal) + + sub $128, %rdx + movdqa %xmm0, (%rdi) + movdqa %xmm0, 0x10(%rdi) + movdqa %xmm0, 0x20(%rdi) + movdqa %xmm0, 0x30(%rdi) + movdqa %xmm0, 0x40(%rdi) + movdqa %xmm0, 0x50(%rdi) + movdqa %xmm0, 0x60(%rdi) + movdqa %xmm0, 0x70(%rdi) + lea 128(%rdi), %rdi + cmp $128, %rdx + jge L(128bytesormore_normal) + +L(128bytesless_normal): + add %rdx, %rdi + shr $1, %rdx + BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4) + + ALIGN (4) +L(128bytesormore_nt): + sub $128, %rdx + movntdq %xmm0, (%rdi) + movntdq %xmm0, 0x10(%rdi) + movntdq %xmm0, 0x20(%rdi) + movntdq %xmm0, 0x30(%rdi) + movntdq %xmm0, 0x40(%rdi) + movntdq %xmm0, 0x50(%rdi) + movntdq %xmm0, 0x60(%rdi) + movntdq %xmm0, 0x70(%rdi) + lea 128(%rdi), %rdi + cmp $128, %rdx + jge L(128bytesormore_nt) + + sfence + add %rdx, %rdi + shr $1, %rdx + BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4) + + .pushsection .rodata.sse2,"a",@progbits + ALIGN (2) +L(table_16_128bytes): + .int JMPTBL (L(aligned_16_0bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_2bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_4bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_6bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_8bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_10bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_12bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_14bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_16bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_18bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_20bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_22bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_24bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_26bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_28bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_30bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_32bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_34bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_36bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_38bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_40bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_42bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_44bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_46bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_48bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_50bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_52bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_54bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_56bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_58bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_60bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_62bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_64bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_66bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_68bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_70bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_72bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_74bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_76bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_78bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_80bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_82bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_84bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_86bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_88bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_90bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_92bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_94bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_96bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_98bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_100bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_102bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_104bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_106bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_108bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_110bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_112bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_114bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_116bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_118bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_120bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_122bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_124bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_126bytes), L(table_16_128bytes)) + .popsection + + ALIGN (4) +L(aligned_16_112bytes): + movdqa %xmm0, -112(%rdi) +L(aligned_16_96bytes): + movdqa %xmm0, -96(%rdi) +L(aligned_16_80bytes): + movdqa %xmm0, -80(%rdi) +L(aligned_16_64bytes): + movdqa %xmm0, -64(%rdi) +L(aligned_16_48bytes): + movdqa %xmm0, -48(%rdi) +L(aligned_16_32bytes): + movdqa %xmm0, -32(%rdi) +L(aligned_16_16bytes): + movdqa %xmm0, -16(%rdi) +L(aligned_16_0bytes): + ret + + ALIGN (4) +L(aligned_16_114bytes): + movdqa %xmm0, -114(%rdi) +L(aligned_16_98bytes): + movdqa %xmm0, -98(%rdi) +L(aligned_16_82bytes): + movdqa %xmm0, -82(%rdi) +L(aligned_16_66bytes): + movdqa %xmm0, -66(%rdi) +L(aligned_16_50bytes): + movdqa %xmm0, -50(%rdi) +L(aligned_16_34bytes): + movdqa %xmm0, -34(%rdi) +L(aligned_16_18bytes): + movdqa %xmm0, -18(%rdi) +L(aligned_16_2bytes): + movw %cx, -2(%rdi) + ret + + ALIGN (4) +L(aligned_16_116bytes): + movdqa %xmm0, -116(%rdi) +L(aligned_16_100bytes): + movdqa %xmm0, -100(%rdi) +L(aligned_16_84bytes): + movdqa %xmm0, -84(%rdi) +L(aligned_16_68bytes): + movdqa %xmm0, -68(%rdi) +L(aligned_16_52bytes): + movdqa %xmm0, -52(%rdi) +L(aligned_16_36bytes): + movdqa %xmm0, -36(%rdi) +L(aligned_16_20bytes): + movdqa %xmm0, -20(%rdi) +L(aligned_16_4bytes): + movl %ecx, -4(%rdi) + ret + + ALIGN (4) +L(aligned_16_118bytes): + movdqa %xmm0, -118(%rdi) +L(aligned_16_102bytes): + movdqa %xmm0, -102(%rdi) +L(aligned_16_86bytes): + movdqa %xmm0, -86(%rdi) +L(aligned_16_70bytes): + movdqa %xmm0, -70(%rdi) +L(aligned_16_54bytes): + movdqa %xmm0, -54(%rdi) +L(aligned_16_38bytes): + movdqa %xmm0, -38(%rdi) +L(aligned_16_22bytes): + movdqa %xmm0, -22(%rdi) +L(aligned_16_6bytes): + movl %ecx, -6(%rdi) + movw %cx, -2(%rdi) + ret + + ALIGN (4) +L(aligned_16_120bytes): + movdqa %xmm0, -120(%rdi) +L(aligned_16_104bytes): + movdqa %xmm0, -104(%rdi) +L(aligned_16_88bytes): + movdqa %xmm0, -88(%rdi) +L(aligned_16_72bytes): + movdqa %xmm0, -72(%rdi) +L(aligned_16_56bytes): + movdqa %xmm0, -56(%rdi) +L(aligned_16_40bytes): + movdqa %xmm0, -40(%rdi) +L(aligned_16_24bytes): + movdqa %xmm0, -24(%rdi) +L(aligned_16_8bytes): + movq %xmm0, -8(%rdi) + ret + + ALIGN (4) +L(aligned_16_122bytes): + movdqa %xmm0, -122(%rdi) +L(aligned_16_106bytes): + movdqa %xmm0, -106(%rdi) +L(aligned_16_90bytes): + movdqa %xmm0, -90(%rdi) +L(aligned_16_74bytes): + movdqa %xmm0, -74(%rdi) +L(aligned_16_58bytes): + movdqa %xmm0, -58(%rdi) +L(aligned_16_42bytes): + movdqa %xmm0, -42(%rdi) +L(aligned_16_26bytes): + movdqa %xmm0, -26(%rdi) +L(aligned_16_10bytes): + movq %xmm0, -10(%rdi) + movw %cx, -2(%rdi) + ret + + ALIGN (4) +L(aligned_16_124bytes): + movdqa %xmm0, -124(%rdi) +L(aligned_16_108bytes): + movdqa %xmm0, -108(%rdi) +L(aligned_16_92bytes): + movdqa %xmm0, -92(%rdi) +L(aligned_16_76bytes): + movdqa %xmm0, -76(%rdi) +L(aligned_16_60bytes): + movdqa %xmm0, -60(%rdi) +L(aligned_16_44bytes): + movdqa %xmm0, -44(%rdi) +L(aligned_16_28bytes): + movdqa %xmm0, -28(%rdi) +L(aligned_16_12bytes): + movq %xmm0, -12(%rdi) + movl %ecx, -4(%rdi) + ret + + ALIGN (4) +L(aligned_16_126bytes): + movdqa %xmm0, -126(%rdi) +L(aligned_16_110bytes): + movdqa %xmm0, -110(%rdi) +L(aligned_16_94bytes): + movdqa %xmm0, -94(%rdi) +L(aligned_16_78bytes): + movdqa %xmm0, -78(%rdi) +L(aligned_16_62bytes): + movdqa %xmm0, -62(%rdi) +L(aligned_16_46bytes): + movdqa %xmm0, -46(%rdi) +L(aligned_16_30bytes): + movdqa %xmm0, -30(%rdi) +L(aligned_16_14bytes): + movq %xmm0, -14(%rdi) + movl %ecx, -6(%rdi) + movw %cx, -2(%rdi) + ret + +END (android_memset16) diff --git a/libcutils/arch-x86_64/android_memset32_SSE2-atom.S b/libcutils/arch-x86_64/android_memset32_SSE2-atom.S new file mode 100644 index 000000000..4bdea8e0a --- /dev/null +++ b/libcutils/arch-x86_64/android_memset32_SSE2-atom.S @@ -0,0 +1,372 @@ +/* + * 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. + */ +/* + * Contributed by: Intel Corporation + */ + +#include "cache.h" + +#ifndef L +# define L(label) .L##label +#endif + +#ifndef ALIGN +# define ALIGN(n) .p2align n +#endif + +#ifndef cfi_startproc +# define cfi_startproc .cfi_startproc +#endif + +#ifndef cfi_endproc +# define cfi_endproc .cfi_endproc +#endif + +#ifndef ENTRY +# define ENTRY(name) \ + .type name, @function; \ + .globl name; \ + .p2align 4; \ +name: \ + cfi_startproc +#endif + +#ifndef END +# define END(name) \ + cfi_endproc; \ + .size name, .-name +#endif + +#define JMPTBL(I, B) I - B + +/* Branch to an entry in a jump table. TABLE is a jump table with + relative offsets. INDEX is a register contains the index into the + jump table. SCALE is the scale of INDEX. */ +#define BRANCH_TO_JMPTBL_ENTRY(TABLE, INDEX, SCALE) \ + lea TABLE(%rip), %r11; \ + movslq (%r11, INDEX, SCALE), INDEX; \ + lea (%r11, INDEX), INDEX; \ + jmp *INDEX + + .section .text.sse2,"ax",@progbits + ALIGN (4) +ENTRY (android_memset32) // Address in rdi + shr $2, %rdx // Count in rdx + movl %esi, %ecx // Pattern in ecx + + cmp $16, %rdx + jae L(16dbwordsormore) + +L(write_less16dbwords): + lea (%rdi, %rdx, 4), %rdi + BRANCH_TO_JMPTBL_ENTRY (L(table_less16dbwords), %rdx, 4) + + .pushsection .rodata.sse2,"a",@progbits + ALIGN (2) +L(table_less16dbwords): + .int JMPTBL (L(write_0dbwords), L(table_less16dbwords)) + .int JMPTBL (L(write_1dbwords), L(table_less16dbwords)) + .int JMPTBL (L(write_2dbwords), L(table_less16dbwords)) + .int JMPTBL (L(write_3dbwords), L(table_less16dbwords)) + .int JMPTBL (L(write_4dbwords), L(table_less16dbwords)) + .int JMPTBL (L(write_5dbwords), L(table_less16dbwords)) + .int JMPTBL (L(write_6dbwords), L(table_less16dbwords)) + .int JMPTBL (L(write_7dbwords), L(table_less16dbwords)) + .int JMPTBL (L(write_8dbwords), L(table_less16dbwords)) + .int JMPTBL (L(write_9dbwords), L(table_less16dbwords)) + .int JMPTBL (L(write_10dbwords), L(table_less16dbwords)) + .int JMPTBL (L(write_11dbwords), L(table_less16dbwords)) + .int JMPTBL (L(write_12dbwords), L(table_less16dbwords)) + .int JMPTBL (L(write_13dbwords), L(table_less16dbwords)) + .int JMPTBL (L(write_14dbwords), L(table_less16dbwords)) + .int JMPTBL (L(write_15dbwords), L(table_less16dbwords)) + .popsection + + ALIGN (4) +L(write_15dbwords): + movl %ecx, -60(%rdi) +L(write_14dbwords): + movl %ecx, -56(%rdi) +L(write_13dbwords): + movl %ecx, -52(%rdi) +L(write_12dbwords): + movl %ecx, -48(%rdi) +L(write_11dbwords): + movl %ecx, -44(%rdi) +L(write_10dbwords): + movl %ecx, -40(%rdi) +L(write_9dbwords): + movl %ecx, -36(%rdi) +L(write_8dbwords): + movl %ecx, -32(%rdi) +L(write_7dbwords): + movl %ecx, -28(%rdi) +L(write_6dbwords): + movl %ecx, -24(%rdi) +L(write_5dbwords): + movl %ecx, -20(%rdi) +L(write_4dbwords): + movl %ecx, -16(%rdi) +L(write_3dbwords): + movl %ecx, -12(%rdi) +L(write_2dbwords): + movl %ecx, -8(%rdi) +L(write_1dbwords): + movl %ecx, -4(%rdi) +L(write_0dbwords): + ret + + ALIGN (4) +L(16dbwordsormore): + test $3, %edi + jz L(aligned4bytes) + mov %ecx, (%rdi) + mov %ecx, -4(%rdi, %rdx, 4) + sub $1, %rdx + rol $24, %ecx + add $1, %rdi + test $3, %edi + jz L(aligned4bytes) + ror $8, %ecx + add $1, %rdi + test $3, %edi + jz L(aligned4bytes) + ror $8, %ecx + add $1, %rdi +L(aligned4bytes): + shl $2, %rdx + + /* Fill xmm0 with the pattern. */ + movd %ecx, %xmm0 + pshufd $0, %xmm0, %xmm0 + + testl $0xf, %edi + jz L(aligned_16) +/* RDX > 32 and RDI is not 16 byte aligned. */ + movdqu %xmm0, (%rdi) + mov %rdi, %rsi + and $-16, %rdi + add $16, %rdi + sub %rdi, %rsi + add %rsi, %rdx + + ALIGN (4) +L(aligned_16): + cmp $128, %rdx + jge L(128bytesormore) + +L(aligned_16_less128bytes): + add %rdx, %rdi + shr $2, %rdx + BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4) + + ALIGN (4) +L(128bytesormore): + cmp $SHARED_CACHE_SIZE, %rdx + jg L(128bytesormore_nt) + +L(128bytesormore_normal): + sub $128, %rdx + movdqa %xmm0, (%rdi) + movdqa %xmm0, 0x10(%rdi) + movdqa %xmm0, 0x20(%rdi) + movdqa %xmm0, 0x30(%rdi) + movdqa %xmm0, 0x40(%rdi) + movdqa %xmm0, 0x50(%rdi) + movdqa %xmm0, 0x60(%rdi) + movdqa %xmm0, 0x70(%rdi) + lea 128(%rdi), %rdi + cmp $128, %rdx + jl L(128bytesless_normal) + + sub $128, %rdx + movdqa %xmm0, (%rdi) + movdqa %xmm0, 0x10(%rdi) + movdqa %xmm0, 0x20(%rdi) + movdqa %xmm0, 0x30(%rdi) + movdqa %xmm0, 0x40(%rdi) + movdqa %xmm0, 0x50(%rdi) + movdqa %xmm0, 0x60(%rdi) + movdqa %xmm0, 0x70(%rdi) + lea 128(%rdi), %rdi + cmp $128, %rdx + jl L(128bytesless_normal) + + sub $128, %rdx + movdqa %xmm0, (%rdi) + movdqa %xmm0, 0x10(%rdi) + movdqa %xmm0, 0x20(%rdi) + movdqa %xmm0, 0x30(%rdi) + movdqa %xmm0, 0x40(%rdi) + movdqa %xmm0, 0x50(%rdi) + movdqa %xmm0, 0x60(%rdi) + movdqa %xmm0, 0x70(%rdi) + lea 128(%rdi), %rdi + cmp $128, %rdx + jl L(128bytesless_normal) + + sub $128, %rdx + movdqa %xmm0, (%rdi) + movdqa %xmm0, 0x10(%rdi) + movdqa %xmm0, 0x20(%rdi) + movdqa %xmm0, 0x30(%rdi) + movdqa %xmm0, 0x40(%rdi) + movdqa %xmm0, 0x50(%rdi) + movdqa %xmm0, 0x60(%rdi) + movdqa %xmm0, 0x70(%rdi) + lea 128(%rdi), %rdi + cmp $128, %rdx + jge L(128bytesormore_normal) + +L(128bytesless_normal): + add %rdx, %rdi + shr $2, %rdx + BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4) + + ALIGN (4) +L(128bytesormore_nt): + sub $128, %rdx + movntdq %xmm0, (%rdi) + movntdq %xmm0, 0x10(%rdi) + movntdq %xmm0, 0x20(%rdi) + movntdq %xmm0, 0x30(%rdi) + movntdq %xmm0, 0x40(%rdi) + movntdq %xmm0, 0x50(%rdi) + movntdq %xmm0, 0x60(%rdi) + movntdq %xmm0, 0x70(%rdi) + lea 128(%rdi), %rdi + cmp $128, %rdx + jge L(128bytesormore_nt) + + sfence + add %rdx, %rdi + shr $2, %rdx + BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4) + + .pushsection .rodata.sse2,"a",@progbits + ALIGN (2) +L(table_16_128bytes): + .int JMPTBL (L(aligned_16_0bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_4bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_8bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_12bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_16bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_20bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_24bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_28bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_32bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_36bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_40bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_44bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_48bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_52bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_56bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_60bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_64bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_68bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_72bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_76bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_80bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_84bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_88bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_92bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_96bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_100bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_104bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_108bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_112bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_116bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_120bytes), L(table_16_128bytes)) + .int JMPTBL (L(aligned_16_124bytes), L(table_16_128bytes)) + .popsection + + ALIGN (4) +L(aligned_16_112bytes): + movdqa %xmm0, -112(%rdi) +L(aligned_16_96bytes): + movdqa %xmm0, -96(%rdi) +L(aligned_16_80bytes): + movdqa %xmm0, -80(%rdi) +L(aligned_16_64bytes): + movdqa %xmm0, -64(%rdi) +L(aligned_16_48bytes): + movdqa %xmm0, -48(%rdi) +L(aligned_16_32bytes): + movdqa %xmm0, -32(%rdi) +L(aligned_16_16bytes): + movdqa %xmm0, -16(%rdi) +L(aligned_16_0bytes): + ret + + ALIGN (4) +L(aligned_16_116bytes): + movdqa %xmm0, -116(%rdi) +L(aligned_16_100bytes): + movdqa %xmm0, -100(%rdi) +L(aligned_16_84bytes): + movdqa %xmm0, -84(%rdi) +L(aligned_16_68bytes): + movdqa %xmm0, -68(%rdi) +L(aligned_16_52bytes): + movdqa %xmm0, -52(%rdi) +L(aligned_16_36bytes): + movdqa %xmm0, -36(%rdi) +L(aligned_16_20bytes): + movdqa %xmm0, -20(%rdi) +L(aligned_16_4bytes): + movl %ecx, -4(%rdi) + ret + + ALIGN (4) +L(aligned_16_120bytes): + movdqa %xmm0, -120(%rdi) +L(aligned_16_104bytes): + movdqa %xmm0, -104(%rdi) +L(aligned_16_88bytes): + movdqa %xmm0, -88(%rdi) +L(aligned_16_72bytes): + movdqa %xmm0, -72(%rdi) +L(aligned_16_56bytes): + movdqa %xmm0, -56(%rdi) +L(aligned_16_40bytes): + movdqa %xmm0, -40(%rdi) +L(aligned_16_24bytes): + movdqa %xmm0, -24(%rdi) +L(aligned_16_8bytes): + movq %xmm0, -8(%rdi) + ret + + ALIGN (4) +L(aligned_16_124bytes): + movdqa %xmm0, -124(%rdi) +L(aligned_16_108bytes): + movdqa %xmm0, -108(%rdi) +L(aligned_16_92bytes): + movdqa %xmm0, -92(%rdi) +L(aligned_16_76bytes): + movdqa %xmm0, -76(%rdi) +L(aligned_16_60bytes): + movdqa %xmm0, -60(%rdi) +L(aligned_16_44bytes): + movdqa %xmm0, -44(%rdi) +L(aligned_16_28bytes): + movdqa %xmm0, -28(%rdi) +L(aligned_16_12bytes): + movq %xmm0, -12(%rdi) + movl %ecx, -4(%rdi) + ret + +END (android_memset32) diff --git a/libcutils/arch-x86_64/cache.h b/libcutils/arch-x86_64/cache.h new file mode 100644 index 000000000..ab5dd2fdc --- /dev/null +++ b/libcutils/arch-x86_64/cache.h @@ -0,0 +1,31 @@ +/* + * 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. + */ +/* + * Contributed by: Intel Corporation + */ + +#if defined(__slm__) +/* Values are optimized for Silvermont */ +#define SHARED_CACHE_SIZE (1024*1024) /* Silvermont L2 Cache */ +#define DATA_CACHE_SIZE (24*1024) /* Silvermont L1 Data Cache */ +#else +/* Values are optimized for Atom */ +#define SHARED_CACHE_SIZE (512*1024) /* Atom L2 Cache */ +#define DATA_CACHE_SIZE (24*1024) /* Atom L1 Data Cache */ +#endif + +#define SHARED_CACHE_SIZE_HALF (SHARED_CACHE_SIZE / 2) +#define DATA_CACHE_SIZE_HALF (DATA_CACHE_SIZE / 2) diff --git a/libcutils/iosched_policy.c b/libcutils/iosched_policy.c index 67e101dec..a6da9cac6 100644 --- a/libcutils/iosched_policy.c +++ b/libcutils/iosched_policy.c @@ -21,31 +21,19 @@ #include <string.h> #include <unistd.h> -#ifdef HAVE_SCHED_H - #include <cutils/iosched_policy.h> #ifdef HAVE_ANDROID_OS -/* #include <linux/ioprio.h> */ -extern int ioprio_set(int which, int who, int ioprio); -extern int ioprio_get(int which, int who); +#include <linux/ioprio.h> +#include <sys/syscall.h> #define __android_unused #else #define __android_unused __attribute__((__unused__)) #endif -enum { - WHO_PROCESS = 1, - WHO_PGRP, - WHO_USER, -}; - -#define CLASS_SHIFT 13 -#define IOPRIO_NORM 4 - int android_set_ioprio(int pid __android_unused, IoSchedClass clazz __android_unused, int ioprio __android_unused) { #ifdef HAVE_ANDROID_OS - if (ioprio_set(WHO_PROCESS, pid, ioprio | (clazz << CLASS_SHIFT))) { + if (syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, pid, ioprio | (clazz << IOPRIO_CLASS_SHIFT))) { return -1; } #endif @@ -56,11 +44,11 @@ int android_get_ioprio(int pid __android_unused, IoSchedClass *clazz, int *iopri #ifdef HAVE_ANDROID_OS int rc; - if ((rc = ioprio_get(WHO_PROCESS, pid)) < 0) { + if ((rc = syscall(SYS_ioprio_get, IOPRIO_WHO_PROCESS, pid)) < 0) { return -1; } - *clazz = (rc >> CLASS_SHIFT); + *clazz = (rc >> IOPRIO_CLASS_SHIFT); *ioprio = (rc & 0xff); #else *clazz = IoSchedClass_NONE; @@ -68,5 +56,3 @@ int android_get_ioprio(int pid __android_unused, IoSchedClass *clazz, int *iopri #endif return 0; } - -#endif /* HAVE_SCHED_H */ diff --git a/libcutils/properties.c b/libcutils/properties.c index 28d8b2f59..b283658aa 100644 --- a/libcutils/properties.c +++ b/libcutils/properties.c @@ -15,17 +15,95 @@ */ #define LOG_TAG "properties" +// #define LOG_NDEBUG 0 #include <stdlib.h> #include <string.h> +#include <ctype.h> #include <unistd.h> #include <cutils/sockets.h> #include <errno.h> #include <assert.h> #include <cutils/properties.h> +#include <stdbool.h> +#include <inttypes.h> #include "loghack.h" +int8_t property_get_bool(const char *key, int8_t default_value) { + if (!key) { + return default_value; + } + + int8_t result = default_value; + char buf[PROPERTY_VALUE_MAX] = {'\0',}; + + int len = property_get(key, buf, ""); + if (len == 1) { + char ch = buf[0]; + if (ch == '0' || ch == 'n') { + result = false; + } else if (ch == '1' || ch == 'y') { + result = true; + } + } else if (len > 1) { + if (!strcmp(buf, "no") || !strcmp(buf, "false") || !strcmp(buf, "off")) { + result = false; + } else if (!strcmp(buf, "yes") || !strcmp(buf, "true") || !strcmp(buf, "on")) { + result = true; + } + } + + return result; +} + +// Convert string property to int (default if fails); return default value if out of bounds +static intmax_t property_get_imax(const char *key, intmax_t lower_bound, intmax_t upper_bound, + intmax_t default_value) { + if (!key) { + return default_value; + } + + intmax_t result = default_value; + char buf[PROPERTY_VALUE_MAX] = {'\0',}; + char *end = NULL; + + int len = property_get(key, buf, ""); + if (len > 0) { + int tmp = errno; + errno = 0; + + // Infer base automatically + result = strtoimax(buf, &end, /*base*/0); + if ((result == INTMAX_MIN || result == INTMAX_MAX) && errno == ERANGE) { + // Over or underflow + result = default_value; + ALOGV("%s(%s,%" PRIdMAX ") - overflow", __FUNCTION__, key, default_value); + } else if (result < lower_bound || result > upper_bound) { + // Out of range of requested bounds + result = default_value; + ALOGV("%s(%s,%" PRIdMAX ") - out of range", __FUNCTION__, key, default_value); + } else if (end == buf) { + // Numeric conversion failed + result = default_value; + ALOGV("%s(%s,%" PRIdMAX ") - numeric conversion failed", + __FUNCTION__, key, default_value); + } + + errno = tmp; + } + + return result; +} + +int64_t property_get_int64(const char *key, int64_t default_value) { + return (int64_t)property_get_imax(key, INT64_MIN, INT64_MAX, default_value); +} + +int32_t property_get_int32(const char *key, int32_t default_value) { + return (int32_t)property_get_imax(key, INT32_MIN, INT32_MAX, default_value); +} + #ifdef HAVE_LIBC_SYSTEM_PROPERTIES #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ @@ -44,10 +122,13 @@ int property_get(const char *key, char *value, const char *default_value) if(len > 0) { return len; } - if(default_value) { len = strlen(default_value); - memcpy(value, default_value, len + 1); + if (len >= PROPERTY_VALUE_MAX) { + len = PROPERTY_VALUE_MAX - 1; + } + memcpy(value, default_value, len); + value[len] = '\0'; } return len; } diff --git a/libcutils/tests/Android.mk b/libcutils/tests/Android.mk new file mode 100644 index 000000000..8e6531074 --- /dev/null +++ b/libcutils/tests/Android.mk @@ -0,0 +1,48 @@ +# 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. + +LOCAL_PATH := $(call my-dir) + +test_src_files := \ + MemsetTest.cpp \ + PropertiesTest.cpp \ + +include $(CLEAR_VARS) +LOCAL_MODULE := libcutils_test +LOCAL_SRC_FILES := $(test_src_files) +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + liblog \ + libutils \ + +LOCAL_MULTILIB := both +LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32 +LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64 +include $(BUILD_NATIVE_TEST) + +include $(CLEAR_VARS) +LOCAL_MODULE := libcutils_test_static +LOCAL_FORCE_STATIC_EXECUTABLE := true +LOCAL_SRC_FILES := $(test_src_files) +LOCAL_STATIC_LIBRARIES := \ + libc \ + libcutils \ + liblog \ + libstlport_static \ + libutils \ + +LOCAL_MULTILIB := both +LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32 +LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64 +include $(BUILD_NATIVE_TEST) diff --git a/libcutils/tests/MemsetTest.cpp b/libcutils/tests/MemsetTest.cpp new file mode 100644 index 000000000..45efc519c --- /dev/null +++ b/libcutils/tests/MemsetTest.cpp @@ -0,0 +1,181 @@ +/* + * 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 <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/types.h> + +#include <cutils/memory.h> +#include <gtest/gtest.h> + +#define FENCEPOST_LENGTH 8 + +#define MAX_TEST_SIZE (64*1024) +// Choose values that have no repeating byte values. +#define MEMSET16_PATTERN 0xb139 +#define MEMSET32_PATTERN 0x48193a27 + +enum test_e { + MEMSET16 = 0, + MEMSET32, +}; + +static int g_memset16_aligns[][2] = { + { 2, 0 }, + { 4, 0 }, + { 8, 0 }, + { 16, 0 }, + { 32, 0 }, + { 64, 0 }, + { 128, 0 }, + + { 4, 2 }, + + { 8, 2 }, + { 8, 4 }, + { 8, 6 }, + + { 128, 2 }, + { 128, 4 }, + { 128, 6 }, + { 128, 8 }, + { 128, 10 }, + { 128, 12 }, + { 128, 14 }, + { 128, 16 }, +}; + +static int g_memset32_aligns[][2] = { + { 4, 0 }, + { 8, 0 }, + { 16, 0 }, + { 32, 0 }, + { 64, 0 }, + { 128, 0 }, + + { 8, 4 }, + + { 128, 4 }, + { 128, 8 }, + { 128, 12 }, + { 128, 16 }, +}; + +static size_t GetIncrement(size_t len, size_t min_incr) { + if (len >= 4096) { + return 1024; + } else if (len >= 1024) { + return 256; + } + return min_incr; +} + +// Return a pointer into the current buffer with the specified alignment. +static void *GetAlignedPtr(void *orig_ptr, int alignment, int or_mask) { + uint64_t ptr = reinterpret_cast<uint64_t>(orig_ptr); + if (alignment > 0) { + // When setting the alignment, set it to exactly the alignment chosen. + // The pointer returned will be guaranteed not to be aligned to anything + // more than that. + ptr += alignment - (ptr & (alignment - 1)); + ptr |= alignment | or_mask; + } + + return reinterpret_cast<void*>(ptr); +} + +static void SetFencepost(uint8_t *buffer) { + for (int i = 0; i < FENCEPOST_LENGTH; i += 2) { + buffer[i] = 0xde; + buffer[i+1] = 0xad; + } +} + +static void VerifyFencepost(uint8_t *buffer) { + for (int i = 0; i < FENCEPOST_LENGTH; i += 2) { + if (buffer[i] != 0xde || buffer[i+1] != 0xad) { + uint8_t expected_value; + if (buffer[i] == 0xde) { + i++; + expected_value = 0xad; + } else { + expected_value = 0xde; + } + ASSERT_EQ(expected_value, buffer[i]); + } + } +} + +void RunMemsetTests(test_e test_type, uint32_t value, int align[][2], size_t num_aligns) { + size_t min_incr = 4; + if (test_type == MEMSET16) { + min_incr = 2; + value |= value << 16; + } + uint32_t* expected_buf = new uint32_t[MAX_TEST_SIZE/sizeof(uint32_t)]; + for (size_t i = 0; i < MAX_TEST_SIZE/sizeof(uint32_t); i++) { + expected_buf[i] = value; + } + + // Allocate one large buffer with lots of extra space so that we can + // guarantee that all possible alignments will fit. + uint8_t *buf = new uint8_t[3*MAX_TEST_SIZE]; + uint8_t *buf_align; + for (size_t i = 0; i < num_aligns; i++) { + size_t incr = min_incr; + for (size_t len = incr; len <= MAX_TEST_SIZE; len += incr) { + incr = GetIncrement(len, min_incr); + + buf_align = reinterpret_cast<uint8_t*>(GetAlignedPtr( + buf+FENCEPOST_LENGTH, align[i][0], align[i][1])); + + SetFencepost(&buf_align[-FENCEPOST_LENGTH]); + SetFencepost(&buf_align[len]); + + memset(buf_align, 0xff, len); + if (test_type == MEMSET16) { + android_memset16(reinterpret_cast<uint16_t*>(buf_align), value, len); + } else { + android_memset32(reinterpret_cast<uint32_t*>(buf_align), value, len); + } + ASSERT_EQ(0, memcmp(expected_buf, buf_align, len)) + << "Failed size " << len << " align " << align[i][0] << " " << align[i][1] << "\n"; + + VerifyFencepost(&buf_align[-FENCEPOST_LENGTH]); + VerifyFencepost(&buf_align[len]); + } + } + delete expected_buf; + delete buf; +} + +TEST(libcutils, android_memset16_non_zero) { + RunMemsetTests(MEMSET16, MEMSET16_PATTERN, g_memset16_aligns, sizeof(g_memset16_aligns)/sizeof(int[2])); +} + +TEST(libcutils, android_memset16_zero) { + RunMemsetTests(MEMSET16, 0, g_memset16_aligns, sizeof(g_memset16_aligns)/sizeof(int[2])); +} + +TEST(libcutils, android_memset32_non_zero) { + RunMemsetTests(MEMSET32, MEMSET32_PATTERN, g_memset32_aligns, sizeof(g_memset32_aligns)/sizeof(int[2])); +} + +TEST(libcutils, android_memset32_zero) { + RunMemsetTests(MEMSET32, 0, g_memset32_aligns, sizeof(g_memset32_aligns)/sizeof(int[2])); +} diff --git a/libcutils/tests/PropertiesTest.cpp b/libcutils/tests/PropertiesTest.cpp new file mode 100644 index 000000000..659821c2e --- /dev/null +++ b/libcutils/tests/PropertiesTest.cpp @@ -0,0 +1,309 @@ +/* + * 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. + */ + +#define LOG_TAG "Properties_test" +#include <utils/Log.h> +#include <gtest/gtest.h> + +#include <cutils/properties.h> +#include <limits.h> +#include <string> +#include <sstream> +#include <iostream> + +namespace android { + +#define STRINGIFY_INNER(x) #x +#define STRINGIFY(x) STRINGIFY_INNER(x) +#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) +#define ASSERT_OK(x) ASSERT_EQ(0, (x)) +#define EXPECT_OK(x) EXPECT_EQ(0, (x)) + +#define PROPERTY_TEST_KEY "libcutils.test.key" +#define PROPERTY_TEST_VALUE_DEFAULT "<<<default_value>>>" + +template <typename T> +static std::string HexString(T value) { + std::stringstream ss; + ss << "0x" << std::hex << std::uppercase << value; + return ss.str(); +} + +template <typename T> +static ::testing::AssertionResult AssertEqualHex(const char *mExpr, + const char *nExpr, + T m, + T n) { + if (m == n) { + return ::testing::AssertionSuccess(); + } + + return ::testing::AssertionFailure() + << mExpr << " and " << nExpr << " (expected: " << HexString(m) << + ", actual: " << HexString(n) << ") are not equal"; +} + +class PropertiesTest : public testing::Test { +public: + PropertiesTest() : mValue() {} +protected: + virtual void SetUp() { + EXPECT_OK(property_set(PROPERTY_TEST_KEY, /*value*/NULL)); + } + + virtual void TearDown() { + EXPECT_OK(property_set(PROPERTY_TEST_KEY, /*value*/NULL)); + } + + char mValue[PROPERTY_VALUE_MAX]; + + template <typename T> + static std::string ToString(T value) { + std::stringstream ss; + ss << value; + + return ss.str(); + } + + // Return length of property read; value is written into mValue + int SetAndGetProperty(const char* value, const char* defaultValue = PROPERTY_TEST_VALUE_DEFAULT) { + EXPECT_OK(property_set(PROPERTY_TEST_KEY, value)) << "value: '" << value << "'"; + return property_get(PROPERTY_TEST_KEY, mValue, defaultValue); + } + + void ResetValue(unsigned char c = 0xFF) { + for (size_t i = 0; i < ARRAY_SIZE(mValue); ++i) { + mValue[i] = (char) c; + } + } +}; + +TEST_F(PropertiesTest, SetString) { + + // Null key -> unsuccessful set + { + // Null key -> fails + EXPECT_GT(0, property_set(/*key*/NULL, PROPERTY_TEST_VALUE_DEFAULT)); + } + + // Null value -> returns default value + { + // Null value -> OK , and it clears the value + EXPECT_OK(property_set(PROPERTY_TEST_KEY, /*value*/NULL)); + ResetValue(); + + // Since the value is null, default value will be returned + int len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT); + EXPECT_EQ(strlen(PROPERTY_TEST_VALUE_DEFAULT), len); + EXPECT_STREQ(PROPERTY_TEST_VALUE_DEFAULT, mValue); + } + + // Trivial case => get returns what was set + { + int len = SetAndGetProperty("hello_world"); + EXPECT_EQ(strlen("hello_world"), len) << "hello_world key"; + EXPECT_STREQ("hello_world", mValue); + ResetValue(); + } + + // Set to empty string => get returns default always + { + const char* EMPTY_STRING_DEFAULT = "EMPTY_STRING"; + int len = SetAndGetProperty("", EMPTY_STRING_DEFAULT); + EXPECT_EQ(strlen(EMPTY_STRING_DEFAULT), len) << "empty key"; + EXPECT_STREQ(EMPTY_STRING_DEFAULT, mValue); + ResetValue(); + } + + // Set to max length => get returns what was set + { + std::string maxLengthString = std::string(PROPERTY_VALUE_MAX-1, 'a'); + + int len = SetAndGetProperty(maxLengthString.c_str()); + EXPECT_EQ(PROPERTY_VALUE_MAX-1, len) << "max length key"; + EXPECT_STREQ(maxLengthString.c_str(), mValue); + ResetValue(); + } + + // Set to max length + 1 => set fails + { + const char* VALID_TEST_VALUE = "VALID_VALUE"; + ASSERT_OK(property_set(PROPERTY_TEST_KEY, VALID_TEST_VALUE)); + + std::string oneLongerString = std::string(PROPERTY_VALUE_MAX, 'a'); + + // Expect that the value set fails since it's too long + EXPECT_GT(0, property_set(PROPERTY_TEST_KEY, oneLongerString.c_str())); + int len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT); + + EXPECT_EQ(strlen(VALID_TEST_VALUE), len) << "set should've failed"; + EXPECT_STREQ(VALID_TEST_VALUE, mValue); + ResetValue(); + } +} + +TEST_F(PropertiesTest, GetString) { + + // Try to use a default value that's too long => set fails + { + ASSERT_OK(property_set(PROPERTY_TEST_KEY, "")); + + std::string maxLengthString = std::string(PROPERTY_VALUE_MAX-1, 'a'); + std::string oneLongerString = std::string(PROPERTY_VALUE_MAX, 'a'); + + // Expect that the value is truncated since it's too long (by 1) + int len = property_get(PROPERTY_TEST_KEY, mValue, oneLongerString.c_str()); + EXPECT_EQ(PROPERTY_VALUE_MAX-1, len); + EXPECT_STREQ(maxLengthString.c_str(), mValue); + ResetValue(); + } +} + +TEST_F(PropertiesTest, GetBool) { + /** + * TRUE + */ + const char *valuesTrue[] = { "1", "true", "y", "yes", "on", }; + for (size_t i = 0; i < ARRAY_SIZE(valuesTrue); ++i) { + ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesTrue[i])); + bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/false); + EXPECT_TRUE(val) << "Property should've been TRUE for value: '" << valuesTrue[i] << "'"; + } + + /** + * FALSE + */ + const char *valuesFalse[] = { "0", "false", "n", "no", "off", }; + for (size_t i = 0; i < ARRAY_SIZE(valuesFalse); ++i) { + ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesFalse[i])); + bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/true); + EXPECT_FALSE(val) << "Property shoud've been FALSE For string value: '" << valuesFalse[i] << "'"; + } + + /** + * NEITHER + */ + const char *valuesNeither[] = { "x0", "x1", "2", "-2", "True", "False", "garbage", "", " ", + "+1", " 1 ", " true", " true ", " y ", " yes", "yes ", + "+0", "-0", "00", " 00 ", " false", "false ", + }; + for (size_t i = 0; i < ARRAY_SIZE(valuesNeither); ++i) { + ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesNeither[i])); + + // The default value should always be used + bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/true); + EXPECT_TRUE(val) << "Property should've been NEITHER (true) for string value: '" << valuesNeither[i] << "'"; + + val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/false); + EXPECT_FALSE(val) << "Property should've been NEITHER (false) for string value: '" << valuesNeither[i] << "'"; + } +} + +TEST_F(PropertiesTest, GetInt64) { + const int64_t DEFAULT_VALUE = INT64_C(0xDEADBEEFBEEFDEAD); + + const std::string longMaxString = ToString(INT64_MAX); + const std::string longStringOverflow = longMaxString + "0"; + + const std::string longMinString = ToString(INT64_MIN); + const std::string longStringUnderflow = longMinString + "0"; + + const char* setValues[] = { + // base 10 + "1", "2", "12345", "-1", "-2", "-12345", + // base 16 + "0xFF", "0x0FF", "0xC0FFEE", + // base 8 + "0", "01234", "07", + // corner cases + " 2", "2 ", "+0", "-0", " +0 ", longMaxString.c_str(), longMinString.c_str(), + // failing cases + NULL, "", " ", " ", "hello", " true ", "y", + longStringOverflow.c_str(), longStringUnderflow.c_str(), + }; + + int64_t getValues[] = { + // base 10 + 1, 2, 12345, -1, -2, -12345, + // base 16 + 0xFF, 0x0FF, 0xC0FFEE, + // base 8 + 0, 01234, 07, + // corner cases + 2, 2, 0, 0, 0, INT64_MAX, INT64_MIN, + // failing cases + DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, + DEFAULT_VALUE, DEFAULT_VALUE, + }; + + ASSERT_EQ(ARRAY_SIZE(setValues), ARRAY_SIZE(getValues)); + + for (size_t i = 0; i < ARRAY_SIZE(setValues); ++i) { + ASSERT_OK(property_set(PROPERTY_TEST_KEY, setValues[i])); + + int64_t val = property_get_int64(PROPERTY_TEST_KEY, DEFAULT_VALUE); + EXPECT_PRED_FORMAT2(AssertEqualHex, getValues[i], val) << "Property was set to '" << setValues[i] << "'"; + } +} + +TEST_F(PropertiesTest, GetInt32) { + const int32_t DEFAULT_VALUE = INT32_C(0xDEADBEEF); + + const std::string intMaxString = ToString(INT32_MAX); + const std::string intStringOverflow = intMaxString + "0"; + + const std::string intMinString = ToString(INT32_MIN); + const std::string intStringUnderflow = intMinString + "0"; + + const char* setValues[] = { + // base 10 + "1", "2", "12345", "-1", "-2", "-12345", + // base 16 + "0xFF", "0x0FF", "0xC0FFEE", "0Xf00", + // base 8 + "0", "01234", "07", + // corner cases + " 2", "2 ", "+0", "-0", " +0 ", intMaxString.c_str(), intMinString.c_str(), + // failing cases + NULL, "", " ", " ", "hello", " true ", "y", + intStringOverflow.c_str(), intStringUnderflow.c_str(), + }; + + int32_t getValues[] = { + // base 10 + 1, 2, 12345, -1, -2, -12345, + // base 16 + 0xFF, 0x0FF, 0xC0FFEE, 0Xf00, + // base 8 + 0, 01234, 07, + // corner cases + 2, 2, 0, 0, 0, INT32_MAX, INT32_MIN, + // failing cases + DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, + DEFAULT_VALUE, DEFAULT_VALUE, + }; + + ASSERT_EQ(ARRAY_SIZE(setValues), ARRAY_SIZE(getValues)); + + for (size_t i = 0; i < ARRAY_SIZE(setValues); ++i) { + ASSERT_OK(property_set(PROPERTY_TEST_KEY, setValues[i])); + + int32_t val = property_get_int32(PROPERTY_TEST_KEY, DEFAULT_VALUE); + EXPECT_PRED_FORMAT2(AssertEqualHex, getValues[i], val) << "Property was set to '" << setValues[i] << "'"; + } +} + +} // namespace android diff --git a/liblog/Android.mk b/liblog/Android.mk index 69ca4164f..a7eead974 100644 --- a/liblog/Android.mk +++ b/liblog/Android.mk @@ -58,6 +58,7 @@ endif LOCAL_MODULE := liblog LOCAL_SRC_FILES := $(liblog_host_sources) LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1 -Werror +LOCAL_MULTILIB := both include $(BUILD_HOST_STATIC_LIBRARY) include $(CLEAR_VARS) @@ -66,6 +67,7 @@ LOCAL_WHOLE_STATIC_LIBRARIES := liblog ifeq ($(strip $(HOST_OS)),linux) LOCAL_LDLIBS := -lrt endif +LOCAL_MULTILIB := both include $(BUILD_HOST_SHARED_LIBRARY) diff --git a/libutils/Android.mk b/libutils/Android.mk index 3afc1ec4b..9a50147e3 100644 --- a/libutils/Android.mk +++ b/libutils/Android.mk @@ -69,6 +69,7 @@ endif LOCAL_MODULE:= libutils LOCAL_STATIC_LIBRARIES := liblog LOCAL_CFLAGS += $(host_commonCflags) +LOCAL_MULTILIB := both include $(BUILD_HOST_STATIC_LIBRARY) diff --git a/libziparchive/Android.mk b/libziparchive/Android.mk index 1d48fea82..705caa5a1 100644 --- a/libziparchive/Android.mk +++ b/libziparchive/Android.mk @@ -42,6 +42,7 @@ LOCAL_C_INCLUDES += ${includes} LOCAL_STATIC_LIBRARIES := libz libutils LOCAL_MODULE:= libziparchive-host LOCAL_CFLAGS := -Werror +LOCAL_MULTILIB := both include $(BUILD_HOST_STATIC_LIBRARY) include $(CLEAR_VARS) diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc index 6781ebe49..128bad440 100644 --- a/libziparchive/zip_archive.cc +++ b/libziparchive/zip_archive.cc @@ -35,57 +35,173 @@ #include "ziparchive/zip_archive.h" -// This is for windows. If we don't open a file in binary mode, weirds +// This is for windows. If we don't open a file in binary mode, weird // things will happen. #ifndef O_BINARY #define O_BINARY 0 #endif -/* - * Zip file constants. - */ -static const uint32_t kEOCDSignature = 0x06054b50; -static const uint32_t kEOCDLen = 2; -static const uint32_t kEOCDNumEntries = 8; // offset to #of entries in file -static const uint32_t kEOCDSize = 12; // size of the central directory -static const uint32_t kEOCDFileOffset = 16; // offset to central directory - -static const uint32_t kMaxCommentLen = 65535; // longest possible in ushort -static const uint32_t kMaxEOCDSearch = (kMaxCommentLen + kEOCDLen); - -static const uint32_t kLFHSignature = 0x04034b50; -static const uint32_t kLFHLen = 30; // excluding variable-len fields -static const uint32_t kLFHGPBFlags = 6; // general purpose bit flags -static const uint32_t kLFHCRC = 14; // offset to CRC -static const uint32_t kLFHCompLen = 18; // offset to compressed length -static const uint32_t kLFHUncompLen = 22; // offset to uncompressed length -static const uint32_t kLFHNameLen = 26; // offset to filename length -static const uint32_t kLFHExtraLen = 28; // offset to extra length - -static const uint32_t kCDESignature = 0x02014b50; -static const uint32_t kCDELen = 46; // excluding variable-len fields -static const uint32_t kCDEMethod = 10; // offset to compression method -static const uint32_t kCDEModWhen = 12; // offset to modification timestamp -static const uint32_t kCDECRC = 16; // offset to entry CRC -static const uint32_t kCDECompLen = 20; // offset to compressed length -static const uint32_t kCDEUncompLen = 24; // offset to uncompressed length -static const uint32_t kCDENameLen = 28; // offset to filename length -static const uint32_t kCDEExtraLen = 30; // offset to extra length -static const uint32_t kCDECommentLen = 32; // offset to comment length -static const uint32_t kCDELocalOffset = 42; // offset to local hdr - -static const uint32_t kDDOptSignature = 0x08074b50; // *OPTIONAL* data descriptor signature -static const uint32_t kDDSignatureLen = 4; -static const uint32_t kDDLen = 12; -static const uint32_t kDDMaxLen = 16; // max of 16 bytes with a signature, 12 bytes without -static const uint32_t kDDCrc32 = 0; // offset to crc32 -static const uint32_t kDDCompLen = 4; // offset to compressed length -static const uint32_t kDDUncompLen = 8; // offset to uncompressed length - -static const uint32_t kGPBDDFlagMask = 0x0008; // mask value that signifies that the entry has a DD - +#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ + TypeName(); \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) + +// The "end of central directory" (EOCD) record. Each archive +// contains exactly once such record which appears at the end of +// the archive. It contains archive wide information like the +// number of entries in the archive and the offset to the central +// directory of the offset. +struct EocdRecord { + static const uint32_t kSignature = 0x06054b50; + + // End of central directory signature, should always be + // |kSignature|. + uint32_t eocd_signature; + // The number of the current "disk", i.e, the "disk" that this + // central directory is on. + // + // This implementation assumes that each archive spans a single + // disk only. i.e, that disk_num == 1. + uint16_t disk_num; + // The disk where the central directory starts. + // + // This implementation assumes that each archive spans a single + // disk only. i.e, that cd_start_disk == 1. + uint16_t cd_start_disk; + // The number of central directory records on this disk. + // + // This implementation assumes that each archive spans a single + // disk only. i.e, that num_records_on_disk == num_records. + uint16_t num_records_on_disk; + // The total number of central directory records. + uint16_t num_records; + // The size of the central directory (in bytes). + uint32_t cd_size; + // The offset of the start of the central directory, relative + // to the start of the file. + uint32_t cd_start_offset; + // Length of the central directory comment. + uint16_t comment_length; + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(EocdRecord); +} __attribute__((packed)); + +// A structure representing the fixed length fields for a single +// record in the central directory of the archive. In addition to +// the fixed length fields listed here, each central directory +// record contains a variable length "file_name" and "extra_field" +// whose lengths are given by |file_name_length| and |extra_field_length| +// respectively. +struct CentralDirectoryRecord { + static const uint32_t kSignature = 0x02014b50; + + // The start of record signature. Must be |kSignature|. + uint32_t record_signature; + // Tool version. Ignored by this implementation. + uint16_t version_made_by; + // Tool version. Ignored by this implementation. + uint16_t version_needed; + // The "general purpose bit flags" for this entry. The only + // flag value that we currently check for is the "data descriptor" + // flag. + uint16_t gpb_flags; + // The compression method for this entry, one of |kCompressStored| + // and |kCompressDeflated|. + uint16_t compression_method; + // The file modification time and date for this entry. + uint16_t last_mod_time; + uint16_t last_mod_date; + // The CRC-32 checksum for this entry. + uint32_t crc32; + // The compressed size (in bytes) of this entry. + uint32_t compressed_size; + // The uncompressed size (in bytes) of this entry. + uint32_t uncompressed_size; + // The length of the entry file name in bytes. The file name + // will appear immediately after this record. + uint16_t file_name_length; + // The length of the extra field info (in bytes). This data + // will appear immediately after the entry file name. + uint16_t extra_field_length; + // The length of the entry comment (in bytes). This data will + // appear immediately after the extra field. + uint16_t comment_length; + // The start disk for this entry. Ignored by this implementation). + uint16_t file_start_disk; + // File attributes. Ignored by this implementation. + uint16_t internal_file_attributes; + // File attributes. Ignored by this implementation. + uint32_t external_file_attributes; + // The offset to the local file header for this entry, from the + // beginning of this archive. + uint32_t local_file_header_offset; + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(CentralDirectoryRecord); +} __attribute__((packed)); + +// The local file header for a given entry. This duplicates information +// present in the central directory of the archive. It is an error for +// the information here to be different from the central directory +// information for a given entry. +struct LocalFileHeader { + static const uint32_t kSignature = 0x04034b50; + + // The local file header signature, must be |kSignature|. + uint32_t lfh_signature; + // Tool version. Ignored by this implementation. + uint16_t version_needed; + // The "general purpose bit flags" for this entry. The only + // flag value that we currently check for is the "data descriptor" + // flag. + uint16_t gpb_flags; + // The compression method for this entry, one of |kCompressStored| + // and |kCompressDeflated|. + uint16_t compression_method; + // The file modification time and date for this entry. + uint16_t last_mod_time; + uint16_t last_mod_date; + // The CRC-32 checksum for this entry. + uint32_t crc32; + // The compressed size (in bytes) of this entry. + uint32_t compressed_size; + // The uncompressed size (in bytes) of this entry. + uint32_t uncompressed_size; + // The length of the entry file name in bytes. The file name + // will appear immediately after this record. + uint16_t file_name_length; + // The length of the extra field info (in bytes). This data + // will appear immediately after the entry file name. + uint16_t extra_field_length; + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(LocalFileHeader); +} __attribute__((packed)); + +struct DataDescriptor { + // The *optional* data descriptor start signature. + static const uint32_t kOptSignature = 0x08074b50; + + // CRC-32 checksum of the entry. + uint32_t crc32; + // Compressed size of the entry. + uint32_t compressed_size; + // Uncompressed size of the entry. + uint32_t uncompressed_size; + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(DataDescriptor); +} __attribute__((packed)); + +#undef DISALLOW_IMPLICIT_CONSTRUCTORS + +static const uint32_t kGPBDDFlagMask = 0x0008; // mask value that signifies that the entry has a DD static const uint32_t kMaxErrorLen = 1024; +// The maximum size of a central directory or a file +// comment in bytes. +static const uint32_t kMaxCommentLen = 65535; + +// The maximum number of bytes to scan backwards for the EOCD start. +static const uint32_t kMaxEOCDSearch = kMaxCommentLen + sizeof(EocdRecord); + static const char* kErrorMessages[] = { "Unknown return code.", "Iteration ended", @@ -311,39 +427,21 @@ static int32_t AddToHash(ZipEntryName *hash_table, const uint64_t hash_table_siz return 0; } -/* - * Get 2 little-endian bytes. - */ -static uint16_t get2LE(const uint8_t* src) { - return src[0] | (src[1] << 8); -} - -/* - * Get 4 little-endian bytes. - */ -static uint32_t get4LE(const uint8_t* src) { - uint32_t result; - - result = src[0]; - result |= src[1] << 8; - result |= src[2] << 16; - result |= src[3] << 24; - - return result; -} - static int32_t MapCentralDirectory0(int fd, const char* debug_file_name, ZipArchive* archive, off64_t file_length, - uint32_t read_amount, uint8_t* scan_buffer) { + off64_t read_amount, uint8_t* scan_buffer) { const off64_t search_start = file_length - read_amount; if (lseek64(fd, search_start, SEEK_SET) != search_start) { - ALOGW("Zip: seek %" PRId64 " failed: %s", (int64_t)search_start, strerror(errno)); + ALOGW("Zip: seek %" PRId64 " failed: %s", static_cast<int64_t>(search_start), + strerror(errno)); return kIoError; } - ssize_t actual = TEMP_FAILURE_RETRY(read(fd, scan_buffer, read_amount)); - if (actual != (ssize_t) read_amount) { - ALOGW("Zip: read %" PRIu32 " failed: %s", read_amount, strerror(errno)); + ssize_t actual = TEMP_FAILURE_RETRY( + read(fd, scan_buffer, static_cast<size_t>(read_amount))); + if (actual != static_cast<ssize_t>(read_amount)) { + ALOGW("Zip: read %" PRId64 " failed: %s", static_cast<int64_t>(read_amount), + strerror(errno)); return kIoError; } @@ -353,9 +451,10 @@ static int32_t MapCentralDirectory0(int fd, const char* debug_file_name, * doing an initial minimal read; if we don't find it, retry with a * second read as above.) */ - int i; - for (i = read_amount - kEOCDLen; i >= 0; i--) { - if (scan_buffer[i] == 0x50 && get4LE(&scan_buffer[i]) == kEOCDSignature) { + int i = read_amount - sizeof(EocdRecord); + for (; i >= 0; i--) { + if (scan_buffer[i] == 0x50 && + ((*reinterpret_cast<uint32_t*>(&scan_buffer[i])) == EocdRecord::kSignature)) { ALOGV("+++ Found EOCD at buf+%d", i); break; } @@ -366,46 +465,52 @@ static int32_t MapCentralDirectory0(int fd, const char* debug_file_name, } const off64_t eocd_offset = search_start + i; - const uint8_t* eocd_ptr = scan_buffer + i; - - assert(eocd_offset < file_length); + const EocdRecord* eocd = reinterpret_cast<const EocdRecord*>(scan_buffer + i); + /* + * Verify that there's no trailing space at the end of the central directory + * and its comment. + */ + const off64_t calculated_length = eocd_offset + sizeof(EocdRecord) + + eocd->comment_length; + if (calculated_length != file_length) { + ALOGW("Zip: %" PRId64 " extraneous bytes at the end of the central directory", + static_cast<int64_t>(file_length - calculated_length)); + return kInvalidFile; + } /* * Grab the CD offset and size, and the number of entries in the - * archive. Verify that they look reasonable. Widen dir_size and - * dir_offset to the file offset type. + * archive and verify that they look reasonable. */ - const uint16_t num_entries = get2LE(eocd_ptr + kEOCDNumEntries); - const off64_t dir_size = get4LE(eocd_ptr + kEOCDSize); - const off64_t dir_offset = get4LE(eocd_ptr + kEOCDFileOffset); - - if (dir_offset + dir_size > eocd_offset) { - ALOGW("Zip: bad offsets (dir %" PRId64 ", size %" PRId64 ", eocd %" PRId64 ")", - (int64_t)dir_offset, (int64_t)dir_size, (int64_t)eocd_offset); + if (eocd->cd_start_offset + eocd->cd_size > eocd_offset) { + ALOGW("Zip: bad offsets (dir %" PRIu32 ", size %" PRIu32 ", eocd %" PRId64 ")", + eocd->cd_start_offset, eocd->cd_size, static_cast<int64_t>(eocd_offset)); return kInvalidOffset; } - if (num_entries == 0) { + if (eocd->num_records == 0) { ALOGW("Zip: empty archive?"); return kEmptyArchive; } - ALOGV("+++ num_entries=%d dir_size=%" PRId64 " dir_offset=%" PRId64, - num_entries, (int64_t)dir_size, (int64_t)dir_offset); + ALOGV("+++ num_entries=%" PRIu32 "dir_size=%" PRIu32 " dir_offset=%" PRIu32, + eocd->num_records, eocd->cd_size, eocd->cd_start_offset); /* * It all looks good. Create a mapping for the CD, and set the fields * in archive. */ - android::FileMap* map = MapFileSegment(fd, dir_offset, dir_size, - true /* read only */, debug_file_name); + android::FileMap* map = MapFileSegment(fd, + static_cast<off64_t>(eocd->cd_start_offset), + static_cast<size_t>(eocd->cd_size), + true /* read only */, debug_file_name); if (map == NULL) { archive->directory_map = NULL; return kMmapFailed; } archive->directory_map = map; - archive->num_entries = num_entries; - archive->directory_offset = dir_offset; + archive->num_entries = eocd->num_records; + archive->directory_offset = eocd->cd_start_offset; return 0; } @@ -431,12 +536,12 @@ static int32_t MapCentralDirectory(int fd, const char* debug_file_name, } if (file_length > (off64_t) 0xffffffff) { - ALOGV("Zip: zip file too long %" PRId64, (int64_t)file_length); + ALOGV("Zip: zip file too long %" PRId64, static_cast<int64_t>(file_length)); return kInvalidFile; } - if (file_length < (int64_t) kEOCDLen) { - ALOGV("Zip: length %" PRId64 " is too small to be zip", (int64_t)file_length); + if (file_length < static_cast<off64_t>(sizeof(EocdRecord))) { + ALOGV("Zip: length %" PRId64 " is too small to be zip", static_cast<int64_t>(file_length)); return kInvalidFile; } @@ -452,12 +557,12 @@ static int32_t MapCentralDirectory(int fd, const char* debug_file_name, * * We start by pulling in the last part of the file. */ - uint32_t read_amount = kMaxEOCDSearch; - if (file_length < (off64_t) read_amount) { + off64_t read_amount = kMaxEOCDSearch; + if (file_length < read_amount) { read_amount = file_length; } - uint8_t* scan_buffer = (uint8_t*) malloc(read_amount); + uint8_t* scan_buffer = reinterpret_cast<uint8_t*>(malloc(read_amount)); int32_t result = MapCentralDirectory0(fd, debug_file_name, archive, file_length, read_amount, scan_buffer); @@ -473,9 +578,9 @@ static int32_t MapCentralDirectory(int fd, const char* debug_file_name, */ static int32_t ParseZipArchive(ZipArchive* archive) { int32_t result = -1; - const uint8_t* cd_ptr = (const uint8_t*) archive->directory_map->getDataPtr(); - size_t cd_length = archive->directory_map->getDataLength(); - uint16_t num_entries = archive->num_entries; + const uint8_t* const cd_ptr = (const uint8_t*) archive->directory_map->getDataPtr(); + const size_t cd_length = archive->directory_map->getDataLength(); + const uint16_t num_entries = archive->num_entries; /* * Create hash table. We have a minimum 75% load factor, possibly as @@ -490,39 +595,43 @@ static int32_t ParseZipArchive(ZipArchive* archive) { * Walk through the central directory, adding entries to the hash * table and verifying values. */ + const uint8_t* const cd_end = cd_ptr + cd_length; const uint8_t* ptr = cd_ptr; for (uint16_t i = 0; i < num_entries; i++) { - if (get4LE(ptr) != kCDESignature) { + const CentralDirectoryRecord* cdr = + reinterpret_cast<const CentralDirectoryRecord*>(ptr); + if (cdr->record_signature != CentralDirectoryRecord::kSignature) { ALOGW("Zip: missed a central dir sig (at %" PRIu16 ")", i); goto bail; } - if (ptr + kCDELen > cd_ptr + cd_length) { + if (ptr + sizeof(CentralDirectoryRecord) > cd_end) { ALOGW("Zip: ran off the end (at %" PRIu16 ")", i); goto bail; } - const off64_t local_header_offset = get4LE(ptr + kCDELocalOffset); + const off64_t local_header_offset = cdr->local_file_header_offset; if (local_header_offset >= archive->directory_offset) { ALOGW("Zip: bad LFH offset %" PRId64 " at entry %" PRIu16, (int64_t)local_header_offset, i); goto bail; } - const uint16_t file_name_length = get2LE(ptr + kCDENameLen); - const uint16_t extra_length = get2LE(ptr + kCDEExtraLen); - const uint16_t comment_length = get2LE(ptr + kCDECommentLen); + const uint16_t file_name_length = cdr->file_name_length; + const uint16_t extra_length = cdr->extra_field_length; + const uint16_t comment_length = cdr->comment_length; /* add the CDE filename to the hash table */ + const char* file_name = reinterpret_cast<const char *>(ptr + sizeof(CentralDirectoryRecord)); const int add_result = AddToHash(archive->hash_table, - archive->hash_table_size, (const char*) ptr + kCDELen, file_name_length); + archive->hash_table_size, file_name, file_name_length); if (add_result) { ALOGW("Zip: Error adding entry to hash table %d", add_result); result = add_result; goto bail; } - ptr += kCDELen + file_name_length + extra_length + comment_length; - if ((size_t)(ptr - cd_ptr) > cd_length) { + ptr += sizeof(CentralDirectoryRecord) + file_name_length + extra_length + comment_length; + if ((ptr - cd_ptr) > static_cast<int64_t>(cd_length)) { ALOGW("Zip: bad CD advance (%tu vs %zu) at entry %" PRIu16, ptr - cd_ptr, cd_length, i); goto bail; @@ -597,21 +706,19 @@ void CloseArchive(ZipArchiveHandle handle) { static int32_t UpdateEntryFromDataDescriptor(int fd, ZipEntry *entry) { - uint8_t ddBuf[kDDMaxLen]; + uint8_t ddBuf[sizeof(DataDescriptor) + sizeof(DataDescriptor::kOptSignature)]; ssize_t actual = TEMP_FAILURE_RETRY(read(fd, ddBuf, sizeof(ddBuf))); if (actual != sizeof(ddBuf)) { return kIoError; } - const uint32_t ddSignature = get4LE(ddBuf); - uint16_t ddOffset = 0; - if (ddSignature == kDDOptSignature) { - ddOffset = 4; - } + const uint32_t ddSignature = *(reinterpret_cast<const uint32_t*>(ddBuf)); + const uint16_t offset = (ddSignature == DataDescriptor::kOptSignature) ? 4 : 0; + const DataDescriptor* descriptor = reinterpret_cast<const DataDescriptor*>(ddBuf + offset); - entry->crc32 = get4LE(ddBuf + ddOffset + kDDCrc32); - entry->compressed_length = get4LE(ddBuf + ddOffset + kDDCompLen); - entry->uncompressed_length = get4LE(ddBuf + ddOffset + kDDUncompLen); + entry->crc32 = descriptor->crc32; + entry->compressed_length = descriptor->compressed_size; + entry->uncompressed_length = descriptor->uncompressed_size; return 0; } @@ -647,19 +754,22 @@ static int32_t FindEntry(const ZipArchive* archive, const int ent, // Recover the start of the central directory entry from the filename // pointer. The filename is the first entry past the fixed-size data, // so we can just subtract back from that. - const unsigned char* ptr = (const unsigned char*) name; - ptr -= kCDELen; + const uint8_t* ptr = reinterpret_cast<const uint8_t*>(name); + ptr -= sizeof(CentralDirectoryRecord); // This is the base of our mmapped region, we have to sanity check that // the name that's in the hash table is a pointer to a location within // this mapped region. - const unsigned char* base_ptr = (const unsigned char*) - archive->directory_map->getDataPtr(); + const uint8_t* base_ptr = reinterpret_cast<const uint8_t*>( + archive->directory_map->getDataPtr()); if (ptr < base_ptr || ptr > base_ptr + archive->directory_map->getDataLength()) { ALOGW("Zip: Invalid entry pointer"); return kInvalidOffset; } + const CentralDirectoryRecord *cdr = + reinterpret_cast<const CentralDirectoryRecord*>(ptr); + // The offset of the start of the central directory in the zipfile. // We keep this lying around so that we can sanity check all our lengths // and our per-file structures. @@ -668,22 +778,22 @@ static int32_t FindEntry(const ZipArchive* archive, const int ent, // Fill out the compression method, modification time, crc32 // and other interesting attributes from the central directory. These // will later be compared against values from the local file header. - data->method = get2LE(ptr + kCDEMethod); - data->mod_time = get4LE(ptr + kCDEModWhen); - data->crc32 = get4LE(ptr + kCDECRC); - data->compressed_length = get4LE(ptr + kCDECompLen); - data->uncompressed_length = get4LE(ptr + kCDEUncompLen); + data->method = cdr->compression_method; + data->mod_time = cdr->last_mod_time; + data->crc32 = cdr->crc32; + data->compressed_length = cdr->compressed_size; + data->uncompressed_length = cdr->uncompressed_size; // Figure out the local header offset from the central directory. The // actual file data will begin after the local header and the name / // extra comments. - const off64_t local_header_offset = get4LE(ptr + kCDELocalOffset); - if (local_header_offset + (off64_t) kLFHLen >= cd_offset) { + const off64_t local_header_offset = cdr->local_file_header_offset; + if (local_header_offset + static_cast<off64_t>(sizeof(LocalFileHeader)) >= cd_offset) { ALOGW("Zip: bad local hdr offset in zip"); return kInvalidOffset; } - uint8_t lfh_buf[kLFHLen]; + uint8_t lfh_buf[sizeof(LocalFileHeader)]; ssize_t actual = ReadAtOffset(archive->fd, lfh_buf, sizeof(lfh_buf), local_header_offset); if (actual != sizeof(lfh_buf)) { @@ -691,30 +801,25 @@ static int32_t FindEntry(const ZipArchive* archive, const int ent, return kIoError; } - if (get4LE(lfh_buf) != kLFHSignature) { + const LocalFileHeader *lfh = reinterpret_cast<const LocalFileHeader*>(lfh_buf); + + if (lfh->lfh_signature != LocalFileHeader::kSignature) { ALOGW("Zip: didn't find signature at start of lfh, offset=%" PRId64, - (int64_t)local_header_offset); + static_cast<int64_t>(local_header_offset)); return kInvalidOffset; } // Paranoia: Match the values specified in the local file header // to those specified in the central directory. - const uint16_t lfhGpbFlags = get2LE(lfh_buf + kLFHGPBFlags); - const uint16_t lfhNameLen = get2LE(lfh_buf + kLFHNameLen); - const uint16_t lfhExtraLen = get2LE(lfh_buf + kLFHExtraLen); - - if ((lfhGpbFlags & kGPBDDFlagMask) == 0) { - const uint32_t lfhCrc = get4LE(lfh_buf + kLFHCRC); - const uint32_t lfhCompLen = get4LE(lfh_buf + kLFHCompLen); - const uint32_t lfhUncompLen = get4LE(lfh_buf + kLFHUncompLen); - + if ((lfh->gpb_flags & kGPBDDFlagMask) == 0) { data->has_data_descriptor = 0; - if (data->compressed_length != lfhCompLen || data->uncompressed_length != lfhUncompLen - || data->crc32 != lfhCrc) { + if (data->compressed_length != lfh->compressed_size + || data->uncompressed_length != lfh->uncompressed_size + || data->crc32 != lfh->crc32) { ALOGW("Zip: size/crc32 mismatch. expected {%" PRIu32 ", %" PRIu32 ", %" PRIx32 "}, was {%" PRIu32 ", %" PRIu32 ", %" PRIx32 "}", data->compressed_length, data->uncompressed_length, data->crc32, - lfhCompLen, lfhUncompLen, lfhCrc); + lfh->compressed_size, lfh->uncompressed_size, lfh->crc32); return kInconsistentInformation; } } else { @@ -723,9 +828,9 @@ static int32_t FindEntry(const ZipArchive* archive, const int ent, // Check that the local file header name matches the declared // name in the central directory. - if (lfhNameLen == nameLen) { - const off64_t name_offset = local_header_offset + kLFHLen; - if (name_offset + lfhNameLen >= cd_offset) { + if (lfh->file_name_length == nameLen) { + const off64_t name_offset = local_header_offset + sizeof(LocalFileHeader); + if (name_offset + lfh->file_name_length >= cd_offset) { ALOGW("Zip: Invalid declared length"); return kInvalidOffset; } @@ -751,7 +856,8 @@ static int32_t FindEntry(const ZipArchive* archive, const int ent, return kInconsistentInformation; } - const off64_t data_offset = local_header_offset + kLFHLen + lfhNameLen + lfhExtraLen; + const off64_t data_offset = local_header_offset + sizeof(LocalFileHeader) + + lfh->file_name_length + lfh->extra_field_length; if (data_offset > cd_offset) { ALOGW("Zip: bad data offset %" PRId64 " in zip", (int64_t)data_offset); return kInvalidOffset; diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc index 2eb931833..875b6dec7 100644 --- a/libziparchive/zip_archive_test.cc +++ b/libziparchive/zip_archive_test.cc @@ -140,11 +140,7 @@ TEST(ziparchive, ExtractToMemory) { CloseArchive(handle); } -TEST(ziparchive, EmptyEntries) { - char temp_file_pattern[] = "empty_entries_test_XXXXXX"; - int fd = mkstemp(temp_file_pattern); - ASSERT_NE(-1, fd); - const uint32_t data[] = { +static const uint32_t kEmptyEntriesZip[] = { 0x04034b50, 0x0000000a, 0x63600000, 0x00004438, 0x00000000, 0x00000000, 0x00090000, 0x6d65001c, 0x2e797470, 0x55747874, 0x03000954, 0x52e25c13, 0x52e25c24, 0x000b7875, 0x42890401, 0x88040000, 0x50000013, 0x1e02014b, @@ -152,8 +148,28 @@ TEST(ziparchive, EmptyEntries) { 0x00001800, 0x00000000, 0xa0000000, 0x00000081, 0x706d6500, 0x742e7974, 0x54557478, 0x13030005, 0x7552e25c, 0x01000b78, 0x00428904, 0x13880400, 0x4b500000, 0x00000605, 0x00010000, 0x004f0001, 0x00430000, 0x00000000 }; - const ssize_t file_size = 168; - ASSERT_EQ(file_size, TEMP_FAILURE_RETRY(write(fd, data, file_size))); + +static int make_temporary_file(const char* file_name_pattern) { + char full_path[1024]; + // Account for differences between the host and the target. + // + // TODO: Maybe reuse bionic/tests/TemporaryFile.h. + snprintf(full_path, sizeof(full_path), "/data/local/tmp/%s", file_name_pattern); + int fd = mkstemp(full_path); + if (fd == -1) { + snprintf(full_path, sizeof(full_path), "/tmp/%s", file_name_pattern); + fd = mkstemp(full_path); + } + + return fd; +} + +TEST(ziparchive, EmptyEntries) { + char temp_file_pattern[] = "empty_entries_test_XXXXXX"; + int fd = make_temporary_file(temp_file_pattern); + ASSERT_NE(-1, fd); + const ssize_t file_size = sizeof(kEmptyEntriesZip); + ASSERT_EQ(file_size, TEMP_FAILURE_RETRY(write(fd, kEmptyEntriesZip, file_size))); ZipArchiveHandle handle; ASSERT_EQ(0, OpenArchiveFd(fd, "EmptyEntriesTest", &handle)); @@ -165,7 +181,7 @@ TEST(ziparchive, EmptyEntries) { ASSERT_EQ(0, ExtractToMemory(handle, &entry, buffer, 1)); char output_file_pattern[] = "empty_entries_output_XXXXXX"; - int output_fd = mkstemp(output_file_pattern); + int output_fd = make_temporary_file(output_file_pattern); ASSERT_NE(-1, output_fd); ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, output_fd)); @@ -177,9 +193,25 @@ TEST(ziparchive, EmptyEntries) { close(output_fd); } +TEST(ziparchive, TrailerAfterEOCD) { + char temp_file_pattern[] = "trailer_after_eocd_test_XXXXXX"; + int fd = make_temporary_file(temp_file_pattern); + ASSERT_NE(-1, fd); + + // Create a file with 8 bytes of random garbage. + static const uint8_t trailer[] = { 'A' ,'n', 'd', 'r', 'o', 'i', 'd', 'z' }; + const ssize_t file_size = sizeof(kEmptyEntriesZip); + const ssize_t trailer_size = sizeof(trailer); + ASSERT_EQ(file_size, TEMP_FAILURE_RETRY(write(fd, kEmptyEntriesZip, file_size))); + ASSERT_EQ(trailer_size, TEMP_FAILURE_RETRY(write(fd, trailer, trailer_size))); + + ZipArchiveHandle handle; + ASSERT_GT(0, OpenArchiveFd(fd, "EmptyEntriesTest", &handle)); +} + TEST(ziparchive, ExtractToFile) { char kTempFilePattern[] = "zip_archive_input_XXXXXX"; - int fd = mkstemp(kTempFilePattern); + int fd = make_temporary_file(kTempFilePattern); ASSERT_NE(-1, fd); const uint8_t data[8] = { '1', '2', '3', '4', '5', '6', '7', '8' }; const ssize_t data_size = sizeof(data); diff --git a/libzipfile/Android.mk b/libzipfile/Android.mk index 614a4607f..12a22291d 100644 --- a/libzipfile/Android.mk +++ b/libzipfile/Android.mk @@ -16,6 +16,8 @@ LOCAL_C_INCLUDES += external/zlib LOCAL_CFLAGS := -Werror +LOCAL_MULTILIB := both + include $(BUILD_HOST_STATIC_LIBRARY) # build device static library diff --git a/logcat/tests/Android.mk b/logcat/tests/Android.mk index 5d4d29ebc..015a23df1 100644 --- a/logcat/tests/Android.mk +++ b/logcat/tests/Android.mk @@ -16,11 +16,7 @@ LOCAL_PATH := $(call my-dir) -# ----------------------------------------------------------------------------- -# Unit tests. -# ----------------------------------------------------------------------------- - -test_module := logcat-unit-tests +test_module_prefix := logcat- test_tags := tests test_c_flags := \ @@ -28,7 +24,29 @@ test_c_flags := \ -g \ -Wall -Wextra \ -Werror \ - -fno-builtin + -fno-builtin \ + -std=gnu++11 + +# ----------------------------------------------------------------------------- +# Benchmarks (actually a gTest where the result code does not matter) +# ---------------------------------------------------------------------------- + +benchmark_src_files := \ + logcat_benchmark.cpp + +# Build benchmarks for the device. Run with: +# adb shell /data/nativetest/logcat-benchmarks/logcat-benchmarks +include $(CLEAR_VARS) +LOCAL_MODULE := $(test_module_prefix)benchmarks +LOCAL_MODULE_TAGS := $(test_tags) +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk +LOCAL_CFLAGS += $(test_c_flags) +LOCAL_SRC_FILES := $(benchmark_src_files) +include $(BUILD_NATIVE_TEST) + +# ----------------------------------------------------------------------------- +# Unit tests. +# ----------------------------------------------------------------------------- test_src_files := \ logcat_test.cpp \ @@ -36,7 +54,7 @@ test_src_files := \ # Build tests for the device (with .so). Run with: # adb shell /data/nativetest/logcat-unit-tests/logcat-unit-tests include $(CLEAR_VARS) -LOCAL_MODULE := $(test_module) +LOCAL_MODULE := $(test_module_prefix)unit-tests LOCAL_MODULE_TAGS := $(test_tags) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_CFLAGS += $(test_c_flags) diff --git a/logcat/tests/logcat_benchmark.cpp b/logcat/tests/logcat_benchmark.cpp new file mode 100644 index 000000000..be815be1b --- /dev/null +++ b/logcat/tests/logcat_benchmark.cpp @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2013-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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <gtest/gtest.h> + +static const char begin[] = "--------- beginning of "; + +TEST(logcat, sorted_order) { + FILE *fp; + + ASSERT_TRUE(NULL != (fp = popen( + "logcat -v time -b radio -b events -b system -b main -d 2>/dev/null", + "r"))); + + class timestamp { + private: + int month; + int day; + int hour; + int minute; + int second; + int millisecond; + bool ok; + + public: + void init(const char *buffer) + { + ok = false; + if (buffer != NULL) { + ok = sscanf(buffer, "%d-%d %d:%d:%d.%d ", + &month, &day, &hour, &minute, &second, &millisecond) == 6; + } + } + + timestamp(const char *buffer) + { + init(buffer); + } + + bool operator< (timestamp &T) + { + return !ok || !T.ok + || (month < T.month) + || ((month == T.month) + && ((day < T.day) + || ((day == T.day) + && ((hour < T.hour) + || ((hour == T.hour) + && ((minute < T.minute) + || ((minute == T.minute) + && ((second < T.second) + || ((second == T.second) + && (millisecond < T.millisecond)))))))))); + } + + bool valid(void) + { + return ok; + } + } last(NULL); + + char *last_buffer = NULL; + char buffer[5120]; + + int count = 0; + int next_lt_last = 0; + + while (fgets(buffer, sizeof(buffer), fp)) { + if (!strncmp(begin, buffer, sizeof(begin) - 1)) { + continue; + } + if (!last.valid()) { + free(last_buffer); + last_buffer = strdup(buffer); + last.init(buffer); + } + timestamp next(buffer); + if (next < last) { + if (last_buffer) { + fprintf(stderr, "<%s", last_buffer); + } + fprintf(stderr, ">%s", buffer); + ++next_lt_last; + } + if (next.valid()) { + free(last_buffer); + last_buffer = strdup(buffer); + last.init(buffer); + } + ++count; + } + free(last_buffer); + + pclose(fp); + + static const int max_ok = 2; + + // Allow few fails, happens with readers active + fprintf(stderr, "%s: %d/%d out of order entries\n", + (next_lt_last) + ? ((next_lt_last <= max_ok) + ? "WARNING" + : "ERROR") + : "INFO", + next_lt_last, count); + + EXPECT_GE(max_ok, next_lt_last); + + // sample statistically too small + EXPECT_LT(100, count); +} diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp index 2e8ae8b6d..9b316d150 100644 --- a/logcat/tests/logcat_test.cpp +++ b/logcat/tests/logcat_test.cpp @@ -17,6 +17,7 @@ #include <ctype.h> #include <signal.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> #include <gtest/gtest.h> @@ -41,99 +42,6 @@ static const char begin[] = "--------- beginning of "; -TEST(logcat, sorted_order) { - FILE *fp; - - ASSERT_TRUE(NULL != (fp = popen( - "logcat -v time -b radio -b events -b system -b main -d 2>/dev/null", - "r"))); - - class timestamp { - private: - int month; - int day; - int hour; - int minute; - int second; - int millisecond; - bool ok; - - public: - void init(const char *buffer) - { - ok = false; - if (buffer != NULL) { - ok = sscanf(buffer, "%d-%d %d:%d:%d.%d ", - &month, &day, &hour, &minute, &second, &millisecond) == 6; - } - } - - timestamp(const char *buffer) - { - init(buffer); - } - - bool operator< (timestamp &T) - { - return !ok || !T.ok - || (month < T.month) - || ((month == T.month) - && ((day < T.day) - || ((day == T.day) - && ((hour < T.hour) - || ((hour == T.hour) - && ((minute < T.minute) - || ((minute == T.minute) - && ((second < T.second) - || ((second == T.second) - && (millisecond < T.millisecond)))))))))); - } - - bool valid(void) - { - return ok; - } - } last(NULL); - - char *last_buffer = NULL; - char buffer[5120]; - - int count = 0; - int next_lt_last = 0; - - while (fgets(buffer, sizeof(buffer), fp)) { - if (!strncmp(begin, buffer, sizeof(begin) - 1)) { - continue; - } - if (!last.valid()) { - free(last_buffer); - last_buffer = strdup(buffer); - last.init(buffer); - } - timestamp next(buffer); - if (next < last) { - if (last_buffer) { - fprintf(stderr, "<%s", last_buffer); - } - fprintf(stderr, ">%s", buffer); - ++next_lt_last; - } - if (next.valid()) { - free(last_buffer); - last_buffer = strdup(buffer); - last.init(buffer); - } - ++count; - } - free(last_buffer); - - pclose(fp); - - EXPECT_EQ(0, next_lt_last); - - EXPECT_LT(100, count); -} - TEST(logcat, buckets) { FILE *fp; @@ -362,9 +270,10 @@ TEST(logcat, End_to_End) { ASSERT_EQ(1, count); } -TEST(logcat, get_) { +TEST(logcat, get_size) { FILE *fp; + // NB: crash log only available in user space ASSERT_TRUE(NULL != (fp = popen( "logcat -b radio -b events -b system -b main -g 2>/dev/null", "r"))); @@ -375,13 +284,49 @@ TEST(logcat, get_) { while (fgets(buffer, sizeof(buffer), fp)) { int size, consumed, max, payload; + char size_mult, consumed_mult; + long full_size, full_consumed; size = consumed = max = payload = 0; - if ((4 == sscanf(buffer, "%*s ring buffer is %dKb (%dKb consumed)," - " max entry is %db, max payload is %db", - &size, &consumed, &max, &payload)) - && ((size * 3) >= consumed) - && ((size * 1024) > max) + // NB: crash log can be very small, not hit a Kb of consumed space + // doubly lucky we are not including it. + if (6 != sscanf(buffer, "%*s ring buffer is %d%cb (%d%cb consumed)," + " max entry is %db, max payload is %db", + &size, &size_mult, &consumed, &consumed_mult, + &max, &payload)) { + fprintf(stderr, "WARNING: Parse error: %s", buffer); + continue; + } + full_size = size; + switch(size_mult) { + case 'G': + full_size *= 1024; + /* FALLTHRU */ + case 'M': + full_size *= 1024; + /* FALLTHRU */ + case 'K': + full_size *= 1024; + break; + } + full_consumed = consumed; + switch(consumed_mult) { + case 'G': + full_consumed *= 1024; + /* FALLTHRU */ + case 'M': + full_consumed *= 1024; + /* FALLTHRU */ + case 'K': + full_consumed *= 1024; + break; + } + EXPECT_GT((full_size * 9) / 4, full_consumed); + EXPECT_GT(full_size, max); + EXPECT_GT(max, payload); + + if ((((full_size * 9) / 4) >= full_consumed) + && (full_size > max) && (max > payload)) { ++count; } @@ -649,7 +594,7 @@ static bool set_white_black(const char *list) { char buffer[5120]; - snprintf(buffer, sizeof(buffer), "logcat -P '%s' 2>&1", list); + snprintf(buffer, sizeof(buffer), "logcat -P '%s' 2>&1", list ? list : ""); fp = popen(buffer, "r"); if (fp == NULL) { fprintf(stderr, "ERROR: %s\n", buffer); @@ -662,10 +607,10 @@ static bool set_white_black(const char *list) { ++buf; } char *end = buf + strlen(buf); - while (isspace(*--end) && (end >= buf)) { + while ((end > buf) && isspace(*--end)) { *end = '\0'; } - if (end < buf) { + if (end <= buf) { continue; } fprintf(stderr, "%s\n", buf); @@ -679,7 +624,7 @@ TEST(logcat, white_black_adjust) { char *list = NULL; char *adjust = NULL; - ASSERT_EQ(true, get_white_black(&list)); + get_white_black(&list); static const char adjustment[] = "~! 300/20 300/25 2000 ~1000/5 ~1000/30"; ASSERT_EQ(true, set_white_black(adjustment)); @@ -696,8 +641,8 @@ TEST(logcat, white_black_adjust) { adjust = NULL; ASSERT_EQ(true, set_white_black(list)); - ASSERT_EQ(true, get_white_black(&adjust)); - EXPECT_STREQ(list, adjust); + get_white_black(&adjust); + EXPECT_STREQ(list ? list : "", adjust ? adjust : ""); free(adjust); adjust = NULL; diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp index 9d7d152fb..d7088b4db 100644 --- a/logd/CommandListener.cpp +++ b/logd/CommandListener.cpp @@ -74,9 +74,9 @@ static void setname() { int CommandListener::ClearCmd::runCommand(SocketClient *cli, int argc, char **argv) { setname(); - if (!clientHasLogCredentials(cli)) { - cli->sendMsg("Permission Denied"); - return 0; + uid_t uid = cli->getUid(); + if (clientHasLogCredentials(cli)) { + uid = AID_ROOT; } if (argc < 2) { @@ -90,7 +90,7 @@ int CommandListener::ClearCmd::runCommand(SocketClient *cli, return 0; } - mBuf.clear((log_id_t) id); + mBuf.clear((log_id_t) id, uid); cli->sendMsg("success"); return 0; } diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp index 0448afac1..cd9ea2097 100644 --- a/logd/LogBuffer.cpp +++ b/logd/LogBuffer.cpp @@ -232,7 +232,7 @@ void LogBuffer::maybePrune(log_id_t id) { // prune "pruneRows" of type "id" from the buffer. // // mLogElementsLock must be held when this function is called. -void LogBuffer::prune(log_id_t id, unsigned long pruneRows) { +void LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) { LogTimeEntry *oldest = NULL; LogTimeEntry::lock(); @@ -250,6 +250,38 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows) { LogBufferElementCollection::iterator it; + if (caller_uid != AID_ROOT) { + for(it = mLogElements.begin(); it != mLogElements.end();) { + LogBufferElement *e = *it; + + if (oldest && (oldest->mStart <= e->getMonotonicTime())) { + break; + } + + if (e->getLogId() != id) { + ++it; + continue; + } + + uid_t uid = e->getUid(); + + if (uid == caller_uid) { + it = mLogElements.erase(it); + unsigned short len = e->getMsgLen(); + stats.subtract(len, id, uid, e->getPid()); + delete e; + pruneRows--; + if (pruneRows == 0) { + break; + } + } else { + ++it; + } + } + LogTimeEntry::unlock(); + return; + } + // prune by worst offender by uid while (pruneRows > 0) { // recalculate the worst offender on every batched pass @@ -375,9 +407,9 @@ void LogBuffer::prune(log_id_t id, unsigned long pruneRows) { } // clear all rows of type "id" from the buffer. -void LogBuffer::clear(log_id_t id) { +void LogBuffer::clear(log_id_t id, uid_t uid) { pthread_mutex_lock(&mLogElementsLock); - prune(id, ULONG_MAX); + prune(id, ULONG_MAX, uid); pthread_mutex_unlock(&mLogElementsLock); } diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h index b8a54b909..4b982a878 100644 --- a/logd/LogBuffer.h +++ b/logd/LogBuffer.h @@ -23,6 +23,8 @@ #include <sysutils/SocketClient.h> #include <utils/List.h> +#include <private/android_filesystem_config.h> + #include "LogBufferElement.h" #include "LogTimes.h" #include "LogStatistics.h" @@ -55,7 +57,7 @@ public: bool (*filter)(const LogBufferElement *element, void *arg) = NULL, void *arg = NULL); - void clear(log_id_t id); + void clear(log_id_t id, uid_t uid = AID_ROOT); unsigned long getSize(log_id_t id); int setSize(log_id_t id, unsigned long size); unsigned long getSizeUsed(log_id_t id); @@ -77,7 +79,7 @@ public: private: void maybePrune(log_id_t id); - void prune(log_id_t id, unsigned long pruneRows); + void prune(log_id_t id, unsigned long pruneRows, uid_t uid = AID_ROOT); }; diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp index 1a9a548f4..e7e3ec218 100644 --- a/logd/LogTimes.cpp +++ b/logd/LogTimes.cpp @@ -193,6 +193,7 @@ bool LogTimeEntry::FilterSecondPass(const LogBufferElement *element, void *obj) if (me->skipAhead) { me->skipAhead--; + goto skip; } me->mStart = element->getMonotonicTime(); diff --git a/logd/tests/Android.mk b/logd/tests/Android.mk index 123e3173b..f8512888b 100644 --- a/logd/tests/Android.mk +++ b/logd/tests/Android.mk @@ -34,7 +34,7 @@ test_c_flags := \ -Werror \ -fno-builtin \ -ifeq ($(TARGET_USES_LOGD),true) +ifneq ($(TARGET_USES_LOGD),false) test_c_flags += -DTARGET_USES_LOGD=1 endif diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp index 5b51b1f73..957fdb5bf 100644 --- a/logd/tests/logd_test.cpp +++ b/logd/tests/logd_test.cpp @@ -568,10 +568,11 @@ TEST(logd, benchmark) { while (fgets(buffer, sizeof(buffer), fp)) { for (unsigned i = 0; i < sizeof(ns) / sizeof(ns[0]); ++i) { - if (strncmp(benchmarks[i], buffer, strlen(benchmarks[i]))) { + char *cp = strstr(buffer, benchmarks[i]); + if (!cp) { continue; } - sscanf(buffer, "%*s %lu %lu", &ns[i], &ns[i]); + sscanf(cp, "%*s %lu %lu", &ns[i], &ns[i]); fprintf(stderr, "%-22s%8lu\n", benchmarks[i], ns[i]); } } @@ -592,15 +593,15 @@ TEST(logd, benchmark) { #endif #ifdef TARGET_USES_LOGD - EXPECT_GE(25000UL, ns[log_maximum]); // 14055 user + EXPECT_GE(30000UL, ns[log_maximum]); // 27305 user #else EXPECT_GE(10000UL, ns[log_maximum]); // 5637 kernel #endif - EXPECT_GE(4000UL, ns[clock_overhead]); // 2008 + EXPECT_GE(4096UL, ns[clock_overhead]); // 4095 #ifdef TARGET_USES_LOGD - EXPECT_GE(250000UL, ns[log_overhead]); // 113219 user + EXPECT_GE(250000UL, ns[log_overhead]); // 121876 user #else EXPECT_GE(100000UL, ns[log_overhead]); // 50945 kernel #endif @@ -612,7 +613,7 @@ TEST(logd, benchmark) { #endif #ifdef TARGET_USES_LOGD - EXPECT_GE(20000000UL, ns[log_delay]); // 9542541 user + EXPECT_GE(20000000UL, ns[log_delay]); // 10500289 user #else EXPECT_GE(55000UL, ns[log_delay]); // 27341 kernel #endif @@ -642,36 +643,61 @@ TEST(logd, benchmark) { // 0/4225? 7454388/303656 31488/755 // ^-- benchmark_statistics_found - unsigned long nowSize = atol(benchmark_statistics_found); + unsigned long nowSpamSize = atol(benchmark_statistics_found); delete [] buf; - ASSERT_NE(0UL, nowSize); + ASSERT_NE(0UL, nowSpamSize); + // Determine if we have the spam filter enabled int sock = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM); + + ASSERT_TRUE(sock >= 0); + + static const char getPruneList[] = "getPruneList"; + if (write(sock, getPruneList, sizeof(getPruneList)) > 0) { + char buffer[80]; + memset(buffer, 0, sizeof(buffer)); + read(sock, buffer, sizeof(buffer)); + char *cp = strchr(buffer, '\n'); + if (!cp || (cp[1] != '~') || (cp[2] != '!')) { + close(sock); + fprintf(stderr, + "WARNING: " + "Logger has SPAM filtration turned off \"%s\"\n", buffer); + return; + } + } else { + int save_errno = errno; + close(sock); + FAIL() << "Can not send " << getPruneList << " to logger -- " << strerror(save_errno); + } + static const unsigned long expected_absolute_minimum_log_size = 65536UL; unsigned long totalSize = expected_absolute_minimum_log_size; - if (sock >= 0) { - static const char getSize[] = { - 'g', 'e', 't', 'L', 'o', 'g', 'S', 'i', 'z', 'e', ' ', - LOG_ID_MAIN + '0', '\0' - }; - if (write(sock, getSize, sizeof(getSize)) > 0) { - char buffer[80]; - memset(buffer, 0, sizeof(buffer)); - read(sock, buffer, sizeof(buffer)); - totalSize = atol(buffer); - if (totalSize < expected_absolute_minimum_log_size) { - totalSize = expected_absolute_minimum_log_size; - } + static const char getSize[] = { + 'g', 'e', 't', 'L', 'o', 'g', 'S', 'i', 'z', 'e', ' ', + LOG_ID_MAIN + '0', '\0' + }; + if (write(sock, getSize, sizeof(getSize)) > 0) { + char buffer[80]; + memset(buffer, 0, sizeof(buffer)); + read(sock, buffer, sizeof(buffer)); + totalSize = atol(buffer); + if (totalSize < expected_absolute_minimum_log_size) { + fprintf(stderr, + "WARNING: " + "Logger had unexpected referenced size \"%s\"\n", buffer); + totalSize = expected_absolute_minimum_log_size; } - close(sock); } + close(sock); + // logd allows excursions to 110% of total size totalSize = (totalSize * 11 ) / 10; // 50% threshold for SPAM filter (<20% typical, lots of engineering margin) - ASSERT_GT(totalSize, nowSize * 2); + ASSERT_GT(totalSize, nowSpamSize * 2); } diff --git a/rootdir/Android.mk b/rootdir/Android.mk index 2c1608442..aca08bfdf 100644 --- a/rootdir/Android.mk +++ b/rootdir/Android.mk @@ -30,9 +30,17 @@ LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \ include $(BUILD_SYSTEM)/base_rules.mk -$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/init.environ.rc.in +# Regenerate init.environ.rc if PRODUCT_BOOTCLASSPATH has changed. +bcp_md5 := $(word 1, $(shell echo $(PRODUCT_BOOTCLASSPATH) | $(MD5SUM))) +bcp_dep := $(intermediates)/$(bcp_md5).bcp.dep +$(bcp_dep) : + $(hide) mkdir -p $(dir $@) && rm -rf $(dir $@)*.bcp.dep && touch $@ + +$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/init.environ.rc.in $(bcp_dep) @echo "Generate: $< -> $@" @mkdir -p $(dir $@) $(hide) sed -e 's?%BOOTCLASSPATH%?$(PRODUCT_BOOTCLASSPATH)?g' $< >$@ +bcp_md5 := +bcp_dep := ####################################### diff --git a/rootdir/init.rc b/rootdir/init.rc index e3a3017c4..08b08fe01 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -26,29 +26,28 @@ on early-init start ueventd -# create mountpoints + # create mountpoints mkdir /mnt 0775 root system on init + sysclktz 0 -sysclktz 0 + loglevel 3 -loglevel 3 - -# Backward compatibility + # Backward compatibility symlink /system/etc /etc symlink /sys/kernel/debug /d -# Right now vendor lives on the same filesystem as system, -# but someday that may change. + # Right now vendor lives on the same filesystem as system, + # but someday that may change. symlink /system/vendor /vendor -# Create cgroup mount point for cpu accounting + # Create cgroup mount point for cpu accounting mkdir /acct mount cgroup none /acct cpuacct mkdir /acct/uid -# Create cgroup mount point for memory + # Create cgroup mount point for memory mount tmpfs none /sys/fs/cgroup mode=0750,uid=0,gid=1000 mkdir /sys/fs/cgroup/memory 0750 root system mount cgroup none /sys/fs/cgroup/memory memory @@ -111,7 +110,7 @@ loglevel 3 # set fwmark on accepted sockets write /proc/sys/net/ipv4/tcp_fwmark_accept 1 -# Create cgroup mount points for process groups + # Create cgroup mount points for process groups mkdir /dev/cpuctl mount cgroup none /dev/cpuctl cpu chown system system /dev/cpuctl @@ -136,25 +135,50 @@ loglevel 3 write /dev/cpuctl/apps/bg_non_interactive/cpu.rt_runtime_us 700000 write /dev/cpuctl/apps/bg_non_interactive/cpu.rt_period_us 1000000 -# qtaguid will limit access to specific data based on group memberships. -# net_bw_acct grants impersonation of socket owners. -# net_bw_stats grants access to other apps' detailed tagged-socket stats. + # qtaguid will limit access to specific data based on group memberships. + # net_bw_acct grants impersonation of socket owners. + # net_bw_stats grants access to other apps' detailed tagged-socket stats. chown root net_bw_acct /proc/net/xt_qtaguid/ctrl chown root net_bw_stats /proc/net/xt_qtaguid/stats -# Allow everybody to read the xt_qtaguid resource tracking misc dev. -# This is needed by any process that uses socket tagging. + # Allow everybody to read the xt_qtaguid resource tracking misc dev. + # This is needed by any process that uses socket tagging. chmod 0644 /dev/xt_qtaguid -# Create location for fs_mgr to store abbreviated output from filesystem -# checker programs. + # Create location for fs_mgr to store abbreviated output from filesystem + # checker programs. mkdir /dev/fscklogs 0770 root system -# pstore/ramoops previous console log + # pstore/ramoops previous console log mount pstore pstore /sys/fs/pstore chown system log /sys/fs/pstore/console-ramoops chmod 0440 /sys/fs/pstore/console-ramoops +# Healthd can trigger a full boot from charger mode by signaling this +# property when the power button is held. +on property:sys.boot_from_charger_mode=1 + class_stop charger + trigger late-init + +# Load properties from /system/ + /factory after fs mount. +on load_all_props_action + load_all_props + +# Mount filesystems and start core system services. +on late-init + trigger early-fs + trigger fs + trigger post-fs + trigger post-fs-data + + # Load properties from /system/ + /factory after fs mount. Place + # this in another action so that the load will be scheduled after the prior + # issued fs triggers have completed. + trigger load_all_props_action + + trigger early-boot + trigger boot + on post-fs # once everything is setup, no need to modify / mount rootfs rootfs / ro remount @@ -257,6 +281,7 @@ on post-fs-data # create dalvik-cache, so as to enforce our permissions mkdir /data/dalvik-cache 0771 system system + mkdir /data/dalvik-cache/profiles 0711 system system # create resource-cache and double-check the perms mkdir /data/resource-cache 0771 system system @@ -293,17 +318,17 @@ on post-fs-data #setprop vold.post_fs_data_done 1 on boot -# basic network init + # basic network init ifup lo hostname localhost domainname localdomain -# set RLIMIT_NICE to allow priorities from 19 to -20 + # set RLIMIT_NICE to allow priorities from 19 to -20 setrlimit 13 40 40 -# Memory management. Basic kernel parameters, and allow the high -# level system server to be able to adjust the kernel OOM driver -# parameters to match how it is managing things. + # Memory management. Basic kernel parameters, and allow the high + # level system server to be able to adjust the kernel OOM driver + # parameters to match how it is managing things. write /proc/sys/vm/overcommit_memory 1 write /proc/sys/vm/min_free_order_shift 4 chown root system /sys/module/lowmemorykiller/parameters/adj @@ -379,8 +404,8 @@ on boot chown system system /sys/kernel/ipv4/tcp_rmem_max chown root radio /proc/cmdline -# Define TCP buffer sizes for various networks -# ReadMin, ReadInitial, ReadMax, WriteMin, WriteInitial, WriteMax, + # Define TCP buffer sizes for various networks + # ReadMin, ReadInitial, ReadMax, WriteMin, WriteInitial, WriteMax, setprop net.tcp.buffersize.default 4096,87380,110208,4096,16384,110208 setprop net.tcp.buffersize.wifi 524288,1048576,2097152,262144,524288,1048576 setprop net.tcp.buffersize.ethernet 524288,1048576,3145728,524288,1048576,2097152 @@ -394,7 +419,7 @@ on boot setprop net.tcp.buffersize.gprs 4092,8760,48000,4096,8760,48000 setprop net.tcp.buffersize.evdo 4094,87380,262144,4096,16384,262144 -# Define default initial receive window size in segments. + # Define default initial receive window size in segments. setprop net.tcp.default_init_rwnd 60 class_start core @@ -434,6 +459,7 @@ on property:sys.powerctl=* # So proxy writes through init. on property:sys.sysctl.extra_free_kbytes=* write /proc/sys/vm/extra_free_kbytes ${sys.sysctl.extra_free_kbytes} + # "tcp_default_init_rwnd" Is too long! on property:sys.sysctl.tcp_def_init_rwnd=* write /proc/sys/net/ipv4/tcp_default_init_rwnd ${sys.sysctl.tcp_def_init_rwnd} @@ -468,7 +494,7 @@ service console /system/bin/sh console disabled user shell - group log + group shell log seclabel u:r:shell:s0 on property:ro.debuggable=1 diff --git a/toolbox/Android.mk b/toolbox/Android.mk index fddf0a901..c53f17da5 100644 --- a/toolbox/Android.mk +++ b/toolbox/Android.mk @@ -2,73 +2,75 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) TOOLS := \ - ls \ - mount \ cat \ - ps \ - kill \ - ln \ - insmod \ - rmmod \ - lsmod \ - ifconfig \ - rm \ - mkdir \ - rmdir \ - getevent \ - sendevent \ - date \ - wipe \ - sync \ - umount \ - start \ - stop \ - notify \ + chcon \ + chmod \ + chown \ + clear \ cmp \ - dmesg \ - route \ - hd \ + date \ dd \ df \ + dmesg \ + du \ + getenforce \ + getevent \ getprop \ - setprop \ - watchprops \ - log \ - sleep \ - renice \ - printenv \ - smd \ - chmod \ - chown \ - newfs_msdos \ - netstat \ - ioctl \ - mv \ - schedtop \ - top \ - iftop \ + getsebool \ + hd \ id \ - uptime \ - vmstat \ - nandread \ + ifconfig \ + iftop \ + insmod \ + ioctl \ ionice \ - touch \ + kill \ + ln \ + load_policy \ + log \ + ls \ + lsmod \ lsof \ - du \ md5 \ - clear \ - getenforce \ - setenforce \ - chcon \ + mkdir \ + mknod \ + mkswap \ + mount \ + mv \ + nandread \ + netstat \ + newfs_msdos \ + nohup \ + notify \ + printenv \ + ps \ + readlink \ + renice \ restorecon \ + rm \ + rmdir \ + rmmod \ + route \ runcon \ - getsebool \ + schedtop \ + sendevent \ + setenforce \ + setprop \ setsebool \ - load_policy \ - swapon \ + sleep \ + smd \ + start \ + stop \ swapoff \ - mkswap \ - readlink + swapon \ + sync \ + top \ + touch \ + umount \ + uptime \ + vmstat \ + watchprops \ + wipe \ ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT))) TOOLS += r @@ -92,21 +94,25 @@ LOCAL_SRC_FILES := \ toolbox.c \ uid_from_user.c \ -LOCAL_C_INCLUDES := bionic/libc/bionic - LOCAL_CFLAGS += \ -std=gnu99 \ -Werror -Wno-unused-parameter \ -include bsd-compatibility.h \ +LOCAL_C_INCLUDES += external/openssl/include + LOCAL_SHARED_LIBRARIES := \ - libcutils \ - liblog \ - libc \ - libusbhost \ - libselinux + libcrypto \ + libcutils \ + libselinux \ + +# libusbhost is only used by lsusb, and that isn't usually included in toolbox. +# The linker strips out all the unused library code in the normal case. +LOCAL_STATIC_LIBRARIES := \ + libusbhost \ LOCAL_MODULE := toolbox +LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk # Including this will define $(intermediates). # diff --git a/toolbox/getevent.c b/toolbox/getevent.c index c2256ff8d..da83ec38d 100644 --- a/toolbox/getevent.c +++ b/toolbox/getevent.c @@ -295,6 +295,7 @@ static int open_device(const char *device, int print_flags) { int version; int fd; + int clkid = CLOCK_MONOTONIC; struct pollfd *new_ufds; char **new_device_names; char name[80]; @@ -335,6 +336,11 @@ static int open_device(const char *device, int print_flags) idstr[0] = '\0'; } + if (ioctl(fd, EVIOCSCLOCKID, &clkid) != 0) { + fprintf(stderr, "Can't enable monotonic clock reporting: %s\n", strerror(errno)); + // a non-fatal error + } + new_ufds = realloc(ufds, sizeof(ufds[0]) * (nfds + 1)); if(new_ufds == NULL) { fprintf(stderr, "out of memory\n"); @@ -470,9 +476,9 @@ static int scan_dir(const char *dirname, int print_flags) return 0; } -static void usage(int argc, char *argv[]) +static void usage(char *name) { - fprintf(stderr, "Usage: %s [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-d] [-p] [-i] [-l] [-q] [-c count] [-r] [device]\n", argv[0]); + fprintf(stderr, "Usage: %s [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-d] [-p] [-i] [-l] [-q] [-c count] [-r] [device]\n", name); fprintf(stderr, " -t: show time stamps\n"); fprintf(stderr, " -n: don't print newlines\n"); fprintf(stderr, " -s: print switch states for given bits\n"); @@ -568,7 +574,7 @@ int getevent_main(int argc, char *argv[]) fprintf(stderr, "%s: invalid option -%c\n", argv[0], optopt); case 'h': - usage(argc, argv); + usage(argv[0]); exit(1); } } while (1); @@ -580,7 +586,7 @@ int getevent_main(int argc, char *argv[]) optind++; } if (optind != argc) { - usage(argc, argv); + usage(argv[0]); exit(1); } nfds = 1; diff --git a/toolbox/ifconfig.c b/toolbox/ifconfig.c index 80c0e5ce0..b95317638 100644 --- a/toolbox/ifconfig.c +++ b/toolbox/ifconfig.c @@ -61,11 +61,11 @@ int ifconfig_main(int argc, char *argv[]) { struct ifreq ifr; int s; - unsigned int addr, mask, flags; + unsigned int flags; char astring[20]; char mstring[20]; char *updown, *brdcst, *loopbk, *ppp, *running, *multi; - + argc--; argv++; @@ -85,13 +85,17 @@ int ifconfig_main(int argc, char *argv[]) perror(ifr.ifr_name); return -1; } else - addr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr; + strlcpy(astring, + inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr), + sizeof(astring)); if (ioctl(s, SIOCGIFNETMASK, &ifr) < 0) { perror(ifr.ifr_name); return -1; } else - mask = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr; + strlcpy(mstring, + inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr), + sizeof(mstring)); if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) { perror(ifr.ifr_name); @@ -99,16 +103,6 @@ int ifconfig_main(int argc, char *argv[]) } else flags = ifr.ifr_flags; - sprintf(astring, "%d.%d.%d.%d", - addr & 0xff, - ((addr >> 8) & 0xff), - ((addr >> 16) & 0xff), - ((addr >> 24) & 0xff)); - sprintf(mstring, "%d.%d.%d.%d", - mask & 0xff, - ((mask >> 8) & 0xff), - ((mask >> 16) & 0xff), - ((mask >> 24) & 0xff)); printf("%s: ip %s mask %s flags [", ifr.ifr_name, astring, mstring diff --git a/toolbox/md5.c b/toolbox/md5.c index 2fb8b053a..5de4d9ed1 100644 --- a/toolbox/md5.c +++ b/toolbox/md5.c @@ -4,12 +4,7 @@ #include <unistd.h> #include <sys/stat.h> #include <sys/types.h> -#include <md5.h> - -/* When this was written, bionic's md5.h did not define this. */ -#ifndef MD5_DIGEST_LENGTH -#define MD5_DIGEST_LENGTH 16 -#endif +#include <openssl/md5.h> static int usage() { @@ -30,7 +25,6 @@ static int do_md5(const char *path) return -1; } - /* Note that bionic's MD5_* functions return void. */ MD5_Init(&md5_ctx); while (1) { diff --git a/toolbox/mknod.c b/toolbox/mknod.c new file mode 100644 index 000000000..0fedece91 --- /dev/null +++ b/toolbox/mknod.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2014, The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google, Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/stat.h> + +static int print_usage() { + fprintf(stderr, "mknod <path> [b|c|u|p] <major> <minor>\n"); + return EXIT_FAILURE; +} + +int mknod_main(int argc, char **argv) { + char *path = NULL; + int major = 0; + int minor = 0; + int args = 0; + mode_t mode = 0660; + + /* Check correct argument count is 3 or 5 */ + if (argc != 3 && argc != 5) { + fprintf(stderr, "Incorrect argument count\n"); + return print_usage(); + } + + path = argv[1]; + + const char node_type = *argv[2]; + switch (node_type) { + case 'b': + mode |= S_IFBLK; + args = 5; + break; + case 'c': + case 'u': + mode |= S_IFCHR; + args = 5; + break; + case 'p': + mode |= S_IFIFO; + args = 3; + break; + default: + fprintf(stderr, "Invalid node type '%c'\n", node_type); + return print_usage(); + } + + if (argc != args) { + if (args == 5) { + fprintf(stderr, "Node type '%c' requires <major> and <minor>\n", node_type); + } else { + fprintf(stderr, "Node type '%c' does not require <major> and <minor>\n", node_type); + } + return print_usage(); + } + + if (args == 5) { + major = atoi(argv[3]); + minor = atoi(argv[4]); + } + + if (mknod(path, mode, makedev(major, minor))) { + perror("Unable to create node"); + return EXIT_FAILURE; + } + return 0; +} diff --git a/toolbox/nandread.c b/toolbox/nandread.c index 971c232f5..bd1994265 100644 --- a/toolbox/nandread.c +++ b/toolbox/nandread.c @@ -1,9 +1,10 @@ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> #include <ctype.h> #include <errno.h> #include <fcntl.h> +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <unistd.h> #include <mtd/mtd-user.h> @@ -189,18 +190,18 @@ int nandread_main(int argc, char **argv) for (pos = start, opos = 0; pos < end; pos += mtdinfo.writesize) { bad_block = 0; if (verbose > 3) - printf("reading at %llx\n", pos); + printf("reading at %" PRIx64 "\n", pos); lseek64(fd, pos, SEEK_SET); ret = read(fd, buffer, mtdinfo.writesize + rawmode); if (ret < (int)mtdinfo.writesize) { - fprintf(stderr, "short read at %llx, %d\n", pos, ret); + fprintf(stderr, "short read at %" PRIx64 ", %d\n", pos, ret); bad_block = 2; } if (!rawmode) { oobbuf.start = pos; ret = ioctl(fd, MEMREADOOB, &oobbuf); if (ret) { - fprintf(stderr, "failed to read oob data at %llx, %d\n", pos, ret); + fprintf(stderr, "failed to read oob data at %" PRIx64 ", %d\n", pos, ret); bad_block = 2; } } @@ -213,17 +214,17 @@ int nandread_main(int argc, char **argv) bpos = pos / mtdinfo.erasesize * mtdinfo.erasesize; ret = ioctl(fd, MEMGETBADBLOCK, &bpos); if (ret && errno != EOPNOTSUPP) { - printf("badblock at %llx\n", pos); + printf("badblock at %" PRIx64 "\n", pos); bad_block = 1; } if (ecc.corrected != last_ecc.corrected) - printf("ecc corrected, %u, at %llx\n", ecc.corrected - last_ecc.corrected, pos); + printf("ecc corrected, %u, at %" PRIx64 "\n", ecc.corrected - last_ecc.corrected, pos); if (ecc.failed != last_ecc.failed) - printf("ecc failed, %u, at %llx\n", ecc.failed - last_ecc.failed, pos); + printf("ecc failed, %u, at %" PRIx64 "\n", ecc.failed - last_ecc.failed, pos); if (ecc.badblocks != last_ecc.badblocks) - printf("ecc badblocks, %u, at %llx\n", ecc.badblocks - last_ecc.badblocks, pos); + printf("ecc badblocks, %u, at %" PRIx64 "\n", ecc.badblocks - last_ecc.badblocks, pos); if (ecc.bbtblocks != last_ecc.bbtblocks) - printf("ecc bbtblocks, %u, at %llx\n", ecc.bbtblocks - last_ecc.bbtblocks, pos); + printf("ecc bbtblocks, %u, at %" PRIx64 "\n", ecc.bbtblocks - last_ecc.bbtblocks, pos); if (!rawmode) { oob_fixed = (uint8_t *)oob_data; @@ -241,18 +242,18 @@ int nandread_main(int argc, char **argv) if (outfd >= 0) { ret = write(outfd, buffer, mtdinfo.writesize + spare_size); if (ret < (int)(mtdinfo.writesize + spare_size)) { - fprintf(stderr, "short write at %llx, %d\n", pos, ret); + fprintf(stderr, "short write at %" PRIx64 ", %d\n", pos, ret); close(outfd); outfd = -1; } if (ecc.corrected != last_ecc.corrected) - fprintf(statusfile, "%08llx: ecc corrected\n", opos); + fprintf(statusfile, "%08" PRIx64 ": ecc corrected\n", opos); if (ecc.failed != last_ecc.failed) - fprintf(statusfile, "%08llx: ecc failed\n", opos); + fprintf(statusfile, "%08" PRIx64 ": ecc failed\n", opos); if (bad_block == 1) - fprintf(statusfile, "%08llx: badblock\n", opos); + fprintf(statusfile, "%08" PRIx64 ": badblock\n", opos); if (bad_block == 2) - fprintf(statusfile, "%08llx: read error\n", opos); + fprintf(statusfile, "%08" PRIx64 ": read error\n", opos); opos += mtdinfo.writesize + spare_size; } @@ -261,7 +262,7 @@ int nandread_main(int argc, char **argv) if (test_empty(buffer, mtdinfo.writesize + mtdinfo.oobsize + spare_size)) empty_pages++; else if (verbose > 2 || (verbose > 1 && !(pos & (mtdinfo.erasesize - 1)))) - printf("page at %llx (%d oobbytes): %08x %08x %08x %08x " + printf("page at %" PRIx64 " (%d oobbytes): %08x %08x %08x %08x " "%08x %08x %08x %08x\n", pos, oobbuf.start, oob_data[0], oob_data[1], oob_data[2], oob_data[3], oob_data[4], oob_data[5], oob_data[6], oob_data[7]); diff --git a/toolbox/nohup.c b/toolbox/nohup.c new file mode 100644 index 000000000..363999d0b --- /dev/null +++ b/toolbox/nohup.c @@ -0,0 +1,26 @@ +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +int nohup_main(int argc, char *argv[]) +{ + if (argc < 2) { + fprintf(stderr, "Usage: %s [-n] program args...\n", argv[0]); + return EXIT_FAILURE; + } + signal(SIGHUP, SIG_IGN); + argv++; + if (strcmp(argv[0], "-n") == 0) { + argv++; + signal(SIGINT, SIG_IGN); + signal(SIGSTOP, SIG_IGN); + signal(SIGTTIN, SIG_IGN); + signal(SIGTTOU, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGTERM, SIG_IGN); + } + execvp(argv[0], argv); + perror(argv[0]); + return EXIT_FAILURE; +} |
