diff options
53 files changed, 1864 insertions, 701 deletions
diff --git a/adb/Android.mk b/adb/Android.mk index 32dd95a..a803978 100644 --- a/adb/Android.mk +++ b/adb/Android.mk @@ -17,6 +17,7 @@ ifeq ($(HOST_OS),linux) USB_SRCS := usb_linux.c EXTRA_SRCS := get_my_path_linux.c LOCAL_LDLIBS += -lrt -ldl -lpthread + LOCAL_CFLAGS += -DWORKAROUND_BUG6558362 endif ifeq ($(HOST_OS),darwin) @@ -77,6 +78,7 @@ endif LOCAL_CFLAGS += -O2 -g -DADB_HOST=1 -Wall -Wno-unused-parameter LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE LOCAL_MODULE := adb +LOCAL_MODULE_TAGS := debug LOCAL_STATIC_LIBRARIES := libzipfile libunz libcrypto_static $(EXTRA_STATIC_LIBS) ifeq ($(USE_SYSDEPS_WIN32),) @@ -326,7 +326,7 @@ static void send_connect(atransport *t) send_packet(cp, t); } -static void send_auth_request(atransport *t) +void send_auth_request(atransport *t) { D("Calling send_auth_request\n"); apacket *p; @@ -403,6 +403,8 @@ static char *connection_state_name(atransport *t) return "device"; case CS_OFFLINE: return "offline"; + case CS_UNAUTHORIZED: + return "unauthorized"; default: return "unknown"; } @@ -532,6 +534,7 @@ void handle_packet(apacket *p, atransport *t) case A_AUTH: if (p->msg.arg0 == ADB_AUTH_TOKEN) { + t->connection_state = CS_UNAUTHORIZED; t->key = adb_auth_nextkey(t->key); if (t->key) { send_auth_response(p->data, p->msg.data_length, t); @@ -984,6 +987,33 @@ void start_device_log(void) #endif #if ADB_HOST + +#ifdef WORKAROUND_BUG6558362 +#include <sched.h> +#define AFFINITY_ENVVAR "ADB_CPU_AFFINITY_BUG6558362" +void adb_set_affinity(void) +{ + cpu_set_t cpu_set; + const char* cpunum_str = getenv(AFFINITY_ENVVAR); + char* strtol_res; + int cpu_num; + + if (!cpunum_str || !*cpunum_str) + return; + cpu_num = strtol(cpunum_str, &strtol_res, 0); + if (*strtol_res != '\0') + fatal("bad number (%s) in env var %s. Expecting 0..n.\n", cpunum_str, AFFINITY_ENVVAR); + + sched_getaffinity(0, sizeof(cpu_set), &cpu_set); + D("orig cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]); + CPU_ZERO(&cpu_set); + CPU_SET(cpu_num, &cpu_set); + sched_setaffinity(0, sizeof(cpu_set), &cpu_set); + sched_getaffinity(0, sizeof(cpu_set), &cpu_set); + D("new cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]); +} +#endif + int launch_server(int server_port) { #ifdef HAVE_WIN32_PROC @@ -1154,6 +1184,32 @@ void build_local_name(char* target_str, size_t target_size, int server_port) } #if !ADB_HOST + +static void drop_capabilities_bounding_set_if_needed() { +#ifdef ALLOW_ADBD_ROOT + char value[PROPERTY_VALUE_MAX]; + property_get("ro.debuggable", value, ""); + if (strcmp(value, "1") == 0) { + return; + } +#endif + int i; + for (i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) { + if ((i == CAP_SETUID) || (i == CAP_SETGID)) { + // CAP_SETUID CAP_SETGID needed by /system/bin/run-as + continue; + } + int err = prctl(PR_CAPBSET_DROP, i, 0, 0, 0); + + // Some kernels don't have file capabilities compiled in, and + // prctl(PR_CAPBSET_DROP) returns EINVAL. Don't automatically + // die when we see such misconfigured kernels. + if ((err < 0) && (errno != EINVAL)) { + exit(1); + } + } +} + static int should_drop_privileges() { #ifndef ALLOW_ADBD_ROOT return 1; @@ -1208,6 +1264,10 @@ int adb_main(int is_daemon, int server_port) #if ADB_HOST HOST = 1; + +#ifdef WORKAROUND_BUG6558362 + if(is_daemon) adb_set_affinity(); +#endif usb_vendors_init(); usb_init(); local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT); @@ -1244,6 +1304,8 @@ int adb_main(int is_daemon, int server_port) exit(1); } + drop_capabilities_bounding_set_if_needed(); + /* add extra groups: ** AID_ADB to access the USB driver ** AID_LOG to read system logs (adb logcat) @@ -468,6 +468,7 @@ int connection_state(atransport *t); #define CS_RECOVERY 4 #define CS_NOPERM 5 /* Insufficient permissions to communicate with the device */ #define CS_SIDELOAD 6 +#define CS_UNAUTHORIZED 7 extern int HOST; extern int SHELL_EXIT_NOTIFY_FD; diff --git a/adb/adb_auth.h b/adb/adb_auth.h index 1fffa49..b24c674 100644 --- a/adb/adb_auth.h +++ b/adb/adb_auth.h @@ -20,6 +20,8 @@ void adb_auth_init(void); void adb_auth_verified(atransport *t); +void send_auth_request(atransport *t); + /* AUTH packets first argument */ /* Request */ #define ADB_AUTH_TOKEN 1 @@ -36,7 +38,6 @@ int adb_auth_get_userkey(unsigned char *data, size_t len); static inline int adb_auth_generate_token(void *token, size_t token_size) { return 0; } static inline int adb_auth_verify(void *token, void *sig, int siglen) { return 0; } static inline void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t) { } -static inline void adb_auth_reload_keys(void) { } #else // !ADB_HOST @@ -47,7 +48,6 @@ static inline int adb_auth_get_userkey(unsigned char *data, size_t len) { return int adb_auth_generate_token(void *token, size_t token_size); int adb_auth_verify(void *token, void *sig, int siglen); void adb_auth_confirm_key(unsigned char *data, size_t len, atransport *t); -void adb_auth_reload_keys(void); #endif // ADB_HOST diff --git a/adb/adb_auth_client.c b/adb/adb_auth_client.c index 0b4913e..efc49eb 100644 --- a/adb/adb_auth_client.c +++ b/adb/adb_auth_client.c @@ -34,8 +34,6 @@ struct adb_public_key { RSAPublicKey key; }; -static struct listnode key_list; - static char *key_paths[] = { "/adb_keys", "/data/misc/adb/adb_keys", @@ -45,6 +43,10 @@ static char *key_paths[] = { static fdevent listener_fde; static int framework_fd = -1; +static void usb_disconnected(void* unused, atransport* t); +static struct adisconnect usb_disconnect = { usb_disconnected, 0, 0, 0 }; +static atransport* usb_transport; +static bool needs_retry = false; static void read_keys(const char *file, struct listnode *list) { @@ -102,18 +104,18 @@ static void free_keys(struct listnode *list) } } -void adb_auth_reload_keys(void) +static void load_keys(struct listnode *list) { char *path; char **paths = key_paths; struct stat buf; - free_keys(&key_list); + list_init(list); while ((path = *paths++)) { if (!stat(path, &buf)) { D("Loading keys from '%s'\n", path); - read_keys(path, &key_list); + read_keys(path, list); } } } @@ -137,37 +139,50 @@ int adb_auth_verify(void *token, void *sig, int siglen) { struct listnode *item; struct adb_public_key *key; - int ret; + struct listnode key_list; + int ret = 0; if (siglen != RSANUMBYTES) return 0; + load_keys(&key_list); + list_for_each(item, &key_list) { key = node_to_item(item, struct adb_public_key, node); ret = RSA_verify(&key->key, sig, siglen, token); if (ret) - return 1; + break; } - return 0; + free_keys(&key_list); + + return ret; +} + +static void usb_disconnected(void* unused, atransport* t) +{ + D("USB disconnect"); + remove_transport_disconnect(usb_transport, &usb_disconnect); + usb_transport = NULL; + needs_retry = false; } static void adb_auth_event(int fd, unsigned events, void *data) { - atransport *t = data; char response[2]; int ret; if (events & FDE_READ) { ret = unix_read(fd, response, sizeof(response)); if (ret < 0) { - D("Disconnect"); - fdevent_remove(&t->auth_fde); + D("Framework disconnect"); + if (usb_transport) + fdevent_remove(&usb_transport->auth_fde); framework_fd = -1; } else if (ret == 2 && response[0] == 'O' && response[1] == 'K') { - adb_auth_reload_keys(); - adb_auth_verified(t); + if (usb_transport) + adb_auth_verified(usb_transport); } } } @@ -177,8 +192,12 @@ void adb_auth_confirm_key(unsigned char *key, size_t len, atransport *t) char msg[MAX_PAYLOAD]; int ret; + usb_transport = t; + add_transport_disconnect(t, &usb_disconnect); + if (framework_fd < 0) { D("Client not connected\n"); + needs_retry = true; return; } @@ -219,15 +238,17 @@ static void adb_auth_listener(int fd, unsigned events, void *data) } framework_fd = s; + + if (needs_retry) { + needs_retry = false; + send_auth_request(usb_transport); + } } void adb_auth_init(void) { int fd, ret; - list_init(&key_list); - adb_auth_reload_keys(); - fd = android_get_control_socket("adbd"); if (fd < 0) { D("Failed to get adbd socket\n"); diff --git a/adb/commandline.c b/adb/commandline.c index a927423..27a1754 100644 --- a/adb/commandline.c +++ b/adb/commandline.c @@ -144,12 +144,15 @@ void help() " adb bugreport - return all information from the device\n" " that should be included in a bug report.\n" "\n" - " adb backup [-f <file>] [-apk|-noapk] [-shared|-noshared] [-all] [-system|-nosystem] [<packages...>]\n" + " adb backup [-f <file>] [-apk|-noapk] [-obb|-noobb] [-shared|-noshared] [-all] [-system|-nosystem] [<packages...>]\n" " - write an archive of the device's data to <file>.\n" " If no -f option is supplied then the data is written\n" " to \"backup.ab\" in the current directory.\n" " (-apk|-noapk enable/disable backup of the .apks themselves\n" " in the archive; the default is noapk.)\n" + " (-obb|-noobb enable/disable backup of any installed apk expansion\n" + " (aka .obb) files associated with each application; the default\n" + " is noobb.)\n" " (-shared|-noshared enable/disable backup of the device's\n" " shared storage / SD card contents; the default is noshared.)\n" " (-all means to back up all installed applications)\n" diff --git a/adb/transport.c b/adb/transport.c index 9fd6cc2..b4abb66 100644 --- a/adb/transport.c +++ b/adb/transport.c @@ -851,6 +851,12 @@ retry: adb_mutex_unlock(&transport_lock); if (result) { + if (result->connection_state == CS_UNAUTHORIZED) { + if (error_out) + *error_out = "device unauthorized. Please check the confirmation dialog on your device."; + result = NULL; + } + /* offline devices are ignored -- they are either being born or dying */ if (result && result->connection_state == CS_OFFLINE) { if (error_out) @@ -888,6 +894,7 @@ static const char *statename(atransport *t) case CS_RECOVERY: return "recovery"; case CS_SIDELOAD: return "sideload"; case CS_NOPERM: return "no permissions"; + case CS_UNAUTHORIZED: return "unauthorized"; default: return "unknown"; } } diff --git a/charger/charger.c b/charger/charger.c index 353bdf0..66ddeaf 100644 --- a/charger/charger.c +++ b/charger/charger.c @@ -610,7 +610,7 @@ static int draw_text(const char *str, int x, int y) x = (gr_fb_width() - str_len_px) / 2; if (y < 0) y = (gr_fb_height() - char_height) / 2; - gr_text(x, y, str); + gr_text(x, y, str, 0); return y + char_height; } diff --git a/debuggerd/debuggerd.c b/debuggerd/debuggerd.c index 55222c5..65ff0f6 100644 --- a/debuggerd/debuggerd.c +++ b/debuggerd/debuggerd.c @@ -202,18 +202,20 @@ static int read_request(int fd, debugger_request_t* out_request) { pollfds[0].revents = 0; status = TEMP_FAILURE_RETRY(poll(pollfds, 1, 3000)); if (status != 1) { - LOG("timed out reading tid\n"); + LOG("timed out reading tid (from pid=%d uid=%d)\n", cr.pid, cr.uid); return -1; } debugger_msg_t msg; status = TEMP_FAILURE_RETRY(read(fd, &msg, sizeof(msg))); if (status < 0) { - LOG("read failure? %s\n", strerror(errno)); + LOG("read failure? %s (pid=%d uid=%d)\n", + strerror(errno), cr.pid, cr.uid); return -1; } if (status != sizeof(msg)) { - LOG("invalid crash request of size %d\n", status); + LOG("invalid crash request of size %d (from pid=%d uid=%d)\n", + status, cr.pid, cr.uid); return -1; } @@ -245,7 +247,7 @@ static int read_request(int fd, debugger_request_t* out_request) { return -1; } } else { - /* No one else is not allowed to dump arbitrary processes. */ + /* No one else is allowed to dump arbitrary processes. */ return -1; } return 0; diff --git a/fastboot/Android.mk b/fastboot/Android.mk index 5025dae..1189e1f 100644 --- a/fastboot/Android.mk +++ b/fastboot/Android.mk @@ -20,6 +20,7 @@ LOCAL_C_INCLUDES := $(LOCAL_PATH)/../mkbootimg \ $(LOCAL_PATH)/../../extras/ext4_utils LOCAL_SRC_FILES := protocol.c engine.c bootimg.c fastboot.c LOCAL_MODULE := fastboot +LOCAL_MODULE_TAGS := debug ifeq ($(HOST_OS),linux) LOCAL_SRC_FILES += usb_linux.c util_linux.c diff --git a/fastboot/bootimg.c b/fastboot/bootimg.c index 9e0e45c..240784f 100644 --- a/fastboot/bootimg.c +++ b/fastboot/bootimg.c @@ -37,10 +37,10 @@ void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline) strcpy((char*) h->cmdline, cmdline); } -boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size, - void *ramdisk, unsigned ramdisk_size, - void *second, unsigned second_size, - unsigned page_size, unsigned base, +boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size, unsigned kernel_offset, + void *ramdisk, unsigned ramdisk_size, unsigned ramdisk_offset, + void *second, unsigned second_size, unsigned second_offset, + unsigned page_size, unsigned base, unsigned tags_offset, unsigned *bootimg_size) { unsigned kernel_actual; @@ -68,12 +68,15 @@ boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size, hdr->kernel_size = kernel_size; hdr->ramdisk_size = ramdisk_size; hdr->second_size = second_size; - hdr->kernel_addr = base + 0x00008000; - hdr->ramdisk_addr = base + 0x01000000; - hdr->second_addr = base + 0x00F00000; - hdr->tags_addr = base + 0x00000100; + + hdr->kernel_addr = base + kernel_offset; + hdr->ramdisk_addr = base + ramdisk_offset; + hdr->second_addr = base + second_offset; + hdr->tags_addr = base + tags_offset; + hdr->page_size = page_size; + memcpy(hdr->magic + page_size, kernel, kernel_size); memcpy(hdr->magic + page_size + kernel_actual, diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c index 3de6d7d..447b257 100644 --- a/fastboot/fastboot.c +++ b/fastboot/fastboot.c @@ -58,10 +58,10 @@ char cur_product[FB_RESPONSE_SZ + 1]; void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline); -boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size, - void *ramdisk, unsigned ramdisk_size, - void *second, unsigned second_size, - unsigned page_size, unsigned base, +boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size, unsigned kernel_offset, + void *ramdisk, unsigned ramdisk_size, unsigned ramdisk_offset, + void *second, unsigned second_size, unsigned second_offset, + unsigned page_size, unsigned base, unsigned tags_offset, unsigned *bootimg_size); static usb_handle *usb = 0; @@ -74,7 +74,13 @@ static int long_listing = 0; static int64_t sparse_limit = -1; static int64_t target_sparse_limit = -1; -static unsigned base_addr = 0x10000000; +unsigned page_size = 2048; +unsigned base_addr = 0x10000000; +unsigned kernel_offset = 0x00008000; +unsigned ramdisk_offset = 0x01000000; +unsigned second_offset = 0x00f00000; +unsigned tags_offset = 0x00000100; + void die(const char *fmt, ...) { @@ -186,11 +192,6 @@ oops: } #endif -int match_fastboot(usb_ifc_info *info) -{ - return match_fastboot_with_serial(info, serial); -} - int match_fastboot_with_serial(usb_ifc_info *info, const char *local_serial) { if(!(vendor_id && (info->dev_vendor == vendor_id)) && @@ -217,6 +218,11 @@ int match_fastboot_with_serial(usb_ifc_info *info, const char *local_serial) return 0; } +int match_fastboot(usb_ifc_info *info) +{ + return match_fastboot_with_serial(info, serial); +} + int list_devices_callback(usb_ifc_info *info) { if (match_fastboot_with_serial(info, NULL) == 0) { @@ -297,14 +303,14 @@ void usage(void) " -p <product> specify product name\n" " -c <cmdline> override kernel commandline\n" " -i <vendor id> specify a custom USB vendor id\n" - " -b <base_addr> specify a custom kernel base address\n" + " -b <base_addr> specify a custom kernel base address. default: 0x10000000\n" " -n <page size> specify the nand page size. default: 2048\n" " -S <size>[K|M|G] automatically sparse files greater than\n" " size. 0 to disable\n" ); } -void *load_bootable_image(unsigned page_size, const char *kernel, const char *ramdisk, +void *load_bootable_image(const char *kernel, const char *ramdisk, unsigned *sz, const char *cmdline) { void *kdata = 0, *rdata = 0; @@ -345,7 +351,10 @@ void *load_bootable_image(unsigned page_size, const char *kernel, const char *ra } fprintf(stderr,"creating boot image...\n"); - bdata = mkbootimg(kdata, ksize, rdata, rsize, 0, 0, page_size, base_addr, &bsize); + bdata = mkbootimg(kdata, ksize, kernel_offset, + rdata, rsize, ramdisk_offset, + 0, 0, second_offset, + page_size, base_addr, tags_offset, &bsize); if(bdata == 0) { fprintf(stderr,"failed to create boot.img\n"); return 0; @@ -806,35 +815,64 @@ int main(int argc, char **argv) int erase_first = 1; void *data; unsigned sz; - unsigned page_size = 2048; int status; int c; int r; - const struct option longopts = { 0, 0, 0, 0 }; + const struct option longopts[] = { + {"base", required_argument, 0, 'b'}, + {"kernel_offset", required_argument, 0, 'k'}, + {"page_size", required_argument, 0, 'n'}, + {"ramdisk_offset", required_argument, 0, 'r'}, + {"help", 0, 0, 'h'}, + {0, 0, 0, 0} + }; serial = getenv("ANDROID_SERIAL"); while (1) { - c = getopt_long(argc, argv, "wub:n:s:S:lp:c:i:m:h", &longopts, NULL); + int option_index = 0; + c = getopt_long(argc, argv, "wub:k:n:r:s:S:lp:c:i:m:h", longopts, NULL); if (c < 0) { break; } - + /* Alphabetical cases */ switch (c) { - case 'w': - wants_wipe = 1; - break; - case 'u': - erase_first = 0; - break; case 'b': base_addr = strtoul(optarg, 0, 16); break; + case 'c': + cmdline = optarg; + break; + case 'h': + usage(); + return 1; + case 'i': { + char *endptr = NULL; + unsigned long val; + + val = strtoul(optarg, &endptr, 0); + if (!endptr || *endptr != '\0' || (val & ~0xffff)) + die("invalid vendor id '%s'", optarg); + vendor_id = (unsigned short)val; + break; + } + case 'k': + kernel_offset = strtoul(optarg, 0, 16); + break; + case 'l': + long_listing = 1; + break; case 'n': page_size = (unsigned)strtoul(optarg, NULL, 0); if (!page_size) die("invalid page size"); break; + case 'p': + product = optarg; + break; + case 'r': + ramdisk_offset = strtoul(optarg, 0, 16); + break; case 's': serial = optarg; break; @@ -844,28 +882,12 @@ int main(int argc, char **argv) die("invalid sparse limit"); } break; - case 'l': - long_listing = 1; - break; - case 'p': - product = optarg; + case 'u': + erase_first = 0; break; - case 'c': - cmdline = optarg; + case 'w': + wants_wipe = 1; break; - case 'i': { - char *endptr = NULL; - unsigned long val; - - val = strtoul(optarg, &endptr, 0); - if (!endptr || *endptr != '\0' || (val & ~0xffff)) - die("invalid vendor id '%s'", optarg); - vendor_id = (unsigned short)val; - break; - } - case 'h': - usage(); - return 1; case '?': return 1; default: @@ -944,7 +966,7 @@ int main(int argc, char **argv) rname = argv[0]; skip(1); } - data = load_bootable_image(page_size, kname, rname, &sz, cmdline); + data = load_bootable_image(kname, rname, &sz, cmdline); if (data == 0) return 1; fb_queue_download("boot.img", data, sz); fb_queue_command("boot", "booting"); @@ -975,7 +997,7 @@ int main(int argc, char **argv) } else { skip(3); } - data = load_bootable_image(page_size, kname, rname, &sz, cmdline); + data = load_bootable_image(kname, rname, &sz, cmdline); if (data == 0) die("cannot load bootable image"); fb_queue_flash(pname, data, sz); } else if(!strcmp(*argv, "flashall")) { diff --git a/fastboot/fastboot_protocol.txt b/fastboot/fastboot_protocol.txt new file mode 100644 index 0000000..2248992 --- /dev/null +++ b/fastboot/fastboot_protocol.txt @@ -0,0 +1,173 @@ + +FastBoot Version 0.4 +---------------------- + +The fastboot protocol is a mechanism for communicating with bootloaders +over USB. It is designed to be very straightforward to implement, to +allow it to be used across a wide range of devices and from hosts running +Linux, Windows, or OSX. + + +Basic Requirements +------------------ + +* Two bulk endpoints (in, out) are required +* Max packet size must be 64 bytes for full-speed and 512 bytes for + high-speed USB +* The protocol is entirely host-driven and synchronous (unlike the + multi-channel, bi-directional, asynchronous ADB protocol) + + +Transport and Framing +--------------------- + +1. Host sends a command, which is an ascii string in a single + packet no greater than 64 bytes. + +2. Client response with a single packet no greater than 64 bytes. + The first four bytes of the response are "OKAY", "FAIL", "DATA", + or "INFO". Additional bytes may contain an (ascii) informative + message. + + a. INFO -> the remaining 60 bytes are an informative message + (providing progress or diagnostic messages). They should + be displayed and then step #2 repeats + + b. FAIL -> the requested command failed. The remaining 60 bytes + of the response (if present) provide a textual failure message + to present to the user. Stop. + + c. OKAY -> the requested command completed successfully. Go to #5 + + d. DATA -> the requested command is ready for the data phase. + A DATA response packet will be 12 bytes long, in the form of + DATA00000000 where the 8 digit hexidecimal number represents + the total data size to transfer. + +3. Data phase. Depending on the command, the host or client will + send the indicated amount of data. Short packets are always + acceptable and zero-length packets are ignored. This phase continues + until the client has sent or received the number of bytes indicated + in the "DATA" response above. + +4. Client responds with a single packet no greater than 64 bytes. + The first four bytes of the response are "OKAY", "FAIL", or "INFO". + Similar to #2: + + a. INFO -> display the remaining 60 bytes and return to #4 + + b. FAIL -> display the remaining 60 bytes (if present) as a failure + reason and consider the command failed. Stop. + + c. OKAY -> success. Go to #5 + +5. Success. Stop. + + +Example Session +--------------- + +Host: "getvar:version" request version variable + +Client: "OKAY0.4" return version "0.4" + +Host: "getvar:nonexistant" request some undefined variable + +Client: "OKAY" return value "" + +Host: "download:00001234" request to send 0x1234 bytes of data + +Client: "DATA00001234" ready to accept data + +Host: < 0x1234 bytes > send data + +Client: "OKAY" success + +Host: "flash:bootloader" request to flash the data to the bootloader + +Client: "INFOerasing flash" indicate status / progress + "INFOwriting flash" + "OKAY" indicate success + +Host: "powerdown" send a command + +Client: "FAILunknown command" indicate failure + + +Command Reference +----------------- + +* Command parameters are indicated by printf-style escape sequences. + +* Commands are ascii strings and sent without the quotes (which are + for illustration only here) and without a trailing 0 byte. + +* Commands that begin with a lowercase letter are reserved for this + specification. OEM-specific commands should not begin with a + lowercase letter, to prevent incompatibilities with future specs. + + "getvar:%s" Read a config/version variable from the bootloader. + The variable contents will be returned after the + OKAY response. + + "download:%08x" Write data to memory which will be later used + by "boot", "ramdisk", "flash", etc. The client + will reply with "DATA%08x" if it has enough + space in RAM or "FAIL" if not. The size of + the download is remembered. + + "verify:%08x" Send a digital signature to verify the downloaded + data. Required if the bootloader is "secure" + otherwise "flash" and "boot" will be ignored. + + "flash:%s" Write the previously downloaded image to the + named partition (if possible). + + "erase:%s" Erase the indicated partition (clear to 0xFFs) + + "boot" The previously downloaded data is a boot.img + and should be booted according to the normal + procedure for a boot.img + + "continue" Continue booting as normal (if possible) + + "reboot" Reboot the device. + + "reboot-bootloader" Reboot back into the bootloader. + Useful for upgrade processes that require upgrading + the bootloader and then upgrading other partitions + using the new bootloader. + + "powerdown" Power off the device. + + + +Client Variables +---------------- + +The "getvar:%s" command is used to read client variables which +represent various information about the device and the software +on it. + +The various currently defined names are: + + version Version of FastBoot protocol supported. + It should be "0.3" for this document. + + version-bootloader Version string for the Bootloader. + + version-baseband Version string of the Baseband Software + + product Name of the product + + serialno Product serial number + + secure If the value is "yes", this is a secure + bootloader requiring a signature before + it will install or boot images. + +Names starting with a lowercase character are reserved by this +specification. OEM-specific names should not start with lowercase +characters. + + diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c index e51c9cf..8f64757 100644 --- a/fs_mgr/fs_mgr.c +++ b/fs_mgr/fs_mgr.c @@ -72,6 +72,10 @@ static struct flag_list fs_mgr_flags[] = { { "wait", MF_WAIT }, { "check", MF_CHECK }, { "encryptable=",MF_CRYPT }, + { "nonremovable",MF_NONREMOVABLE }, + { "voldmanaged=",MF_VOLDMANAGED}, + { "length=", MF_LENGTH }, + { "recoveryonly",MF_RECOVERYONLY }, { "defaults", 0 }, { 0, 0 }, }; @@ -106,7 +110,8 @@ static int wait_for_file(const char *filename, int timeout) return ret; } -static int parse_flags(char *flags, struct flag_list *fl, char **key_loc, +static int parse_flags(char *flags, struct flag_list *fl, + char **key_loc, long long *part_length, char **label, int *partnum, char *fs_options, int fs_options_len) { int f = 0; @@ -119,6 +124,18 @@ static int parse_flags(char *flags, struct flag_list *fl, char **key_loc, if (key_loc) { *key_loc = NULL; } + /* initialize part_length to 0, if we find an MF_LENGTH flag, + * then we'll set part_length to the proper value */ + if (part_length) { + *part_length = 0; + } + if (partnum) { + *partnum = -1; + } + if (label) { + *label = NULL; + } + /* initialize fs_options to the null string */ if (fs_options && (fs_options_len > 0)) { fs_options[0] = '\0'; @@ -137,6 +154,36 @@ static int parse_flags(char *flags, struct flag_list *fl, char **key_loc, * location of the keys. Get it and return it. */ *key_loc = strdup(strchr(p, '=') + 1); + } else if ((fl[i].flag == MF_LENGTH) && part_length) { + /* The length flag is followed by an = and the + * size of the partition. Get it and return it. + */ + *part_length = strtoll(strchr(p, '=') + 1, NULL, 0); + } else if ((fl[i].flag == MF_VOLDMANAGED) && label && partnum) { + /* The voldmanaged flag is followed by an = and the + * label, a colon and the partition number or the + * word "auto", e.g. + * voldmanaged=sdcard:3 + * Get and return them. + */ + char *label_start; + char *label_end; + char *part_start; + + label_start = strchr(p, '=') + 1; + label_end = strchr(p, ':'); + if (label_end) { + *label = strndup(label_start, + (int) (label_end - label_start)); + part_start = strchr(p, ':') + 1; + if (!strcmp(part_start, "auto")) { + *partnum = -1; + } else { + *partnum = strtol(part_start, NULL, 0); + } + } else { + ERROR("Warning: voldmanaged= flag malformed\n"); + } } break; } @@ -227,7 +274,7 @@ static char *fs_getline(char *buf, int size, FILE *file) } } -static struct fstab_rec *read_fstab(char *fstab_path) +struct fstab *fs_mgr_read_fstab(const char *fstab_path) { FILE *fstab_file; int cnt, entries; @@ -235,8 +282,12 @@ static struct fstab_rec *read_fstab(char *fstab_path) char line[256]; const char *delim = " \t"; char *save_ptr, *p; - struct fstab_rec *fstab; + struct fstab *fstab; + struct fstab_rec *recs; char *key_loc; + long long part_length; + char *label; + int partnum; #define FS_OPTIONS_LEN 1024 char tmp_fs_options[FS_OPTIONS_LEN]; @@ -269,7 +320,11 @@ static struct fstab_rec *read_fstab(char *fstab_path) return 0; } - fstab = calloc(entries + 1, sizeof(struct fstab_rec)); + /* Allocate and init the fstab structure */ + fstab = calloc(1, sizeof(struct fstab)); + fstab->num_entries = entries; + fstab->fstab_filename = strdup(fstab_path); + fstab->recs = calloc(fstab->num_entries, sizeof(struct fstab_rec)); fseek(fstab_file, 0, SEEK_SET); @@ -303,41 +358,48 @@ static struct fstab_rec *read_fstab(char *fstab_path) ERROR("Error parsing mount source\n"); return 0; } - fstab[cnt].blk_dev = strdup(p); + fstab->recs[cnt].blk_device = strdup(p); if (!(p = strtok_r(NULL, delim, &save_ptr))) { - ERROR("Error parsing mnt_point\n"); + ERROR("Error parsing mount_point\n"); return 0; } - fstab[cnt].mnt_point = strdup(p); + fstab->recs[cnt].mount_point = strdup(p); if (!(p = strtok_r(NULL, delim, &save_ptr))) { ERROR("Error parsing fs_type\n"); return 0; } - fstab[cnt].type = strdup(p); + fstab->recs[cnt].fs_type = strdup(p); if (!(p = strtok_r(NULL, delim, &save_ptr))) { ERROR("Error parsing mount_flags\n"); return 0; } tmp_fs_options[0] = '\0'; - fstab[cnt].flags = parse_flags(p, mount_flags, 0, tmp_fs_options, FS_OPTIONS_LEN); + fstab->recs[cnt].flags = parse_flags(p, mount_flags, + NULL, NULL, NULL, NULL, + tmp_fs_options, FS_OPTIONS_LEN); /* fs_options are optional */ if (tmp_fs_options[0]) { - fstab[cnt].fs_options = strdup(tmp_fs_options); + fstab->recs[cnt].fs_options = strdup(tmp_fs_options); } else { - fstab[cnt].fs_options = NULL; + fstab->recs[cnt].fs_options = NULL; } if (!(p = strtok_r(NULL, delim, &save_ptr))) { ERROR("Error parsing fs_mgr_options\n"); return 0; } - fstab[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags, &key_loc, 0, 0); - fstab[cnt].key_loc = key_loc; - + fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags, + &key_loc, &part_length, + &label, &partnum, + NULL, 0); + fstab->recs[cnt].key_loc = key_loc; + fstab->recs[cnt].length = part_length; + fstab->recs[cnt].label = label; + fstab->recs[cnt].partnum = partnum; cnt++; } fclose(fstab_file); @@ -345,26 +407,32 @@ static struct fstab_rec *read_fstab(char *fstab_path) return fstab; } -static void free_fstab(struct fstab_rec *fstab) +void fs_mgr_free_fstab(struct fstab *fstab) { - int i = 0; + int i; - while (fstab[i].blk_dev) { + for (i = 0; i < fstab->num_entries; i++) { /* Free the pointers return by strdup(3) */ - free(fstab[i].blk_dev); - free(fstab[i].mnt_point); - free(fstab[i].type); - free(fstab[i].fs_options); - free(fstab[i].key_loc); - + free(fstab->recs[i].blk_device); + free(fstab->recs[i].mount_point); + free(fstab->recs[i].fs_type); + free(fstab->recs[i].fs_options); + free(fstab->recs[i].key_loc); + free(fstab->recs[i].label); i++; } - /* Free the actual fstab array created by calloc(3) */ + /* Free the fstab_recs array created by calloc(3) */ + free(fstab->recs); + + /* Free the fstab filename */ + free(fstab->fstab_filename); + + /* Free fstab */ free(fstab); } -static void check_fs(char *blk_dev, char *type, char *target) +static void check_fs(char *blk_device, char *fs_type, char *target) { pid_t pid; int status; @@ -373,7 +441,7 @@ static void check_fs(char *blk_dev, char *type, char *target) char *tmpmnt_opts = "nomblk_io_submit,errors=remount-ro"; /* Check for the types of filesystems we know how to check */ - if (!strcmp(type, "ext2") || !strcmp(type, "ext3") || !strcmp(type, "ext4")) { + if (!strcmp(fs_type, "ext2") || !strcmp(fs_type, "ext3") || !strcmp(fs_type, "ext4")) { /* * First try to mount and unmount the filesystem. We do this because * the kernel is more efficient than e2fsck in running the journal and @@ -387,19 +455,19 @@ static void check_fs(char *blk_dev, char *type, char *target) * filesytsem due to an error, e2fsck is still run to do a full check * fix the filesystem. */ - ret = mount(blk_dev, target, type, tmpmnt_flags, tmpmnt_opts); - if (! ret) { + ret = mount(blk_device, target, fs_type, tmpmnt_flags, tmpmnt_opts); + if (!ret) { umount(target); } - INFO("Running %s on %s\n", E2FSCK_BIN, blk_dev); + INFO("Running %s on %s\n", E2FSCK_BIN, blk_device); pid = fork(); if (pid > 0) { /* Parent, wait for the child to return */ waitpid(pid, &status, 0); } else if (pid == 0) { /* child, run checker */ - execlp(E2FSCK_BIN, E2FSCK_BIN, "-y", blk_dev, (char *)NULL); + execlp(E2FSCK_BIN, E2FSCK_BIN, "-y", blk_device, (char *)NULL); /* Only gets here on error */ ERROR("Cannot run fs_mgr binary %s\n", E2FSCK_BIN); @@ -443,49 +511,62 @@ static int fs_match(char *in1, char *in2) return ret; } -int fs_mgr_mount_all(char *fstab_file) +int fs_mgr_mount_all(struct fstab *fstab) { int i = 0; int encrypted = 0; int ret = -1; int mret; - struct fstab_rec *fstab = 0; - if (!(fstab = read_fstab(fstab_file))) { + if (!fstab) { return ret; } - for (i = 0; fstab[i].blk_dev; i++) { - if (fstab[i].fs_mgr_flags & MF_WAIT) { - wait_for_file(fstab[i].blk_dev, WAIT_TIMEOUT); + for (i = 0; i < fstab->num_entries; i++) { + /* Don't mount entries that are managed by vold */ + if (fstab->recs[i].fs_mgr_flags & (MF_VOLDMANAGED | MF_RECOVERYONLY)) { + continue; } - if (fstab[i].fs_mgr_flags & MF_CHECK) { - check_fs(fstab[i].blk_dev, fstab[i].type, fstab[i].mnt_point); + /* Skip raw partition entries such as boot, recovery, etc */ + if (!strcmp(fstab->recs[i].fs_type, "emmc") || + !strcmp(fstab->recs[i].fs_type, "mtd")) { + continue; } - mret = mount(fstab[i].blk_dev, fstab[i].mnt_point, fstab[i].type, - fstab[i].flags, fstab[i].fs_options); + if (fstab->recs[i].fs_mgr_flags & MF_WAIT) { + wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT); + } + + if (fstab->recs[i].fs_mgr_flags & MF_CHECK) { + check_fs(fstab->recs[i].blk_device, fstab->recs[i].fs_type, + fstab->recs[i].mount_point); + } + + mret = mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point, + fstab->recs[i].fs_type, fstab->recs[i].flags, + fstab->recs[i].fs_options); if (!mret) { /* Success! Go get the next one */ continue; } /* mount(2) returned an error, check if it's encrypted and deal with it */ - if ((fstab[i].fs_mgr_flags & MF_CRYPT) && !partition_wiped(fstab[i].blk_dev)) { + if ((fstab->recs[i].fs_mgr_flags & MF_CRYPT) && + !partition_wiped(fstab->recs[i].blk_device)) { /* Need to mount a tmpfs at this mountpoint for now, and set * properties that vold will query later for decrypting */ - if (mount("tmpfs", fstab[i].mnt_point, "tmpfs", + if (mount("tmpfs", fstab->recs[i].mount_point, "tmpfs", MS_NOATIME | MS_NOSUID | MS_NODEV, CRYPTO_TMPFS_OPTIONS) < 0) { ERROR("Cannot mount tmpfs filesystem for encrypted fs at %s\n", - fstab[i].mnt_point); + fstab->recs[i].mount_point); goto out; } encrypted = 1; } else { ERROR("Cannot mount filesystem on %s at %s\n", - fstab[i].blk_dev, fstab[i].mnt_point); + fstab->recs[i].blk_device, fstab->recs[i].mount_point); goto out; } } @@ -497,49 +578,57 @@ int fs_mgr_mount_all(char *fstab_file) } out: - free_fstab(fstab); return ret; } -/* If tmp_mnt_point is non-null, mount the filesystem there. This is for the +/* If tmp_mount_point is non-null, mount the filesystem there. This is for the * tmp mount we do to check the user password */ -int fs_mgr_do_mount(char *fstab_file, char *n_name, char *n_blk_dev, char *tmp_mnt_point) +int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device, + char *tmp_mount_point) { int i = 0; int ret = -1; - struct fstab_rec *fstab = 0; char *m; - if (!(fstab = read_fstab(fstab_file))) { + if (!fstab) { return ret; } - for (i = 0; fstab[i].blk_dev; i++) { - if (!fs_match(fstab[i].mnt_point, n_name)) { + for (i = 0; i < fstab->num_entries; i++) { + if (!fs_match(fstab->recs[i].mount_point, n_name)) { continue; } /* We found our match */ + /* If this is a raw partition, report an error */ + if (!strcmp(fstab->recs[i].fs_type, "emmc") || + !strcmp(fstab->recs[i].fs_type, "mtd")) { + ERROR("Cannot mount filesystem of type %s on %s\n", + fstab->recs[i].fs_type, n_blk_device); + goto out; + } + /* First check the filesystem if requested */ - if (fstab[i].fs_mgr_flags & MF_WAIT) { - wait_for_file(n_blk_dev, WAIT_TIMEOUT); + if (fstab->recs[i].fs_mgr_flags & MF_WAIT) { + wait_for_file(n_blk_device, WAIT_TIMEOUT); } - if (fstab[i].fs_mgr_flags & MF_CHECK) { - check_fs(n_blk_dev, fstab[i].type, fstab[i].mnt_point); + if (fstab->recs[i].fs_mgr_flags & MF_CHECK) { + check_fs(n_blk_device, fstab->recs[i].fs_type, + fstab->recs[i].mount_point); } /* Now mount it where requested */ - if (tmp_mnt_point) { - m = tmp_mnt_point; + if (tmp_mount_point) { + m = tmp_mount_point; } else { - m = fstab[i].mnt_point; + m = fstab->recs[i].mount_point; } - if (mount(n_blk_dev, m, fstab[i].type, - fstab[i].flags, fstab[i].fs_options)) { + if (mount(n_blk_device, m, fstab->recs[i].fs_type, + fstab->recs[i].flags, fstab->recs[i].fs_options)) { ERROR("Cannot mount filesystem on %s at %s\n", - n_blk_dev, m); + n_blk_device, m); goto out; } else { ret = 0; @@ -548,10 +637,9 @@ int fs_mgr_do_mount(char *fstab_file, char *n_name, char *n_blk_dev, char *tmp_m } /* We didn't find a match, say so and return an error */ - ERROR("Cannot find mount point %s in fstab\n", fstab[i].mnt_point); + ERROR("Cannot find mount point %s in fstab\n", fstab->recs[i].mount_point); out: - free_fstab(fstab); return ret; } @@ -574,65 +662,128 @@ int fs_mgr_do_tmpfs_mount(char *n_name) return 0; } -int fs_mgr_unmount_all(char *fstab_file) +int fs_mgr_unmount_all(struct fstab *fstab) { int i = 0; int ret = 0; - struct fstab_rec *fstab = 0; - if (!(fstab = read_fstab(fstab_file))) { + if (!fstab) { return -1; } - while (fstab[i].blk_dev) { - if (umount(fstab[i].mnt_point)) { - ERROR("Cannot unmount filesystem at %s\n", fstab[i].mnt_point); + while (fstab->recs[i].blk_device) { + if (umount(fstab->recs[i].mount_point)) { + ERROR("Cannot unmount filesystem at %s\n", fstab->recs[i].mount_point); ret = -1; } i++; } - free_fstab(fstab); return ret; } /* * key_loc must be at least PROPERTY_VALUE_MAX bytes long * - * real_blk_dev must be at least PROPERTY_VALUE_MAX bytes long + * real_blk_device must be at least PROPERTY_VALUE_MAX bytes long */ -int fs_mgr_get_crypt_info(char *fstab_file, char *key_loc, char *real_blk_dev, int size) +int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc, char *real_blk_device, int size) { int i = 0; - struct fstab_rec *fstab = 0; - if (!(fstab = read_fstab(fstab_file))) { + if (!fstab) { return -1; } /* Initialize return values to null strings */ if (key_loc) { *key_loc = '\0'; } - if (real_blk_dev) { - *real_blk_dev = '\0'; + if (real_blk_device) { + *real_blk_device = '\0'; } /* Look for the encryptable partition to find the data */ - for (i = 0; fstab[i].blk_dev; i++) { - if (!(fstab[i].fs_mgr_flags & MF_CRYPT)) { + for (i = 0; i < fstab->num_entries; i++) { + /* Don't deal with vold managed enryptable partitions here */ + if (fstab->recs[i].fs_mgr_flags & MF_VOLDMANAGED) { + continue; + } + if (!(fstab->recs[i].fs_mgr_flags & MF_CRYPT)) { continue; } /* We found a match */ if (key_loc) { - strlcpy(key_loc, fstab[i].key_loc, size); + strlcpy(key_loc, fstab->recs[i].key_loc, size); } - if (real_blk_dev) { - strlcpy(real_blk_dev, fstab[i].blk_dev, size); + if (real_blk_device) { + strlcpy(real_blk_device, fstab->recs[i].blk_device, size); } break; } - free_fstab(fstab); return 0; } +/* Add an entry to the fstab, and return 0 on success or -1 on error */ +int fs_mgr_add_entry(struct fstab *fstab, + const char *mount_point, const char *fs_type, + const char *blk_device, long long length) +{ + struct fstab_rec *new_fstab_recs; + int n = fstab->num_entries; + + new_fstab_recs = (struct fstab_rec *) + realloc(fstab->recs, sizeof(struct fstab_rec) * (n + 1)); + + if (!new_fstab_recs) { + return -1; + } + + /* A new entry was added, so initialize it */ + memset(&new_fstab_recs[n], 0, sizeof(struct fstab_rec)); + new_fstab_recs[n].mount_point = strdup(mount_point); + new_fstab_recs[n].fs_type = strdup(fs_type); + new_fstab_recs[n].blk_device = strdup(blk_device); + new_fstab_recs[n].length = 0; + + /* Update the fstab struct */ + fstab->recs = new_fstab_recs; + fstab->num_entries++; + + return 0; +} + +struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path) +{ + int i; + + if (!fstab) { + return NULL; + } + + for (i = 0; i < fstab->num_entries; i++) { + int len = strlen(fstab->recs[i].mount_point); + if (strncmp(path, fstab->recs[i].mount_point, len) == 0 && + (path[len] == '\0' || path[len] == '/')) { + return &fstab->recs[i]; + } + } + + return NULL; +} + +int fs_mgr_is_voldmanaged(struct fstab_rec *fstab) +{ + return fstab->fs_mgr_flags & MF_VOLDMANAGED; +} + +int fs_mgr_is_nonremovable(struct fstab_rec *fstab) +{ + return fstab->fs_mgr_flags & MF_NONREMOVABLE; +} + +int fs_mgr_is_encryptable(struct fstab_rec *fstab) +{ + return fstab->fs_mgr_flags & MF_CRYPT; +} + diff --git a/fs_mgr/fs_mgr_main.c b/fs_mgr/fs_mgr_main.c index 81febf1..4bde4a1 100644 --- a/fs_mgr/fs_mgr_main.c +++ b/fs_mgr/fs_mgr_main.c @@ -82,7 +82,8 @@ int main(int argc, char *argv[]) int n_flag=0; char *n_name; char *n_blk_dev; - char *fstab; + char *fstab_file; + struct fstab *fstab; klog_init(); klog_set_level(6); @@ -90,7 +91,9 @@ int main(int argc, char *argv[]) parse_options(argc, argv, &a_flag, &u_flag, &n_flag, &n_name, &n_blk_dev); /* The name of the fstab file is last, after the option */ - fstab = argv[argc - 1]; + fstab_file = argv[argc - 1]; + + fstab = fs_mgr_read_fstab(fstab_file); if (a_flag) { return fs_mgr_mount_all(fstab); @@ -103,6 +106,8 @@ int main(int argc, char *argv[]) exit(1); } + fs_mgr_free_fstab(fstab); + /* Should not get here */ exit(1); } diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h index 175fdab..75dad49 100644 --- a/fs_mgr/fs_mgr_priv.h +++ b/fs_mgr/fs_mgr_priv.h @@ -25,16 +25,6 @@ #define CRYPTO_TMPFS_OPTIONS "size=128m,mode=0771,uid=1000,gid=1000" -struct fstab_rec { - char *blk_dev; - char *mnt_point; - char *type; - unsigned long flags; - char *fs_options; - int fs_mgr_flags; - char *key_loc; -}; - #define WAIT_TIMEOUT 5 /* fstab has the following format: @@ -59,8 +49,8 @@ struct fstab_rec { * run an fscheck program on the <source> before mounting the filesystem. * If check is specifed on a read-only filesystem, it is ignored. * Also, "encryptable" means that filesystem can be encrypted. - * The "encryptable" flag _MUST_ be followed by a : and a string which - * is the location of the encryption keys. I can either be a path + * The "encryptable" flag _MUST_ be followed by a = and a string which + * is the location of the encryption keys. It can either be a path * to a file or partition which contains the keys, or the word "footer" * which means the keys are in the last 16 Kbytes of the partition * containing the filesystem. @@ -72,9 +62,13 @@ struct fstab_rec { * */ -#define MF_WAIT 0x1 -#define MF_CHECK 0x2 -#define MF_CRYPT 0x4 +#define MF_WAIT 0x1 +#define MF_CHECK 0x2 +#define MF_CRYPT 0x4 +#define MF_NONREMOVABLE 0x8 +#define MF_VOLDMANAGED 0x10 +#define MF_LENGTH 0x20 +#define MF_RECOVERYONLY 0x40 #endif /* __CORE_FS_MGR_PRIV_H */ diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h index 76abb83..05bcc1b 100644 --- a/fs_mgr/include/fs_mgr.h +++ b/fs_mgr/include/fs_mgr.h @@ -17,11 +17,48 @@ #ifndef __CORE_FS_MGR_H #define __CORE_FS_MGR_H -int fs_mgr_mount_all(char *fstab_file); -int fs_mgr_do_mount(char *fstab_file, char *n_name, char *n_blk_dev, char *tmp_mnt_point); +#ifdef __cplusplus +extern "C" { +#endif + +struct fstab { + int num_entries; + struct fstab_rec *recs; + char *fstab_filename; +}; + +struct fstab_rec { + char *blk_device; + char *mount_point; + char *fs_type; + unsigned long flags; + char *fs_options; + int fs_mgr_flags; + char *key_loc; + long long length; + char *label; + int partnum; +}; + +struct fstab *fs_mgr_read_fstab(const char *fstab_path); +void fs_mgr_free_fstab(struct fstab *fstab); +int fs_mgr_mount_all(struct fstab *fstab); +int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device, + char *tmp_mount_point); int fs_mgr_do_tmpfs_mount(char *n_name); -int fs_mgr_unmount_all(char *fstab_file); -int fs_mgr_get_crypt_info(char *fstab_file, char *key_loc, char *real_blk_dev, int size); +int fs_mgr_unmount_all(struct fstab *fstab); +int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc, + char *real_blk_device, int size); +int fs_mgr_add_entry(struct fstab *fstab, + const char *mount_point, const char *fs_type, + const char *blk_device, long long length); +struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path); +int fs_mgr_is_voldmanaged(struct fstab_rec *fstab); +int fs_mgr_is_nonremovable(struct fstab_rec *fstab); +int fs_mgr_is_encryptable(struct fstab_rec *fstab); +#ifdef __cplusplus +} +#endif #endif /* __CORE_FS_MGR_H */ diff --git a/include/cutils/aref.h b/include/cutils/aref.h new file mode 100644 index 0000000..460ac02 --- /dev/null +++ b/include/cutils/aref.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2013 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 _CUTILS_AREF_H_ +#define _CUTILS_AREF_H_ + +#include <stddef.h> +#include <sys/cdefs.h> + +#ifdef ANDROID_SMP +#include <cutils/atomic-inline.h> +#else +#include <cutils/atomic.h> +#endif + +__BEGIN_DECLS + +#define AREF_TO_ITEM(aref, container, member) \ + (container *) (((char*) (aref)) - offsetof(container, member)) + +struct aref +{ + volatile int32_t count; +}; + +static inline void aref_init(struct aref *r) +{ + r->count = 1; +} + +static inline int32_t aref_count(struct aref *r) +{ + return r->count; +} + +static inline void aref_get(struct aref *r) +{ + android_atomic_inc(&r->count); +} + +static inline void aref_put(struct aref *r, void (*release)(struct aref *)) +{ + if (android_atomic_dec(&r->count) == 1) + release(r); +} + +__END_DECLS + +#endif // _CUTILS_AREF_H_ diff --git a/include/cutils/atomic-arm.h b/include/cutils/atomic-arm.h index 172a0cd..795afd3 100644 --- a/include/cutils/atomic-arm.h +++ b/include/cutils/atomic-arm.h @@ -18,33 +18,55 @@ #define ANDROID_CUTILS_ATOMIC_ARM_H #include <stdint.h> +#include <machine/cpu-features.h> #ifndef ANDROID_ATOMIC_INLINE #define ANDROID_ATOMIC_INLINE inline __attribute__((always_inline)) #endif -extern ANDROID_ATOMIC_INLINE void android_compiler_barrier() +extern ANDROID_ATOMIC_INLINE void android_compiler_barrier(void) { __asm__ __volatile__ ("" : : : "memory"); } -extern ANDROID_ATOMIC_INLINE void android_memory_barrier() -{ #if ANDROID_SMP == 0 +extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void) +{ android_compiler_barrier(); -#else - __asm__ __volatile__ ("dmb" : : : "memory"); -#endif } - -extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier() +extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void) { -#if ANDROID_SMP == 0 android_compiler_barrier(); -#else +} +#elif defined(__ARM_HAVE_DMB) +extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void) +{ + __asm__ __volatile__ ("dmb" : : : "memory"); +} +extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void) +{ __asm__ __volatile__ ("dmb st" : : : "memory"); -#endif } +#elif defined(__ARM_HAVE_LDREX_STREX) +extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void) +{ + __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" : : "r" (0) : "memory"); +} +extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void) +{ + android_memory_barrier(); +} +#else +extern ANDROID_ATOMIC_INLINE void android_memory_barrier(void) +{ + typedef void (kuser_memory_barrier)(void); + (*(kuser_memory_barrier *)0xffff0fa0)(); +} +extern ANDROID_ATOMIC_INLINE void android_memory_store_barrier(void) +{ + android_memory_barrier(); +} +#endif extern ANDROID_ATOMIC_INLINE int32_t android_atomic_acquire_load(volatile const int32_t *ptr) @@ -61,32 +83,32 @@ int32_t android_atomic_release_load(volatile const int32_t *ptr) return *ptr; } -extern ANDROID_ATOMIC_INLINE -void android_atomic_acquire_store(int32_t value, volatile int32_t *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_release_store(int32_t value, volatile int32_t *ptr) +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 -int android_atomic_cas(int32_t old_value, int32_t new_value, - volatile int32_t *ptr) +#if defined(__thumb__) +extern int android_atomic_cas(int32_t old_value, int32_t new_value, + volatile int32_t *ptr); +#elif defined(__ARM_HAVE_LDREX_STREX) +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__ ("ldrex %0, [%3]\n" "mov %1, #0\n" "teq %0, %4\n" -#ifdef __thumb2__ - "it eq\n" -#endif "strexeq %1, %5, [%3]" : "=&r" (prev), "=&r" (status), "+m"(*ptr) : "r" (ptr), "Ir" (old_value), "r" (new_value) @@ -94,26 +116,49 @@ int android_atomic_cas(int32_t old_value, int32_t new_value, } while (__builtin_expect(status != 0, 0)); return prev != old_value; } +#else +extern ANDROID_ATOMIC_INLINE int +android_atomic_cas(int32_t old_value, int32_t new_value, volatile int32_t *ptr) +{ + typedef int (kuser_cmpxchg)(int32_t, int32_t, volatile int32_t *); + int32_t prev, status; + prev = *ptr; + do { + status = (*(kuser_cmpxchg *)0xffff0fc0)(old_value, new_value, ptr); + if (__builtin_expect(status == 0, 1)) + return 0; + prev = *ptr; + } while (prev == old_value); + return 1; +} +#endif -extern ANDROID_ATOMIC_INLINE -int android_atomic_acquire_cas(int32_t old_value, int32_t new_value, - volatile int32_t *ptr) +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 -int android_atomic_release_cas(int32_t old_value, int32_t new_value, - volatile int32_t *ptr) +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 -int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr) + +#if defined(__thumb__) +extern int32_t android_atomic_add(int32_t increment, + volatile int32_t *ptr); +#elif defined(__ARM_HAVE_LDREX_STREX) +extern ANDROID_ATOMIC_INLINE int32_t +android_atomic_add(int32_t increment, volatile int32_t *ptr) { int32_t prev, tmp, status; android_memory_barrier(); @@ -128,6 +173,19 @@ int32_t android_atomic_add(int32_t increment, volatile int32_t *ptr) } while (__builtin_expect(status != 0, 0)); return prev; } +#else +extern ANDROID_ATOMIC_INLINE int32_t +android_atomic_add(int32_t increment, volatile int32_t *ptr) +{ + int32_t prev, status; + android_memory_barrier(); + do { + prev = *ptr; + status = android_atomic_cas(prev, prev + increment, ptr); + } while (__builtin_expect(status != 0, 0)); + return prev; +} +#endif extern ANDROID_ATOMIC_INLINE int32_t android_atomic_inc(volatile int32_t *addr) { @@ -139,8 +197,11 @@ 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) +#if defined(__thumb__) +extern int32_t android_atomic_and(int32_t value, volatile int32_t *ptr); +#elif defined(__ARM_HAVE_LDREX_STREX) +extern ANDROID_ATOMIC_INLINE int32_t +android_atomic_and(int32_t value, volatile int32_t *ptr) { int32_t prev, tmp, status; android_memory_barrier(); @@ -155,9 +216,25 @@ int32_t android_atomic_and(int32_t value, volatile int32_t *ptr) } while (__builtin_expect(status != 0, 0)); return prev; } +#else +extern ANDROID_ATOMIC_INLINE int32_t +android_atomic_and(int32_t value, volatile int32_t *ptr) +{ + int32_t prev, status; + android_memory_barrier(); + do { + prev = *ptr; + status = android_atomic_cas(prev, prev & value, ptr); + } while (__builtin_expect(status != 0, 0)); + return prev; +} +#endif -extern ANDROID_ATOMIC_INLINE -int32_t android_atomic_or(int32_t value, volatile int32_t *ptr) +#if defined(__thumb__) +extern int32_t android_atomic_or(int32_t value, volatile int32_t *ptr); +#elif defined(__ARM_HAVE_LDREX_STREX) +extern ANDROID_ATOMIC_INLINE int32_t +android_atomic_or(int32_t value, volatile int32_t *ptr) { int32_t prev, tmp, status; android_memory_barrier(); @@ -172,5 +249,18 @@ int32_t android_atomic_or(int32_t value, volatile int32_t *ptr) } while (__builtin_expect(status != 0, 0)); return prev; } +#else +extern ANDROID_ATOMIC_INLINE int32_t +android_atomic_or(int32_t value, volatile int32_t *ptr) +{ + int32_t prev, status; + android_memory_barrier(); + do { + prev = *ptr; + status = android_atomic_cas(prev, prev | value, ptr); + } while (__builtin_expect(status != 0, 0)); + return prev; +} +#endif #endif /* ANDROID_CUTILS_ATOMIC_ARM_H */ diff --git a/include/cutils/bitops.h b/include/cutils/bitops.h index 1b3b762..eb44236 100644 --- a/include/cutils/bitops.h +++ b/include/cutils/bitops.h @@ -17,10 +17,79 @@ #ifndef __CUTILS_BITOPS_H #define __CUTILS_BITOPS_H +#include <stdbool.h> +#include <string.h> +#include <strings.h> #include <sys/cdefs.h> __BEGIN_DECLS +/* + * Bitmask Operations + * + * Note this doesn't provide any locking/exclusion, and isn't atomic. + * Additionally no bounds checking is done on the bitmask array. + * + * Example: + * + * int num_resources; + * unsigned int resource_bits[BITS_TO_WORDS(num_resources)]; + * bitmask_init(resource_bits, num_resources); + * ... + * int bit = bitmask_ffz(resource_bits, num_resources); + * bitmask_set(resource_bits, bit); + * ... + * if (bitmask_test(resource_bits, bit)) { ... } + * ... + * bitmask_clear(resource_bits, bit); + * + */ + +#define BITS_PER_WORD (sizeof(unsigned int) * 8) +#define BITS_TO_WORDS(x) (((x) + BITS_PER_WORD - 1) / BITS_PER_WORD) +#define BIT_IN_WORD(x) ((x) % BITS_PER_WORD) +#define BIT_WORD(x) ((x) / BITS_PER_WORD) +#define BIT_MASK(x) (1 << BIT_IN_WORD(x)) + +static inline void bitmask_init(unsigned int *bitmask, int num_bits) +{ + memset(bitmask, 0, BITS_TO_WORDS(num_bits)*sizeof(unsigned int)); +} + +static inline int bitmask_ffz(unsigned int *bitmask, int num_bits) +{ + int bit, result; + unsigned int i; + + for (i = 0; i < BITS_TO_WORDS(num_bits); i++) { + bit = ffs(~bitmask[i]); + if (bit) { + // ffs is 1-indexed, return 0-indexed result + bit--; + result = BITS_PER_WORD * i + bit; + if (result >= num_bits) + return -1; + return result; + } + } + return -1; +} + +static inline void bitmask_set(unsigned int *bitmask, int bit) +{ + bitmask[BIT_WORD(bit)] |= BIT_MASK(bit); +} + +static inline void bitmask_clear(unsigned int *bitmask, int bit) +{ + bitmask[BIT_WORD(bit)] &= ~BIT_MASK(bit); +} + +static inline bool bitmask_test(unsigned int *bitmask, int bit) +{ + return bitmask[BIT_WORD(bit)] & BIT_MASK(bit); +} + static inline int popcount(unsigned int x) { return __builtin_popcount(x); diff --git a/include/cutils/trace.h b/include/cutils/trace.h new file mode 100644 index 0000000..1db3903 --- /dev/null +++ b/include/cutils/trace.h @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2012 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 _LIBS_CUTILS_TRACE_H +#define _LIBS_CUTILS_TRACE_H + +#include <sys/cdefs.h> +#include <sys/types.h> +#include <stdint.h> +#include <unistd.h> +#include <cutils/compiler.h> + +#ifdef ANDROID_SMP +#include <cutils/atomic-inline.h> +#else +#include <cutils/atomic.h> +#endif + +__BEGIN_DECLS + +/** + * The ATRACE_TAG macro can be defined before including this header to trace + * using one of the tags defined below. It must be defined to one of the + * following ATRACE_TAG_* macros. The trace tag is used to filter tracing in + * userland to avoid some of the runtime cost of tracing when it is not desired. + * + * Defining ATRACE_TAG to be ATRACE_TAG_ALWAYS will result in the tracing always + * being enabled - this should ONLY be done for debug code, as userland tracing + * has a performance cost even when the trace is not being recorded. Defining + * ATRACE_TAG to be ATRACE_TAG_NEVER or leaving ATRACE_TAG undefined will result + * in the tracing always being disabled. + * + * ATRACE_TAG_HAL should be bitwise ORed with the relevant tags for tracing + * within a hardware module. For example a camera hardware module would set: + * #define ATRACE_TAG (ATRACE_TAG_CAMERA | ATRACE_TAG_HAL) + * + * Keep these in sync with frameworks/base/core/java/android/os/Trace.java. + */ +#define ATRACE_TAG_NEVER 0 // This tag is never enabled. +#define ATRACE_TAG_ALWAYS (1<<0) // This tag is always enabled. +#define ATRACE_TAG_GRAPHICS (1<<1) +#define ATRACE_TAG_INPUT (1<<2) +#define ATRACE_TAG_VIEW (1<<3) +#define ATRACE_TAG_WEBVIEW (1<<4) +#define ATRACE_TAG_WINDOW_MANAGER (1<<5) +#define ATRACE_TAG_ACTIVITY_MANAGER (1<<6) +#define ATRACE_TAG_SYNC_MANAGER (1<<7) +#define ATRACE_TAG_AUDIO (1<<8) +#define ATRACE_TAG_VIDEO (1<<9) +#define ATRACE_TAG_CAMERA (1<<10) +#define ATRACE_TAG_HAL (1<<11) +#define ATRACE_TAG_LAST ATRACE_TAG_HAL + +// Reserved for initialization. +#define ATRACE_TAG_NOT_READY (1LL<<63) + +#define ATRACE_TAG_VALID_MASK ((ATRACE_TAG_LAST - 1) | ATRACE_TAG_LAST) + +#ifndef ATRACE_TAG +#define ATRACE_TAG ATRACE_TAG_NEVER +#elif ATRACE_TAG > ATRACE_TAG_VALID_MASK +#error ATRACE_TAG must be defined to be one of the tags defined in cutils/trace.h +#endif + +/** + * Maximum size of a message that can be logged to the trace buffer. + * Note this message includes a tag, the pid, and the string given as the name. + * Names should be kept short to get the most use of the trace buffer. + */ +#define ATRACE_MESSAGE_LENGTH 1024 + +/** + * Opens the trace file for writing and reads the property for initial tags. + * The atrace.tags.enableflags property sets the tags to trace. + * This function should not be explicitly called, the first call to any normal + * trace function will cause it to be run safely. + */ +void atrace_setup(); + +/** + * If tracing is ready, set atrace_enabled_tags to the system property + * debug.atrace.tags.enableflags. Can be used as a sysprop change callback. + */ +void atrace_update_tags(); + +/** + * Flag indicating whether setup has been completed, initialized to 0. + * Nonzero indicates setup has completed. + * Note: This does NOT indicate whether or not setup was successful. + */ +extern int32_t atrace_is_ready; + +/** + * Set of ATRACE_TAG flags to trace for, initialized to ATRACE_TAG_NOT_READY. + * A value of zero indicates setup has failed. + * Any other nonzero value indicates setup has succeeded, and tracing is on. + */ +extern uint64_t atrace_enabled_tags; + +/** + * Handle to the kernel's trace buffer, initialized to -1. + * Any other value indicates setup has succeeded, and is a valid fd for tracing. + */ +extern int atrace_marker_fd; + +/** + * atrace_init readies the process for tracing by opening the trace_marker file. + * Calling any trace function causes this to be run, so calling it is optional. + * This can be explicitly run to avoid setup delay on first trace function. + */ +#define ATRACE_INIT() atrace_init() +static inline void atrace_init() +{ + if (CC_UNLIKELY(!android_atomic_acquire_load(&atrace_is_ready))) { + atrace_setup(); + } +} + +/** + * Get the mask of all tags currently enabled. + * It can be used as a guard condition around more expensive trace calculations. + * Every trace function calls this, which ensures atrace_init is run. + */ +#define ATRACE_GET_ENABLED_TAGS() atrace_get_enabled_tags() +static inline uint64_t atrace_get_enabled_tags() +{ + atrace_init(); + return atrace_enabled_tags; +} + +/** + * Test if a given tag is currently enabled. + * Returns nonzero if the tag is enabled, otherwise zero. + * It can be used as a guard condition around more expensive trace calculations. + */ +#define ATRACE_ENABLED() atrace_is_tag_enabled(ATRACE_TAG) +static inline uint64_t atrace_is_tag_enabled(uint64_t tag) +{ + return atrace_get_enabled_tags() & tag; +} + +/** + * Trace the beginning of a context. name is used to identify the context. + * This is often used to time function execution. + */ +#define ATRACE_BEGIN(name) atrace_begin(ATRACE_TAG, name) +static inline void atrace_begin(uint64_t tag, const char* name) +{ + if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) { + char buf[ATRACE_MESSAGE_LENGTH]; + size_t len; + + len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "B|%d|%s", getpid(), name); + write(atrace_marker_fd, buf, len); + } +} + +/** + * Trace the end of a context. + * This should match up (and occur after) a corresponding ATRACE_BEGIN. + */ +#define ATRACE_END() atrace_end(ATRACE_TAG) +static inline void atrace_end(uint64_t tag) +{ + if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) { + char c = 'E'; + write(atrace_marker_fd, &c, 1); + } +} + +/** + * Traces an integer counter value. name is used to identify the counter. + * This can be used to track how a value changes over time. + */ +#define ATRACE_INT(name, value) atrace_int(ATRACE_TAG, name, value) +static inline void atrace_int(uint64_t tag, const char* name, int32_t value) +{ + if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) { + char buf[ATRACE_MESSAGE_LENGTH]; + size_t len; + + len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "C|%d|%s|%d", + getpid(), name, value); + write(atrace_marker_fd, buf, len); + } +} + +__END_DECLS + +#endif // _LIBS_CUTILS_TRACE_H diff --git a/include/cutils/zygote.h b/include/cutils/zygote.h index 22721a6..a7480d3 100644 --- a/include/cutils/zygote.h +++ b/include/cutils/zygote.h @@ -23,7 +23,6 @@ extern "C" { int zygote_run_oneshot(int sendStdio, int argc, const char **argv); int zygote_run(int argc, const char **argv); -int zygote_run_wait(int argc, const char **argv, void (*post_run_func)(int)); #ifdef __cplusplus } diff --git a/include/netutils/dhcp.h b/include/netutils/dhcp.h index d25e58f..bd2c957 100644 --- a/include/netutils/dhcp.h +++ b/include/netutils/dhcp.h @@ -27,11 +27,18 @@ extern int dhcp_do_request(const char *ifname, char *ipaddr, char *gateway, uint32_t *prefixLength, - char *dns1, - char *dns2, + char *dns[], char *server, uint32_t *lease, char *vendorInfo); +extern int dhcp_do_request_renew(const char *ifname, + char *ipaddr, + char *gateway, + uint32_t *prefixLength, + char *dns[], + char *server, + uint32_t *lease, + char *vendorInfo); extern int dhcp_stop(const char *ifname); extern int dhcp_release_lease(const char *ifname); extern char *dhcp_get_errmsg(); diff --git a/include/sync/sw_sync.h b/include/sync/sw_sync.h new file mode 100644 index 0000000..3bf4110 --- /dev/null +++ b/include/sync/sw_sync.h @@ -0,0 +1,37 @@ +/* + * sw_sync.h + * + * Copyright 2013 Google, Inc + * + * 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 __SYS_CORE_SW_SYNC_H +#define __SYS_CORE_SW_SYNC_H + +#include "sync.h" + +__BEGIN_DECLS + +/* + * sw_sync is mainly intended for testing and should not be compiled into + * production kernels + */ + +int sw_sync_timeline_create(void); +int sw_sync_timeline_inc(int fd, unsigned count); +int sw_sync_fence_create(int fd, const char *name, unsigned value); + +__END_DECLS + +#endif /* __SYS_CORE_SW_SYNC_H */ diff --git a/include/sync/sync.h b/include/sync/sync.h index 918acf6..2e5d82f 100644 --- a/include/sync/sync.h +++ b/include/sync/sync.h @@ -49,14 +49,6 @@ struct sync_pt_info *sync_pt_info(struct sync_fence_info_data *info, struct sync_pt_info *itr); void sync_fence_info_free(struct sync_fence_info_data *info); -/* sw_sync is mainly inteded for testing and should not be complied into - * production kernels - */ - -int sw_sync_timeline_create(void); -int sw_sync_timeline_inc(int fd, unsigned count); -int sw_sync_fence_create(int fd, const char *name, unsigned value); - __END_DECLS #endif /* __SYS_CORE_SYNC_H */ diff --git a/include/system/audio.h b/include/system/audio.h index d246070..da235dd 100644 --- a/include/system/audio.h +++ b/include/system/audio.h @@ -239,6 +239,7 @@ enum { AUDIO_CHANNEL_IN_MONO = AUDIO_CHANNEL_IN_FRONT, AUDIO_CHANNEL_IN_STEREO = (AUDIO_CHANNEL_IN_LEFT | AUDIO_CHANNEL_IN_RIGHT), + AUDIO_CHANNEL_IN_FRONT_BACK = (AUDIO_CHANNEL_IN_FRONT | AUDIO_CHANNEL_IN_BACK), AUDIO_CHANNEL_IN_ALL = (AUDIO_CHANNEL_IN_LEFT | AUDIO_CHANNEL_IN_RIGHT | AUDIO_CHANNEL_IN_FRONT | diff --git a/include/system/window.h b/include/system/window.h index 4698fb3..b8a19c8 100644 --- a/include/system/window.h +++ b/include/system/window.h @@ -321,7 +321,6 @@ enum { enum { NATIVE_WINDOW_FRAMEBUFFER = 0, /* FramebufferNativeWindow */ NATIVE_WINDOW_SURFACE = 1, /* Surface */ - NATIVE_WINDOW_SURFACE_TEXTURE_CLIENT = 2, /* SurfaceTextureClient */ }; /* parameter for NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP diff --git a/init/builtins.c b/init/builtins.c index dc7900e..0f9f131 100644 --- a/init/builtins.c +++ b/init/builtins.c @@ -464,6 +464,7 @@ int do_mount_all(int nargs, char **args) int child_ret = -1; int status; const char *prop; + struct fstab *fstab; if (nargs != 2) { return -1; @@ -487,7 +488,9 @@ int do_mount_all(int nargs, char **args) } else if (pid == 0) { /* child, call fs_mgr_mount_all() */ klog_set_level(6); /* So we can see what fs_mgr_mount_all() does */ - child_ret = fs_mgr_mount_all(args[1]); + fstab = fs_mgr_read_fstab(args[1]); + child_ret = fs_mgr_mount_all(fstab); + fs_mgr_free_fstab(fstab); if (child_ret == -1) { ERROR("fs_mgr_mount_all returned an error\n"); } diff --git a/init/devices.c b/init/devices.c index b07a1a6..e25034c 100644 --- a/init/devices.c +++ b/init/devices.c @@ -83,7 +83,8 @@ struct perm_node { struct platform_node { char *name; - int name_len; + char *path; + int path_len; struct listnode list; }; @@ -215,61 +216,69 @@ static void make_device(const char *path, } } -static void add_platform_device(const char *name) +static void add_platform_device(const char *path) { - int name_len = strlen(name); + int path_len = strlen(path); struct listnode *node; struct platform_node *bus; + const char *name = path; + + if (!strncmp(path, "/devices/", 9)) { + name += 9; + if (!strncmp(name, "platform/", 9)) + name += 9; + } list_for_each_reverse(node, &platform_names) { bus = node_to_item(node, struct platform_node, list); - if ((bus->name_len < name_len) && - (name[bus->name_len] == '/') && - !strncmp(name, bus->name, bus->name_len)) + if ((bus->path_len < path_len) && + (path[bus->path_len] == '/') && + !strncmp(path, bus->path, bus->path_len)) /* subdevice of an existing platform, ignore it */ return; } - INFO("adding platform device %s\n", name); + INFO("adding platform device %s (%s)\n", name, path); bus = calloc(1, sizeof(struct platform_node)); - bus->name = strdup(name); - bus->name_len = name_len; + bus->path = strdup(path); + bus->path_len = path_len; + bus->name = bus->path + (name - path); list_add_tail(&platform_names, &bus->list); } /* - * given a name that may start with a platform device, find the length of the + * given a path that may start with a platform device, find the length of the * platform device prefix. If it doesn't start with a platform device, return * 0. */ -static const char *find_platform_device(const char *name) +static struct platform_node *find_platform_device(const char *path) { - int name_len = strlen(name); + int path_len = strlen(path); struct listnode *node; struct platform_node *bus; list_for_each_reverse(node, &platform_names) { bus = node_to_item(node, struct platform_node, list); - if ((bus->name_len < name_len) && - (name[bus->name_len] == '/') && - !strncmp(name, bus->name, bus->name_len)) - return bus->name; + if ((bus->path_len < path_len) && + (path[bus->path_len] == '/') && + !strncmp(path, bus->path, bus->path_len)) + return bus; } return NULL; } -static void remove_platform_device(const char *name) +static void remove_platform_device(const char *path) { struct listnode *node; struct platform_node *bus; list_for_each_reverse(node, &platform_names) { bus = node_to_item(node, struct platform_node, list); - if (!strcmp(name, bus->name)) { - INFO("removing platform device %s\n", name); - free(bus->name); + if (!strcmp(path, bus->path)) { + INFO("removing platform device %s\n", bus->name); + free(bus->path); list_remove(node); free(bus); return; @@ -355,8 +364,10 @@ static char **get_character_device_symlinks(struct uevent *uevent) char **links; int link_num = 0; int width; + struct platform_node *pdev; - if (strncmp(uevent->path, "/devices/platform/", 18)) + pdev = find_platform_device(uevent->path); + if (!pdev) return NULL; links = malloc(sizeof(char *) * 2); @@ -365,7 +376,7 @@ static char **get_character_device_symlinks(struct uevent *uevent) memset(links, 0, sizeof(char *) * 2); /* skip "/devices/platform/<driver>" */ - parent = strchr(uevent->path + 18, '/'); + parent = strchr(uevent->path + pdev->path_len, '/'); if (!*parent) goto err; @@ -402,7 +413,7 @@ err: static char **parse_platform_block_device(struct uevent *uevent) { const char *device; - const char *path; + struct platform_node *pdev; char *slash; int width; char buf[256]; @@ -414,18 +425,16 @@ static char **parse_platform_block_device(struct uevent *uevent) unsigned int size; struct stat info; + pdev = find_platform_device(uevent->path); + if (!pdev) + return NULL; + device = pdev->name; + char **links = malloc(sizeof(char *) * 4); if (!links) return NULL; memset(links, 0, sizeof(char *) * 4); - /* Drop "/devices/platform/" */ - path = uevent->path; - device = path + 18; - device = find_platform_device(device); - if (!device) - goto err; - INFO("found platform device %s\n", device); snprintf(link_path, sizeof(link_path), "/dev/block/platform/%s", device); @@ -447,17 +456,13 @@ static char **parse_platform_block_device(struct uevent *uevent) links[link_num] = NULL; } - slash = strrchr(path, '/'); + slash = strrchr(uevent->path, '/'); if (asprintf(&links[link_num], "%s/%s", link_path, slash + 1) > 0) link_num++; else links[link_num] = NULL; return links; - -err: - free(links); - return NULL; } static void handle_device(const char *action, const char *devpath, @@ -490,12 +495,12 @@ static void handle_device(const char *action, const char *devpath, static void handle_platform_device_event(struct uevent *uevent) { - const char *name = uevent->path + 18; /* length of /devices/platform/ */ + const char *path = uevent->path; if (!strcmp(uevent->action, "add")) - add_platform_device(name); + add_platform_device(path); else if (!strcmp(uevent->action, "remove")) - remove_platform_device(name); + remove_platform_device(path); } static const char *parse_device_name(struct uevent *uevent, unsigned int len) @@ -533,7 +538,7 @@ static void handle_block_device_event(struct uevent *uevent) snprintf(devpath, sizeof(devpath), "%s%s", base, name); make_dir(base, 0755); - if (!strncmp(uevent->path, "/devices/platform/", 18)) + if (!strncmp(uevent->path, "/devices/", 9)) links = parse_platform_block_device(uevent); handle_device(uevent->action, devpath, uevent->path, 1, diff --git a/init/init_parser.c b/init/init_parser.c index beb9188..686640e 100644 --- a/init/init_parser.c +++ b/init/init_parser.c @@ -571,6 +571,7 @@ void queue_builtin_action(int (*func)(int nargs, char **args), char *name) 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 queue_builtin_action(int (*func)(int nargs, char **args), char *name) 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 action *action_remove_queue_head(void) 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 @@ static void *parse_action(struct parse_state *state, int nargs, char **args) 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/property_service.c b/init/property_service.c index 61dd86f..5780001 100755 --- a/init/property_service.c +++ b/init/property_service.c @@ -123,7 +123,7 @@ static int init_workspace(workspace *w, size_t size) /* 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); + fd = open(PROP_FILENAME, O_RDWR | O_CREAT | O_NOFOLLOW, 0644); if (fd < 0) return -1; @@ -136,12 +136,10 @@ static int init_workspace(workspace *w, size_t size) close(fd); - fd = open("/dev/__properties__", O_RDONLY | O_NOFOLLOW); + fd = open(PROP_FILENAME, O_RDONLY | O_NOFOLLOW); if (fd < 0) return -1; - unlink("/dev/__properties__"); - w->data = data; w->size = size; w->fd = fd; diff --git a/libcutils/Android.mk b/libcutils/Android.mk index 3485392..7931684 100644 --- a/libcutils/Android.mk +++ b/libcutils/Android.mk @@ -121,6 +121,7 @@ LOCAL_SRC_FILES := $(commonSources) \ mq.c \ partition_utils.c \ qtaguid.c \ + trace.c \ uevent.c ifeq ($(TARGET_ARCH),arm) diff --git a/libcutils/fs.c b/libcutils/fs.c index 1226d44..116526d 100644 --- a/libcutils/fs.c +++ b/libcutils/fs.c @@ -26,6 +26,7 @@ #include <errno.h> #include <string.h> #include <limits.h> +#include <stdlib.h> #define ALL_PERMS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO) #define BUF_SIZE 64 diff --git a/libcutils/trace.c b/libcutils/trace.c new file mode 100644 index 0000000..152ea61 --- /dev/null +++ b/libcutils/trace.c @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <pthread.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <cutils/atomic.h> +#include <cutils/compiler.h> +#include <cutils/properties.h> +#include <cutils/trace.h> + +#define LOG_TAG "cutils-trace" +#include <cutils/log.h> + +int32_t atrace_is_ready = 0; +int atrace_marker_fd = -1; +uint64_t atrace_enabled_tags = ATRACE_TAG_NOT_READY; +static pthread_once_t atrace_once_control = PTHREAD_ONCE_INIT; +static pthread_mutex_t atrace_tags_mutex = PTHREAD_MUTEX_INITIALIZER; + +// Read the sysprop and return the value tags should be set to +static uint64_t atrace_get_property() +{ + char value[PROPERTY_VALUE_MAX]; + char *endptr; + uint64_t tags; + + property_get("debug.atrace.tags.enableflags", value, "0"); + errno = 0; + tags = strtoull(value, &endptr, 0); + if (value[0] == '\0' || *endptr != '\0') { + ALOGE("Error parsing trace property: Not a number: %s", value); + return 0; + } else if (errno == ERANGE || tags == ULLONG_MAX) { + ALOGE("Error parsing trace property: Number too large: %s", value); + return 0; + } + return (tags | ATRACE_TAG_ALWAYS) & ATRACE_TAG_VALID_MASK; +} + +// Update tags if tracing is ready. Useful as a sysprop change callback. +void atrace_update_tags() +{ + uint64_t tags; + if (CC_UNLIKELY(android_atomic_acquire_load(&atrace_is_ready))) { + tags = atrace_get_property(); + pthread_mutex_lock(&atrace_tags_mutex); + atrace_enabled_tags = tags; + pthread_mutex_unlock(&atrace_tags_mutex); + } +} + +static void atrace_init_once() +{ + atrace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_WRONLY); + if (atrace_marker_fd == -1) { + ALOGE("Error opening trace file: %s (%d)", strerror(errno), errno); + atrace_enabled_tags = 0; + goto done; + } + + atrace_enabled_tags = atrace_get_property(); + +done: + android_atomic_release_store(1, &atrace_is_ready); +} + +void atrace_setup() +{ + pthread_once(&atrace_once_control, atrace_init_once); +} diff --git a/libcutils/zygote.c b/libcutils/zygote.c index 75ce3ba..37236e8 100644 --- a/libcutils/zygote.c +++ b/libcutils/zygote.c @@ -159,44 +159,6 @@ static int send_request(int fd, int sendStdio, int argc, const char **argv) #endif /* HAVE_ANDROID_OS */ } -int zygote_run_wait(int argc, const char **argv, void (*post_run_func)(int)) -{ - int fd; - int pid; - int err; - const char *newargv[argc + 1]; - - fd = socket_local_client(ZYGOTE_SOCKET, - ANDROID_SOCKET_NAMESPACE_RESERVED, AF_LOCAL); - - if (fd < 0) { - return -1; - } - - // The command socket is passed to the peer as close-on-exec - // and will close when the peer dies - newargv[0] = "--peer-wait"; - memcpy(newargv + 1, argv, argc * sizeof(*argv)); - - pid = send_request(fd, 1, argc + 1, newargv); - - if (pid > 0 && post_run_func != NULL) { - post_run_func(pid); - } - - // Wait for socket to close - do { - int dummy; - err = read(fd, &dummy, sizeof(dummy)); - } while ((err < 0 && errno == EINTR) || err != 0); - - do { - err = close(fd); - } while (err < 0 && errno == EINTR); - - return 0; -} - /** * Spawns a new dalvik instance via the Zygote process. The non-zygote * arguments are passed to com.android.internal.os.RuntimeInit(). The diff --git a/libnetutils/dhcp_utils.c b/libnetutils/dhcp_utils.c index b4caaf9..bd48eff 100644 --- a/libnetutils/dhcp_utils.c +++ b/libnetutils/dhcp_utils.c @@ -88,16 +88,17 @@ static int fill_ip_info(const char *interface, char *ipaddr, char *gateway, uint32_t *prefixLength, - char *dns1, - char *dns2, + char *dns[], char *server, uint32_t *lease, - char *vendorInfo) + char *vendorInfo, + char *domain) { char prop_name[PROPERTY_KEY_MAX]; char prop_value[PROPERTY_VALUE_MAX]; /* Interface name after converting p2p0-p2p0-X to p2p to reuse system properties */ char p2p_interface[MAX_INTERFACE_LENGTH]; + int x; get_p2p_interface_replacement(interface, p2p_interface); @@ -111,7 +112,7 @@ static int fill_ip_info(const char *interface, property_get(prop_name, server, NULL); //TODO: Handle IPv6 when we change system property usage - if (strcmp(gateway, "0.0.0.0") == 0) { + if (gateway[0] == '\0' || strncmp(gateway, "0.0.0.0", 7) == 0) { //DHCP server is our best bet as gateway strncpy(gateway, server, PROPERTY_VALUE_MAX); } @@ -138,11 +139,11 @@ static int fill_ip_info(const char *interface, } *prefixLength = p; } - snprintf(prop_name, sizeof(prop_name), "%s.%s.dns1", DHCP_PROP_NAME_PREFIX, p2p_interface); - property_get(prop_name, dns1, NULL); - snprintf(prop_name, sizeof(prop_name), "%s.%s.dns2", DHCP_PROP_NAME_PREFIX, p2p_interface); - property_get(prop_name, dns2, NULL); + for (x=0; dns[x] != NULL; x++) { + snprintf(prop_name, sizeof(prop_name), "%s.%s.dns%d", DHCP_PROP_NAME_PREFIX, p2p_interface, x+1); + property_get(prop_name, dns[x], NULL); + } snprintf(prop_name, sizeof(prop_name), "%s.%s.leasetime", DHCP_PROP_NAME_PREFIX, p2p_interface); if (property_get(prop_name, prop_value, NULL)) { @@ -153,6 +154,10 @@ static int fill_ip_info(const char *interface, p2p_interface); property_get(prop_name, vendorInfo, NULL); + snprintf(prop_name, sizeof(prop_name), "%s.%s.domain", DHCP_PROP_NAME_PREFIX, + p2p_interface); + property_get(prop_name, domain, NULL); + return 0; } @@ -177,11 +182,11 @@ int dhcp_do_request(const char *interface, char *ipaddr, char *gateway, uint32_t *prefixLength, - char *dns1, - char *dns2, + char *dns[], char *server, uint32_t *lease, - char *vendorInfo) + char *vendorInfo, + char *domain) { char result_prop_name[PROPERTY_KEY_MAX]; char daemon_prop_name[PROPERTY_KEY_MAX]; @@ -232,17 +237,10 @@ int dhcp_do_request(const char *interface, } if (strcmp(prop_value, "ok") == 0) { char dns_prop_name[PROPERTY_KEY_MAX]; - if (fill_ip_info(interface, ipaddr, gateway, prefixLength, - dns1, dns2, server, lease, vendorInfo) == -1) { + if (fill_ip_info(interface, ipaddr, gateway, prefixLength, dns, + server, lease, vendorInfo, domain) == -1) { return -1; } - - /* copy dns data to system properties - TODO - remove this after we have async - * notification of renewal's */ - snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns1", interface); - property_set(dns_prop_name, *dns1 ? ipaddr_to_string(*dns1) : ""); - snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns2", interface); - property_set(dns_prop_name, *dns2 ? ipaddr_to_string(*dns2) : ""); return 0; } else { snprintf(errmsg, sizeof(errmsg), "DHCP result was %s", prop_value); @@ -327,11 +325,11 @@ int dhcp_do_request_renew(const char *interface, char *ipaddr, char *gateway, uint32_t *prefixLength, - char *dns1, - char *dns2, + char *dns[], char *server, uint32_t *lease, - char *vendorInfo) + char *vendorInfo, + char *domain) { char result_prop_name[PROPERTY_KEY_MAX]; char prop_value[PROPERTY_VALUE_MAX] = {'\0'}; @@ -367,8 +365,8 @@ int dhcp_do_request_renew(const char *interface, return -1; } if (strcmp(prop_value, "ok") == 0) { - fill_ip_info(interface, ipaddr, gateway, prefixLength, - dns1, dns2, server, lease, vendorInfo); + fill_ip_info(interface, ipaddr, gateway, prefixLength, dns, + server, lease, vendorInfo, domain); return 0; } else { snprintf(errmsg, sizeof(errmsg), "DHCP Renew result was %s", prop_value); diff --git a/logwrapper/Android.mk b/logwrapper/Android.mk index 5fd6356..b4b6b29 100644 --- a/logwrapper/Android.mk +++ b/logwrapper/Android.mk @@ -1,7 +1,34 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) + +# ======================================================== +# Static library +# ======================================================== +include $(CLEAR_VARS) +LOCAL_MODULE := liblogwrap +LOCAL_SRC_FILES := logwrap.c +LOCAL_SHARED_LIBRARIES := libcutils liblog +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include +include $(BUILD_STATIC_LIBRARY) + +# ======================================================== +# Shared library +# ======================================================== +include $(CLEAR_VARS) +LOCAL_MODULE := liblogwrap +LOCAL_SHARED_LIBRARIES := libcutils liblog +LOCAL_WHOLE_STATIC_LIBRARIES := liblogwrap +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include +include $(BUILD_SHARED_LIBRARY) + +# ======================================================== +# Executable +# ======================================================== +include $(CLEAR_VARS) LOCAL_SRC_FILES:= logwrapper.c LOCAL_MODULE := logwrapper -LOCAL_STATIC_LIBRARIES := liblog +LOCAL_STATIC_LIBRARIES := liblog liblogwrap include $(BUILD_EXECUTABLE) diff --git a/logwrapper/include/logwrap/logwrap.h b/logwrapper/include/logwrap/logwrap.h new file mode 100644 index 0000000..2be8736 --- /dev/null +++ b/logwrapper/include/logwrap/logwrap.h @@ -0,0 +1,60 @@ +/* system/core/include/logwrap/logwrap.h + * + * Copyright 2013, 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 __LIBS_LOGWRAP_H +#define __LIBS_LOGWRAP_H + +#include <stdbool.h> + +__BEGIN_DECLS + +/* + * Run a command while logging its stdout and stderr + * + * WARNING: while this function is running it will clear all SIGCHLD handlers + * if you rely on SIGCHLD in the caller there is a chance zombies will be + * created if you're not calling waitpid after calling this. This function will + * log a warning when it clears SIGCHLD for processes other than the child it + * created. + * + * Arguments: + * argc: the number of elements in argv + * argv: an array of strings containing the command to be executed and its + * arguments as separate strings. argv does not need to be + * NULL-terminated + * status: the equivalent child status as populated by wait(status). This + * value is only valid when logwrap successfully completes. If NULL + * the return value of the child will be the function's return value. + * ignore_int_quit: set to true if you want to completely ignore SIGINT and + * SIGQUIT while logwrap is running. This may force the end-user to + * send a signal twice to signal the caller (once for the child, and + * once for the caller) + * logwrap: when true, log messages from the child + * + * Return value: + * 0 when logwrap successfully run the child process and captured its status + * -1 when an internal error occurred + * -ECHILD if status is NULL and the child didn't exit properly + * the return value of the child if it exited properly and status is NULL + * + */ +int android_fork_execvp(int argc, char* argv[], int *status, bool ignore_int_quit, + bool logwrap); + +__END_DECLS + +#endif /* __LIBS_LOGWRAP_H */ diff --git a/logwrapper/logwrap.c b/logwrapper/logwrap.c new file mode 100644 index 0000000..d9247ec --- /dev/null +++ b/logwrapper/logwrap.c @@ -0,0 +1,307 @@ +/* + * Copyright (C) 2008 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 <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <signal.h> +#include <poll.h> +#include <sys/wait.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> +#include <libgen.h> +#include <stdbool.h> + +#include <logwrap/logwrap.h> +#include "private/android_filesystem_config.h" +#include "cutils/log.h" + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) + +static int signal_fd_write; + +#define ERROR(fmt, args...) \ +do { \ + fprintf(stderr, fmt, ## args); \ + ALOG(LOG_ERROR, "logwrapper", fmt, ## args); \ +} while(0) + +#define FATAL_CHILD(fmt, args...) \ +do { \ + ERROR(fmt, ## args); \ + _exit(-1); \ +} while(0) + +static int parent(const char *tag, int parent_read, int signal_fd, pid_t pid, + int *chld_sts, bool logwrap) { + int status = 0; + char buffer[4096]; + struct pollfd poll_fds[] = { + [0] = { + .fd = signal_fd, + .events = POLLIN, + }, + [1] = { + .fd = parent_read, + .events = POLLIN, + }, + }; + int rc = 0; + sigset_t chldset; + + int a = 0; // start index of unprocessed data + int b = 0; // end index of unprocessed data + int sz; + bool remote_hung = false; + bool found_child = false; + + char *btag = basename(tag); + if (!btag) btag = (char*) tag; + + sigemptyset(&chldset); + sigaddset(&chldset, SIGCHLD); + pthread_sigmask(SIG_UNBLOCK, &chldset, NULL); + + while (!found_child) { + if (poll(poll_fds, remote_hung ? 1 : 2, -1) < 0) { + if (errno == EINTR) + continue; + ERROR("poll failed\n"); + rc = -1; + goto err_poll; + } + + if (!remote_hung) { + if (poll_fds[1].revents & POLLIN) { + sz = read(parent_read, &buffer[b], sizeof(buffer) - 1 - b); + + sz += b; + // Log one line at a time + for (b = 0; b < sz; b++) { + if (buffer[b] == '\r') { + buffer[b] = '\0'; + } else if (buffer[b] == '\n') { + buffer[b] = '\0'; + if (logwrap) + ALOG(LOG_INFO, btag, "%s", &buffer[a]); + a = b + 1; + } + } + + if (a == 0 && b == sizeof(buffer) - 1) { + // buffer is full, flush + buffer[b] = '\0'; + if (logwrap) + ALOG(LOG_INFO, btag, "%s", &buffer[a]); + b = 0; + } else if (a != b) { + // Keep left-overs + b -= a; + memmove(buffer, &buffer[a], b); + a = 0; + } else { + a = 0; + b = 0; + } + } + + if (poll_fds[1].revents & POLLHUP) { + remote_hung = true; + } + } + + if (poll_fds[0].revents & POLLIN) { + char tmp[32]; + int ret; + + read(signal_fd, tmp, sizeof(tmp)); + while (!found_child) { + do { + ret = waitpid(-1, &status, WNOHANG); + } while (ret < 0 && errno == EINTR); + + if (ret <= 0) + break; + + found_child = (pid == ret); + } + } + } + + if (chld_sts != NULL) { + *chld_sts = status; + } else { + if (WIFEXITED(status)) + rc = WEXITSTATUS(status); + else + rc = -ECHILD; + } + + if (logwrap) { + // Flush remaining data + if (a != b) { + buffer[b] = '\0'; + ALOG(LOG_INFO, btag, "%s", &buffer[a]); + } + if (WIFEXITED(status)) { + if (WEXITSTATUS(status)) + ALOG(LOG_INFO, "logwrapper", "%s terminated by exit(%d)", btag, + WEXITSTATUS(status)); + } else { + if (WIFSIGNALED(status)) + ALOG(LOG_INFO, "logwrapper", "%s terminated by signal %d", btag, + WTERMSIG(status)); + else if (WIFSTOPPED(status)) + ALOG(LOG_INFO, "logwrapper", "%s stopped by signal %d", btag, + WSTOPSIG(status)); + } + } + +err_poll: + return rc; +} + +static void child(int argc, char* argv[], bool logwrap) { + // create null terminated argv_child array + char* argv_child[argc + 1]; + memcpy(argv_child, argv, argc * sizeof(char *)); + argv_child[argc] = NULL; + + if (execvp(argv_child[0], argv_child)) { + FATAL_CHILD("executing %s failed: %s\n", argv_child[0], + strerror(errno)); + } +} + +static void sigchld_handler(int sig) { + write(signal_fd_write, &sig, 1); +} + +int android_fork_execvp(int argc, char* argv[], int *status, bool ignore_int_quit, + bool logwrap) { + pid_t pid; + int parent_ptty; + int child_ptty; + char *child_devname = NULL; + struct sigaction chldact; + struct sigaction oldchldact; + struct sigaction intact; + struct sigaction quitact; + sigset_t blockset; + sigset_t oldset; + int sockets[2]; + int rc = 0; + + /* Use ptty instead of socketpair so that STDOUT is not buffered */ + parent_ptty = open("/dev/ptmx", O_RDWR); + if (parent_ptty < 0) { + ERROR("Cannot create parent ptty\n"); + rc = -1; + goto err_open; + } + + if (grantpt(parent_ptty) || unlockpt(parent_ptty) || + ((child_devname = (char*)ptsname(parent_ptty)) == 0)) { + ERROR("Problem with /dev/ptmx\n"); + rc = -1; + goto err_ptty; + } + + sigemptyset(&blockset); + sigaddset(&blockset, SIGINT); + sigaddset(&blockset, SIGQUIT); + sigaddset(&blockset, SIGCHLD); + pthread_sigmask(SIG_BLOCK, &blockset, &oldset); + + pid = fork(); + if (pid < 0) { + ERROR("Failed to fork\n"); + rc = -1; + goto err_fork; + } else if (pid == 0) { + pthread_sigmask(SIG_SETMASK, &oldset, NULL); + close(parent_ptty); + + child_ptty = open(child_devname, O_RDWR); + if (child_ptty < 0) { + FATAL_CHILD("Problem with child ptty\n"); + return -1; + } + + // redirect stdout and stderr + dup2(child_ptty, 1); + dup2(child_ptty, 2); + close(child_ptty); + + child(argc, argv, logwrap); + } else { + struct sigaction ignact; + + memset(&chldact, 0, sizeof(chldact)); + chldact.sa_handler = sigchld_handler; + chldact.sa_flags = SA_NOCLDSTOP; + + sigaction(SIGCHLD, &chldact, &oldchldact); + if ((!(oldchldact.sa_flags & SA_SIGINFO) && + oldchldact.sa_handler != SIG_DFL && + oldchldact.sa_handler != SIG_IGN) || + ((oldchldact.sa_flags & SA_SIGINFO) && + oldchldact.sa_sigaction != NULL)) { + ALOG(LOG_WARN, "logwrapper", "logwrap replaced the SIGCHLD " + "handler and might cause interaction issues"); + } + + if (ignore_int_quit) { + memset(&ignact, 0, sizeof(ignact)); + ignact.sa_handler = SIG_IGN; + sigaction(SIGINT, &ignact, &intact); + sigaction(SIGQUIT, &ignact, &quitact); + } + + rc = socketpair(AF_UNIX, SOCK_STREAM, 0, sockets); + if (rc == -1) { + ERROR("socketpair failed: %s\n", strerror(errno)); + goto err_socketpair; + } + + fcntl(sockets[0], F_SETFD, FD_CLOEXEC); + fcntl(sockets[0], F_SETFL, O_NONBLOCK); + fcntl(sockets[1], F_SETFD, FD_CLOEXEC); + fcntl(sockets[1], F_SETFL, O_NONBLOCK); + + signal_fd_write = sockets[0]; + + rc = parent(argv[0], parent_ptty, sockets[1], pid, status, logwrap); + } + + close(sockets[0]); + close(sockets[1]); +err_socketpair: + if (ignore_int_quit) { + sigaction(SIGINT, &intact, NULL); + sigaction(SIGQUIT, &quitact, NULL); + } + sigaction(SIGCHLD, &oldchldact, NULL); +err_fork: + pthread_sigmask(SIG_SETMASK, &oldset, NULL); +err_ptty: + close(parent_ptty); +err_open: + return rc; +} diff --git a/logwrapper/logwrapper.c b/logwrapper/logwrapper.c index dd777c0..ed71a29 100644 --- a/logwrapper/logwrapper.c +++ b/logwrapper/logwrapper.c @@ -14,17 +14,12 @@ * limitations under the License. */ -#include <string.h> -#include <sys/types.h> -#include <sys/wait.h> #include <stdio.h> #include <stdlib.h> -#include <unistd.h> -#include <errno.h> -#include <fcntl.h> -#include <libgen.h> +#include <sys/wait.h> + +#include <logwrap/logwrap.h> -#include "private/android_filesystem_config.h" #include "cutils/log.h" void fatal(const char *msg) { @@ -45,90 +40,10 @@ void usage() { " fault address is set to the status of wait()\n"); } -void parent(const char *tag, int seg_fault_on_exit, int parent_read) { - int status; - char buffer[4096]; - - int a = 0; // start index of unprocessed data - int b = 0; // end index of unprocessed data - int sz; - - char *btag = basename(tag); - if (!btag) btag = (char*) tag; - - while ((sz = read(parent_read, &buffer[b], sizeof(buffer) - 1 - b)) > 0) { - - sz += b; - // Log one line at a time - for (b = 0; b < sz; b++) { - if (buffer[b] == '\r') { - buffer[b] = '\0'; - } else if (buffer[b] == '\n') { - buffer[b] = '\0'; - ALOG(LOG_INFO, btag, "%s", &buffer[a]); - a = b + 1; - } - } - - if (a == 0 && b == sizeof(buffer) - 1) { - // buffer is full, flush - buffer[b] = '\0'; - ALOG(LOG_INFO, btag, "%s", &buffer[a]); - b = 0; - } else if (a != b) { - // Keep left-overs - b -= a; - memmove(buffer, &buffer[a], b); - a = 0; - } else { - a = 0; - b = 0; - } - - } - // Flush remaining data - if (a != b) { - buffer[b] = '\0'; - ALOG(LOG_INFO, btag, "%s", &buffer[a]); - } - status = 0xAAAA; - if (wait(&status) != -1) { // Wait for child - if (WIFEXITED(status) && WEXITSTATUS(status)) - ALOG(LOG_INFO, "logwrapper", "%s terminated by exit(%d)", tag, - WEXITSTATUS(status)); - else if (WIFSIGNALED(status)) - ALOG(LOG_INFO, "logwrapper", "%s terminated by signal %d", tag, - WTERMSIG(status)); - else if (WIFSTOPPED(status)) - ALOG(LOG_INFO, "logwrapper", "%s stopped by signal %d", tag, - WSTOPSIG(status)); - } else - ALOG(LOG_INFO, "logwrapper", "%s wait() failed: %s (%d)", tag, - strerror(errno), errno); - if (seg_fault_on_exit) - *(int *)status = 0; // causes SIGSEGV with fault_address = status -} - -void child(int argc, char* argv[]) { - // create null terminated argv_child array - char* argv_child[argc + 1]; - memcpy(argv_child, argv, argc * sizeof(char *)); - argv_child[argc] = NULL; - - if (execvp(argv_child[0], argv_child)) { - ALOG(LOG_ERROR, "logwrapper", - "executing %s failed: %s\n", argv_child[0], strerror(errno)); - exit(-1); - } -} - int main(int argc, char* argv[]) { - pid_t pid; int seg_fault_on_exit = 0; - - int parent_ptty; - int child_ptty; - char *child_devname = NULL; + int status = 0xAAAA; + int rc; if (argc < 2) { usage(); @@ -144,43 +59,17 @@ int main(int argc, char* argv[]) { usage(); } - /* Use ptty instead of socketpair so that STDOUT is not buffered */ - parent_ptty = open("/dev/ptmx", O_RDWR); - if (parent_ptty < 0) { - fatal("Cannot create parent ptty\n"); + rc = android_fork_execvp(argc - 1, &argv[1], &status, true, true); + if (!rc) { + if (WIFEXITED(status)) + rc = WEXITSTATUS(status); + else + rc = -ECHILD; } - if (grantpt(parent_ptty) || unlockpt(parent_ptty) || - ((child_devname = (char*)ptsname(parent_ptty)) == 0)) { - fatal("Problem with /dev/ptmx\n"); - } - - pid = fork(); - if (pid < 0) { - fatal("Failed to fork\n"); - } else if (pid == 0) { - child_ptty = open(child_devname, O_RDWR); - if (child_ptty < 0) { - fatal("Problem with child ptty\n"); - } - - // redirect stdout and stderr - close(parent_ptty); - dup2(child_ptty, 1); - dup2(child_ptty, 2); - close(child_ptty); - - child(argc - 1, &argv[1]); - - } else { - // switch user and group to "log" - // this may fail if we are not root, - // but in that case switching user/group is unnecessary - setgid(AID_LOG); - setuid(AID_LOG); - - parent(argv[1], seg_fault_on_exit, parent_ptty); + if (seg_fault_on_exit) { + *(int *)status = 0; // causes SIGSEGV with fault_address = status } - return 0; + return rc; } diff --git a/rootdir/Android.mk b/rootdir/Android.mk index 64ff522..e6887bb 100644 --- a/rootdir/Android.mk +++ b/rootdir/Android.mk @@ -7,25 +7,6 @@ copy_from := \ etc/dbus.conf \ etc/hosts -ifeq ($(TARGET_PRODUCT),full) -copy_from += etc/vold.fstab -endif - -ifeq ($(TARGET_PRODUCT),full_x86) -copy_from += etc/vold.fstab -endif - -ifeq ($(TARGET_PRODUCT),full_mips) -copy_from += etc/vold.fstab -endif - -# the /system/etc/init.goldfish.sh is needed to enable emulator support -# in the system image. In theory, we don't need these for -user builds -# which are device-specific. However, these builds require at the moment -# to run the dex pre-optimization *in* the emulator. So keep the file until -# we are capable of running dex preopt on the host. -# -copy_from += etc/init.goldfish.sh copy_to := $(addprefix $(TARGET_OUT)/,$(copy_from)) copy_from := $(addprefix $(LOCAL_PATH)/,$(copy_from)) @@ -56,20 +37,6 @@ $(INSTALLED_RAMDISK_TARGET): $(file) # init.usb.rc is handled by build/target/product/core.rc -# Just like /system/etc/init.goldfish.sh, the /init.godlfish.rc is here -# to allow -user builds to properly run the dex pre-optimization pass in -# the emulator. -file := $(TARGET_ROOT_OUT)/init.goldfish.rc -$(file) : $(LOCAL_PATH)/etc/init.goldfish.rc | $(ACP) - $(transform-prebuilt-to-target) -ALL_PREBUILT += $(file) -$(INSTALLED_RAMDISK_TARGET): $(file) - -file := $(TARGET_ROOT_OUT)/ueventd.goldfish.rc -$(file) : $(LOCAL_PATH)/etc/ueventd.goldfish.rc | $(ACP) - $(transform-prebuilt-to-target) -ALL_PREBUILT += $(file) -$(INSTALLED_RAMDISK_TARGET): $(file) # create some directories (some are mount points) DIRS := $(addprefix $(TARGET_ROOT_OUT)/, \ diff --git a/rootdir/etc/init.goldfish.rc b/rootdir/etc/init.goldfish.rc deleted file mode 100644 index a0c1c4f..0000000 --- a/rootdir/etc/init.goldfish.rc +++ /dev/null @@ -1,82 +0,0 @@ -on early-init - export EXTERNAL_STORAGE /mnt/sdcard - mkdir /mnt/sdcard 0000 system system - # for backwards compatibility - symlink /mnt/sdcard /sdcard - -on boot - setsebool in_qemu 1 - restorecon /sys/qemu_trace/process_name - restorecon /sys/qemu_trace/state - restorecon /sys/qemu_trace/symbol - setprop ARGH ARGH - setprop net.eth0.gw 10.0.2.2 - setprop net.eth0.dns1 10.0.2.3 - setprop net.gprs.local-ip 10.0.2.15 - setprop ro.radio.use-ppp no - setprop ro.build.product generic - setprop ro.product.device generic - -# fake some battery state - setprop status.battery.state Slow - setprop status.battery.level 5 - setprop status.battery.level_raw 50 - setprop status.battery.level_scale 9 - -# disable some daemons the emulator doesn't want - stop dund - stop akmd - -# start essential services - start qemud - start goldfish-logcat - start goldfish-setup - - setprop ro.setupwizard.mode EMULATOR - -# enable Google-specific location features, -# like NetworkLocationProvider and LocationCollector - setprop ro.com.google.locationfeatures 1 - -# For the emulator, which bypasses Setup Wizard, you can specify -# account info for the device via these two properties. Google -# Login Service will insert these accounts into the database when -# it is created (ie, after a data wipe). -# -# setprop ro.config.hosted_account username@hosteddomain.org:password -# setprop ro.config.google_account username@gmail.com:password -# -# You MUST have a Google account on the device, and you MAY -# additionally have a hosted account. No other configuration is -# supported, and arbitrary breakage may result if you specify -# something else. - -service goldfish-setup /system/etc/init.goldfish.sh - user root - group root - oneshot - -# The qemu-props program is used to set various system -# properties on boot. It must be run early during the boot -# process to avoid race conditions with other daemons that -# might read them (e.g. surface flinger), so define it in -# class 'core' -# -service qemu-props /system/bin/qemu-props - class core - user root - group root - oneshot - -service qemud /system/bin/qemud - socket qemud stream 666 - oneshot - -# -Q is a special logcat option that forces the -# program to check wether it runs on the emulator -# if it does, it redirects its output to the device -# named by the androidboot.console kernel option -# if not, is simply exits immediately - -service goldfish-logcat /system/bin/logcat -Q - oneshot diff --git a/rootdir/etc/init.goldfish.sh b/rootdir/etc/init.goldfish.sh deleted file mode 100755 index ece75b4..0000000 --- a/rootdir/etc/init.goldfish.sh +++ /dev/null @@ -1,68 +0,0 @@ -#!/system/bin/sh - -# Setup networking when boot starts -ifconfig eth0 10.0.2.15 netmask 255.255.255.0 up -route add default gw 10.0.2.2 dev eth0 - -# ro.kernel.android.qemud is normally set when we -# want the RIL (radio interface layer) to talk to -# the emulated modem through qemud. -# -# However, this will be undefined in two cases: -# -# - When we want the RIL to talk directly to a guest -# serial device that is connected to a host serial -# device by the emulator. -# -# - We don't want to use the RIL but the VM-based -# modem emulation that runs inside the guest system -# instead. -# -# The following detects the latter case and sets up the -# system for it. -# -qemud=`getprop ro.kernel.android.qemud` -case "$qemud" in - "") - radio_ril=`getprop ro.kernel.android.ril` - case "$radio_ril" in - "") - # no need for the radio interface daemon - # telephony is entirely emulated in Java - setprop ro.radio.noril yes - stop ril-daemon - ;; - esac - ;; -esac - -# Setup additionnal DNS servers if needed -num_dns=`getprop ro.kernel.ndns` -case "$num_dns" in - 2) setprop net.eth0.dns2 10.0.2.4 - ;; - 3) setprop net.eth0.dns2 10.0.2.4 - setprop net.eth0.dns3 10.0.2.5 - ;; - 4) setprop net.eth0.dns2 10.0.2.4 - setprop net.eth0.dns3 10.0.2.5 - setprop net.eth0.dns4 10.0.2.6 - ;; -esac - -# disable boot animation for a faster boot sequence when needed -boot_anim=`getprop ro.kernel.android.bootanim` -case "$boot_anim" in - 0) setprop debug.sf.nobootanimation 1 - ;; -esac - -# set up the second interface (for inter-emulator connections) -# if required -my_ip=`getprop net.shared_net_ip` -case "$my_ip" in - "") - ;; - *) ifconfig eth1 "$my_ip" netmask 255.255.255.0 up - ;; -esac diff --git a/rootdir/etc/ueventd.goldfish.rc b/rootdir/etc/ueventd.goldfish.rc deleted file mode 100644 index 8de7049..0000000 --- a/rootdir/etc/ueventd.goldfish.rc +++ /dev/null @@ -1,5 +0,0 @@ -# These settings are specific to running under the Android emulator -/dev/qemu_trace 0666 system system -/dev/qemu_pipe 0666 system system -/dev/ttyS* 0666 system system -/proc 0666 system system diff --git a/rootdir/etc/vold.fstab b/rootdir/etc/vold.fstab deleted file mode 100644 index 4aad8dc..0000000 --- a/rootdir/etc/vold.fstab +++ /dev/null @@ -1,24 +0,0 @@ -## Vold 2.0 Generic fstab -## - San Mehat (san@android.com) -## - -####################### -## Regular device mount -## -## Format: dev_mount <label> <mount_point> <part> <sysfs_path1...> -## label - Label for the volume -## mount_point - Where the volume will be mounted -## part - Partition # (1 based), or 'auto' for first usable partition. -## <sysfs_path> - List of sysfs paths to source devices -###################### - -## Example of a standard sdcard mount for the emulator / Dream -# Mounts the first usable partition of the specified device -dev_mount sdcard /mnt/sdcard auto /devices/platform/goldfish_mmc.0 /devices/platform/msm_sdcc.2/mmc_host/mmc1 - -## Example of a dual card setup -# dev_mount left_sdcard /sdcard1 auto /devices/platform/goldfish_mmc.0 /devices/platform/msm_sdcc.2/mmc_host/mmc1 -# dev_mount right_sdcard /sdcard2 auto /devices/platform/goldfish_mmc.1 /devices/platform/msm_sdcc.3/mmc_host/mmc1 - -## Example of specifying a specific partition for mounts -# dev_mount sdcard /sdcard 2 /devices/platform/goldfish_mmc.0 /devices/platform/msm_sdcc.2/mmc_host/mmc1 diff --git a/rootdir/init.rc b/rootdir/init.rc index d6182e8..832c3f2 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -37,7 +37,7 @@ loglevel 3 export ANDROID_STORAGE /storage export ASEC_MOUNTPOINT /mnt/asec export LOOP_MOUNTPOINT /mnt/obb - export BOOTCLASSPATH /system/framework/core.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/telephony-common.jar:/system/framework/mms-common.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/apache-xml.jar + export BOOTCLASSPATH /system/framework/core.jar:/system/framework/core-junit.jar:/system/framework/bouncycastle.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/telephony-common.jar:/system/framework/voip-common.jar:/system/framework/mms-common.jar:/system/framework/android.policy.jar:/system/framework/services.jar:/system/framework/apache-xml.jar # Backward compatibility symlink /system/etc /etc @@ -214,6 +214,7 @@ on post-fs-data mkdir /data/misc/wifi 0770 wifi wifi chmod 0660 /data/misc/wifi/wpa_supplicant.conf mkdir /data/local 0751 root root + mkdir /data/misc/media 0700 media media # For security reasons, /data/local/tmp should always be empty. # Do not place files or directories in /data/local/tmp @@ -288,10 +289,14 @@ on boot chown system system /sys/devices/system/cpu/cpufreq/interactive/timer_rate chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/timer_rate + chown system system /sys/devices/system/cpu/cpufreq/interactive/timer_slack + chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/timer_slack chown system system /sys/devices/system/cpu/cpufreq/interactive/min_sample_time chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/min_sample_time chown system system /sys/devices/system/cpu/cpufreq/interactive/hispeed_freq chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/hispeed_freq + chown system system /sys/devices/system/cpu/cpufreq/interactive/target_loads + chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/target_loads chown system system /sys/devices/system/cpu/cpufreq/interactive/go_hispeed_load chmod 0660 /sys/devices/system/cpu/cpufreq/interactive/go_hispeed_load chown system system /sys/devices/system/cpu/cpufreq/interactive/above_hispeed_delay diff --git a/rootdir/init.usb.rc b/rootdir/init.usb.rc index f37b630..15467cc 100644 --- a/rootdir/init.usb.rc +++ b/rootdir/init.usb.rc @@ -88,5 +88,4 @@ on property:sys.usb.config=accessory,audio_source,adb # Used to set USB configuration at boot and to switch the configuration # when changing the default configuration on property:persist.sys.usb.config=* - setprop sys.usb.config none setprop sys.usb.config ${persist.sys.usb.config} diff --git a/run-as/package.c b/run-as/package.c index 143d647..683dae6 100644 --- a/run-as/package.c +++ b/run-as/package.c @@ -76,13 +76,30 @@ map_file(const char* filename, size_t* filesize) struct stat st; size_t length = 0; void* address = NULL; + gid_t oldegid; *filesize = 0; + /* + * Temporarily switch effective GID to allow us to read + * the packages file + */ + + oldegid = getegid(); + if (setegid(AID_SYSTEM) < 0) { + return NULL; + } + /* open the file for reading */ fd = TEMP_FAILURE_RETRY(open(filename, O_RDONLY)); - if (fd < 0) + if (fd < 0) { return NULL; + } + + /* restore back to our old egid */ + if (setegid(oldegid) < 0) { + goto EXIT; + } /* get its size */ ret = TEMP_FAILURE_RETRY(fstat(fd, &st)); diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c index 8d87ee9..bff6e67 100644 --- a/sdcard/sdcard.c +++ b/sdcard/sdcard.c @@ -28,6 +28,8 @@ #include <limits.h> #include <ctype.h> #include <pthread.h> +#include <sys/time.h> +#include <sys/resource.h> #include <private/android_filesystem_config.h> @@ -1305,6 +1307,7 @@ int main(int argc, char **argv) gid_t gid = 0; int num_threads = DEFAULT_NUM_THREADS; int i; + struct rlimit rlim; for (i = 1; i < argc; i++) { char* arg = argv[i]; @@ -1353,6 +1356,12 @@ int main(int argc, char **argv) return usage(); } + rlim.rlim_cur = 8192; + rlim.rlim_max = 8192; + if (setrlimit(RLIMIT_NOFILE, &rlim)) { + ERROR("Error setting RLIMIT_NOFILE, errno = %d\n", errno); + } + res = run(source_path, dest_path, uid, gid, num_threads); return res < 0 ? 1 : 0; } diff --git a/toolbox/Android.mk b/toolbox/Android.mk index dbbce06..2ecb626 100644 --- a/toolbox/Android.mk +++ b/toolbox/Android.mk @@ -58,6 +58,7 @@ TOOLS := \ lsof \ du \ md5 \ + clear \ getenforce \ setenforce \ chcon \ diff --git a/toolbox/clear.c b/toolbox/clear.c new file mode 100644 index 0000000..df46ad2 --- /dev/null +++ b/toolbox/clear.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2012, The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google, Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdio.h> + +int clear_main(int argc, char **argv) { + /* This prints the clear screen and move cursor to top-left corner control + * characters for VT100 terminals. This means it will not work on + * non-VT100 compliant terminals, namely Windows' cmd.exe, but should + * work on anything unix-y. */ + fputs("\x1b[2J\x1b[H", stdout); + return 0; +} diff --git a/toolbox/du.c b/toolbox/du.c index 06374a4..fc7c943 100644 --- a/toolbox/du.c +++ b/toolbox/du.c @@ -62,7 +62,7 @@ __RCSID("$NetBSD: du.c,v 1.33 2008/07/30 22:03:40 dsl Exp $"); int linkchk(dev_t, ino_t); void prstat(const char *, int64_t); -void usage(void); +static void usage(void); long blocksize; @@ -312,7 +312,7 @@ linkchk(dev_t dev, ino_t ino) return 0; } -void +static void usage(void) { diff --git a/toolbox/renice.c b/toolbox/renice.c index 978b329..9dfeb51 100644 --- a/toolbox/renice.c +++ b/toolbox/renice.c @@ -35,11 +35,12 @@ #include <sys/time.h> #include <sys/resource.h> #include <sched.h> +#include <getopt.h> static void usage(const char *s) { - fprintf(stderr, "USAGE: %s [[-r] priority pids ...] [-g pid]\n", s); + fprintf(stderr, "USAGE: %s [[-r] [-t TYPE] priority pids ...] [-g pid]\n", s); exit(EXIT_FAILURE); } @@ -74,32 +75,49 @@ void print_prio(pid_t pid) sched_get_priority_min(sched), sched_get_priority_max(sched)); } +int get_sched(char *str) +{ + if (strcasecmp(str, "RR") == 0) + return SCHED_RR; + else if (strcasecmp(str, "FIFO") == 0) + return SCHED_FIFO; + else if (strcasecmp(str, "NORMAL") == 0) + return SCHED_OTHER; + else if (strcasecmp(str, "OTHER") == 0) + return SCHED_OTHER; + return SCHED_RR; +} + int renice_main(int argc, char *argv[]) { int prio; int realtime = 0; + int opt; + int sched = SCHED_RR; char *cmd = argv[0]; - // consume command name - argc--; - argv++; - - if (argc < 1) - usage(cmd); - - if(strcmp("-r", argv[0]) == 0) { - // do realtime priority adjustment - realtime = 1; - argc--; - argv++; - } - - if(strcmp("-g", argv[0]) == 0) { - if (argc < 2) + do { + opt = getopt(argc, argv, "rt:g:"); + if (opt == -1) + break; + switch (opt) { + case 'r': + // do realtime priority adjustment + realtime = 1; + break; + case 't': + sched = get_sched(optarg); + break; + case 'g': + print_prio(atoi(optarg)); + return 0; + default: usage(cmd); - print_prio(atoi(argv[1])); - return 0; - } + } + } while (1); + + argc -= optind; + argv += optind; if (argc < 1) usage(cmd); @@ -122,7 +140,7 @@ int renice_main(int argc, char *argv[]) struct sched_param sp = { .sched_priority = prio }; int ret; - ret = sched_setscheduler(pid, SCHED_RR, &sp); + ret = sched_setscheduler(pid, sched, &sp); if (ret) { perror("sched_set_scheduler"); exit(EXIT_FAILURE); @@ -137,8 +155,6 @@ int renice_main(int argc, char *argv[]) } } } - + return 0; } - - |