diff options
| -rw-r--r-- | adb/file_sync_client.c | 6 | ||||
| -rw-r--r-- | adb/usb_vendors.c | 15 | ||||
| -rw-r--r-- | debuggerd/crasher.c | 59 | ||||
| -rw-r--r-- | debuggerd/debuggerd.c | 4 | ||||
| -rw-r--r-- | include/cutils/properties.h | 3 | ||||
| -rw-r--r-- | include/cutils/trace.h | 2 | ||||
| -rw-r--r-- | init/builtins.c | 3 | ||||
| -rw-r--r-- | init/devices.c | 1 | ||||
| -rw-r--r--[-rwxr-xr-x] | init/init.c | 103 | ||||
| -rw-r--r-- | init/init.h | 2 | ||||
| -rw-r--r-- | init/init_parser.c | 16 | ||||
| -rw-r--r-- | init/keychords.c | 7 | ||||
| -rw-r--r-- | init/property_service.c | 109 | ||||
| -rw-r--r-- | init/property_service.h | 19 | ||||
| -rw-r--r-- | init/signal_handler.c | 10 | ||||
| -rw-r--r-- | libcutils/properties.c | 29 | ||||
| -rw-r--r-- | toolbox/watchprops.c | 103 |
17 files changed, 257 insertions, 234 deletions
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 @@ static void END() 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 @@ int builtInVendorIds[] = { 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 @@ extern const char* __progname; 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 @@ static void debuggerd_connect() 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 @@ int smash_stack(int i) { 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 @@ void *noisy(void *x) return 0; } -int ctest() +static int ctest() { pthread_t thr; pthread_attr_t attr; @@ -90,7 +95,7 @@ static void* thread_callback(void* raw_arg) 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 @@ int do_action_on_thread(const char* arg) 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)) static int crash2(int a) { + a = crash3(a) + 2; + return a*3; } -__attribute__((noinline)) int crash2(int a) { - a = crash3(a) + 2; - return a*3; +__attribute__((noinline)) static int crash(int a) { + a = crash2(a) + 1; + return a*2; } -__attribute__((noinline)) int crash(int a) { - a = crash2(a) + 1; - return a*2; +static void abuse_heap() { + char buf[16]; + free((void*) buf); // GCC is smart enough to warn about this, but we're doing it deliberately. } -int do_action(const char* arg) +static int do_action(const char* arg) { fprintf(stderr,"crasher: init pid=%d tid=%d\n", getpid(), gettid()); @@ -134,12 +144,16 @@ int do_action(const char* arg) 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 @@ int main(int argc, char **argv) } else { crash1(); } - - return 0; -} -void maybeabort() -{ - if(time(0) != 42) abort(); + return 0; } diff --git a/debuggerd/debuggerd.c b/debuggerd/debuggerd.c index da2e9b0..0028bda 100644 --- a/debuggerd/debuggerd.c +++ b/debuggerd/debuggerd.c @@ -435,11 +435,13 @@ static int do_server() { signal(SIGBUS, SIG_DFL); signal(SIGFPE, SIG_DFL); signal(SIGSEGV, SIG_DFL); - signal(SIGPIPE, SIG_DFL); #ifdef SIGSTKFLT signal(SIGSTKFLT, SIG_DFL); #endif + // Ignore failed writes to closed sockets + signal(SIGPIPE, SIG_IGN); + logsocket = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_DGRAM); if(logsocket < 0) { diff --git a/include/cutils/properties.h b/include/cutils/properties.h index 228b73e..2c70165 100644 --- a/include/cutils/properties.h +++ b/include/cutils/properties.h @@ -54,8 +54,7 @@ int property_list(void (*propfn)(const char *key, const char *value, void *cooki extern int __property_get_real(const char *, char *, const char *) __asm__(__USER_LABEL_PREFIX__ "property_get"); -extern void __property_get_too_small_error() - __attribute__((__error__("property_get() called with too small of a buffer"))); +__errordecl(__property_get_too_small_error, "property_get() called with too small of a buffer"); __BIONIC_FORTIFY_INLINE int property_get(const char *key, char *value, const char *default_value) { diff --git a/include/cutils/trace.h b/include/cutils/trace.h index fbb6077..a0dd1e0 100644 --- a/include/cutils/trace.h +++ b/include/cutils/trace.h @@ -263,7 +263,7 @@ static inline void atrace_int(uint64_t tag, const char* name, int32_t value) #define ATRACE_INIT() #define ATRACE_GET_ENABLED_TAGS() -#define ATRACE_ENABLED() +#define ATRACE_ENABLED() 0 #define ATRACE_BEGIN(name) #define ATRACE_END() #define ATRACE_ASYNC_BEGIN(name, cookie) diff --git a/init/builtins.c b/init/builtins.c index 9ae9ba3..6e37d08 100644 --- a/init/builtins.c +++ b/init/builtins.c @@ -594,8 +594,7 @@ int do_restart(int nargs, char **args) 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/devices.c b/init/devices.c index 69f5fc8..de27a7a 100644 --- a/init/devices.c +++ b/init/devices.c @@ -785,6 +785,7 @@ loading_close_out: file_free_out: free(file1); free(file2); + free(file3); data_free_out: free(data); loading_free_out: diff --git a/init/init.c b/init/init.c index f8b21e6..4196620 100755..100644 --- a/init/init.c +++ b/init/init.c @@ -39,6 +39,7 @@ #include <libgen.h> #include <cutils/list.h> +#include <cutils/android_reboot.h> #include <cutils/sockets.h> #include <cutils/iosched_policy.h> #include <private/android_filesystem_config.h> @@ -73,8 +74,6 @@ static char hardware[32]; static unsigned revision = 0; static char qemu[32]; -static int selinux_enabled = 1; - static struct action *cur_action = NULL; static struct command *cur_command = NULL; static struct listnode *command_queue = NULL; @@ -164,7 +163,7 @@ void service_start(struct service *svc, const char *dynamic_args) * 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 +358,14 @@ void service_start(struct service *svc, const char *dynamic_args) 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 +397,17 @@ void service_stop(struct service *svc) 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 +476,17 @@ static void msg_stop(const char *name) } } +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 +494,7 @@ void handle_control_message(const char *msg, const char *arg) } 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); } @@ -594,10 +613,6 @@ static void import_kernel_nv(char *name, int for_emulator) *value++ = 0; if (name_len == 0) return; - if (!strcmp(name,"selinux")) { - selinux_enabled = atoi(value); - } - if (for_emulator) { /* in the emulator, export any kernel option with the * ro.kernel. prefix */ @@ -625,7 +640,7 @@ static void import_kernel_nv(char *name, int for_emulator) 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 +654,26 @@ static void export_kernel_boot_props(void) }; 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); @@ -776,10 +795,6 @@ void selinux_init_all_handles(void) int selinux_reload_policy(void) { - if (!selinux_enabled) { - return -1; - } - INFO("SELinux: Attempting to reload policy files\n"); if (selinux_android_reload_policy() == -1) { @@ -802,6 +817,24 @@ int audit_callback(void *data, security_class_t cls, char *buf, size_t len) return 0; } +static void selinux_initialize(void) +{ + if (access("/sys/fs/selinux", F_OK) != 0) { + // SELinux is not compiled into this kernel. Fail gracefully. + return; + } + + INFO("loading selinux policy\n"); + if (selinux_android_load_policy() < 0) { + ERROR("SELinux: Failed to load policy; rebooting into recovery mode\n"); + android_reboot(ANDROID_RB_RESTART2, 0, "recovery"); + while (1) { pause(); } // never reached + } + + selinux_init_all_handles(); + security_setenforce(1); +} + int main(int argc, char **argv) { int fd_count = 0; @@ -862,17 +895,7 @@ int main(int argc, char **argv) cb.func_audit = audit_callback; selinux_set_callback(SELINUX_CB_AUDIT, cb); - INFO("loading selinux policy\n"); - if (selinux_enabled) { - if (selinux_android_load_policy() < 0) { - selinux_enabled = 0; - INFO("SELinux: Disabled due to failed policy load\n"); - } else { - selinux_init_all_handles(); - } - } else { - INFO("SELinux: Disabled by command line option\n"); - } + selinux_initialize(); /* These directories were necessarily created before initial policy load * and therefore need their security context restored to the proper value. * This must happen before /dev is populated by ueventd. 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 @@ struct svcenvinfo { #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 service_for_each_flags(unsigned matchflags, 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 a1d2423..28bf30c 100644 --- a/init/init_parser.c +++ b/init/init_parser.c @@ -208,8 +208,9 @@ int expand_props(char *dst, const char *src, int dst_size) 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) { @@ -267,14 +268,14 @@ int expand_props(char *dst, const char *src, int dst_size) 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; @@ -545,7 +546,7 @@ void queue_all_property_triggers() 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); @@ -554,9 +555,8 @@ void queue_all_property_triggers() 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); } } diff --git a/init/keychords.c b/init/keychords.c index 061d157..4a64042 100644 --- a/init/keychords.c +++ b/init/keychords.c @@ -95,20 +95,19 @@ void keychord_init() void handle_keychord() { struct service *svc; - const char* debuggable; - const char* adb_enabled; + char adb_enabled[PROP_VALUE_MAX]; int ret; __u16 id; // Only handle keychords if adb is enabled. - adb_enabled = property_get("init.svc.adbd"); + 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 ((adb_enabled && !strcmp(adb_enabled, "running"))) { + if (!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 33ec146..9afc756 100644 --- a/init/property_service.c +++ b/init/property_service.c @@ -112,7 +112,6 @@ struct { }; typedef struct { - void *data; size_t size; int fd; } workspace; @@ -120,83 +119,34 @@ typedef struct { 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(PROP_FILENAME, O_RDWR | O_CREAT | O_NOFOLLOW, 0644); - 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(PROP_FILENAME, O_RDONLY | O_NOFOLLOW); + int fd = open(PROP_FILENAME, O_RDONLY | O_NOFOLLOW); if (fd < 0) return -1; - 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 (property_area_inited) + return -1; - if(pa_info_array) + if(__system_property_area_init()) return -1; - if(init_workspace(&pa_workspace, PA_SIZE)) + 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) @@ -299,19 +249,9 @@ static int check_perms(const char *name, unsigned int uid, unsigned int gid, cha 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) @@ -338,8 +278,8 @@ static void write_persistent_property(const char *name, const char *value) 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); @@ -354,29 +294,13 @@ int property_set(const char *name, const char *value) /* 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) { @@ -598,8 +522,11 @@ int properties_inited(void) 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 property_load_boot_defaults(void); 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 @@ static int wait_for_one_process(int block) 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 @@ static int wait_for_one_process(int block) 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 @@ static int wait_for_one_process(int block) } 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 @@ static int wait_for_one_process(int block) } } + svc->flags &= (~SVC_RESTART); svc->flags |= SVC_RESTARTING; /* Execute all onrestart commands for this service. */ 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 @@ int property_get(const char *key, char *value, const char *default_value) 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/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 bool str_equals(void *keyA, void *keyB) +{ + return strcmp(keyA, keyB) == 0; +} -static void announce(const prop_info *pi) +static void announce(char *name, char *value) { - char name[PROP_NAME_MAX]; - char value[PROP_VALUE_MAX]; char *x; - __system_property_read(pi, name, value); - for(x = value; *x; x++) { if((*x < 32) || (*x > 127)) *x = '.'; } @@ -37,40 +32,64 @@ static void announce(const prop_info *pi) 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; } |
