Merge "property_service: get rid of hard coded property / control list"
diff --git a/adb/adb.c b/adb/adb.c
index 6d3a71b..90bdbaa 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -1344,29 +1344,29 @@
" 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/usb_vendors.c b/adb/usb_vendors.c
index 705f02b..957e5db 100755
--- a/adb/usb_vendors.c
+++ b/adb/usb_vendors.c
@@ -84,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
@@ -160,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
@@ -217,6 +221,7 @@
VENDOR_ID_HAIER,
VENDOR_ID_HARRIS,
VENDOR_ID_HISENSE,
+ VENDOR_ID_HONEYWELL,
VENDOR_ID_HP,
VENDOR_ID_HTC,
VENDOR_ID_HUAWEI,
@@ -255,6 +260,7 @@
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 e3cadb1..15add87 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 @@
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/arm64/machine.cpp b/debuggerd/arm64/machine.cpp
index f3409d5..48308c3 100644
--- a/debuggerd/arm64/machine.cpp
+++ b/debuggerd/arm64/machine.cpp
@@ -44,7 +44,7 @@
io.iov_len = sizeof(regs);
if (ptrace(PTRACE_GETREGSET, tid, (void*)NT_PRSTATUS, &io) == -1) {
- LOG_ERROR("%s: ptrace failed to get registers: %s\n",
+ _LOG(log, logtype::ERROR, "%s: ptrace failed to get registers: %s\n",
__func__, strerror(errno));
return;
}
@@ -80,7 +80,7 @@
io.iov_len = sizeof(r);
if (ptrace(PTRACE_GETREGSET, tid, (void*) NT_PRSTATUS, (void*) &io) == -1) {
- LOG_ERROR("ptrace error: %s\n", strerror(errno));
+ _LOG(log, logtype::ERROR, "ptrace error: %s\n", strerror(errno));
return;
}
@@ -105,7 +105,7 @@
io.iov_len = sizeof(f);
if (ptrace(PTRACE_GETREGSET, tid, (void*) NT_PRFPREG, (void*) &io) == -1) {
- LOG_ERROR("ptrace error: %s\n", strerror(errno));
+ _LOG(log, logtype::ERROR, "ptrace error: %s\n", strerror(errno));
return;
}
diff --git a/debuggerd/backtrace.cpp b/debuggerd/backtrace.cpp
index d08242e..c4a2143 100644
--- a/debuggerd/backtrace.cpp
+++ b/debuggerd/backtrace.cpp
@@ -49,8 +49,9 @@
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, logtype::BACKTRACE, "\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, logtype::BACKTRACE, "Cmd line: %s\n", procname);
@@ -95,7 +96,7 @@
}
if (!attached && ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
- LOG_ERROR("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;
}
}
@@ -105,7 +106,6 @@
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);
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index dde8f90..fc13977 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -61,34 +61,24 @@
char exe[PATH_MAX];
int count;
if ((count = readlink(path, exe, sizeof(exe) - 1)) == -1) {
- LOG_ERROR("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_ERROR( "********************************************************\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) {
@@ -103,7 +93,7 @@
uninit_getevent();
}
- LOG_ERROR("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) {
@@ -139,11 +129,11 @@
socklen_t len = sizeof(cr);
int status = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
if (status != 0) {
- LOG_ERROR("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];
@@ -152,7 +142,7 @@
pollfds[0].revents = 0;
status = TEMP_FAILURE_RETRY(poll(pollfds, 1, 3000));
if (status != 1) {
- LOG_ERROR("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;
}
@@ -160,14 +150,11 @@
memset(&msg, 0, sizeof(msg));
status = TEMP_FAILURE_RETRY(read(fd, &msg, sizeof(msg)));
if (status < 0) {
- LOG_ERROR("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_ERROR("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;
}
@@ -185,7 +172,7 @@
struct stat s;
snprintf(buf, sizeof buf, "/proc/%d/task/%d", out_request->pid, out_request->tid);
if (stat(buf, &s)) {
- LOG_ERROR("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;
}
@@ -196,7 +183,7 @@
status = get_process_info(out_request->tid, &out_request->pid,
&out_request->uid, &out_request->gid);
if (status < 0) {
- LOG_ERROR("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 {
@@ -217,13 +204,13 @@
}
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
@@ -237,12 +224,12 @@
// See details in bionic/libc/linker/debugger.c, in function
// debugger_signal_handler().
if (ptrace(PTRACE_ATTACH, request.tid, 0, 0)) {
- LOG_ERROR("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_ERROR("failed responding to client: %s\n", strerror(errno));
+ ALOGE("failed responding to client: %s\n", strerror(errno));
} else {
char* tombstone_path = NULL;
@@ -261,20 +248,20 @@
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_ERROR("ptrace continue failed: %s\n", strerror(errno));
+ ALOGE("ptrace continue failed: %s\n", strerror(errno));
}
continue; // loop again
}
@@ -290,7 +277,7 @@
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:
@@ -300,13 +287,12 @@
// 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_ERROR("process stopped due to unexpected signal %d\n", signal);
+ ALOGE("process stopped due to unexpected signal %d\n", signal);
break;
}
break;
@@ -322,14 +308,14 @@
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_ERROR("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;
}
@@ -341,7 +327,7 @@
} else {
// just detach
if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) {
- LOG_ERROR("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;
}
}
@@ -353,7 +339,7 @@
// 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_ERROR("debuggerd committing suicide to free the zombie!\n");
+ ALOGE("debuggerd committing suicide to free the zombie!\n");
kill(getpid(), SIGKILL);
}
}
@@ -399,16 +385,16 @@
return 1;
fcntl(s, F_SETFD, FD_CLOEXEC);
- LOG_ERROR("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/mips/machine.cpp b/debuggerd/mips/machine.cpp
index 605275b..97834c7 100644
--- a/debuggerd/mips/machine.cpp
+++ b/debuggerd/mips/machine.cpp
@@ -87,7 +87,7 @@
void dump_registers(log_t* log, pid_t tid) {
pt_regs_mips_t r;
if(ptrace(PTRACE_GETREGS, tid, 0, &r)) {
- LOG_ERROR("cannot get registers: %s\n", strerror(errno));
+ _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
return;
}
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index 37839aa..a58d9e5 100755
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -58,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:
@@ -235,7 +220,7 @@
fclose(fp);
}
- _LOG(log, logtype::THREAD, "pid: %d, tid: %d, name: %s >>> %s <<<\n", pid, tid,
+ _LOG(log, logtype::HEADER, "pid: %d, tid: %d, name: %s >>> %s <<<\n", pid, tid,
threadname ? threadname : "UNKNOWN", procname ? procname : "UNKNOWN");
}
@@ -343,8 +328,9 @@
}
}
-static void dump_map(log_t* log, const backtrace_map_t* map) {
- _LOG(log, logtype::MAPS, " %" 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());
}
@@ -366,10 +352,18 @@
return;
}
- _LOG(log, logtype::MAPS, "\nmemory map:\n");
+ _LOG(log, logtype::MAPS, "\nmemory map: (fault address prefixed with --->)\n");
+ bool found_map = false;
for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) {
- dump_map(log, &*it);
+ bool in_map = addr >= (*it).start && addr < (*it).end;
+ dump_map(log, &*it, in_map);
+ if(in_map) {
+ found_map = true;
+ }
+ }
+ if(!found_map) {
+ _LOG(log, logtype::ERROR, "\nFault address was not in any map!");
}
}
@@ -395,7 +389,7 @@
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;
}
@@ -416,15 +410,14 @@
// Skip this thread if cannot ptrace it
if (ptrace(PTRACE_ATTACH, new_tid, 0, 0) < 0) {
- LOG_ERROR("ptrace attach to %d failed: %s\n", new_tid, strerror(errno));
+ _LOG(log, logtype::ERROR, "ptrace attach to %d failed: %s\n", new_tid, strerror(errno));
continue;
}
+ log->current_tid = new_tid;
_LOG(log, logtype::THREAD, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
dump_thread_info(log, pid, new_tid);
- log->current_tid = new_tid;
-
UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, new_tid, map));
if (backtrace->Unwind(0)) {
dump_thread(backtrace.get(), log, total_sleep_time_usec);
@@ -433,7 +426,7 @@
log->current_tid = log->crashed_tid;
if (ptrace(PTRACE_DETACH, new_tid, 0, 0) != 0) {
- LOG_ERROR("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;
}
}
@@ -457,7 +450,7 @@
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;
}
@@ -474,17 +467,17 @@
// non-blocking EOF; we're done
break;
} else {
- LOG_ERROR("Error while reading log: %s\n",
+ _LOG(log, logtype::ERROR, "Error while reading log: %s\n",
strerror(-actual));
break;
}
} else if (actual == 0) {
- LOG_ERROR("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.
@@ -690,7 +683,7 @@
}
if (oldest < 0) {
- LOG_ERROR("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;
}
@@ -698,7 +691,7 @@
snprintf(path, sizeof(path), TOMBSTONE_TEMPLATE, oldest);
*fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
if (*fd < 0) {
- LOG_ERROR("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);
@@ -736,7 +729,7 @@
}
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;
@@ -744,11 +737,11 @@
log.crashed_tid = tid;
if ((mkdir(TOMBSTONE_DIR, 0755) == -1) && (errno != EEXIST)) {
- LOG_ERROR("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_ERROR("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;
@@ -756,11 +749,11 @@
if (selinux_android_restorecon(TOMBSTONE_DIR, 0) == 0) {
path = find_and_open_tombstone(&fd);
} else {
- LOG_ERROR("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_ERROR("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;
}
@@ -770,7 +763,6 @@
// 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);
diff --git a/debuggerd/tombstone.h b/debuggerd/tombstone.h
index 3574e84..7e2b2fe 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 f0d9220..a163344 100644
--- a/debuggerd/utility.cpp
+++ b/debuggerd/utility.cpp
@@ -37,7 +37,7 @@
int written = TEMP_FAILURE_RETRY(write(fd, buf + len - to_write, to_write));
if (written < 0) {
// hard failure
- LOG_ERROR("AM write failure (%d / %s)\n", errno, strerror(errno));
+ ALOGE("AM write failure (%d / %s)\n", errno, strerror(errno));
return -1;
}
to_write -= written;
@@ -57,12 +57,10 @@
}
void _LOG(log_t* log, enum logtype ltype, const char* fmt, ...) {
- bool write_to_tombstone = log && log->tfd;
- bool write_to_logcat = (!log || !log->quiet) && is_allowed_in_logcat(ltype);
- if (log != NULL) {
- write_to_logcat &= (log->crashed_tid == log->current_tid);
- }
- bool write_to_activitymanager = log && log->amfd >= 0 && is_allowed_in_logcat(ltype);
+ 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;
@@ -98,25 +96,25 @@
if (n < 0) {
if (errno == EAGAIN)
continue;
- LOG_ERROR("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_ERROR("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_ERROR("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;
}
@@ -126,7 +124,7 @@
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_ERROR("timed out waiting for tid=%d to stop\n", tid);
+ ALOGE("timed out waiting for tid=%d to stop\n", tid);
break;
}
diff --git a/debuggerd/utility.h b/debuggerd/utility.h
index fdfb2ec..f2e2d29 100644
--- a/debuggerd/utility.h
+++ b/debuggerd/utility.h
@@ -21,13 +21,27 @@
#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.
@@ -51,10 +65,6 @@
void _LOG(log_t* log, logtype ltype, const char *fmt, ...)
__attribute__ ((format(printf, 3, 4)));
-/* Further helpful macros */
-#define LOG_ERROR(fmt...) _LOG(NULL, logtype::ERROR, fmt)
-#define XLOG(fmt...) do {} while(0)
-
int wait_for_signal(pid_t tid, int* total_sleep_time_usec);
void wait_for_stop(pid_t tid, int* total_sleep_time_usec);
diff --git a/debuggerd/x86/machine.cpp b/debuggerd/x86/machine.cpp
index 2d553fa..57330c1 100644
--- a/debuggerd/x86/machine.cpp
+++ b/debuggerd/x86/machine.cpp
@@ -31,7 +31,7 @@
void dump_registers(log_t* log, pid_t tid) {
struct pt_regs r;
if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) {
- LOG_ERROR("cannot get registers: %s\n", strerror(errno));
+ _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
return;
}
_LOG(log, logtype::REGISTERS, " eax %08lx ebx %08lx ecx %08lx edx %08lx\n",
diff --git a/debuggerd/x86_64/machine.cpp b/debuggerd/x86_64/machine.cpp
index 6cb0e8d..af4f35a 100755
--- a/debuggerd/x86_64/machine.cpp
+++ b/debuggerd/x86_64/machine.cpp
@@ -33,7 +33,7 @@
void dump_registers(log_t* log, pid_t tid) {
struct user_regs_struct r;
if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) {
- LOG_ERROR("cannot get registers: %s\n", strerror(errno));
+ _LOG(log, logtype::ERROR, "cannot get registers: %s\n", strerror(errno));
return;
}
_LOG(log, logtype::REGISTERS, " rax %016lx rbx %016lx rcx %016lx rdx %016lx\n",
diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c
index 9c04c21..266d0b5 100644
--- a/fastboot/fastboot.c
+++ b/fastboot/fastboot.c
@@ -1216,6 +1216,7 @@
}
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 9b84c3e..d30e771 100644
--- a/healthd/healthd.cpp
+++ b/healthd/healthd.cpp
@@ -126,7 +126,7 @@
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/cutils/atomic-inline.h b/include/cutils/atomic-inline.h
index 4f90ef1..007a905 100644
--- a/include/cutils/atomic-inline.h
+++ b/include/cutils/atomic-inline.h
@@ -51,6 +51,8 @@
#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 f9d3e25..1ed833d 100644
--- a/include/cutils/atomic-mips.h
+++ b/include/cutils/atomic-mips.h
@@ -117,23 +117,6 @@
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 0000000..99bbe3a
--- /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 2c70165..798db8b 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 @@
*/
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/init/builtins.c b/init/builtins.c
index d9f7bbe..0c32b2a 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -877,6 +877,14 @@
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 02698ef..ea9a4b2 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 @@
unsigned int uid;
unsigned int gid;
unsigned short prefix;
+ unsigned short wildcard;
};
struct perm_node {
@@ -97,7 +99,8 @@
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 @@
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 @@
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 @@
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;
diff --git a/init/devices.h b/init/devices.h
index a84fa58..5d0fe88 100644
--- a/init/devices.h
+++ b/init/devices.h
@@ -23,6 +23,7 @@
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 c79929b..f001071 100644
--- a/init/init.c
+++ b/init/init.c
@@ -938,7 +938,7 @@
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 @@
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 @@
/* 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 7800082..289e759 100644
--- a/init/init_parser.c
+++ b/init/init_parser.c
@@ -120,6 +120,7 @@
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 6625330..2d97e5b 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -39,6 +39,7 @@
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 @@
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 0ba770f..e9cb65a 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 aaf6c1e..d112699 100644
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -520,10 +520,8 @@
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.*");
@@ -532,6 +530,11 @@
/* 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 46cbd8f..730495e 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -24,6 +24,7 @@
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 662196d..833e4fd 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 @@
}
#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 @@
uid_t uid;
gid_t gid;
int prefix = 0;
+ int wildcard = 0;
char *endptr;
int ret;
char *tmp = 0;
@@ -154,9 +160,13 @@
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 @@
}
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.mk b/libbacktrace/Android.mk
index 1de81e7..c321369 100755
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -201,6 +201,8 @@
LOCAL_SRC_FILES := \
BacktraceMap.cpp \
+LOCAL_MULTILIB := both
+
include $(BUILD_HOST_SHARED_LIBRARY)
endif # TARGET_BUILD_APPS
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index c0faed4..933a77b 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -134,6 +134,9 @@
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 \
@@ -146,6 +149,7 @@
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
diff --git a/libcutils/arch-arm/memset32.S b/libcutils/arch-arm/memset32.S
index 4697265..6efab9f 100644
--- a/libcutils/arch-arm/memset32.S
+++ b/libcutils/arch-arm/memset32.S
@@ -51,8 +51,10 @@
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 @@
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 0000000..9a83a68
--- /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/properties.c b/libcutils/properties.c
index 28d8b2f..b283658 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 @@
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 0000000..8e65310
--- /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 0000000..45efc51
--- /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 0000000..659821c
--- /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/logcat/tests/Android.mk b/logcat/tests/Android.mk
index 5d4d29e..015a23d 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 @@
-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 @@
# 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 0000000..be815be
--- /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 2e8ae8b..9b316d1 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 @@
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 @@
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 @@
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 @@
++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 @@
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 @@
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 9d7d152..d7088b4 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -74,9 +74,9 @@
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 @@
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 0448afa..cd9ea20 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -232,7 +232,7 @@
// 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 @@
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 @@
}
// 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 b8a54b9..4b982a8 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 @@
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 @@
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/tests/Android.mk b/logd/tests/Android.mk
index 123e317..f851288 100644
--- a/logd/tests/Android.mk
+++ b/logd/tests/Android.mk
@@ -34,7 +34,7 @@
-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 5b51b1f..957fdb5 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -568,10 +568,11 @@
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 @@
#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 @@
#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 @@
// 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 2c16084..aca08bf 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -30,9 +30,17 @@
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 484bd10..08b08fe 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -26,29 +26,28 @@
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 @@
# 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 @@
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
@@ -294,17 +318,17 @@
#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
@@ -380,8 +404,8 @@
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
@@ -395,7 +419,7 @@
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
@@ -435,6 +459,7 @@
# 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}
diff --git a/toolbox/ifconfig.c b/toolbox/ifconfig.c
index 80c0e5c..b953176 100644
--- a/toolbox/ifconfig.c
+++ b/toolbox/ifconfig.c
@@ -61,11 +61,11 @@
{
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 @@
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 @@
} 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/nandread.c b/toolbox/nandread.c
index 971c232..bd19942 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 @@
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 @@
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 @@
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 @@
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]);