Merge "Added net.dns1 prop for emulator, as Android emulator ignores it by default."
diff --git a/adb/file_sync_client.c b/adb/file_sync_client.c
index 64e393c..354d0fb 100644
--- a/adb/file_sync_client.c
+++ b/adb/file_sync_client.c
@@ -32,7 +32,7 @@
#include "file_sync_service.h"
-static unsigned total_bytes;
+static unsigned long long total_bytes;
static long long start_time;
static long long NOW()
@@ -58,8 +58,8 @@
t = 1000000;
fprintf(stderr,"%lld KB/s (%lld bytes in %lld.%03llds)\n",
- ((((long long) total_bytes) * 1000000LL) / t) / 1024LL,
- (long long) total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
+ ((total_bytes * 1000000LL) / t) / 1024LL,
+ total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
}
void sync_quit(int fd)
diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c
index 698f8a9..e132c67 100644
--- a/adb/usb_vendors.c
+++ b/adb/usb_vendors.c
@@ -143,6 +143,16 @@
#define VENDOR_ID_BYD 0x19D1
// OUYA's USB Vendor ID
#define VENDOR_ID_OUYA 0x2836
+// Haier's USB Vendor ID
+#define VENDOR_ID_HAIER 0x201E
+// Hisense's USB Vendor ID
+#define VENDOR_ID_HISENSE 0x109b
+// MTK's USB Vendor ID
+#define VENDOR_ID_MTK 0x0e8d
+// B&N Nook's USB Vendor ID
+#define VENDOR_ID_NOOK 0x2080
+// Qisda's USB Vendor ID
+#define VENDOR_ID_QISDA 0x1D45
/** built-in vendor list */
@@ -201,6 +211,11 @@
VENDOR_ID_XIAOMI,
VENDOR_ID_BYD,
VENDOR_ID_OUYA,
+ VENDOR_ID_HAIER,
+ VENDOR_ID_HISENSE,
+ VENDOR_ID_MTK,
+ VENDOR_ID_NOOK,
+ VENDOR_ID_QISDA,
};
#define BUILT_IN_VENDOR_COUNT (sizeof(builtInVendorIds)/sizeof(builtInVendorIds[0]))
diff --git a/debuggerd/crasher.c b/debuggerd/crasher.c
index d88ef88..8c225cb 100644
--- a/debuggerd/crasher.c
+++ b/debuggerd/crasher.c
@@ -21,8 +21,7 @@
void crash1(void);
void crashnostack(void);
-void maybeabort(void);
-int do_action(const char* arg);
+static int do_action(const char* arg);
static void debuggerd_connect()
{
@@ -30,14 +29,20 @@
int s;
sprintf(tmp, "%d", gettid());
s = socket_local_client("android:debuggerd",
- ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
+ ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
if(s >= 0) {
read(s, tmp, 1);
close(s);
}
}
-int smash_stack(int i) {
+static void maybeabort() {
+ if(time(0) != 42) {
+ abort();
+ }
+}
+
+static int smash_stack(int i) {
printf("crasher: deliberately corrupting stack...\n");
// Unless there's a "big enough" buffer on the stack, gcc
// doesn't bother inserting checks.
@@ -49,19 +54,19 @@
return *(int*)(&buf[0]);
}
-__attribute__((noinline)) void overflow_stack(void* p) {
+__attribute__((noinline)) static void overflow_stack(void* p) {
fprintf(stderr, "p = %p\n", p);
void* buf[1];
buf[0] = p;
overflow_stack(&buf);
}
-void test_call1()
+static void test_call1()
{
*((int*) 32) = 1;
}
-void *noisy(void *x)
+static void *noisy(void *x)
{
char c = (unsigned) x;
for(;;) {
@@ -72,7 +77,7 @@
return 0;
}
-int ctest()
+static int ctest()
{
pthread_t thr;
pthread_attr_t attr;
@@ -90,7 +95,7 @@
return (void*) do_action((const char*) raw_arg);
}
-int do_action_on_thread(const char* arg)
+static int do_action_on_thread(const char* arg)
{
pthread_t t;
pthread_create(&t, NULL, thread_callback, (void*) arg);
@@ -99,22 +104,27 @@
return (int) result;
}
-__attribute__((noinline)) int crash3(int a) {
- *((int*) 0xdead) = a;
- return a*4;
+__attribute__((noinline)) static int crash3(int a) {
+ *((int*) 0xdead) = a;
+ return a*4;
}
-__attribute__((noinline)) int crash2(int a) {
- a = crash3(a) + 2;
- return a*3;
+__attribute__((noinline)) static int crash2(int a) {
+ a = crash3(a) + 2;
+ return a*3;
}
-__attribute__((noinline)) int crash(int a) {
- a = crash2(a) + 1;
- return a*2;
+__attribute__((noinline)) static int crash(int a) {
+ a = crash2(a) + 1;
+ return a*2;
}
-int do_action(const char* arg)
+static void abuse_heap() {
+ char buf[16];
+ free((void*) buf); // GCC is smart enough to warn about this, but we're doing it deliberately.
+}
+
+static int do_action(const char* arg)
{
fprintf(stderr,"crasher: init pid=%d tid=%d\n", getpid(), gettid());
@@ -134,12 +144,16 @@
return crash(42);
} else if (!strcmp(arg,"abort")) {
maybeabort();
+ } else if (!strcmp(arg, "heap-usage")) {
+ abuse_heap();
}
fprintf(stderr, "%s OP\n", __progname);
fprintf(stderr, "where OP is:\n");
fprintf(stderr, " smash-stack overwrite a stack-guard canary\n");
fprintf(stderr, " stack-overflow recurse until the stack overflows\n");
+ fprintf(stderr, " heap-corruption cause a libc abort by corrupting the heap\n");
+ fprintf(stderr, " heap-usage cause a libc abort by abusing a heap function\n");
fprintf(stderr, " nostack crash with a NULL stack pointer\n");
fprintf(stderr, " ctest (obsoleted by thread-crash?)\n");
fprintf(stderr, " exit call exit(1)\n");
@@ -159,11 +173,6 @@
} else {
crash1();
}
-
- return 0;
-}
-void maybeabort()
-{
- if(time(0) != 42) abort();
+ return 0;
}
diff --git a/include/corkscrew/map_info.h b/include/corkscrew/map_info.h
index c9b241d..14bfad6 100644
--- a/include/corkscrew/map_info.h
+++ b/include/corkscrew/map_info.h
@@ -63,6 +63,10 @@
* previous acquired using acquire_my_map_info_list(). */
void release_my_map_info_list(map_info_t* milist);
+/* Flushes the cached memory map so the next call to
+ * acquire_my_map_info_list() gets fresh data. */
+void flush_my_map_info_list();
+
#ifdef __cplusplus
}
#endif
diff --git a/init/builtins.c b/init/builtins.c
index dc7900e..07bd6d3 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -590,8 +590,7 @@
struct service *svc;
svc = service_find_by_name(args[1]);
if (svc) {
- service_stop(svc);
- service_start(svc, NULL);
+ service_restart(svc);
}
return 0;
}
diff --git a/init/init.c b/init/init.c
index 39df0ff..c21a495 100755
--- a/init/init.c
+++ b/init/init.c
@@ -164,7 +164,7 @@
* state and immediately takes it out of the restarting
* state if it was in there
*/
- svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET));
+ svc->flags &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART));
svc->time_started = 0;
/* running processes require no additional work -- if
@@ -359,15 +359,14 @@
notify_service_state(svc->name, "running");
}
-/* The how field should be either SVC_DISABLED or SVC_RESET */
+/* The how field should be either SVC_DISABLED, SVC_RESET, or SVC_RESTART */
static void service_stop_or_reset(struct service *svc, int how)
{
- /* we are no longer running, nor should we
- * attempt to restart
- */
- svc->flags &= (~(SVC_RUNNING|SVC_RESTARTING));
+ /* The service is still SVC_RUNNING until its process exits, but if it has
+ * already exited it shoudn't attempt a restart yet. */
+ svc->flags &= (~SVC_RESTARTING);
- if ((how != SVC_DISABLED) && (how != SVC_RESET)) {
+ if ((how != SVC_DISABLED) && (how != SVC_RESET) && (how != SVC_RESTART)) {
/* Hrm, an illegal flag. Default to SVC_DISABLED */
how = SVC_DISABLED;
}
@@ -399,6 +398,17 @@
service_stop_or_reset(svc, SVC_DISABLED);
}
+void service_restart(struct service *svc)
+{
+ if (svc->flags & SVC_RUNNING) {
+ /* Stop, wait, then start the service. */
+ service_stop_or_reset(svc, SVC_RESTART);
+ } else if (!(svc->flags & SVC_RESTARTING)) {
+ /* Just start the service since it's not running. */
+ service_start(svc, NULL);
+ } /* else: Service is restarting anyways. */
+}
+
void property_changed(const char *name, const char *value)
{
if (property_triggers_enabled)
@@ -467,6 +477,17 @@
}
}
+static void msg_restart(const char *name)
+{
+ struct service *svc = service_find_by_name(name);
+
+ if (svc) {
+ service_restart(svc);
+ } else {
+ ERROR("no such service '%s'\n", name);
+ }
+}
+
void handle_control_message(const char *msg, const char *arg)
{
if (!strcmp(msg,"start")) {
@@ -474,8 +495,7 @@
} else if (!strcmp(msg,"stop")) {
msg_stop(arg);
} else if (!strcmp(msg,"restart")) {
- msg_stop(arg);
- msg_start(arg);
+ msg_restart(arg);
} else {
ERROR("unknown control msg '%s'\n", msg);
}
@@ -625,7 +645,7 @@
static void export_kernel_boot_props(void)
{
char tmp[PROP_VALUE_MAX];
- const char *pval;
+ int ret;
unsigned i;
struct {
const char *src_prop;
@@ -639,22 +659,26 @@
};
for (i = 0; i < ARRAY_SIZE(prop_map); i++) {
- pval = property_get(prop_map[i].src_prop);
- property_set(prop_map[i].dest_prop, pval ?: prop_map[i].def_val);
+ ret = property_get(prop_map[i].src_prop, tmp);
+ if (ret > 0)
+ property_set(prop_map[i].dest_prop, tmp);
+ else
+ property_set(prop_map[i].dest_prop, prop_map[i].def_val);
}
- pval = property_get("ro.boot.console");
- if (pval)
- strlcpy(console, pval, sizeof(console));
+ ret = property_get("ro.boot.console", tmp);
+ if (ret)
+ strlcpy(console, tmp, sizeof(console));
/* save a copy for init's usage during boot */
- strlcpy(bootmode, property_get("ro.bootmode"), sizeof(bootmode));
+ property_get("ro.bootmode", tmp);
+ strlcpy(bootmode, tmp, sizeof(bootmode));
/* if this was given on kernel command line, override what we read
* before (e.g. from /proc/cpuinfo), if anything */
- pval = property_get("ro.boot.hardware");
- if (pval)
- strlcpy(hardware, pval, sizeof(hardware));
+ ret = property_get("ro.boot.hardware", tmp);
+ if (ret)
+ strlcpy(hardware, tmp, sizeof(hardware));
property_set("ro.hardware", hardware);
snprintf(tmp, PROP_VALUE_MAX, "%d", revision);
diff --git a/init/init.h b/init/init.h
index 955e1f0..aa6a4ab 100644
--- a/init/init.h
+++ b/init/init.h
@@ -72,6 +72,7 @@
#define SVC_RESET 0x40 /* Use when stopping a process, but not disabling
so it can be restarted with its class */
#define SVC_RC_DISABLED 0x80 /* Remember if the disabled flag was set in the rc script */
+#define SVC_RESTART 0x100 /* Use to safely restart (stop, wait, start) a service */
#define NR_SVC_SUPP_GIDS 12 /* twelve supplementary groups */
@@ -127,6 +128,7 @@
void (*func)(struct service *svc));
void service_stop(struct service *svc);
void service_reset(struct service *svc);
+void service_restart(struct service *svc);
void service_start(struct service *svc, const char *dynamic_args);
void property_changed(const char *name, const char *value);
diff --git a/init/init_parser.c b/init/init_parser.c
index beb9188..cce1093 100644
--- a/init/init_parser.c
+++ b/init/init_parser.c
@@ -206,8 +206,9 @@
while (*src_ptr && left > 0) {
char *c;
char prop[PROP_NAME_MAX + 1];
- const char *prop_val;
+ char prop_val[PROP_VALUE_MAX];
int prop_len = 0;
+ int prop_val_len;
c = strchr(src_ptr, '$');
if (!c) {
@@ -265,14 +266,14 @@
goto err;
}
- prop_val = property_get(prop);
- if (!prop_val) {
+ prop_val_len = property_get(prop, prop_val);
+ if (!prop_val_len) {
ERROR("property '%s' doesn't exist while expanding '%s'\n",
prop, src);
goto err;
}
- ret = push_chars(&dst_ptr, &left, prop_val, strlen(prop_val));
+ ret = push_chars(&dst_ptr, &left, prop_val, prop_val_len);
if (ret < 0)
goto err_nospace;
src_ptr = c;
@@ -543,7 +544,7 @@
const char* equals = strchr(name, '=');
if (equals) {
char prop_name[PROP_NAME_MAX + 1];
- const char* value;
+ char value[PROP_VALUE_MAX];
int length = equals - name;
if (length > PROP_NAME_MAX) {
ERROR("property name too long in trigger %s", act->name);
@@ -552,9 +553,8 @@
prop_name[length] = 0;
/* does the property exist, and match the trigger value? */
- value = property_get(prop_name);
- if (value && (!strcmp(equals + 1, value) ||
- !strcmp(equals + 1, "*"))) {
+ property_get(prop_name, value);
+ if (!strcmp(equals + 1, value) ||!strcmp(equals + 1, "*")) {
action_add_queue_tail(act);
}
}
@@ -571,6 +571,7 @@
act = calloc(1, sizeof(*act));
act->name = name;
list_init(&act->commands);
+ list_init(&act->qlist);
cmd = calloc(1, sizeof(*cmd));
cmd->func = func;
@@ -583,7 +584,9 @@
void action_add_queue_tail(struct action *act)
{
- list_add_tail(&action_queue, &act->qlist);
+ if (list_empty(&act->qlist)) {
+ list_add_tail(&action_queue, &act->qlist);
+ }
}
struct action *action_remove_queue_head(void)
@@ -594,6 +597,7 @@
struct listnode *node = list_head(&action_queue);
struct action *act = node_to_item(node, struct action, qlist);
list_remove(node);
+ list_init(node);
return act;
}
}
@@ -825,6 +829,7 @@
act = calloc(1, sizeof(*act));
act->name = args[1];
list_init(&act->commands);
+ list_init(&act->qlist);
list_add_tail(&action_list, &act->alist);
/* XXX add to hash */
return act;
diff --git a/init/keychords.c b/init/keychords.c
index aab0819..d18a6e4 100644
--- a/init/keychords.c
+++ b/init/keychords.c
@@ -95,24 +95,23 @@
void handle_keychord()
{
struct service *svc;
- const char* debuggable;
- const char* adb_enabled;
+ char debuggable[PROP_VALUE_MAX];
+ char adb_enabled[PROP_VALUE_MAX];
int ret;
__u16 id;
// only handle keychords if ro.debuggable is set or adb is enabled.
// the logic here is that bugreports should be enabled in userdebug or eng builds
// and on user builds for users that are developers.
- debuggable = property_get("ro.debuggable");
- adb_enabled = property_get("init.svc.adbd");
+ property_get("ro.debuggable", debuggable);
+ property_get("init.svc.adbd", adb_enabled);
ret = read(keychord_fd, &id, sizeof(id));
if (ret != sizeof(id)) {
ERROR("could not read keychord id\n");
return;
}
- if ((debuggable && !strcmp(debuggable, "1")) ||
- (adb_enabled && !strcmp(adb_enabled, "running"))) {
+ if (!strcmp(debuggable, "1") || !strcmp(adb_enabled, "running")) {
svc = service_find_by_keychord(id);
if (svc) {
INFO("starting service %s from keychord\n", svc->name);
diff --git a/init/property_service.c b/init/property_service.c
index 48488be..70ee4a6 100755
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -110,7 +110,6 @@
};
typedef struct {
- void *data;
size_t size;
int fd;
} workspace;
@@ -118,85 +117,34 @@
static int init_workspace(workspace *w, size_t size)
{
void *data;
- int fd;
-
- /* dev is a tmpfs that we can use to carve a shared workspace
- * out of, so let's do that...
- */
- fd = open("/dev/__properties__", O_RDWR | O_CREAT | O_NOFOLLOW, 0600);
+ int fd = open(PROP_FILENAME, O_RDONLY | O_NOFOLLOW);
if (fd < 0)
return -1;
- if (ftruncate(fd, size) < 0)
- goto out;
-
- data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
- if(data == MAP_FAILED)
- goto out;
-
- close(fd);
-
- fd = open("/dev/__properties__", O_RDONLY | O_NOFOLLOW);
- if (fd < 0)
- return -1;
-
- unlink("/dev/__properties__");
-
- w->data = data;
w->size = size;
w->fd = fd;
return 0;
-
-out:
- close(fd);
- return -1;
}
-/* (8 header words + 247 toc words) = 1020 bytes */
-/* 1024 bytes header and toc + 247 prop_infos @ 128 bytes = 32640 bytes */
-
-#define PA_COUNT_MAX 247
-#define PA_INFO_START 1024
-#define PA_SIZE 32768
-
static workspace pa_workspace;
-static prop_info *pa_info_array;
-
-extern prop_area *__system_property_area__;
static int init_property_area(void)
{
- prop_area *pa;
-
- if(pa_info_array)
+ if (property_area_inited)
return -1;
- if(init_workspace(&pa_workspace, PA_SIZE))
+ if(__system_property_area_init())
+ return -1;
+
+ if(init_workspace(&pa_workspace, 0))
return -1;
fcntl(pa_workspace.fd, F_SETFD, FD_CLOEXEC);
- pa_info_array = (void*) (((char*) pa_workspace.data) + PA_INFO_START);
-
- pa = pa_workspace.data;
- memset(pa, 0, PA_SIZE);
- pa->magic = PROP_AREA_MAGIC;
- pa->version = PROP_AREA_VERSION;
-
- /* plug into the lib property services */
- __system_property_area__ = pa;
property_area_inited = 1;
return 0;
}
-static void update_prop_info(prop_info *pi, const char *value, unsigned len)
-{
- pi->serial = pi->serial | 1;
- memcpy(pi->value, value, len + 1);
- pi->serial = (len << 24) | ((pi->serial + 1) & 0xffffff);
- __futex_wake(&pi->serial, INT32_MAX);
-}
-
static int check_mac_perms(const char *name, char *sctx)
{
if (is_selinux_enabled() <= 0)
@@ -292,19 +240,9 @@
return 0;
}
-const char* property_get(const char *name)
+int __property_get(const char *name, char *value)
{
- prop_info *pi;
-
- if(strlen(name) >= PROP_NAME_MAX) return 0;
-
- pi = (prop_info*) __system_property_find(name);
-
- if(pi != 0) {
- return pi->value;
- } else {
- return 0;
- }
+ return __system_property_get(name, value);
}
static void write_persistent_property(const char *name, const char *value)
@@ -331,8 +269,8 @@
int property_set(const char *name, const char *value)
{
- prop_area *pa;
prop_info *pi;
+ int ret;
size_t namelen = strlen(name);
size_t valuelen = strlen(value);
@@ -347,29 +285,13 @@
/* ro.* properties may NEVER be modified once set */
if(!strncmp(name, "ro.", 3)) return -1;
- pa = __system_property_area__;
- update_prop_info(pi, value, valuelen);
- pa->serial++;
- __futex_wake(&pa->serial, INT32_MAX);
+ __system_property_update(pi, value, valuelen);
} else {
- pa = __system_property_area__;
- if(pa->count == PA_COUNT_MAX) {
- ERROR("Failed to set '%s'='%s', property pool is exhausted at %d entries",
- name, value, PA_COUNT_MAX);
- return -1;
+ ret = __system_property_add(name, namelen, value, valuelen);
+ if (ret < 0) {
+ ERROR("Failed to set '%s'='%s'", name, value);
+ return ret;
}
-
- pi = pa_info_array + pa->count;
- pi->serial = (valuelen << 24);
- memcpy(pi->name, name, namelen + 1);
- memcpy(pi->value, value, valuelen + 1);
-
- pa->toc[pa->count] =
- (namelen << 24) | (((unsigned) pi) - ((unsigned) pa));
-
- pa->count++;
- pa->serial++;
- __futex_wake(&pa->serial, INT32_MAX);
}
/* If name starts with "net." treat as a DNS property. */
if (strncmp("net.", name, strlen("net.")) == 0) {
@@ -591,8 +513,11 @@
static void load_override_properties() {
#ifdef ALLOW_LOCAL_PROP_OVERRIDE
- const char *debuggable = property_get("ro.debuggable");
- if (debuggable && (strcmp(debuggable, "1") == 0)) {
+ char debuggable[PROP_VALUE_MAX];
+ int ret;
+
+ ret = property_get("ro.debuggable", debuggable);
+ if (ret && (strcmp(debuggable, "1") == 0)) {
load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE);
}
#endif /* ALLOW_LOCAL_PROP_OVERRIDE */
diff --git a/init/property_service.h b/init/property_service.h
index b9d1bf6..46cbd8f 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -18,6 +18,7 @@
#define _INIT_PROPERTY_H
#include <stdbool.h>
+#include <sys/system_properties.h>
extern void handle_property_set_fd(void);
extern void property_init(void);
@@ -25,9 +26,25 @@
extern void load_persist_props(void);
extern void start_property_service(void);
void get_property_workspace(int *fd, int *sz);
-extern const char* property_get(const char *name);
+extern int __property_get(const char *name, char *value);
extern int property_set(const char *name, const char *value);
extern int properties_inited();
int get_property_set_fd(void);
+extern void __property_get_size_error()
+ __attribute__((__error__("property_get called with too small buffer")));
+
+static inline
+__attribute__ ((always_inline))
+__attribute__ ((gnu_inline))
+__attribute__ ((artificial))
+int property_get(const char *name, char *value)
+{
+ size_t value_len = __builtin_object_size(value, 0);
+ if (value_len != PROP_VALUE_MAX)
+ __property_get_size_error();
+
+ return __property_get(name, value);
+}
+
#endif /* _INIT_PROPERTY_H */
diff --git a/init/signal_handler.c b/init/signal_handler.c
index abccb40..d31ad63 100644
--- a/init/signal_handler.c
+++ b/init/signal_handler.c
@@ -63,7 +63,7 @@
NOTICE("process '%s', pid %d exited\n", svc->name, pid);
- if (!(svc->flags & SVC_ONESHOT)) {
+ if (!(svc->flags & SVC_ONESHOT) || (svc->flags & SVC_RESTART)) {
kill(-pid, SIGKILL);
NOTICE("process '%s' killing any children in process group\n", svc->name);
}
@@ -78,8 +78,9 @@
svc->pid = 0;
svc->flags &= (~SVC_RUNNING);
- /* oneshot processes go into the disabled state on exit */
- if (svc->flags & SVC_ONESHOT) {
+ /* oneshot processes go into the disabled state on exit,
+ * except when manually restarted. */
+ if ((svc->flags & SVC_ONESHOT) && !(svc->flags & SVC_RESTART)) {
svc->flags |= SVC_DISABLED;
}
@@ -90,7 +91,7 @@
}
now = gettime();
- if (svc->flags & SVC_CRITICAL) {
+ if ((svc->flags & SVC_CRITICAL) && !(svc->flags & SVC_RESTART)) {
if (svc->time_crashed + CRITICAL_CRASH_WINDOW >= now) {
if (++svc->nr_crashed > CRITICAL_CRASH_THRESHOLD) {
ERROR("critical process '%s' exited %d times in %d minutes; "
@@ -105,6 +106,7 @@
}
}
+ svc->flags &= (~SVC_RESTART);
svc->flags |= SVC_RESTARTING;
/* Execute all onrestart commands for this service. */
diff --git a/libcorkscrew/Android.mk b/libcorkscrew/Android.mk
index 2786d8f..25512e2 100644
--- a/libcorkscrew/Android.mk
+++ b/libcorkscrew/Android.mk
@@ -59,23 +59,28 @@
# Build test.
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := test.c
-LOCAL_CFLAGS += -std=gnu99 -Werror -fno-inline-small-functions
+LOCAL_SRC_FILES := test.cpp
+LOCAL_CFLAGS += -Werror -fno-inline-small-functions
LOCAL_SHARED_LIBRARIES := libcorkscrew
LOCAL_MODULE := libcorkscrew_test
LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)
+# TODO: reenable darwin-x86
+# ifeq ($(HOST_ARCH),x86)
ifeq ($(HOST_OS)-$(HOST_ARCH),linux-x86)
# Build libcorkscrew.
include $(CLEAR_VARS)
LOCAL_SRC_FILES += $(generic_src_files) $(x86_src_files)
LOCAL_CFLAGS += -DCORKSCREW_HAVE_ARCH
-LOCAL_SHARED_LIBRARIES += libgccdemangle
LOCAL_STATIC_LIBRARIES += libcutils
-LOCAL_LDLIBS += -ldl -lrt
+LOCAL_LDLIBS += -ldl
+ifeq ($(HOST_OS),linux)
+ LOCAL_SHARED_LIBRARIES += libgccdemangle # TODO: is this even needed on Linux?
+ LOCAL_LDLIBS += -lrt
+endif
LOCAL_CFLAGS += -std=gnu99 -Werror
LOCAL_MODULE := libcorkscrew
LOCAL_MODULE_TAGS := optional
@@ -83,11 +88,11 @@
# Build test.
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := test.c
-LOCAL_CFLAGS += -std=gnu99 -Werror -fno-inline-small-functions
+LOCAL_SRC_FILES := test.cpp
+LOCAL_CFLAGS += -Werror
LOCAL_SHARED_LIBRARIES := libcorkscrew
LOCAL_MODULE := libcorkscrew_test
LOCAL_MODULE_TAGS := optional
include $(BUILD_HOST_EXECUTABLE)
-endif # linux-x86
+endif # HOST_ARCH == x86
diff --git a/libcorkscrew/arch-x86/backtrace-x86.c b/libcorkscrew/arch-x86/backtrace-x86.c
index 29159ed..e133ab6 100755
--- a/libcorkscrew/arch-x86/backtrace-x86.c
+++ b/libcorkscrew/arch-x86/backtrace-x86.c
@@ -75,13 +75,18 @@
#endif /* __BIONIC_HAVE_UCONTEXT_T */
-#else /* __BIONIC__ */
+#elif defined(__APPLE__)
+
+#define _XOPEN_SOURCE
+#include <ucontext.h>
+
+#else
// glibc has its own renaming of the Linux kernel's structures.
#define __USE_GNU // For REG_EBP, REG_ESP, and REG_EIP.
#include <ucontext.h>
-#endif /* __ BIONIC__ */
+#endif
/* Unwind state. */
typedef struct {
@@ -819,9 +824,15 @@
const ucontext_t* uc = (const ucontext_t*)sigcontext;
unwind_state_t state;
+#if defined(__APPLE__)
+ state.reg[DWARF_EBP] = uc->uc_mcontext->__ss.__ebp;
+ state.reg[DWARF_ESP] = uc->uc_mcontext->__ss.__esp;
+ state.reg[DWARF_EIP] = uc->uc_mcontext->__ss.__eip;
+#else
state.reg[DWARF_EBP] = uc->uc_mcontext.gregs[REG_EBP];
state.reg[DWARF_ESP] = uc->uc_mcontext.gregs[REG_ESP];
state.reg[DWARF_EIP] = uc->uc_mcontext.gregs[REG_EIP];
+#endif
memory_t memory;
init_memory(&memory, map_info_list);
@@ -831,6 +842,9 @@
ssize_t unwind_backtrace_ptrace_arch(pid_t tid, const ptrace_context_t* context,
backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth) {
+#if defined(__APPLE__)
+ return -1;
+#else
pt_regs_x86_t regs;
if (ptrace(PTRACE_GETREGS, tid, 0, ®s)) {
return -1;
@@ -845,4 +859,5 @@
init_memory_ptrace(&memory, tid);
return unwind_backtrace_common(&memory, context->map_info_list,
&state, backtrace, ignore_depth, max_depth);
+#endif
}
diff --git a/libcorkscrew/backtrace.c b/libcorkscrew/backtrace.c
index 03dbd53..b365e5b 100644
--- a/libcorkscrew/backtrace.c
+++ b/libcorkscrew/backtrace.c
@@ -33,7 +33,6 @@
#include <unwind.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
-#include <elf.h>
#define __USE_GNU // For dladdr(3) in glibc.
#include <dlfcn.h>
@@ -43,6 +42,15 @@
// Bionic implements and exports gettid but only implements tgkill.
extern int tgkill(int tgid, int tid, int sig);
+#elif defined(__APPLE__)
+
+#include <sys/syscall.h>
+
+// Mac OS >= 10.6 has a system call equivalent to Linux's gettid().
+static pid_t gettid() {
+ return syscall(SYS_thread_selfid);
+}
+
#else
// glibc doesn't implement or export either gettid or tgkill.
@@ -97,7 +105,7 @@
state.returned_frames = 0;
init_memory(&state.memory, milist);
- _Unwind_Reason_Code rc =_Unwind_Backtrace(unwind_backtrace_callback, &state);
+ _Unwind_Reason_Code rc = _Unwind_Backtrace(unwind_backtrace_callback, &state);
release_my_map_info_list(milist);
@@ -146,7 +154,9 @@
ALOGV("Unwinding thread %d from thread %d.", tid, gettid());
-#ifdef CORKSCREW_HAVE_ARCH
+ // TODO: there's no tgkill(2) on Mac OS, so we'd either need the
+ // mach_port_t or the pthread_t rather than the tid.
+#if defined(CORKSCREW_HAVE_ARCH) && !defined(__APPLE__)
struct sigaction act;
struct sigaction oact;
memset(&act, 0, sizeof(act));
@@ -305,20 +315,20 @@
const backtrace_symbol_t* symbol, char* buffer, size_t bufferSize) {
const char* mapName = symbol->map_name ? symbol->map_name : "<unknown>";
const char* symbolName = symbol->demangled_name ? symbol->demangled_name : symbol->symbol_name;
- size_t fieldWidth = (bufferSize - 80) / 2;
+ int fieldWidth = (bufferSize - 80) / 2;
if (symbolName) {
uint32_t pc_offset = symbol->relative_pc - symbol->relative_symbol_addr;
if (pc_offset) {
- snprintf(buffer, bufferSize, "#%02d pc %08x %.*s (%.*s+%u)",
- frameNumber, symbol->relative_pc, fieldWidth, mapName,
+ snprintf(buffer, bufferSize, "#%02u pc %p %.*s (%.*s+%u)",
+ frameNumber, (void*) symbol->relative_pc, fieldWidth, mapName,
fieldWidth, symbolName, pc_offset);
} else {
- snprintf(buffer, bufferSize, "#%02d pc %08x %.*s (%.*s)",
- frameNumber, symbol->relative_pc, fieldWidth, mapName,
+ snprintf(buffer, bufferSize, "#%02u pc %p %.*s (%.*s)",
+ frameNumber, (void*) symbol->relative_pc, fieldWidth, mapName,
fieldWidth, symbolName);
}
} else {
- snprintf(buffer, bufferSize, "#%02d pc %08x %.*s",
- frameNumber, symbol->relative_pc, fieldWidth, mapName);
+ snprintf(buffer, bufferSize, "#%02u pc %p %.*s",
+ frameNumber, (void*) symbol->relative_pc, fieldWidth, mapName);
}
}
diff --git a/libcorkscrew/demangle.c b/libcorkscrew/demangle.c
index 54247cb..30ab1b0 100644
--- a/libcorkscrew/demangle.c
+++ b/libcorkscrew/demangle.c
@@ -25,6 +25,12 @@
int *status);
char* demangle_symbol_name(const char* name) {
+#if defined(__APPLE__)
+ // Mac OS' __cxa_demangle demangles "f" as "float"; last tested on 10.7.
+ if (name != NULL && name[0] != '_') {
+ return NULL;
+ }
+#endif
// __cxa_demangle handles NULL by returning NULL
return __cxa_demangle(name, 0, 0, 0);
}
diff --git a/libcorkscrew/map_info.c b/libcorkscrew/map_info.c
index 6a27664..93dffbf 100644
--- a/libcorkscrew/map_info.c
+++ b/libcorkscrew/map_info.c
@@ -29,6 +29,67 @@
#include <cutils/log.h>
#include <sys/time.h>
+#if defined(__APPLE__)
+
+// Mac OS vmmap(1) output:
+// __TEXT 0009f000-000a1000 [ 8K 8K] r-x/rwx SM=COW /Volumes/android/dalvik-dev/out/host/darwin-x86/bin/libcorkscrew_test\n
+// 012345678901234567890123456789012345678901234567890123456789
+// 0 1 2 3 4 5
+static map_info_t* parse_vmmap_line(const char* line) {
+ unsigned long int start;
+ unsigned long int end;
+ char permissions[4];
+ int name_pos;
+ if (sscanf(line, "%*21c %lx-%lx [%*13c] %3c/%*3c SM=%*3c %n",
+ &start, &end, permissions, &name_pos) != 3) {
+ return NULL;
+ }
+
+ const char* name = line + name_pos;
+ size_t name_len = strlen(name);
+
+ map_info_t* mi = calloc(1, sizeof(map_info_t) + name_len);
+ if (mi != NULL) {
+ mi->start = start;
+ mi->end = end;
+ mi->is_readable = permissions[0] == 'r';
+ mi->is_writable = permissions[1] == 'w';
+ mi->is_executable = permissions[2] == 'x';
+ mi->data = NULL;
+ memcpy(mi->name, name, name_len);
+ mi->name[name_len - 1] = '\0';
+ ALOGV("Parsed map: start=0x%08x, end=0x%08x, "
+ "is_readable=%d, is_writable=%d is_executable=%d, name=%s",
+ mi->start, mi->end,
+ mi->is_readable, mi->is_writable, mi->is_executable, mi->name);
+ }
+ return mi;
+}
+
+map_info_t* load_map_info_list(pid_t pid) {
+ char cmd[1024];
+ snprintf(cmd, sizeof(cmd), "vmmap -w -resident -submap -allSplitLibs -interleaved %d", pid);
+ FILE* fp = popen(cmd, "r");
+ if (fp == NULL) {
+ return NULL;
+ }
+
+ char line[1024];
+ map_info_t* milist = NULL;
+ while (fgets(line, sizeof(line), fp) != NULL) {
+ map_info_t* mi = parse_vmmap_line(line);
+ if (mi != NULL) {
+ mi->next = milist;
+ milist = mi;
+ }
+ }
+ pclose(fp);
+ return milist;
+}
+
+#else
+
+// Linux /proc/<pid>/maps lines:
// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so\n
// 012345678901234567890123456789012345678901234567890123456789
// 0 1 2 3 4 5
@@ -63,9 +124,9 @@
memcpy(mi->name, name, name_len);
mi->name[name_len] = '\0';
ALOGV("Parsed map: start=0x%08x, end=0x%08x, "
- "is_readable=%d, is_writable=%d, is_executable=%d, name=%s",
- mi->start, mi->end,
- mi->is_readable, mi->is_writable, mi->is_executable, mi->name);
+ "is_readable=%d, is_writable=%d, is_executable=%d, name=%s",
+ mi->start, mi->end,
+ mi->is_readable, mi->is_writable, mi->is_executable, mi->name);
}
return mi;
}
@@ -91,6 +152,8 @@
return milist;
}
+#endif
+
void free_map_info_list(map_info_t* milist) {
while (milist) {
map_info_t* next = milist->next;
@@ -132,11 +195,17 @@
int64_t timestamp;
} my_map_info_data_t;
-static int64_t now() {
+static int64_t now_ns() {
+#if defined(HAVE_POSIX_CLOCKS)
struct timespec t;
t.tv_sec = t.tv_nsec = 0;
clock_gettime(CLOCK_MONOTONIC, &t);
return t.tv_sec * 1000000000LL + t.tv_nsec;
+#else
+ struct timeval t;
+ gettimeofday(&t, NULL);
+ return t.tv_sec * 1000000000LL + t.tv_usec * 1000LL;
+#endif
}
static void dec_ref(map_info_t* milist, my_map_info_data_t* data) {
@@ -150,8 +219,8 @@
map_info_t* acquire_my_map_info_list() {
pthread_mutex_lock(&g_my_map_info_list_mutex);
- int64_t time = now();
- if (g_my_map_info_list) {
+ int64_t time = now_ns();
+ if (g_my_map_info_list != NULL) {
my_map_info_data_t* data = (my_map_info_data_t*)g_my_map_info_list->data;
int64_t age = time - data->timestamp;
if (age >= MAX_CACHE_AGE) {
@@ -163,10 +232,10 @@
}
}
- if (!g_my_map_info_list) {
+ if (g_my_map_info_list == NULL) {
my_map_info_data_t* data = (my_map_info_data_t*)malloc(sizeof(my_map_info_data_t));
g_my_map_info_list = load_map_info_list(getpid());
- if (g_my_map_info_list) {
+ if (g_my_map_info_list != NULL) {
ALOGV("Loaded my_map_info_list %p.", g_my_map_info_list);
g_my_map_info_list->data = data;
data->refs = 1;
@@ -196,3 +265,15 @@
pthread_mutex_unlock(&g_my_map_info_list_mutex);
}
}
+
+void flush_my_map_info_list() {
+ pthread_mutex_lock(&g_my_map_info_list_mutex);
+
+ if (g_my_map_info_list != NULL) {
+ my_map_info_data_t* data = (my_map_info_data_t*) g_my_map_info_list->data;
+ dec_ref(g_my_map_info_list, data);
+ g_my_map_info_list = NULL;
+ }
+
+ pthread_mutex_unlock(&g_my_map_info_list_mutex);
+}
diff --git a/libcorkscrew/ptrace.c b/libcorkscrew/ptrace.c
index 776ef69..be58f7f 100644
--- a/libcorkscrew/ptrace.c
+++ b/libcorkscrew/ptrace.c
@@ -46,21 +46,25 @@
}
bool try_get_word(const memory_t* memory, uintptr_t ptr, uint32_t* out_value) {
- ALOGV("try_get_word: reading word at 0x%08x", ptr);
+ ALOGV("try_get_word: reading word at %p", (void*) ptr);
if (ptr & 3) {
- ALOGV("try_get_word: invalid pointer 0x%08x", ptr);
+ ALOGV("try_get_word: invalid pointer %p", (void*) ptr);
*out_value = 0xffffffffL;
return false;
}
if (memory->tid < 0) {
if (!is_readable_map(memory->map_info_list, ptr)) {
- ALOGV("try_get_word: pointer 0x%08x not in a readable map", ptr);
+ ALOGV("try_get_word: pointer %p not in a readable map", (void*) ptr);
*out_value = 0xffffffffL;
return false;
}
*out_value = *(uint32_t*)ptr;
return true;
} else {
+#if defined(__APPLE__)
+ ALOGV("no ptrace on Mac OS");
+ return false;
+#else
// ptrace() returns -1 and sets errno when the operation fails.
// To disambiguate -1 from a valid result, we clear errno beforehand.
errno = 0;
@@ -71,6 +75,7 @@
return false;
}
return true;
+#endif
}
}
diff --git a/libcorkscrew/symbol_table.c b/libcorkscrew/symbol_table.c
index 29e4a79..982ccc8 100644
--- a/libcorkscrew/symbol_table.c
+++ b/libcorkscrew/symbol_table.c
@@ -21,13 +21,17 @@
#include <stdbool.h>
#include <stdlib.h>
-#include <elf.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <cutils/log.h>
+#if defined(__APPLE__)
+#else
+
+#include <elf.h>
+
static bool is_elf(Elf32_Ehdr* e) {
return (e->e_ident[EI_MAG0] == ELFMAG0 &&
e->e_ident[EI_MAG1] == ELFMAG1 &&
@@ -35,6 +39,8 @@
e->e_ident[EI_MAG3] == ELFMAG3);
}
+#endif
+
// Compare function for qsort
static int qcompar(const void *a, const void *b) {
const symbol_t* asym = (const symbol_t*)a;
@@ -55,6 +61,7 @@
symbol_table_t* load_symbol_table(const char *filename) {
symbol_table_t* table = NULL;
+#if !defined(__APPLE__)
ALOGV("Loading symbol table from '%s'.", filename);
int fd = open(filename, O_RDONLY);
@@ -197,6 +204,7 @@
out_close:
close(fd);
+#endif
out:
return table;
diff --git a/libcorkscrew/test.c b/libcorkscrew/test.cpp
similarity index 77%
rename from libcorkscrew/test.c
rename to libcorkscrew/test.cpp
index af34c03..22dfa7d 100644
--- a/libcorkscrew/test.c
+++ b/libcorkscrew/test.cpp
@@ -3,11 +3,14 @@
#include <stdio.h>
#include <stdlib.h>
-void do_backtrace() {
+int do_backtrace(float /* just to test demangling */) {
const size_t MAX_DEPTH = 32;
backtrace_frame_t* frames = (backtrace_frame_t*) malloc(sizeof(backtrace_frame_t) * MAX_DEPTH);
ssize_t frame_count = unwind_backtrace(frames, 0, MAX_DEPTH);
fprintf(stderr, "frame_count=%d\n", (int) frame_count);
+ if (frame_count <= 0) {
+ return frame_count;
+ }
backtrace_symbol_t* backtrace_symbols = (backtrace_symbol_t*) malloc(sizeof(backtrace_symbol_t) * frame_count);
get_backtrace_symbols(frames, frame_count, backtrace_symbols);
@@ -31,7 +34,7 @@
symbol = find_symbol(symbols, frames[i].absolute_pc);
}
if (symbol != NULL) {
- uintptr_t offset = frames[i].absolute_pc - symbol->start;
+ int offset = frames[i].absolute_pc - symbol->start;
fprintf(stderr, " %s (%s%+d)\n", line, symbol->name, offset);
} else {
fprintf(stderr, " %s (\?\?\?)\n", line);
@@ -43,22 +46,31 @@
free_backtrace_symbols(backtrace_symbols, frame_count);
free(backtrace_symbols);
free(frames);
+ return frame_count;
}
-__attribute__ ((noinline)) void g() {
- fprintf(stderr, "g()\n");
- do_backtrace();
-}
+struct C {
+ int g(int i);
+};
-__attribute__ ((noinline)) int f(int i) {
- fprintf(stderr, "f(%i)\n", i);
+__attribute__ ((noinline)) int C::g(int i) {
if (i == 0) {
- g();
- return 0;
+ return do_backtrace(0.1);
}
- return f(i - 1);
+ return g(i - 1);
+}
+
+extern "C" __attribute__ ((noinline)) int f() {
+ C c;
+ return c.g(5);
}
int main() {
- return f(5);
+ flush_my_map_info_list();
+ f();
+
+ flush_my_map_info_list();
+ f();
+
+ return 0;
}
diff --git a/libcutils/properties.c b/libcutils/properties.c
index f732ec0..28d8b2f 100644
--- a/libcutils/properties.c
+++ b/libcutils/properties.c
@@ -52,19 +52,28 @@
return len;
}
-int property_list(void (*propfn)(const char *key, const char *value, void *cookie),
- void *cookie)
+struct property_list_callback_data
+{
+ void (*propfn)(const char *key, const char *value, void *cookie);
+ void *cookie;
+};
+
+static void property_list_callback(const prop_info *pi, void *cookie)
{
char name[PROP_NAME_MAX];
char value[PROP_VALUE_MAX];
- const prop_info *pi;
- unsigned n;
-
- for(n = 0; (pi = __system_property_find_nth(n)); n++) {
- __system_property_read(pi, name, value);
- propfn(name, value, cookie);
- }
- return 0;
+ struct property_list_callback_data *data = cookie;
+
+ __system_property_read(pi, name, value);
+ data->propfn(name, value, data->cookie);
+}
+
+int property_list(
+ void (*propfn)(const char *key, const char *value, void *cookie),
+ void *cookie)
+{
+ struct property_list_callback_data data = { propfn, cookie };
+ return __system_property_foreach(property_list_callback, &data);
}
#elif defined(HAVE_SYSTEM_PROPERTY_SERVER)
diff --git a/libnetutils/dhcp_utils.c b/libnetutils/dhcp_utils.c
index b4caaf9..b940453 100644
--- a/libnetutils/dhcp_utils.c
+++ b/libnetutils/dhcp_utils.c
@@ -367,9 +367,8 @@
return -1;
}
if (strcmp(prop_value, "ok") == 0) {
- fill_ip_info(interface, ipaddr, gateway, prefixLength,
+ return fill_ip_info(interface, ipaddr, gateway, prefixLength,
dns1, dns2, server, lease, vendorInfo);
- return 0;
} else {
snprintf(errmsg, sizeof(errmsg), "DHCP Renew result was %s", prop_value);
return -1;
diff --git a/libsysutils/src/SocketClient.cpp b/libsysutils/src/SocketClient.cpp
index 3d4984d..ae0e077 100644
--- a/libsysutils/src/SocketClient.cpp
+++ b/libsysutils/src/SocketClient.cpp
@@ -112,6 +112,12 @@
char *result = (char *)malloc(len * 2 + 3);
char *current = result;
const char *end = arg + len;
+ char *oldresult;
+
+ if(result == NULL) {
+ SLOGW("malloc error (%s)", strerror(errno));
+ return NULL;
+ }
*(current++) = '"';
while (arg < end) {
@@ -125,8 +131,9 @@
}
*(current++) = '"';
*(current++) = '\0';
+ oldresult = result; // save pointer in case realloc fails
result = (char *)realloc(result, current-result);
- return result;
+ return result ? result : oldresult;
}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 4b26f39..5206cd1 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -322,12 +322,6 @@
chown system system /sys/class/leds/red/device/grpfreq
chown system system /sys/class/leds/red/device/grppwm
chown system system /sys/class/leds/red/device/blink
- chown system system /sys/class/leds/red/brightness
- chown system system /sys/class/leds/green/brightness
- chown system system /sys/class/leds/blue/brightness
- chown system system /sys/class/leds/red/device/grpfreq
- chown system system /sys/class/leds/red/device/grppwm
- chown system system /sys/class/leds/red/device/blink
chown system system /sys/class/timed_output/vibrator/enable
chown system system /sys/module/sco/parameters/disable_esco
chown system system /sys/kernel/ipv4/tcp_wmem_min
diff --git a/toolbox/netstat.c b/toolbox/netstat.c
index 5768599..05dc640 100644
--- a/toolbox/netstat.c
+++ b/toolbox/netstat.c
@@ -108,7 +108,7 @@
addr2str(AF_INET, &raddr, rport, rip);
printf("%4s %6d %6d %-22s %-22s %s\n",
- label, txq, rxq, lip, rip,
+ label, rxq, txq, lip, rip,
state2str(state));
}
}
@@ -136,7 +136,7 @@
addr2str(AF_INET6, &raddr6, rport, rip);
printf("%4s %6d %6d %-22s %-22s %s\n",
- label, txq, rxq, lip, rip,
+ label, rxq, txq, lip, rip,
state2str(state));
}
}
diff --git a/toolbox/watchprops.c b/toolbox/watchprops.c
index d311992..bf82882 100644
--- a/toolbox/watchprops.c
+++ b/toolbox/watchprops.c
@@ -1,35 +1,30 @@
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
+#include <errno.h>
#include <cutils/properties.h>
+#include <cutils/hashmap.h>
#include <sys/atomics.h>
#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
#include <sys/_system_properties.h>
-
-extern prop_area *__system_property_area__;
-
-typedef struct pwatch pwatch;
-
-struct pwatch
+static int str_hash(void *key)
{
- const prop_info *pi;
- unsigned serial;
-};
+ return hashmapHash(key, strlen(key));
+}
-static pwatch watchlist[1024];
-
-static void announce(const prop_info *pi)
+static bool str_equals(void *keyA, void *keyB)
{
- char name[PROP_NAME_MAX];
- char value[PROP_VALUE_MAX];
+ return strcmp(keyA, keyB) == 0;
+}
+
+static void announce(char *name, char *value)
+{
char *x;
- __system_property_read(pi, name, value);
-
for(x = value; *x; x++) {
if((*x < 32) || (*x > 127)) *x = '.';
}
@@ -37,40 +32,64 @@
fprintf(stderr,"%10d %s = '%s'\n", (int) time(0), name, value);
}
+static void add_to_watchlist(Hashmap *watchlist, const char *name,
+ const prop_info *pi)
+{
+ char *key = strdup(name);
+ unsigned *value = malloc(sizeof(unsigned));
+ if (!key || !value)
+ exit(1);
+
+ *value = __system_property_serial(pi);
+ hashmapPut(watchlist, key, value);
+}
+
+static void populate_watchlist(const prop_info *pi, void *cookie)
+{
+ Hashmap *watchlist = cookie;
+ char name[PROP_NAME_MAX];
+ char value_unused[PROP_VALUE_MAX];
+
+ __system_property_read(pi, name, value_unused);
+ add_to_watchlist(watchlist, name, pi);
+}
+
+static void update_watchlist(const prop_info *pi, void *cookie)
+{
+ Hashmap *watchlist = cookie;
+ char name[PROP_NAME_MAX];
+ char value[PROP_VALUE_MAX];
+ unsigned *serial;
+
+ __system_property_read(pi, name, value);
+ serial = hashmapGet(watchlist, name);
+ if (!serial) {
+ add_to_watchlist(watchlist, name, pi);
+ announce(name, value);
+ } else {
+ unsigned tmp = __system_property_serial(pi);
+ if (*serial != tmp) {
+ *serial = tmp;
+ announce(name, value);
+ }
+ }
+}
+
int watchprops_main(int argc, char *argv[])
{
- prop_area *pa = __system_property_area__;
- unsigned serial = pa->serial;
- unsigned count = pa->count;
+ unsigned serial = 0;
+ unsigned count = 0;
unsigned n;
- if(count >= 1024) exit(1);
+ Hashmap *watchlist = hashmapCreate(1024, str_hash, str_equals);
+ if (!watchlist)
+ exit(1);
- for(n = 0; n < count; n++) {
- watchlist[n].pi = __system_property_find_nth(n);
- watchlist[n].serial = watchlist[n].pi->serial;
- }
+ __system_property_foreach(populate_watchlist, watchlist);
for(;;) {
- do {
- __futex_wait(&pa->serial, serial, 0);
- } while(pa->serial == serial);
-
- while(count < pa->count){
- watchlist[count].pi = __system_property_find_nth(count);
- watchlist[count].serial = watchlist[n].pi->serial;
- announce(watchlist[count].pi);
- count++;
- if(count == 1024) exit(1);
- }
-
- for(n = 0; n < count; n++){
- unsigned tmp = watchlist[n].pi->serial;
- if(watchlist[n].serial != tmp) {
- announce(watchlist[n].pi);
- watchlist[n].serial = tmp;
- }
- }
+ serial = __system_property_wait_any(serial);
+ __system_property_foreach(update_watchlist, watchlist);
}
return 0;
}