diff --git a/adb/Android.mk b/adb/Android.mk index b70c153d..32de9998 100644 --- a/adb/Android.mk +++ b/adb/Android.mk @@ -62,7 +62,6 @@ LOCAL_SRC_FILES := \ file_sync_client.c \ $(EXTRA_SRCS) \ $(USB_SRCS) \ - usb_vendors.c LOCAL_C_INCLUDES += external/openssl/include @@ -114,6 +113,11 @@ LOCAL_SRC_FILES := \ disable_verity_service.c \ usb_linux_client.c +ifeq ($(call is-vendor-board-platform,QCOM),true) +LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include +LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr +endif + LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter -Werror LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE @@ -162,7 +166,6 @@ LOCAL_SRC_FILES := \ file_sync_client.c \ get_my_path_linux.c \ usb_linux.c \ - usb_vendors.c \ fdevent.c LOCAL_CFLAGS := \ diff --git a/adb/adb.c b/adb/adb.c index 10a1e0da..67c4a685 100644 --- a/adb/adb.c +++ b/adb/adb.c @@ -41,8 +41,6 @@ #include #include #include -#else -#include "usb_vendors.h" #endif #if ADB_TRACE @@ -1318,7 +1316,6 @@ int adb_main(int is_daemon, int server_port) #ifdef WORKAROUND_BUG6558362 if(is_daemon) adb_set_affinity(); #endif - usb_vendors_init(); usb_init(); local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT); adb_auth_init(); @@ -1329,8 +1326,12 @@ int adb_main(int is_daemon, int server_port) exit(1); } #else - property_get("ro.adb.secure", value, "0"); - auth_enabled = !strcmp(value, "1"); + // Override auth in factory test mode + property_get("ro.boot.ftm", value, "0"); + if (!strcmp(value, "0")) { + property_get("ro.adb.secure", value, "0"); + auth_enabled = !strcmp(value, "1"); + } if (auth_enabled) adb_auth_init(); @@ -1349,13 +1350,12 @@ int adb_main(int is_daemon, int server_port) ** AID_LOG to read system logs (adb logcat) ** AID_INPUT to diagnose input issues (getevent) ** AID_INET to diagnose network issues (netcfg, ping) - ** AID_GRAPHICS to access the frame buffer ** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump) ** AID_SDCARD_R to allow reading from the SD card ** AID_SDCARD_RW to allow writing to the SD card ** AID_NET_BW_STATS to read out qtaguid statistics */ - gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_GRAPHICS, + gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_NET_BT, AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW, AID_NET_BW_STATS }; if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) { @@ -1685,6 +1685,10 @@ int handle_host_request(char *service, transport_type ttype, char* serial, int r return -1; } +#if !ADB_HOST +int recovery_mode = 0; +#endif + int main(int argc, char **argv) { #if ADB_HOST @@ -1718,6 +1722,8 @@ int main(int argc, char **argv) } } + recovery_mode = (strcmp(adb_device_banner, "recovery") == 0); + start_device_log(); D("Handling main()\n"); return adb_main(0, DEFAULT_ADB_PORT); diff --git a/adb/adb.h b/adb/adb.h index 44e5981b..385d822c 100644 --- a/adb/adb.h +++ b/adb/adb.h @@ -381,6 +381,8 @@ int adb_commandline(int argc, char **argv); int connection_state(atransport *t); +extern int recovery_mode; + #define CS_ANY -1 #define CS_OFFLINE 0 #define CS_BOOTLOADER 1 @@ -391,6 +393,8 @@ int connection_state(atransport *t); #define CS_SIDELOAD 6 #define CS_UNAUTHORIZED 7 +#define CS_ONLINE 10 /* recovery or device */ + extern int HOST; extern int SHELL_EXIT_NOTIFY_FD; diff --git a/adb/commandline.c b/adb/commandline.c index 77048780..1ab26e4a 100644 --- a/adb/commandline.c +++ b/adb/commandline.c @@ -529,6 +529,8 @@ int adb_download(const char *service, const char *fn, unsigned progress) #define SIDELOAD_HOST_BLOCK_SIZE (CHUNK_SIZE) +#define MB (1024*1024) + /* * The sideload-host protocol serves the data in a file (given on the * command line) to the client, using a simple protocol: @@ -562,6 +564,11 @@ int adb_sideload_host(const char* fn) { fprintf(stderr, "* cannot read '%s' *\n", fn); return -1; } + if (sz == 0) { + printf("\n"); + fprintf(stderr, "* '%s' is empty *\n", fn); + return -1; + } char buf[100]; sprintf(buf, "sideload-host:%d:%d", sz, SIDELOAD_HOST_BLOCK_SIZE); @@ -577,8 +584,29 @@ int adb_sideload_host(const char* fn) { int opt = SIDELOAD_HOST_BLOCK_SIZE; opt = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt)); - int last_percent = -1; + static const char spinner[] = "/-\\|"; + static const int spinlen = sizeof(spinner)-1; + size_t last_xfer = 0; + int spin_index = 0; for (;;) { + fd_set fds; + struct timeval tv; + FD_ZERO(&fds); + FD_SET(fd, &fds); + tv.tv_sec = 1; + tv.tv_usec = 0; + int rc = select(fd+1, &fds, NULL, NULL, &tv); + size_t diff = xfer - last_xfer; + if (rc == 0 || diff >= (1*MB)) { + spin_index = (spin_index+1) % spinlen; + printf("\rserving: '%s' %4umb %.2fx %c", fn, + (unsigned)xfer/(1*MB), (double)xfer/sz, spinner[spin_index]); + fflush(stdout); + last_xfer = xfer; + } + if (rc == 0) { + continue; + } if (readx(fd, buf, 8)) { fprintf(stderr, "* failed to read command: %s\n", adb_error()); status = -1; @@ -613,22 +641,9 @@ int adb_sideload_host(const char* fn) { goto done; } xfer += to_write; - - // For normal OTA packages, we expect to transfer every byte - // twice, plus a bit of overhead (one read during - // verification, one read of each byte for installation, plus - // extra access to things like the zip central directory). - // This estimate of the completion becomes 100% when we've - // transferred ~2.13 (=100/47) times the package size. - int percent = (int)(xfer * 47LL / (sz ? sz : 1)); - if (percent != last_percent) { - printf("\rserving: '%s' (~%d%%) ", fn, percent); - fflush(stdout); - last_percent = percent; - } } - printf("\rTotal xfer: %.2fx%*s\n", (double)xfer / (sz ? sz : 1), (int)strlen(fn)+10, ""); + printf("\ntotal xfer: %4umb %.2fx\n", (unsigned)xfer/(1*MB), (double)xfer/sz); done: if (fd >= 0) adb_close(fd); diff --git a/adb/fdevent.c b/adb/fdevent.c index 43e600cb..0a5d1e9e 100644 --- a/adb/fdevent.c +++ b/adb/fdevent.c @@ -579,6 +579,7 @@ void fdevent_destroy(fdevent *fde) FATAL("fde %p not created by fdevent_create()\n", fde); } fdevent_remove(fde); + free(fde); } void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg) diff --git a/adb/file_sync_client.c b/adb/file_sync_client.c index ad59e817..7fb3e3b8 100644 --- a/adb/file_sync_client.c +++ b/adb/file_sync_client.c @@ -893,6 +893,21 @@ static int set_time_and_mode(const char *lpath, unsigned int time, unsigned int return r1 ? : r2; } +/* Return a copy of the path string with / appended if needed */ +static char *add_slash_to_path(const char *path) +{ + if (path[strlen(path) - 1] != '/') { + size_t len = strlen(path) + 2; + char *path_with_slash = malloc(len); + if (path_with_slash == NULL) + return NULL; + snprintf(path_with_slash, len, "%s/", path); + return path_with_slash; + } else { + return strdup(path); + } +} + static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath, int copy_attrs) { @@ -900,28 +915,32 @@ static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath, copyinfo *ci, *next; int pulled = 0; int skipped = 0; + char *rpath_clean = NULL; + char *lpath_clean = NULL; + int ret = 0; + + if (rpath[0] == '\0' || lpath[0] == '\0') { + ret = -1; + goto finish; + } /* Make sure that both directory paths end in a slash. */ - if (rpath[0] == 0 || lpath[0] == 0) return -1; - if (rpath[strlen(rpath) - 1] != '/') { - int tmplen = strlen(rpath) + 2; - char *tmp = malloc(tmplen); - if (tmp == 0) return -1; - snprintf(tmp, tmplen, "%s/", rpath); - rpath = tmp; + rpath_clean = add_slash_to_path(rpath); + if (!rpath_clean) { + ret = -1; + goto finish; } - if (lpath[strlen(lpath) - 1] != '/') { - int tmplen = strlen(lpath) + 2; - char *tmp = malloc(tmplen); - if (tmp == 0) return -1; - snprintf(tmp, tmplen, "%s/", lpath); - lpath = tmp; + lpath_clean = add_slash_to_path(lpath); + if (!lpath_clean) { + ret = -1; + goto finish; } - fprintf(stderr, "pull: building file list...\n"); /* Recursively build the list of files to copy. */ - if (remote_build_list(fd, &filelist, rpath, lpath)) { - return -1; + fprintf(stderr, "pull: building file list...\n"); + if (remote_build_list(fd, &filelist, rpath_clean, lpath_clean)) { + ret = -1; + goto finish; } for (ci = filelist; ci != 0; ci = next) { @@ -929,11 +948,13 @@ static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath, if (ci->flag == 0) { fprintf(stderr, "pull: %s -> %s\n", ci->src, ci->dst); if (sync_recv(fd, ci->src, ci->dst, 0 /* no show progress */)) { - return 1; + ret = -1; + goto finish; } if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) { - return 1; + ret = -1; + goto finish; } pulled++; } else { @@ -946,7 +967,10 @@ static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath, pulled, (pulled == 1) ? "" : "s", skipped, (skipped == 1) ? "" : "s"); - return 0; +finish: + free(lpath_clean); + free(rpath_clean); + return ret; } int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int copy_attrs) diff --git a/adb/framebuffer_service.c b/adb/framebuffer_service.c index 8cbe8403..61578aa5 100644 --- a/adb/framebuffer_service.c +++ b/adb/framebuffer_service.c @@ -76,6 +76,7 @@ void framebuffer_service(int fd, void *cookie) exit(1); } + close(fds[1]); fd_screencap = fds[0]; /* read w, h & format */ @@ -173,10 +174,9 @@ void framebuffer_service(int fd, void *cookie) } done: - TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0)); - close(fds[0]); - close(fds[1]); + + TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0)); pipefail: close(fd); } diff --git a/adb/services.c b/adb/services.c index 21b08dc2..48ca7eea 100644 --- a/adb/services.c +++ b/adb/services.c @@ -61,6 +61,8 @@ void restart_root_service(int fd, void *cookie) { char buf[100]; char value[PROPERTY_VALUE_MAX]; + char build_type[PROPERTY_VALUE_MAX]; + char radium_version[PROPERTY_VALUE_MAX]; if (getuid() == 0) { snprintf(buf, sizeof(buf), "adbd is already running as root\n"); @@ -75,6 +77,17 @@ void restart_root_service(int fd, void *cookie) return; } + property_get("persist.sys.root_access", value, "0"); + property_get("ro.build.type", build_type, ""); + property_get("ro.radium.version", radium_version, ""); + + if (strlen(radium_version) > 0 && strcmp(build_type, "eng") != 0 && (atoi(value) & 2) != 2) { + snprintf(buf, sizeof(buf), "root access is disabled by system setting - enable in settings -> development options\n"); + writex(fd, buf, strlen(buf)); + adb_close(fd); + return; + } + property_set("service.adb.root", "1"); snprintf(buf, sizeof(buf), "restarting adbd as root\n"); writex(fd, buf, strlen(buf)); @@ -301,8 +314,10 @@ static int create_subproc_raw(const char *cmd, const char *arg0, const char *arg #if ADB_HOST #define SHELL_COMMAND "/bin/sh" +#define ALTERNATE_SHELL_COMMAND "" #else #define SHELL_COMMAND "/system/bin/sh" +#define ALTERNATE_SHELL_COMMAND "/sbin/sh" #endif #if !ADB_HOST @@ -344,6 +359,9 @@ static int create_subproc_thread(const char *name, const subproc_mode mode) int ret_fd; pid_t pid = -1; + const char* shell_command; + struct stat st; + const char *arg0, *arg1; if (name == 0 || *name == 0) { arg0 = "-"; arg1 = 0; @@ -351,12 +369,24 @@ static int create_subproc_thread(const char *name, const subproc_mode mode) arg0 = "-c"; arg1 = name; } + char value[PROPERTY_VALUE_MAX]; + property_get("persist.sys.adb.shell", value, ""); + if (value[0] != '\0' && stat(value, &st) == 0) { + shell_command = value; + } + else if (stat(ALTERNATE_SHELL_COMMAND, &st) == 0) { + shell_command = ALTERNATE_SHELL_COMMAND; + } + else { + shell_command = SHELL_COMMAND; + } + switch (mode) { case SUBPROC_PTY: - ret_fd = create_subproc_pty(SHELL_COMMAND, arg0, arg1, &pid); + ret_fd = create_subproc_pty(shell_command, arg0, arg1, &pid); break; case SUBPROC_RAW: - ret_fd = create_subproc_raw(SHELL_COMMAND, arg0, arg1, &pid); + ret_fd = create_subproc_raw(shell_command, arg0, arg1, &pid); break; default: fprintf(stderr, "invalid subproc_mode %d\n", mode); @@ -382,6 +412,13 @@ static int create_subproc_thread(const char *name, const subproc_mode mode) } #endif +#if !ADB_HOST +static const char* bu_path() +{ + return (recovery_mode ? "/sbin/bu" : "/system/bin/bu"); +} +#endif + int service_to_fd(const char *name) { int ret = -1; @@ -444,13 +481,17 @@ int service_to_fd(const char *name) *c = ' '; } char* cmd; - if (asprintf(&cmd, "/system/bin/bu backup %s", arg) != -1) { + if (asprintf(&cmd, "%s backup %s", bu_path(), arg) != -1) { ret = create_subproc_thread(cmd, SUBPROC_RAW); free(cmd); } free(arg); } else if(!strncmp(name, "restore:", 8)) { - ret = create_subproc_thread("/system/bin/bu restore", SUBPROC_RAW); + char* cmd; + if (asprintf(&cmd, "%s restore", bu_path()) != -1) { + ret = create_subproc_thread(cmd, SUBPROC_RAW); + free(cmd); + } } else if(!strncmp(name, "tcpip:", 6)) { int port; if (sscanf(name + 6, "%d", &port) == 0) { @@ -650,6 +691,15 @@ asocket* host_service_to_socket(const char* name, const char *serial) } else if (!strncmp(name, "any", strlen("any"))) { sinfo->transport = kTransportAny; sinfo->state = CS_DEVICE; + } else if (!strncmp(name, "sideload", strlen("sideload"))) { + sinfo->transport = kTransportAny; + sinfo->state = CS_SIDELOAD; + } else if (!strncmp(name, "recovery", strlen("recovery"))) { + sinfo->transport = kTransportAny; + sinfo->state = CS_RECOVERY; + } else if (!strncmp(name, "online", strlen("online"))) { + sinfo->transport = kTransportAny; + sinfo->state = CS_ONLINE; } else { free(sinfo); return NULL; diff --git a/adb/sysdeps.h b/adb/sysdeps.h index cc1f839e..12ab1820 100644 --- a/adb/sysdeps.h +++ b/adb/sysdeps.h @@ -519,6 +519,26 @@ static __inline__ char* adb_strtok_r(char *str, const char *delim, char **savep #undef strtok_r #define strtok_r ___xxx_strtok_r +#ifndef __FD_SET +#define __FD_SET(fd, fdsetp) \ + (((fd_set *)(fdsetp))->fds_bits[(fd) >> 5] |= (1<<((fd) & 31))) +#endif + +#ifndef __FD_CLR +#define __FD_CLR(fd, fdsetp) \ + (((fd_set *)(fdsetp))->fds_bits[(fd) >> 5] &= ~(1<<((fd) & 31))) +#endif + +#ifndef __FD_ISSET +#define __FD_ISSET(fd, fdsetp) \ + ((((fd_set *)(fdsetp))->fds_bits[(fd) >> 5] & (1<<((fd) & 31))) != 0) +#endif + +#ifndef __FD_ZERO +#define __FD_ZERO(fdsetp) \ + (memset (fdsetp, 0, sizeof (*(fd_set *)(fdsetp)))) +#endif + #endif /* !_WIN32 */ #endif /* _ADB_SYSDEPS_H */ diff --git a/adb/transport.c b/adb/transport.c index f35880cc..30c068f2 100644 --- a/adb/transport.c +++ b/adb/transport.c @@ -871,8 +871,11 @@ atransport *acquire_one_transport(int state, transport_type ttype, const char* s *error_out = "device offline"; result = NULL; } + /* check for required connection state */ - if (result && state != CS_ANY && result->connection_state != state) { + if (result && state != CS_ANY && ((state != CS_ONLINE && result->connection_state != state) + || (state == CS_ONLINE && !(result->connection_state == CS_DEVICE + || result->connection_state == CS_RECOVERY)))) { if (error_out) *error_out = "invalid device state"; result = NULL; diff --git a/adb/transport_usb.c b/adb/transport_usb.c index ee6b637b..3d198030 100644 --- a/adb/transport_usb.c +++ b/adb/transport_usb.c @@ -23,10 +23,6 @@ #define TRACE_TAG TRACE_TRANSPORT #include "adb.h" -#if ADB_HOST -#include "usb_vendors.h" -#endif - #ifdef HAVE_BIG_ENDIAN #define H4(x) (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24) static inline void fix_endians(apacket *p) @@ -131,18 +127,6 @@ void init_usb_transport(atransport *t, usb_handle *h, int state) #if ADB_HOST int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol) { - unsigned i; - for (i = 0; i < vendorIdCount; i++) { - if (vid == vendorIds[i]) { - if (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS && - usb_protocol == ADB_PROTOCOL) { - return 1; - } - - return 0; - } - } - - return 0; + return (usb_class == ADB_CLASS && usb_subclass == ADB_SUBCLASS && usb_protocol == ADB_PROTOCOL); } #endif diff --git a/adb/usb_linux.c b/adb/usb_linux.c index f16bdd03..58de2cdf 100644 --- a/adb/usb_linux.c +++ b/adb/usb_linux.c @@ -237,6 +237,21 @@ static void find_usb_device(const char *base, // looks like ADB... ep1 = (struct usb_endpoint_descriptor *)bufptr; bufptr += USB_DT_ENDPOINT_SIZE; + + // USB3 devices are required to have superspeed + // companion descriptors. They aren't needed to + // locate the target so just skip them. + // + // When using the Android build environment, the old + // ch9.h header from the prebuilts directory for the + // host does not contain superspeed definitions. +#ifndef USB_DT_SS_EP_COMP_SIZE +#define USB_DT_SS_EP_COMP_SIZE 6 +#endif + if (device->bcdUSB >= 0x0300) { + bufptr += USB_DT_SS_EP_COMP_SIZE; + } + ep2 = (struct usb_endpoint_descriptor *)bufptr; bufptr += USB_DT_ENDPOINT_SIZE; diff --git a/adb/usb_linux_client.c b/adb/usb_linux_client.c index 8426e0ea..e3e1057f 100644 --- a/adb/usb_linux_client.c +++ b/adb/usb_linux_client.c @@ -62,6 +62,17 @@ static const struct { struct usb_endpoint_descriptor_no_audio source; struct usb_endpoint_descriptor_no_audio sink; } __attribute__((packed)) fs_descs, hs_descs; +#ifdef FUNCTIONFS_SS_DESC_MAGIC + __le32 ss_magic; + __le32 ss_count; + struct { + struct usb_interface_descriptor intf; + struct usb_endpoint_descriptor_no_audio source; + struct usb_ss_ep_comp_descriptor source_comp; + struct usb_endpoint_descriptor_no_audio sink; + struct usb_ss_ep_comp_descriptor sink_comp; + } __attribute__((packed)) ss_descs; +#endif } __attribute__((packed)) descriptors = { .header = { .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC), @@ -121,6 +132,44 @@ static const struct { .wMaxPacketSize = MAX_PACKET_SIZE_HS, }, }, +#ifdef FUNCTIONFS_SS_DESC_MAGIC + .ss_magic = FUNCTIONFS_SS_DESC_MAGIC, + .ss_count = 5, + .ss_descs = { + .intf = { + .bLength = sizeof(descriptors.ss_descs.intf), + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bNumEndpoints = 2, + .bInterfaceClass = ADB_CLASS, + .bInterfaceSubClass = ADB_SUBCLASS, + .bInterfaceProtocol = ADB_PROTOCOL, + .iInterface = 1, /* first string from the provided table */ + }, + .source = { + .bLength = sizeof(descriptors.ss_descs.source), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 1 | USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = 1024, + }, + .source_comp = { + .bLength = sizeof(descriptors.ss_descs.source_comp), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + }, + .sink = { + .bLength = sizeof(descriptors.ss_descs.sink), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 2 | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = 1024, + }, + .sink_comp = { + .bLength = sizeof(descriptors.ss_descs.sink_comp), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + }, + }, +#endif }; #define STR_INTERFACE_ "ADB Interface" @@ -264,25 +313,23 @@ static void init_functionfs(struct usb_handle *h) { ssize_t ret; - if (h->control < 0) { // might have already done this before - D("OPENING %s\n", USB_FFS_ADB_EP0); - h->control = adb_open(USB_FFS_ADB_EP0, O_RDWR); - if (h->control < 0) { - D("[ %s: cannot open control endpoint: errno=%d]\n", USB_FFS_ADB_EP0, errno); - goto err; - } + D("OPENING %s\n", USB_FFS_ADB_EP0); + h->control = adb_open(USB_FFS_ADB_EP0, O_RDWR); + if (h->control < 0) { + D("[ %s: cannot open control endpoint: errno=%d]\n", USB_FFS_ADB_EP0, errno); + goto err; + } - ret = adb_write(h->control, &descriptors, sizeof(descriptors)); - if (ret < 0) { - D("[ %s: write descriptors failed: errno=%d ]\n", USB_FFS_ADB_EP0, errno); - goto err; - } + ret = adb_write(h->control, &descriptors, sizeof(descriptors)); + if (ret < 0) { + D("[ %s: write descriptors failed: errno=%d ]\n", USB_FFS_ADB_EP0, errno); + goto err; + } - ret = adb_write(h->control, &strings, sizeof(strings)); - if (ret < 0) { - D("[ %s: writing strings failed: errno=%d]\n", USB_FFS_ADB_EP0, errno); - goto err; - } + ret = adb_write(h->control, &strings, sizeof(strings)); + if (ret < 0) { + D("[ %s: writing strings failed: errno=%d]\n", USB_FFS_ADB_EP0, errno); + goto err; } h->bulk_out = adb_open(USB_FFS_ADB_OUT, O_RDWR); @@ -322,14 +369,14 @@ static void *usb_ffs_open_thread(void *x) while (1) { // wait until the USB device needs opening adb_mutex_lock(&usb->lock); - while (usb->control != -1 && usb->bulk_in != -1 && usb->bulk_out != -1) + while (usb->control != -1) adb_cond_wait(&usb->notify, &usb->lock); adb_mutex_unlock(&usb->lock); while (1) { init_functionfs(usb); - if (usb->control >= 0 && usb->bulk_in >= 0 && usb->bulk_out >= 0) + if (usb->control >= 0) break; adb_sleep_ms(1000); @@ -426,13 +473,10 @@ static void usb_ffs_kick(usb_handle *h) D("[ kick: sink (fd=%d) clear halt failed (%d) ]", h->bulk_out, errno); adb_mutex_lock(&h->lock); - - // don't close ep0 here, since we may not need to reinitialize it with - // the same descriptors again. if however ep1/ep2 fail to re-open in - // init_functionfs, only then would we close and open ep0 again. + adb_close(h->control); adb_close(h->bulk_out); adb_close(h->bulk_in); - h->bulk_out = h->bulk_in = -1; + h->control = h->bulk_out = h->bulk_in = -1; // notify usb_ffs_open_thread that we are disconnected adb_cond_signal(&h->notify); diff --git a/adb/usb_osx.c b/adb/usb_osx.c index ca4f2afd..294cc72d 100644 --- a/adb/usb_osx.c +++ b/adb/usb_osx.c @@ -28,12 +28,11 @@ #define TRACE_TAG TRACE_USB #include "adb.h" -#include "usb_vendors.h" #define DBG D static IONotificationPortRef notificationPort = 0; -static io_iterator_t* notificationIterators; +static io_iterator_t notificationIterator; struct usb_handle { @@ -61,8 +60,6 @@ InitUSB() { CFMutableDictionaryRef matchingDict; CFRunLoopSourceRef runLoopSource; - SInt32 vendor, if_subclass, if_protocol; - unsigned i; //* To set up asynchronous notifications, create a notification port and //* add its run loop event source to the program's run loop @@ -70,47 +67,33 @@ InitUSB() runLoopSource = IONotificationPortGetRunLoopSource(notificationPort); CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode); - memset(notificationIterators, 0, sizeof(notificationIterators)); + //* Create our matching dictionary to find the Android device's + //* adb interface + //* IOServiceAddMatchingNotification consumes the reference, so we do + //* not need to release this + matchingDict = IOServiceMatching(kIOUSBInterfaceClassName); - //* loop through all supported vendors - for (i = 0; i < vendorIdCount; i++) { - //* Create our matching dictionary to find the Android device's - //* adb interface - //* IOServiceAddMatchingNotification consumes the reference, so we do - //* not need to release this - matchingDict = IOServiceMatching(kIOUSBInterfaceClassName); - - if (!matchingDict) { - DBG("ERR: Couldn't create USB matching dictionary.\n"); - return -1; - } - - //* Match based on vendor id, interface subclass and protocol - vendor = vendorIds[i]; - if_subclass = ADB_SUBCLASS; - if_protocol = ADB_PROTOCOL; - CFDictionarySetValue(matchingDict, CFSTR(kUSBVendorID), - CFNumberCreate(kCFAllocatorDefault, - kCFNumberSInt32Type, &vendor)); - CFDictionarySetValue(matchingDict, CFSTR(kUSBInterfaceSubClass), - CFNumberCreate(kCFAllocatorDefault, - kCFNumberSInt32Type, &if_subclass)); - CFDictionarySetValue(matchingDict, CFSTR(kUSBInterfaceProtocol), - CFNumberCreate(kCFAllocatorDefault, - kCFNumberSInt32Type, &if_protocol)); - IOServiceAddMatchingNotification( - notificationPort, - kIOFirstMatchNotification, - matchingDict, - AndroidInterfaceAdded, - NULL, - ¬ificationIterators[i]); - - //* Iterate over set of matching interfaces to access already-present - //* devices and to arm the notification - AndroidInterfaceAdded(NULL, notificationIterators[i]); + if (!matchingDict) { + DBG("ERR: Couldn't create USB matching dictionary.\n"); + return -1; } + //* We have to get notifications for all potential candidates and test them + //* at connection time because the matching rules don't allow for a + //* USB interface class of 0xff for class+subclass+protocol matches + //* See https://developer.apple.com/library/mac/qa/qa1076/_index.html + IOServiceAddMatchingNotification( + notificationPort, + kIOFirstMatchNotification, + matchingDict, + AndroidInterfaceAdded, + NULL, + ¬ificationIterator); + + //* Iterate over set of matching interfaces to access already-present + //* devices and to arm the notification + AndroidInterfaceAdded(NULL, notificationIterator); + return 0; } @@ -126,6 +109,7 @@ AndroidInterfaceAdded(void *refCon, io_iterator_t iterator) HRESULT result; SInt32 score; UInt32 locationId; + UInt8 class, subclass, protocol; UInt16 vendor; UInt16 product; UInt8 serialIndex; @@ -156,6 +140,16 @@ AndroidInterfaceAdded(void *refCon, io_iterator_t iterator) continue; } + kr = (*iface)->GetInterfaceClass(iface, &class); + kr = (*iface)->GetInterfaceSubClass(iface, &subclass); + kr = (*iface)->GetInterfaceProtocol(iface, &protocol); + if(class != ADB_CLASS || subclass != ADB_SUBCLASS || protocol != ADB_PROTOCOL) { + // Ignore non-ADB devices. + DBG("Ignoring interface with incorrect class/subclass/protocol - %d, %d, %d\n", class, subclass, protocol); + (*iface)->Release(iface); + continue; + } + //* this gets us an ioservice, with which we will find the actual //* device; after getting a plugin, and querying the interface, of //* course. @@ -192,7 +186,6 @@ AndroidInterfaceAdded(void *refCon, io_iterator_t iterator) //* Now after all that, we actually have a ref to the device and //* the interface that matched our criteria - kr = (*dev)->GetDeviceVendor(dev, &vendor); kr = (*dev)->GetDeviceProduct(dev, &product); kr = (*dev)->GetLocationID(dev, &locationId); @@ -384,8 +377,6 @@ CheckInterface(IOUSBInterfaceInterface **interface, UInt16 vendor, UInt16 produc void* RunLoopThread(void* unused) { - unsigned i; - InitUSB(); currentRunLoop = CFRunLoopGetCurrent(); @@ -398,9 +389,7 @@ void* RunLoopThread(void* unused) CFRunLoopRun(); currentRunLoop = 0; - for (i = 0; i < vendorIdCount; i++) { - IOObjectRelease(notificationIterators[i]); - } + IOObjectRelease(notificationIterator); IONotificationPortDestroy(notificationPort); DBG("RunLoopThread done\n"); @@ -415,9 +404,6 @@ void usb_init() { adb_thread_t tid; - notificationIterators = (io_iterator_t*)malloc( - vendorIdCount * sizeof(io_iterator_t)); - adb_mutex_init(&start_lock, NULL); adb_cond_init(&start_cond, NULL); @@ -442,11 +428,6 @@ void usb_cleanup() close_usb_devices(); if (currentRunLoop) CFRunLoopStop(currentRunLoop); - - if (notificationIterators != NULL) { - free(notificationIterators); - notificationIterators = NULL; - } } int usb_write(usb_handle *handle, const void *buf, int len) diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c index 19bcae41..88495726 100755 --- a/adb/usb_vendors.c +++ b/adb/usb_vendors.c @@ -187,6 +187,8 @@ #define VENDOR_ID_VIZIO 0xE040 // Wacom's USB Vendor ID #define VENDOR_ID_WACOM 0x0531 +// Wileyfox's USB Vendor ID +#define VENDOR_ID_WILEYFOX 0x2970 // Xiaomi's USB Vendor ID #define VENDOR_ID_XIAOMI 0x2717 // YotaDevices's USB Vendor ID @@ -274,6 +276,7 @@ int builtInVendorIds[] = { VENDOR_ID_UNOWHY, VENDOR_ID_VIZIO, VENDOR_ID_WACOM, + VENDOR_ID_WILEYFOX, VENDOR_ID_XIAOMI, VENDOR_ID_YOTADEVICES, VENDOR_ID_YULONG_COOLPAD, diff --git a/auditd/Android.mk b/auditd/Android.mk new file mode 100644 index 00000000..91d592bb --- /dev/null +++ b/auditd/Android.mk @@ -0,0 +1,25 @@ +# Copyright 2005 The Android Open Source Project + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +# Override this in the BoardConfig.mk +# to change the default size +# Note: The value is in Kilobytes +AUDITD_MAX_LOG_FILE_SIZEKB ?= 100 + +LOCAL_SRC_FILES:= \ + auditd.c \ + libaudit.c \ + audit_log.c \ + audit_rules.c \ + fields.c + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libc + +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE := auditd +LOCAL_CFLAGS := -DAUDITD_MAX_LOG_FILE_SIZEKB=$(AUDITD_MAX_LOG_FILE_SIZEKB) +include $(BUILD_EXECUTABLE) diff --git a/auditd/NOTICE b/auditd/NOTICE new file mode 100644 index 00000000..80220968 --- /dev/null +++ b/auditd/NOTICE @@ -0,0 +1,190 @@ + + Copyright 2012, Samsung Telecommunications of America + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + 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. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/auditd/README b/auditd/README new file mode 100644 index 00000000..a29363cf --- /dev/null +++ b/auditd/README @@ -0,0 +1,59 @@ +Auditd Daemon + +The audit daemon is a simplified version of its desktop +counterpart designed to gather the audit logs from the +audit kernel subsystem. The audit subsystem of the kernel +includes Linux Security Modules (LSM) messages as well. + +To enable the audit subsystem, you must add this to your +kernel config: +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y + +To enable a LSM, you must consult that LSM's documentation, the +example below is for SELinux: +CONFIG_SECURITY_SELINUX=y + +This does not include possible dependencies that may need to be +satisfied for that particular LSM. + +The daemon maintains two log files audit.log and audit.old +at /data/misc/audit/. On boot, if audit.log exists, and +the size is greater than 0, audit.log is renamed to +audit.old. The log file is also renamed, or rotated, when +a threshold is hit. This threshold is hard-coded to 100KB +but can be adjusted through the AUDITD_MAX_LOG_FILE_SIZEKB +Makefile file variable that can be overridden in the device.mk + +The daemon is not included by default, and must explicitly be +added to PRODUCT_PACKAGES. This could be set in the device.mk + +The daemon also has no external interfaces, but one could +use inotify to start and build a system from this. The log +files are owned by UID audit and readable by system. A +system UID application could conceivably be used to consume +these logs. + +Example configuration in device.mk: + +# 1MB Log file threshold +AUDITD_MAX_LOG_FILE_SIZEKB := 1000 + +PRODUCT_PACKAGES += auditd + +Rules + +Limited support for loading rules is present in auditd. +Put an audit.rules file in /data/misc/audit/ and it will be read +when auditd is run. Only enable (-e) and watch (-w) rules are +currently supported. For watch files fields that are supported are: +uid, euid, suid, fsuid, loginuid, gid, egid, sgid, fsgid and success. + +An example audit.rules may look like: + +# Audit successful writes to /system not done by the system UID +-w /system -pwa -F success=1 -F uid!=system +# Audit write attempts (successful or not) to /dev/block by anyone +-w /dev/block -pwa +# Audit write attempts to /data/security not done by system UID +-w /data/security -pwa -F uid!=system diff --git a/auditd/audit.rules b/auditd/audit.rules new file mode 100644 index 00000000..2b217aec --- /dev/null +++ b/auditd/audit.rules @@ -0,0 +1,4 @@ +-w /dev/block -pwa -F success=1 -F uid!=system +-w /system -pwa -F success=1 +-w /data/security -pwa -F success=1 -F uid!=system +-w /data/misc/audit -pwa -F success=1 -F uid!=audit diff --git a/auditd/audit_log.c b/auditd/audit_log.c new file mode 100644 index 00000000..ef77a3f2 --- /dev/null +++ b/auditd/audit_log.c @@ -0,0 +1,353 @@ +/* + * Copyright 2012, Samsung Telecommunications of America + * + * 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. + * + * Written by William Roberts + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOG_TAG "audit_log" +#include + +#include "libaudit.h" +#include "audit_log.h" + +/* + * Note that the flags passed to fcntl and the flags used + * by fopen must be compatible. For instance, specifying + * write only on one and read only on the other will yield + * strange behavior. + */ +/* Mode for fopen */ +#define AUDIT_LOG_FMODE "w+" +/* mode for fchmod*/ +#define AUDIT_LOG_MODE (S_IRUSR | S_IWUSR | S_IRGRP) +/* flags for fcntl */ +#define AUDIT_LOG_FLAGS (O_RDWR | O_CREAT | O_SYNC) + +#define AUDIT_TYPE "type=" +#define AUDIT_MSG "msg=" +#define AUDIT_KEYWORD "audit(" + +struct audit_log +{ + FILE *file; + size_t total_bytes; + size_t threshold; + char *rotatefile; + char *logfile; +}; + +/** + * Wraps open with a fchmod to prevent umask issues from arising in + * permission setting as well as a fcntl to set the underlying + * fds mode. However, the rest of the library relies on stdio file + * access, so a FILE pointer is returned. + * + * You must make sure your mode and fmode are compatible + * + * @param file + * File stream output + * @param path + * The path of the log file + * @param flags + * The flags passed to fcntl + * @param fmode + * The mode passed to fopen + * @param mode + * The mode passed to open and fchmod + * @return + * 0 on success with *file set, or -errno on error + */ +static int open_log(FILE **file, const char *path, int flags, const char *fmode, mode_t mode) +{ + int fd; + int rc; + + if(!file) { + return -EINVAL; + } + + *file = fopen(path, fmode); + if(!*file) { + rc = -errno; + SLOGE("Could not open audit log file %s : %s", path, strerror(errno)); + return rc; + } + + rc = setvbuf(*file, NULL, _IONBF, 0); + if (rc != 0) { + rc = -errno; + SLOGE("Could not setvbuf the log file"); + goto err; + } + + fd = fileno(*file); + rc = fchmod(fd, mode); + if (rc < 0) { + rc = -errno; + SLOGE("Could not fchmod the log file"); + goto err; + } + + rc = fcntl(fd, F_SETFD, flags); + if (rc < 0) { + rc = -errno; + SLOGE("Could not fcntl the log file"); + goto err; + } + + return 0; + +err: + fclose(*file); + return rc; +} + +audit_log *audit_log_open(const char *logfile, const char *rotatefile, size_t threshold) +{ + int rc; + audit_log *l = NULL; + struct stat log_file_stats; + + rc = stat(logfile, &log_file_stats); + if (rc < 0) { + if(errno != ENOENT) { + SLOGE("Could not stat audit logfile %s: %s", logfile, strerror(errno)); + return NULL; + } + else { + SLOGI("Previous audit logfile not detected"); + } + } + + /* The existing log had data */ + if (rc == 0 && log_file_stats.st_size >= 0) { + rc = rename(logfile, rotatefile); + if (rc < 0) { + SLOGE("Could not rename %s to %s: %s", logfile, rotatefile, strerror(errno)); + return NULL; + } + SLOGI("Previous audit logfile detected, rotating\n"); + } + + l = calloc(sizeof(struct audit_log), 1); + if (!l) { + SLOGE("Out of memory while allocating audit log"); + return NULL; + } + + /* Open the output logfile */ + rc = open_log(&(l->file), logfile, AUDIT_LOG_FLAGS, AUDIT_LOG_FMODE, AUDIT_LOG_MODE); + if (rc < 0) { + /* Error message handled by open_log() */ + return NULL; + } + + l->rotatefile = strdup(rotatefile); + if (!l->rotatefile) { + SLOGE("Out of memory while duplicating rotatefile string"); + goto err; + } + + l->logfile = strdup(logfile); + if (!l->logfile) { + SLOGE("Out of memory while duplicating logfile string"); + goto err; + } + + l->threshold = threshold; + + return l; + +err: + audit_log_close(l); + return NULL; +} + +int audit_log_write(audit_log *l, const char *fmt, ...) +{ + int rc; + va_list args; + + if (l == NULL || fmt == NULL) { + return -EINVAL; + } + + va_start(args, fmt); + rc = vfprintf(l->file, fmt, args); + va_end(args); + + if(rc < 0) { + SLOGE("Error writing to log file"); + clearerr(l->file); + rc = -EINVAL; + goto out; + } + + l->total_bytes += rc; + +out: + if(l->total_bytes > l->threshold) { + /* audit_log_rotate() handles error message */ + rc = audit_log_rotate(l); + } + + return rc; +} + +int audit_log_rotate(audit_log *l) +{ + FILE *file; + int rc = 0; + + if (!l) { + return -EINVAL; + } + + rc = rename(l->logfile, l->rotatefile); + if (rc < 0) { + rc = -errno; + SLOGE("Could not rename audit log file \"%s\" to \"%s\", error: %s", + l->logfile, l->rotatefile, strerror(errno)); + return rc; + } + + rc = open_log(&file, l->logfile, AUDIT_LOG_FLAGS, AUDIT_LOG_FMODE, AUDIT_LOG_MODE); + if (rc < 0) { + /* Error message handled by open_log() */ + return rc; + } + + fclose(l->file); + l->total_bytes = 0; + l->file = file; + + return 0; +} + +void audit_log_close(audit_log *l) +{ + if (!l) { + return; + } + + free(l->logfile); + free(l->rotatefile); + if (l->file) { + fclose(l->file); + } + free(l); + return; +} + +int audit_log_put_kmsg(audit_log *l) +{ + char *tok; + char *audit; + char *type; + int rc = 0; + char *buf = NULL; + int len = klogctl(KLOG_SIZE_BUFFER, NULL, 0); + + /* No data to read */ + if (len == 0) { + SLOGI("Empty kmsg"); + return 0; + } + + /* Error */ + if (len < 0) { + rc = -errno; + SLOGE("Could not read kernel log length: %s", strerror(errno)); + return rc; + } + + /* Data to read */ + len++; + buf = malloc(len * sizeof(*buf)); + if (!buf) { + SLOGE("Out of memory wile allocating kmsg buffer"); + return -ENOMEM; + } + + rc = klogctl(KLOG_READ_ALL, buf, len); + if (rc < 0) { + rc = -errno; + SLOGE("Could not read kernel log data: %s", strerror(errno)); + goto err; + } + + buf[len - 1] = '\0'; + tok = buf; + + while ((tok = strtok(tok, "\r\n"))) { + + /* Only print audit messages The SPACE is important!! as we want the + * audit pointer pointing to a space and not the beginning of the message. + * This helps ensure that we don't erroneously going down the wrong path when + * parsing this data. + * XXX Should we include the space in the AUDIT_KEYWORD macro? + */ + audit = strstr(tok, " "AUDIT_KEYWORD); + if (audit) { + + /* Place a null terminator at the space, and advance the pointer past it */ + *audit++ = '\0'; + + /* If it has type field, print that than msg= */ + type = strstr(tok, AUDIT_TYPE); + if (type) { + + /* + * The type should be the the left of the space we replaced with a + * null terminator + * + * type is pointing to type=1400\0 and audit is pointing to audit(....\0 + */ + rc = audit_log_write(l, "%s msg=%s\n", type, audit); + if(rc < 0) { + /* audit_log_write handles error message */ + goto err; + } + } + /* It contined the AUDIT_KEWORD but was not formatted as expected, just dump it */ + else { + SLOGW("Improperly formatted kernel audit message, dumping as is"); + rc = audit_log_write(l, "%s\n", audit); + if(rc < 0) { + /* audit_log_write handles error message */ + goto err; + } + } + } + tok = NULL; + } + +err: + free(buf); + return rc; +} diff --git a/auditd/audit_log.h b/auditd/audit_log.h new file mode 100644 index 00000000..3bb98e8d --- /dev/null +++ b/auditd/audit_log.h @@ -0,0 +1,79 @@ +/* + * Copyright 2012, Samsung Telecommunications of America + * + * 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. + * + * Written by William Roberts + */ + +#ifndef _AUDIT_LOG_H_ +#define _AUDIT_LOG_H_ + +#include +#include "libaudit.h" + +typedef struct audit_log audit_log; + +/** + * Opens an audit logfile for writing + * @param logfile + * The logfile name to use + * @param rotatefile + * The logfile to rotate to when threshold is encountered + * @param threshold + * The threshold, in bytes, the log file should grow to + * until rotation. + * @return + * A valid handle to the audit_log or NULL on failure. + */ +extern audit_log *audit_log_open(const char *logfile, const char *rotatefile, size_t threshold); + +/** + * Writes a formatted message to the audit log + * @param l + * The log to write too + * @param fmt + * The fmt specifier as passed to fprintf/printf family of functions + * @return + * 0 on success or -errno on error + * + */ +extern int audit_log_write(audit_log *l, const char *fmt, ...); + +/** + * Forces a rotation of the audit log. + * @param l + * The log file to use + * @return + * 0 on success, -errno on failure. + */ +extern int audit_log_rotate(audit_log *l); + +/** + * Closes the audit log file. + * @param l + * The log file to close. + */ +extern void audit_log_close(audit_log *l); + +/** + * Searches once through kmsg for type=1400 + * kernel messages and logs them to the audit log + * @param l + * The log to append too + * @return + * 0 on success, -errno on failure. + */ +extern int audit_log_put_kmsg(audit_log *l); + +#endif diff --git a/auditd/audit_rules.c b/auditd/audit_rules.c new file mode 100644 index 00000000..768c3b93 --- /dev/null +++ b/auditd/audit_rules.c @@ -0,0 +1,213 @@ +/* + * Copyright 2013, Quark Security 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. + * + * Written by Joshua Brindle + */ + +#include +#include +#include +#include +#include + +#define LOG_TAG "audit_rules" +#include + +#include "libaudit.h" +#include "fields.h" + +#define LINE_LEN 255 +#define OPERS "=><&!" + +static int string_to_oper(const char *s) +{ + if (strcmp(s, "=") == 0) { + return AUDIT_EQUAL; + } else if (strcmp(s, "!=") == 0) { + return AUDIT_NOT_EQUAL; + } else if (strcmp(s, ">=") == 0) { + return AUDIT_GREATER_THAN_OR_EQUAL; + } else if (strcmp(s, "<=") == 0) { + return AUDIT_LESS_THAN_OR_EQUAL; + } else if (strcmp(s, "<") == 0) { + return AUDIT_LESS_THAN; + } else if (strcmp(s, ">") == 0) { + return AUDIT_GREATER_THAN; + } else if (strcmp(s, "&=") == 0) { + return AUDIT_BIT_TEST; + } else if (strcmp(s, "&") == 0) { + return AUDIT_BIT_MASK; + } else { + return -1; + } +} + +static int audit_rules_parse_and_add(int audit_fd, char *line) +{ + char *argv[AUDIT_MAX_FIELDS]; + int argc; + int rc = 0; + int added_rule = 0; + char p; + int opt; + size_t len; + struct audit_rule_data *rule; + + /* Strip crlf */ + line[strlen(line) -1] = '\0'; + + argv[0] = "auditd"; + + for (argc=1; argc < AUDIT_MAX_FIELDS - 1; argc++) { + argv[argc] = strsep(&line, " \n\r"); + if (argv[argc] == NULL) { + break; + } + } + + optind = 0; + char *field; + char *oper; + size_t length; + int audit_field; + int oper_field; + int i; + + while ((opt = getopt(argc, argv, "w:e:p:F:")) != -1) { + switch(opt) { + case 'w': + if (audit_add_dir(&rule, optarg)) { + SLOGE("Error adding rule"); + return -1; + } + added_rule = 1; + break; + case 'e': + if (audit_set_enabled(audit_fd, strtoul(optarg, NULL, 10))) { + return -1; + } + break; + case 'F': + if (added_rule == 0) { + SLOGE("Specify rule type before permissions"); + return -1; + } + + length = strcspn(optarg, OPERS); + field = strndup(optarg, length); + if (field == NULL) { + SLOGE("Out of memory!"); + return -1; + } + audit_field = string_to_audit_field(field); + if (audit_field == 0) { + SLOGE("Invalid field: %s", field); + free(field); + return -1; + } + free(field); + + optarg = &optarg[length]; + length = strspn(optarg, OPERS); + oper = strndup(optarg, length); + oper_field = string_to_oper(oper); + if (oper_field == -1) { + SLOGE("Invalid operator: %s", oper); + free(oper); + return -1; + } + free(oper); + optarg = &optarg[length]; + if (audit_add_field(rule, audit_field, oper_field, optarg) < 0) { + SLOGE("Adding field failed"); + return -1; + } + break; + case 'p': + if (added_rule == 0) { + SLOGE("Specify rule type before permissions"); + return -1; + } + uint32_t perms = 0; + for (len=0; len < strlen(optarg); len++) { + switch(optarg[len]) { + case 'w': + perms |= AUDIT_PERM_WRITE; + break; + case 'e': + perms |= AUDIT_PERM_EXEC; + break; + case 'r': + perms |= AUDIT_PERM_READ; + break; + case 'a': + perms |= AUDIT_PERM_ATTR; + break; + default: + SLOGE("Unknown permission %c", optarg[len]); + break; + } + } + if (audit_update_watch_perms(rule, perms)) { + SLOGE("Could not set perms on rule"); + return -1; + } + break; + case '?': + SLOGE("Unsupported option: %c", optopt); + break; + } + } + + if (added_rule) { + rc = audit_send(audit_fd, AUDIT_ADD_RULE, rule, sizeof(*rule) + rule->buflen); + free(rule); + } + + return rc; +} + +int audit_rules_read_and_add(int audit_fd, const char *rulefile) +{ + int rc; + struct stat s; + char line[LINE_LEN]; + FILE *rules; + + rc = stat(rulefile, &s); + if (rc < 0) { + SLOGE("Could not read audit rules %s: %s", rulefile, strerror(errno)); + return 0; + } + + rules = fopen(rulefile, "r"); + if (rules == NULL) { + return -1; + } + + while (fgets(line, sizeof(line), rules)) { + SLOGE(line); + if (line[0] != '-') { + continue; + } + if (audit_rules_parse_and_add(audit_fd, line) < 0) { + SLOGE("Could not read audit rules"); + return -1; + } + } + + fclose(rules); + return 0; +} diff --git a/auditd/audit_rules.h b/auditd/audit_rules.h new file mode 100644 index 00000000..16a617ec --- /dev/null +++ b/auditd/audit_rules.h @@ -0,0 +1,24 @@ +/* + * Copyright 2013, Quark Security 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. + * + * Written by Joshua Brindle + */ + +#ifndef _AUDIT_RULES_H_ +#define _AUDIT_RULES_H_ + +extern int audit_rules_read_and_add(int audit_fd, const char *rulefile); + +#endif diff --git a/auditd/auditd.c b/auditd/auditd.c new file mode 100644 index 00000000..013827c4 --- /dev/null +++ b/auditd/auditd.c @@ -0,0 +1,241 @@ +/* + * Copyright 2012, Samsung Telecommunications of America + * + * 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. + * + * Written by William Roberts + */ + +#define LOG_TAG "auditd" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include "libaudit.h" +#include "audit_log.h" +#include "audit_rules.h" + +/* + * TODO: + * Just Ideas: + * 1. Add a socket interface for sending events + */ + +#ifndef AUDITD_MAX_LOG_FILE_SIZEKB +#error "AUDITD_MAX_LOG_FILE_SIZEKB not defined by makefile!" +#endif + +#define AUDITD_LOG_DIR "/data/misc/audit" +#define AUDITD_LOG_FILE AUDITD_LOG_DIR "/audit.log" +#define AUDITD_OLD_LOG_FILE AUDITD_LOG_DIR "/audit.old" + +#define AUDITD_RULES_FILE "/data/misc/audit/audit.rules" + +#define AUDITD_MAX_LOG_FILE_SIZE (1024 * AUDITD_MAX_LOG_FILE_SIZEKB) + +static volatile int quit = 0; + +static audit_log *alog = NULL; + +static void signal_handler(int sig) +{ + switch (sig) { + case SIGINT: + case SIGTERM: + quit = 1; + break; + case SIGHUP: + audit_log_rotate(alog); + break; + } + return; +} + +static void usage(char *cmd) +{ + printf("%s - log audit events from the kernel\n" + "OPTIONS\n" + "-k - search dmesg on startup for audit events\n" + "\n", cmd); +} + +#define RAISE(ary, c) ary[CAP_TO_INDEX(c)].permitted |= CAP_TO_MASK(c); + +static void drop_privileges_or_die(void) +{ + + struct __user_cap_header_struct capheader; + struct __user_cap_data_struct capdata[2]; + + if (prctl(PR_SET_KEEPCAPS, 1) < 0) { + SLOGE("Failed on prctl KEEPCAPS: %s", strerror(errno)); + exit(1); + } + + if (setgid(AID_AUDIT) < 0) { + SLOGE("Failed on setgid: %s", strerror(errno)); + exit(1); + } + + if (setuid(AID_AUDIT) < 0) { + SLOGE("Failed on setuid: %s", strerror(errno)); + exit(1); + } + + memset(&capheader, 0, sizeof(capheader)); + memset(&capdata, 0, sizeof(capdata)); + capheader.version = _LINUX_CAPABILITY_VERSION_3; + capheader.pid = 0; + + RAISE(capdata, CAP_AUDIT_CONTROL); + RAISE(capdata, CAP_SYSLOG); + + capdata[0].effective = capdata[0].permitted; + capdata[1].effective = capdata[1].permitted; + capdata[0].inheritable = 0; + capdata[1].inheritable = 0; + + if (capset(&capheader, &capdata[0]) < 0) { + SLOGE("Failed on capset: %s", strerror(errno)); + exit(1); + } +} + +int main(int argc, char *argv[]) +{ + int c; + int rc; + int audit_fd = -1; + int check_kernel_log = 0; + + struct pollfd pfds; + struct audit_reply rep; + struct sigaction action; + + SLOGI("Starting up"); + + drop_privileges_or_die(); + + /* register the signal handler */ + action.sa_handler = signal_handler; + sigemptyset(&action.sa_mask); + action.sa_flags = 0; + rc = sigaction(SIGINT, &action, NULL); + rc |= sigaction(SIGHUP, &action, NULL); + if (rc < 0) { + rc = errno; + SLOGE("Failed on set signal handler: %s", strerror(errno)); + goto err; + } + + while ((c = getopt(argc, argv, "k")) != -1) { + switch (c) { + case 'k': + check_kernel_log = 1; + break; + default: + usage(argv[0]); + goto err; + } + } + + /* Open the netlink socket for audit events */ + audit_fd = audit_open(); + if (audit_fd < 0) { + rc = errno; + SLOGE("Failed on audit_set_pid with error: %s", strerror(errno)); + goto err; + } + + alog = audit_log_open(AUDITD_LOG_FILE, AUDITD_OLD_LOG_FILE, AUDITD_MAX_LOG_FILE_SIZE); + if (!alog) { + SLOGE("Failed on audit_log_open"); + goto err; + } + + if (audit_set_pid(audit_fd, getpid(), WAIT_YES) < 0) { + rc = errno; + SLOGE("Failed on audit_set_pid with error: %s", strerror(errno)); + goto err; + } + + if (audit_set_enabled(audit_fd, 1) < 0) { + rc = errno; + SLOGE("Failed on audit_set_enabled with error: %s", strerror(errno)); + goto err; + } + + if (audit_rules_read_and_add(audit_fd, AUDITD_RULES_FILE)) { + SLOGE("error reading audit rules: %s", strerror(errno)); + } + + pfds.fd = audit_fd; + pfds.events = POLLIN; + + if (check_kernel_log) { + audit_log_put_kmsg(alog); + } + + while (!quit) { + + /* Start reading for events */ + rc = poll(&pfds, 1, -1); + if (rc == 0) { + continue; + } else if (rc < 0) { + if (errno != EINTR) { + SLOGE("Failed to poll audit log socket: %d : %s", errno, strerror(errno)); + } + continue; + } + + if (audit_get_reply(audit_fd, &rep, GET_REPLY_BLOCKING, 0) < 0) { + SLOGE("Failed on audit_get_reply with error: %s", strerror(errno)); + continue; + } + + audit_log_write(alog, "type=%d msg=%.*s\n", rep.type, rep.len, rep.msg.data); + /* Keep reading for events */ + } + +err: + SLOGI("Exiting"); + if (audit_fd >= 0) { + audit_set_pid(audit_fd, 0, WAIT_NO); + audit_close(audit_fd); + } + audit_log_close(alog); + return rc; +} diff --git a/auditd/fields.c b/auditd/fields.c new file mode 100644 index 00000000..75c571ae --- /dev/null +++ b/auditd/fields.c @@ -0,0 +1,91 @@ +/* + * Copyright 2013, Quark Security 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. + * + * Written by Joshua Brindle + */ + +#include +#include +#include +#include +#include + +#define LOG_TAG "audit_fields" +#include + +#define L1(line) L2(line) +#define L2(line) str##line +static const union audit_to_string_data { + struct { +#define S_(v, s) char L1(__LINE__)[sizeof(s)]; +#include "fieldtab.h" +#undef S_ + }; + char str[0]; +} audit_to_string_data = { + { +#define S_(v, s) s, +#include "fieldtab.h" +#undef S_ + } +}; +static const int audit_to_string[] = { +#define S_(v, s) offsetof(union audit_to_string_data, L1(__LINE__)), +#include "fieldtab.h" +#undef S_ +}; + +static const int audit_map[] = { +#define S_(v, s) v, +#include "fieldtab.h" +#undef S_ +}; + +#define FIELDS (sizeof(audit_to_string) / sizeof(audit_to_string[0])) + +int string_to_audit_field(const char *s) +{ + unsigned int val; + + if (isdigit(s[0])) { + val = atoi(s); + if (val > 0 && val < FIELDS) { + return audit_map[val]; + } + } else { + for (val = 0; val < FIELDS; val++) { + if (strcmp(s, (audit_to_string_data.str + + audit_to_string[val])) == 0) { + return audit_map[val]; + } + } + } + + errno = EINVAL; + return 0; +} + +const char* audit_field_to_string(int field) +{ + unsigned int i; + for (i=0; i < FIELDS; i++) { + if (audit_map[i] == field) { + return audit_to_string_data.str + audit_to_string[i]; + } + } + + errno = EINVAL; + return NULL; +} diff --git a/auditd/fields.h b/auditd/fields.h new file mode 100644 index 00000000..3886d138 --- /dev/null +++ b/auditd/fields.h @@ -0,0 +1,2 @@ +extern int string_to_audit_field(const char *s); +extern const char* audit_field_to_string(int i); diff --git a/auditd/fieldtab.h b/auditd/fieldtab.h new file mode 100644 index 00000000..f7decb44 --- /dev/null +++ b/auditd/fieldtab.h @@ -0,0 +1,33 @@ +S_(AUDIT_PID, "pid") +S_(AUDIT_UID, "uid") +S_(AUDIT_EUID, "euid") +S_(AUDIT_SUID, "suid") +S_(AUDIT_FSUID, "fsuid") +S_(AUDIT_GID, "gid") +S_(AUDIT_EGID, "egid") +S_(AUDIT_SGID, "sgid") +S_(AUDIT_FSGID, "fsgid") +S_(AUDIT_LOGINUID, "auid") +S_(AUDIT_PERS, "pers") +S_(AUDIT_ARCH, "arch") +S_(AUDIT_MSGTYPE, "msgtype") +S_(AUDIT_SUBJ_USER, "subj_user") +S_(AUDIT_SUBJ_ROLE, "subj_role") +S_(AUDIT_SUBJ_TYPE, "subj_type") +S_(AUDIT_SUBJ_SEN, "subj_sen") +S_(AUDIT_SUBJ_CLR, "subj_clr") +S_(AUDIT_PPID, "ppid") +S_(AUDIT_OBJ_USER, "obj_user") +S_(AUDIT_OBJ_ROLE, "obj_role") +S_(AUDIT_OBJ_TYPE, "obj_type") +S_(AUDIT_OBJ_LEV_LOW, "obj_lev_low") +S_(AUDIT_OBJ_LEV_HIGH, "obj_lev_high") +S_(AUDIT_DEVMAJOR, "devmajor") +S_(AUDIT_DEVMINOR, "devminor") +S_(AUDIT_INODE, "inode") +S_(AUDIT_EXIT, "exit") +S_(AUDIT_SUCCESS, "success") +S_(AUDIT_WATCH, "path") +S_(AUDIT_PERM, "perm") +S_(AUDIT_DIR, "dir") +S_(AUDIT_FILETYPE, "filetype") diff --git a/auditd/libaudit.c b/auditd/libaudit.c new file mode 100644 index 00000000..d65b6199 --- /dev/null +++ b/auditd/libaudit.c @@ -0,0 +1,488 @@ +/* + * Copyright 2012, Samsung Telecommunications of America + * + * 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. + * + * Written by William Roberts + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LOG_TAG "libaudit" +#include +#include + +#include "libaudit.h" +#include "fields.h" + +/** + * Copies the netlink message data to the reply structure. + * + * When the kernel sends a response back, we must adjust the response from the + * netlink message header. + * All the data is in rep->msg but belongs in the type enforced fields in the struct. + * + * @param rep + * The response + * @param len + * The length of the message, len must never be less than 0! + * @return + * This function returns 0 on success, else -error. + */ +static int set_internal_fields(struct audit_reply *rep, ssize_t len) +{ + int rc; + + /* + * We end up setting a specific field in the union, but since it + * is a union and they are all of type pointer, we can just clear + * one. + */ + rep->status = NULL; + + /* Set the response from the netlink message */ + rep->nlh = &rep->msg.nlh; + rep->len = rep->msg.nlh.nlmsg_len; + rep->type = rep->msg.nlh.nlmsg_type; + + /* Check if the reply from the kernel was ok */ + if (!NLMSG_OK(rep->nlh, (size_t)len)) { + rc = (len == sizeof(rep->msg)) ? -EFBIG : -EBADE; + SLOGE("Bad kernel response %s", strerror(-rc)); + return rc; + } + + /* Next we'll set the data structure to point to msg.data. This is + * to avoid having to use casts later. */ + if (rep->type == NLMSG_ERROR) { + rep->error = NLMSG_DATA(rep->nlh); + } else if (rep->type == AUDIT_GET) { + rep->status = NLMSG_DATA(rep->nlh); + } else if (rep->type == AUDIT_LIST_RULES) { + rep->ruledata = NLMSG_DATA(rep->nlh); + } else if (rep->type == AUDIT_SIGNAL_INFO) { + rep->signal_info = NLMSG_DATA(rep->nlh); + } + /* If it is not any of the above specific events, it must be a generic message */ + else { + rep->message = NLMSG_DATA(rep->nlh); + } + + return 0; +} + +/** + * Waits for an ack from the kernel + * @param fd + * The netlink socket fd + * @param seq + * The current sequence number were acking on + * @return + * This function returns 0 on success, else -errno. + */ +static int get_ack(int fd, int16_t seq) +{ + int rc; + struct audit_reply rep; + + /* Sanity check the input, this is an internal interface this shouldn't happen */ + if (fd < 0) { + return -EINVAL; + } + + rc = audit_get_reply(fd, &rep, GET_REPLY_BLOCKING, MSG_PEEK); + if (rc < 0) { + return rc; + } + + if (rep.type == NLMSG_ERROR) { + audit_get_reply(fd, &rep, GET_REPLY_BLOCKING, 0); + if (rep.error->error) { + return -rep.error->error; + } + } + + if ((int16_t)rep.nlh->nlmsg_seq != seq) { + SLOGW("Expected sequence number between user space and kernel space is out of skew, " + "expected %u got %u", seq, rep.nlh->nlmsg_seq); + } + + return 0; +} + +/** + * + * @param fd + * The netlink socket fd + * @param type + * The type of netlink message + * @param data + * The data to send + * @param size + * The length of the data in bytes + * @return + * This function returns a positive sequence number on success, else -errno. + */ +int audit_send(int fd, int type, const void *data, unsigned int size) +{ + int rc; + static int16_t sequence = 0; + struct audit_message req; + struct sockaddr_nl addr; + + memset(&req, 0, sizeof(req)); + memset(&addr, 0, sizeof(addr)); + + /* We always send netlink messaged */ + addr.nl_family = AF_NETLINK; + + /* Set up the netlink headers */ + req.nlh.nlmsg_type = type; + req.nlh.nlmsg_len = NLMSG_SPACE(size); + req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + + /* + * Check for a valid fd, even though sendto would catch this, its easier to always + * blindly increment the sequence number + */ + if (fd < 0) { + return -EBADF; + } + + /* Ensure the message is not too big */ + if (NLMSG_SPACE(size) > MAX_AUDIT_MESSAGE_LENGTH) { + SLOGE("netlink message is too large"); + return -EINVAL; + } + + /* Only memcpy in the data if it was specified */ + if (size && data) + memcpy(NLMSG_DATA(&req.nlh), data, size); + + /* + * Only increment the sequence number on a guarantee + * you will send it to the kernel. + * + * Also, the sequence is defined as a u32 in the kernel + * struct. Using an int here might not work on 32/64 bit splits. A + * signed 64 bit value can overflow a u32..but a u32 + * might not fit in the response, so we need to use s32. + * Which is still kind of hackish since int could be 16 bits + * in size. The only safe type to use here is a signed 16 + * bit value. + */ + req.nlh.nlmsg_seq = ++sequence; + + /* While failing and its due to interrupts */ + do { + /* Try and send the netlink message */ + rc = sendto(fd, &req, req.nlh.nlmsg_len, 0, (struct sockaddr*) &addr, sizeof(addr)); + + } while (rc < 0 && errno == EINTR); + + /* Not all the bytes were sent */ + if ((uint32_t) rc != req.nlh.nlmsg_len) { + rc = -EPROTO; + goto out; + } else if (rc < 0) { + rc = -errno; + SLOGE("Error sending data over the netlink socket: %s", strerror(-errno)); + goto out; + } + + /* We sent all the bytes, get the ack */ + rc = get_ack(fd, sequence); + + /* If the ack failed, return the error, else return the sequence number */ + rc = (rc == 0) ? (int) sequence : rc; + +out: + /* Don't let sequence roll to negative */ + if (sequence < 0) { + SLOGW("Auditd to Kernel sequence number has rolled over"); + sequence = 0; + } + + return rc; +} + +int audit_update_watch_perms(struct audit_rule_data *rule, int perms) +{ + uint32_t i; + + if (rule == NULL) { + return -EINVAL; + } + + for (i = 0; i < rule->field_count; i++) { + if (rule->fields[i] == AUDIT_PERM) { + rule->values[i] = perms; + break; + } + } + + if (rule->fields[i] == AUDIT_PERM) { + return 0; + } + + if (rule->field_count > AUDIT_MAX_FIELDS - 1) { + return -2; + } + + rule->fields[rule->field_count] = AUDIT_PERM; + rule->fieldflags[rule->field_count] = AUDIT_EQUAL; + rule->values[rule->field_count] = perms; + rule->field_count++; + + return 0; +} + +int audit_add_field(struct audit_rule_data *rule, int field, int oper, char *value) +{ + int i; + struct passwd *pw; + struct group *gr; + + if (rule == NULL) { + return -EINVAL; + } + + if (rule->field_count > AUDIT_MAX_FIELDS - 1) { + return -2; + } + + rule->fields[rule->field_count] = field; + rule->fieldflags[rule->field_count] = oper; + + switch(field) { + case AUDIT_UID: + case AUDIT_EUID: + case AUDIT_SUID: + case AUDIT_FSUID: + case AUDIT_LOGINUID: + if (isdigit(value[0])) { + rule->values[rule->field_count] = strtoul(value, NULL, 0); + } else { + pw = getpwnam(value); + if (pw == NULL) { + SLOGE("Unknown user %s", value); + return -1; + } + rule->values[rule->field_count] = pw->pw_uid; + } + break; + case AUDIT_GID: + case AUDIT_EGID: + case AUDIT_SGID: + case AUDIT_FSGID: + if (isdigit(value[0])) { + rule->values[rule->field_count] = strtoul(value, NULL, 0); + } else { + gr = getgrnam(value); + if (gr == NULL) { + SLOGE("Unknown group %s", value); + return -1; + } + rule->values[rule->field_count] = gr->gr_gid; + } + break; + case AUDIT_SUCCESS: + // According to the auditctl man page success should only have 0 or 1 + if (strcmp(value, "0") == 0 || strcmp(value, "1") == 0) { + rule->values[rule->field_count] = strtoul(value, NULL, 0); + } else { + SLOGE("Invalid value %s for success field", value); + return -1; + } + break; + default: + SLOGE("Unsupported field: %s", audit_field_to_string(field)); + return -1; + } + + rule->field_count++; + return 0; +} + +int audit_add_dir(struct audit_rule_data **rulep, const char *path) +{ + int len = strlen(path); + struct audit_rule_data *rule; + + if (rulep == NULL) { + return -EINVAL; + } + *rulep = calloc(1, sizeof(*rule) + len); + rule = *rulep; + if (!rule) { + SLOGE("Out of memory"); + return -1; + } + + rule->flags = AUDIT_FILTER_EXIT; + rule->action = AUDIT_ALWAYS; + rule->field_count = 2; + + rule->mask[0] = ~0; + rule->fields[0] = AUDIT_DIR; + rule->fieldflags[0] = AUDIT_EQUAL; + rule->values[0] = len; + + rule->mask[1] = ~0; + rule->fields[1] = AUDIT_PERM; + rule->fieldflags[1] = AUDIT_EQUAL; + rule->values[1] = AUDIT_PERM_READ | AUDIT_PERM_WRITE | + AUDIT_PERM_EXEC | AUDIT_PERM_ATTR; + + rule->buflen = len; + memcpy(&rule->buf[0], path, len); + + return 0; +} + +int audit_set_enabled(int fd, uint32_t state) +{ + if (state > AUDIT_LOCKED) { + return -1; + } + + struct audit_status s; + memset(&s, 0, sizeof(s)); + s.mask = AUDIT_STATUS_ENABLED; + s.enabled = state; + + return audit_send(fd, AUDIT_SET, &s, sizeof(s)); +} + +int audit_set_pid(int fd, uint32_t pid, rep_wait_t wmode) +{ + int rc; + struct audit_reply rep; + struct audit_status status; + + memset(&status, 0, sizeof(status)); + + /* + * In order to set the auditd PID we send an audit message over the netlink socket + * with the pid field of the status struct set to our current pid, and the + * the mask set to AUDIT_STATUS_PID + */ + status.pid = pid; + status.mask = AUDIT_STATUS_PID; + + /* Let the kernel know this pid will be registering for audit events */ + rc = audit_send(fd, AUDIT_SET, &status, sizeof(status)); + if (rc < 0) { + SLOGE("Could net set pid for audit events, error: %s", strerror(-rc)); + return rc; + } + + /* + * In a request where we need to wait for a response, wait for the message + * and discard it. This message confirms and sync's us with the kernel. + * This daemon is now registered as the audit logger. Only wait if the + * wmode is != WAIT_NO + */ + if (wmode != WAIT_NO) { + /* TODO + * If the daemon dies and restarts the message didn't come back, + * so I went to non-blocking and it seemed to fix the bug. + * Need to investigate further. + */ + audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0); + } + + return 0; +} + +int audit_open() +{ + return socket(PF_NETLINK, SOCK_RAW, NETLINK_AUDIT); +} + +int audit_get_reply(int fd, struct audit_reply *rep, reply_t block, int peek) +{ + ssize_t len; + int flags; + + struct sockaddr_nl nladdr; + socklen_t nladdrlen = sizeof(nladdr); + + if (fd < 0) { + return -EBADF; + } + + /* Set up the flags for recv from */ + flags = (block == GET_REPLY_NONBLOCKING) ? MSG_DONTWAIT : 0; + flags |= peek; + + /* + * Get the data from the netlink socket but on error we need to be carefull, + * the interface shows that EINTR can never be returned, other errors, however, + * can be returned. + */ + do { + len = recvfrom(fd, &rep->msg, sizeof(rep->msg), flags, (struct sockaddr*) &nladdr, + &nladdrlen); + + /* + * EAGAIN and EINTR should be re-tried until success or + * another error manifests. + */ + if (len < 0 && errno != EINTR) { + if (errno == EAGAIN) { + if (block == GET_REPLY_NONBLOCKING) { + /* If the request is non blocking and the errno is EAGAIN, just return 0 */ + return 0; + } + } else { + SLOGE("Error receiving from netlink socket, error: %s", strerror(errno)); + return -errno; + } + } + + /* 0 or greater indicates success */ + } while (len < 0); + + if (nladdrlen != sizeof(nladdr)) { + SLOGE("Protocol fault, error: %s", strerror(EPROTO)); + return -EPROTO; + } + + /* Make sure the netlink message was not spoof'd */ + if (nladdr.nl_pid) { + SLOGE("Invalid netlink pid received, expected 0 got: %d", nladdr.nl_pid); + return -EINVAL; + } + + return set_internal_fields(rep, len); +} + +void audit_close(int fd) +{ + int rc = close(fd); + if (rc < 0) { + SLOGE("Attempting to close invalid fd %d, error: %s", fd, strerror(errno)); + } + return; +} diff --git a/auditd/libaudit.h b/auditd/libaudit.h new file mode 100644 index 00000000..ffe6b0f1 --- /dev/null +++ b/auditd/libaudit.h @@ -0,0 +1,179 @@ +/* + * Copyright 2012, Samsung Telecommunications of America + * + * 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. + * + * Written by William Roberts + */ + +#ifndef _LIBAUDIT_H_ +#define _LIBAUDIT_H_ + +#include +#include +#include +#include +#include + +#define MAX_AUDIT_MESSAGE_LENGTH 8970 + +#define AUDIT_OFF 0 +#define AUDIT_ON 1 +#define AUDIT_LOCKED 2 + +typedef enum { + GET_REPLY_BLOCKING=0, + GET_REPLY_NONBLOCKING +} reply_t; + +typedef enum { + WAIT_NO, + WAIT_YES +} rep_wait_t; + +struct audit_sig_info { + uid_t uid; + pid_t pid; + char ctx[0]; +}; + +struct audit_message { + struct nlmsghdr nlh; + char data[MAX_AUDIT_MESSAGE_LENGTH]; +}; + +struct audit_reply { + int type; + int len; + struct nlmsghdr *nlh; + struct audit_message msg; + + union { + struct audit_status *status; + struct audit_rule_data *ruledata; + const char *message; + struct nlmsgerr *error; + struct audit_sig_info *signal_info; + }; +}; + +/** + * Opens a connection to the Audit netlink socket + * @return + * A valid fd on success or < 0 on error with errno set. + * Returns the same errors as man 2 socket. + */ +extern int audit_open(void); + +/** + * Closes the fd returned from audit_open() + * @param fd + * The fd to close + */ +extern void audit_close(int fd); + +/** + * + * @param fd + * The fd returned by a call to audit_open() + * @param rep + * The response struct to store the response in. + * @param block + * Whether or not to block on IO + * @param peek + * Whether or not we are to remove the message from + * the queue when we do a read on the netlink socket. + * @return + * This function returns 0 on success, else -errno. + */ +extern int audit_get_reply(int fd, struct audit_reply *rep, reply_t block, + int peek); + +/** + * Sets a pid to recieve audit netlink events from the kernel + * @param fd + * The fd returned by a call to audit_open() + * @param pid + * The pid whom to set as the reciever of audit messages + * @param wmode + * Whether or not to block on the underlying socket io calls. + * @return + * This function returns 0 on success, -errno on error. + */ +extern int audit_set_pid(int fd, uint32_t pid, rep_wait_t wmode); + +/** + * Sends a command to the audit netlink socket + * @param fd + * The fd returned by a call to audit_open() + * @param type + * message type, see audit.h in the kernel + * @param data + * opaque data pointer + * @param size + * size of data in *data + * @return + * This function returns 0 on success, -errno on error. + */ +extern int audit_send(int fd, int type, const void *data, unsigned int size); + +/** + * Allocates a rule and adds a directory to watch, defaults to all permissions. + * Call audit_update_watch_perms() subsequently to update permissions. + * @param rulep + * double pointer to an unallocated audit_rule_data, which will be allocated. This must be freed + * @param path + * path to add to the rule + * @return + * This function returns 0 on success, -errno on error. + */ +extern int audit_add_dir(struct audit_rule_data **rulep, const char *path); + +/** + * Sets enabled flag, 0 for audit off, 1 for audit on, 2 for audit locked + * @param fd + * file descripter returned by audit_open() + * @param state + * 0 for audit off, 1 for audit on, 2 for audit locked + * @return + * This function returns 0 on success, -errno on error, -1 if already locked + */ +extern int audit_set_enabled(int fd, uint32_t state); + +/** + * Sets permissions for an already allocated watch rule + * @param rule + * rule to set permissions on + * @param perms + * permissions to set, AUDIT_PERM_{READ,WRITE,EXEC,ATTR} + * @return + * This function returns 0 on success, -1 if rule is NULL and -2 if there are too many fields + */ +extern int audit_update_watch_perms(struct audit_rule_data *rule, int perms); + +/** + * Sets permissions for an already allocated watch rule + * @param rule + * rule to add field to + * @param field + * field from audit.h AUDIT_PID...AUDIT_FILETYPE + * @param oper + * operator from audit.h AUDIT_EQUAL|AUDIT_NOT_EQUAL|AUDIT_BIT_MASK + * @param value + * value to match for the field (e.g., uid=1000, 1000 is the value) + * @return + * This function returns 0 on success, -1 if rule is NULL and -2 if there are too many fields + */ +extern int audit_add_field(struct audit_rule_data *rule, int field, int oper, char *value); + +#endif diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp index 06c16f8d..5eef93ff 100644 --- a/debuggerd/debuggerd.cpp +++ b/debuggerd/debuggerd.cpp @@ -1,5 +1,6 @@ /* * Copyright 2006, The Android Open Source Project + * Copyright (c) 2013, The Linux Foundation. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,6 +15,8 @@ * limitations under the License. */ +#define LOG_TAG "DEBUG" + #include #include #include @@ -74,11 +77,13 @@ static void wait_for_user_action(const debugger_request_t &request) { "* and start gdbclient:\n" "*\n" "* gdbclient %s :5039 %d\n" + "* or\n" + "* dddclient %s :5039 %d\n" "*\n" "* Wait for gdb to start, then press the VOLUME DOWN key\n" "* to let the process continue crashing.\n" "********************************************************", - request.pid, exe, request.tid); + request.pid, exe, request.tid, exe, request.tid); // Wait for VOLUME DOWN. if (init_getevent() == 0) { @@ -124,6 +129,84 @@ static int get_process_info(pid_t tid, pid_t* out_pid, uid_t* out_uid, uid_t* ou return fields == 7 ? 0 : -1; } +static bool copy_file(const char* src, char* dest) +{ + #define BUF_SIZE 64 + ssize_t bytes; + int source_fh, dest_fh; + int total_size = 0; + char buffer[BUF_SIZE]; + + if ((source_fh = open(src, O_RDONLY, O_NOFOLLOW)) == -1) { + ALOGE("Unable to open source file %s\n", src); + } else { + if((dest_fh = open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW, 0640)) == -1) { + ALOGE("Unable to write destination file %s\n", dest); + } else { + while ((bytes = read(source_fh, buffer, BUF_SIZE)) > 0) { + if (write(dest_fh, buffer, bytes) < 0) { + ALOGE("Write failed for destination file %s. Copied %d bytes\n", + dest, total_size); + break; + } + total_size += bytes; + } + ALOGI("Copied %s to %s - size: %d\n", src, dest, total_size); + fsync(dest_fh); + close(dest_fh); + } + close(source_fh); + if (total_size > 0) { + return true; + } + } + return false; +} + +static void collect_etb_map(int cr_pid) +{ + struct stat s; + char src_buf[64]; + char dest_buf[64]; + + snprintf(dest_buf, sizeof dest_buf, "/data/core/etb.%d", cr_pid); + if (!copy_file("/dev/coresight-tmc-etf", dest_buf)) { + ALOGE("Unable to copy ETB buffer file /dev/coresight-tmc-etf\n"); + } else { + memset(src_buf, 0, sizeof(src_buf)); + snprintf(src_buf, sizeof(src_buf), "/proc/%d/maps", cr_pid); + if(stat(src_buf, &s)) { + ALOGE("map file /proc/%d/maps does not exist for pid %d\n", + cr_pid, cr_pid); + } else { + snprintf(dest_buf, sizeof dest_buf, "/data/core/maps.%d", cr_pid); + if (!copy_file(src_buf, dest_buf)) { + ALOGE("Unable to copy map file /proc/%d/maps", cr_pid); + } + } + } +} + +static void enable_etb_trace(struct ucred cr) { + char value[PROPERTY_VALUE_MAX]; + property_get("persist.debug.trace", value, ""); + if ((strcmp(value,"1") == 0)) { + /* Allow ETB collection only once; Note: in future this behavior can be changed + * To allow this, use a property to indicate whether the ETB has been collected */ + property_get("debug.etb.collected", value, ""); + if(strcmp(value,"1")) { + ALOGI("Collecting ETB dumps (from pid=%d uid=%d)\n", + cr.pid, cr.uid); + property_set("debug.etb.collected", "1"); + collect_etb_map(cr.pid); + } + else { + ALOGI("ETB already collected once, skipping (from pid=%d uid=%d)\n", + cr.pid, cr.uid); + } + } +} + static int read_request(int fd, debugger_request_t* out_request) { ucred cr; socklen_t len = sizeof(cr); @@ -170,6 +253,7 @@ static int read_request(int fd, debugger_request_t* out_request) { // Ensure that the tid reported by the crashing process is valid. char buf[64]; struct stat s; + enable_etb_trace(cr); snprintf(buf, sizeof buf, "/proc/%d/task/%d", out_request->pid, out_request->tid); if (stat(buf, &s)) { ALOGE("tid %d does not exist in pid %d. ignoring debug request\n", @@ -198,7 +282,19 @@ static bool should_attach_gdb(debugger_request_t* request) { char value[PROPERTY_VALUE_MAX]; property_get("debug.db.uid", value, "-1"); int debug_uid = atoi(value); - return debug_uid >= 0 && request->uid <= (uid_t)debug_uid; + if (debug_uid >= 0 && request->uid <= (uid_t)debug_uid) { + return true; + } else { + /* External docs say to use 10,000 but more is likely needed; be helpful. */ + if (request->uid > (uid_t)debug_uid) { + ALOGI("request->uid:%d > property debug.db.uid:%d; NOT waiting for gdb.", + request->uid, debug_uid); + } else { + ALOGI("property debug.db.uid not set; NOT waiting for gdb."); + ALOGI("HINT: adb shell setprop debug.db.uid 100000"); + ALOGI("HINT: adb forward tcp:5039 tcp:5039"); + } + } } return false; } diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp index 0c1b80fd..4234fae3 100644 --- a/debuggerd/tombstone.cpp +++ b/debuggerd/tombstone.cpp @@ -742,16 +742,22 @@ char* engrave_tombstone(pid_t pid, pid_t tid, int signal, int original_si_code, log_t log; log.current_tid = tid; log.crashed_tid = tid; + int fd = -1; if ((mkdir(TOMBSTONE_DIR, 0755) == -1) && (errno != EEXIST)) { _LOG(&log, logtype::ERROR, "failed to create %s: %s\n", TOMBSTONE_DIR, strerror(errno)); } - - if (chown(TOMBSTONE_DIR, AID_SYSTEM, AID_SYSTEM) == -1) { - _LOG(&log, logtype::ERROR, "failed to change ownership of %s: %s\n", TOMBSTONE_DIR, strerror(errno)); + if(((fd = open(TOMBSTONE_DIR, O_NOFOLLOW|O_RDONLY)) != -1) ||((fd = open(TOMBSTONE_DIR, O_NOFOLLOW|O_WRONLY)) != -1)){ + if (fchown(fd, AID_SYSTEM, AID_SYSTEM) < 0){ + _LOG(&log, logtype::ERROR, "failed to change ownership of %s: %s\n", TOMBSTONE_DIR, strerror(errno)); + close(fd); + return NULL; + } + close(fd); + } else { + _LOG(&log, logtype::ERROR, "failed to open %s: %s\n", TOMBSTONE_DIR, strerror(errno)); + return NULL; } - - int fd = -1; char* path = NULL; if (selinux_android_restorecon(TOMBSTONE_DIR, 0) == 0) { path = find_and_open_tombstone(&fd); diff --git a/fastboot/Android.mk b/fastboot/Android.mk index e11691fb..8a42b54a 100644 --- a/fastboot/Android.mk +++ b/fastboot/Android.mk @@ -55,7 +55,8 @@ LOCAL_STATIC_LIBRARIES := \ libunz \ libext4_utils_host \ libsparse_host \ - libz + libz \ + liblz4-host ifneq ($(HOST_OS),windows) LOCAL_STATIC_LIBRARIES += libselinux @@ -68,7 +69,7 @@ LOCAL_LDFLAGS += -ldl -rdynamic -Wl,-rpath,. LOCAL_REQUIRED_MODULES := libf2fs_fmt_host_dyn # The following libf2fs_* are from system/extras/f2fs_utils, # and do not use code in external/f2fs-tools. -LOCAL_STATIC_LIBRARIES += libf2fs_utils_host libf2fs_ioutils_host libf2fs_dlutils_host +LOCAL_STATIC_LIBRARIES += libf2fs_utils_host libf2fs_dlutils_host endif include $(BUILD_HOST_EXECUTABLE) diff --git a/fastboot/fastboot.c b/fastboot/fastboot.c index 43d05aa3..bbbd8073 100644 --- a/fastboot/fastboot.c +++ b/fastboot/fastboot.c @@ -214,7 +214,10 @@ int match_fastboot_with_serial(usb_ifc_info *info, const char *local_serial) (info->dev_vendor != 0x413c) && // DELL (info->dev_vendor != 0x2314) && // INQ Mobile (info->dev_vendor != 0x0b05) && // Asus - (info->dev_vendor != 0x0bb4)) // HTC + (info->dev_vendor != 0x0bb4) && // HTC + (info->dev_vendor != 0x0421) && // Nokia + (info->dev_vendor != 0x1ebf) && // Coolpad + (info->dev_vendor != 0x2a96)) // MMX return -1; if(info->ifc_class != 0xff) return -1; if(info->ifc_subclass != 0x42) return -1; diff --git a/fastboot/fastboot_protocol.txt b/fastboot/fastboot_protocol.txt index 2248992d..37b19590 100644 --- a/fastboot/fastboot_protocol.txt +++ b/fastboot/fastboot_protocol.txt @@ -12,8 +12,8 @@ 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 +* Max packet size must be 64 bytes for full-speed, 512 bytes for + high-speed and 1024 bytes for Super Speed USB. * The protocol is entirely host-driven and synchronous (unlike the multi-channel, bi-directional, asynchronous ADB protocol) diff --git a/fastboot/protocol.c b/fastboot/protocol.c index 84e9837b..10a84c12 100644 --- a/fastboot/protocol.c +++ b/fastboot/protocol.c @@ -216,7 +216,7 @@ int fb_download_data(usb_handle *usb, const void *data, unsigned size) } } -#define USB_BUF_SIZE 512 +#define USB_BUF_SIZE 1024 static char usb_buf[USB_BUF_SIZE]; static int usb_buf_len; diff --git a/fastboot/usb_linux.c b/fastboot/usb_linux.c index fabbd516..a52d3168 100644 --- a/fastboot/usb_linux.c +++ b/fastboot/usb_linux.c @@ -223,6 +223,21 @@ static int filter_usb_device(char* sysfs_name, } else { out = ept->bEndpointAddress; } + + // USB3 devices are required to have superspeed companion + // descriptors. They aren't needed to locate the target + // so just skip them. + // + // When using the Android build environment, the old ch9.h + // header from the prebuilts directory for the host does + // not contain superspeed-related definitions. +#ifndef USB_DT_SS_EP_COMP_SIZE +#define USB_DT_SS_EP_COMP_SIZE 6 +#endif + if (dev->bcdUSB >= 0x0300) { + len -= USB_DT_SS_EP_COMP_SIZE; + ptr += USB_DT_SS_EP_COMP_SIZE; + } } info.has_bulk_in = (in != -1); diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk index 61bf1ee6..cc7d58fc 100644 --- a/fs_mgr/Android.mk +++ b/fs_mgr/Android.mk @@ -4,12 +4,16 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= fs_mgr.c fs_mgr_verity.c fs_mgr_fstab.c +LOCAL_SRC_FILES += fs_mgr_format.c -LOCAL_C_INCLUDES := $(LOCAL_PATH)/include +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include \ + system/vold \ + system/extras/ext4_utils \ + external/openssl/include LOCAL_MODULE:= libfs_mgr -LOCAL_STATIC_LIBRARIES := liblogwrap libmincrypt libext4_utils_static -LOCAL_C_INCLUDES += system/extras/ext4_utils +LOCAL_STATIC_LIBRARIES := liblogwrap libmincrypt libext4_utils_static libext2_blkid libext2_uuid_static +LOCAL_C_INCLUDES += system/extras/ext4_utils external/e2fsprogs/lib LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include LOCAL_CFLAGS := -Werror @@ -34,7 +38,8 @@ LOCAL_FORCE_STATIC_EXECUTABLE := true LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)/sbin LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED) -LOCAL_STATIC_LIBRARIES := libfs_mgr liblogwrap libcutils liblog libc libmincrypt libext4_utils_static +LOCAL_STATIC_LIBRARIES := libfs_mgr liblogwrap libcutils liblog libc libmincrypt libext4_utils_static libext2_blkid libext2_uuid_static +LOCAL_STATIC_LIBRARIES += libsparse_static libz libselinux LOCAL_CFLAGS := -Werror diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c index ad029222..48dfb479 100644 --- a/fs_mgr/fs_mgr.c +++ b/fs_mgr/fs_mgr.c @@ -35,11 +35,15 @@ #include #include #include +#include #include "mincrypt/rsa.h" #include "mincrypt/sha.h" #include "mincrypt/sha256.h" +#include "ext4_utils.h" +#include "wipe.h" + #include "fs_mgr_priv.h" #include "fs_mgr_priv_verity.h" @@ -53,6 +57,7 @@ #define FSCK_LOG_FILE "/dev/fscklogs/log" #define ZRAM_CONF_DEV "/sys/block/zram0/disksize" +#define ZRAM_STREAMS "/sys/block/zram0/max_comp_streams" #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a))) @@ -116,7 +121,17 @@ static void check_fs(char *blk_device, char *fs_type, char *target) ret = mount(blk_device, target, fs_type, tmpmnt_flags, tmpmnt_opts); INFO("%s(): mount(%s,%s,%s)=%d\n", __func__, blk_device, target, fs_type, ret); if (!ret) { - umount(target); + int i; + for (i = 0; i < 5; i++) { + // Try to umount 5 times before continuing on. + // Should we try rebooting if all attempts fail? + int result = umount(target); + if (result == 0) { + break; + } + ERROR("%s(): umount(%s)=%d: %s\n", __func__, target, result, strerror(errno)); + sleep(1); + } } /* @@ -139,12 +154,12 @@ static void check_fs(char *blk_device, char *fs_type, char *target) } } } else if (!strcmp(fs_type, "f2fs")) { - char *f2fs_fsck_argv[] = { - F2FS_FSCK_BIN, - "-f", - blk_device - }; - INFO("Running %s -f %s\n", F2FS_FSCK_BIN, blk_device); + char *f2fs_fsck_argv[] = { + F2FS_FSCK_BIN, + "-a", + blk_device + }; + INFO("Running %s on %s\n", F2FS_FSCK_BIN, blk_device); ret = android_fork_execvp_ext(ARRAY_SIZE(f2fs_fsck_argv), f2fs_fsck_argv, &status, true, LOG_KLOG | LOG_FILE, @@ -281,6 +296,8 @@ static int mount_with_alternatives(struct fstab *fstab, int start_idx, int *end_ int i; int mount_errno = 0; int mounted = 0; + int cmp_len; + char *detected_fs_type; if (!end_idx || !attempted_idx || start_idx >= fstab->num_entries) { errno = EINVAL; @@ -306,8 +323,16 @@ static int mount_with_alternatives(struct fstab *fstab, int start_idx, int *end_ } 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); + /* Skip file system check unless we are sure we are the right type */ + detected_fs_type = blkid_get_tag_value(NULL, "TYPE", fstab->recs[i].blk_device); + if (detected_fs_type) { + cmp_len = (!strncmp(detected_fs_type, "ext", 3) && + strlen(detected_fs_type) == 4) ? 3 : strlen(detected_fs_type); + if (!strncmp(fstab->recs[i].fs_type, detected_fs_type, cmp_len)) { + check_fs(fstab->recs[i].blk_device, fstab->recs[i].fs_type, + fstab->recs[i].mount_point); + } + } } if (!__mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point, &fstab->recs[i])) { *attempted_idx = i; @@ -371,6 +396,7 @@ int fs_mgr_mount_all(struct fstab *fstab) } if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) { + wait_for_file("/dev/device-mapper", WAIT_TIMEOUT); int rc = fs_mgr_setup_verity(&fstab->recs[i]); if (device_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) { INFO("Verity disabled"); @@ -380,6 +406,8 @@ int fs_mgr_mount_all(struct fstab *fstab) } } int last_idx_inspected; + int top_idx = i; + mret = mount_with_alternatives(fstab, i, &last_idx_inspected, &attempted_idx); i = last_idx_inspected; mount_errno = errno; @@ -400,8 +428,8 @@ int fs_mgr_mount_all(struct fstab *fstab) encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED; } } else { - INFO("Could not umount %s - allow continue unencrypted\n", - fstab->recs[attempted_idx].mount_point); + WARNING("Could not umount %s (%s) - allow continue unencrypted\n", + fstab->recs[attempted_idx].mount_point, strerror(errno)); continue; } } @@ -409,10 +437,38 @@ int fs_mgr_mount_all(struct fstab *fstab) continue; } - /* mount(2) returned an error, check if it's encryptable and deal with it */ + /* mount(2) returned an error, handle the encryptable/formattable case */ + bool wiped = partition_wiped(fstab->recs[top_idx].blk_device); + if (mret && mount_errno != EBUSY && mount_errno != EACCES && + fs_mgr_is_formattable(&fstab->recs[top_idx]) && wiped) { + /* top_idx and attempted_idx point at the same partition, but sometimes + * at two different lines in the fstab. Use the top one for formatting + * as that is the preferred one. + */ + ERROR("%s(): %s is wiped and %s %s is formattable. Format it.\n", __func__, + fstab->recs[top_idx].blk_device, fstab->recs[top_idx].mount_point, + fstab->recs[top_idx].fs_type); + if (fs_mgr_is_encryptable(&fstab->recs[top_idx]) && + strcmp(fstab->recs[top_idx].key_loc, KEY_IN_FOOTER)) { + int fd = open(fstab->recs[top_idx].key_loc, O_WRONLY, 0644); + if (fd >= 0) { + INFO("%s(): also wipe %s\n", __func__, fstab->recs[top_idx].key_loc); + wipe_block_device(fd, get_file_size(fd)); + close(fd); + } else { + ERROR("%s(): %s wouldn't open (%s)\n", __func__, + fstab->recs[top_idx].key_loc, strerror(errno)); + } + } + if (fs_mgr_do_format(&fstab->recs[top_idx]) == 0) { + /* Let's replay the mount actions. */ + i = top_idx - 1; + continue; + } + } if (mret && mount_errno != EBUSY && mount_errno != EACCES && fs_mgr_is_encryptable(&fstab->recs[attempted_idx])) { - if(partition_wiped(fstab->recs[attempted_idx].blk_device)) { + if (wiped) { ERROR("%s(): %s is wiped and %s %s is encryptable. Suggest recovery...\n", __func__, fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point, fstab->recs[attempted_idx].fs_type); @@ -605,6 +661,14 @@ int fs_mgr_swapon_all(struct fstab *fstab) */ FILE *zram_fp; + /* The stream count parameter is only available on new kernels. + * It must be set before the disk size. */ + zram_fp = fopen(ZRAM_STREAMS, "r+"); + if (zram_fp) { + fprintf(zram_fp, "%d\n", fstab->recs[i].zram_streams); + fclose(zram_fp); + } + zram_fp = fopen(ZRAM_CONF_DEV, "r+"); if (zram_fp == NULL) { ERROR("Unable to open zram conf device %s\n", ZRAM_CONF_DEV); diff --git a/fs_mgr/fs_mgr_format.c b/fs_mgr/fs_mgr_format.c new file mode 100644 index 00000000..2a3d0a72 --- /dev/null +++ b/fs_mgr/fs_mgr_format.c @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2015 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "ext4_utils.h" +#include "ext4.h" +#include "make_ext4fs.h" +#include "fs_mgr_priv.h" + +extern struct fs_info info; /* magic global from ext4_utils */ +extern void reset_ext4fs_info(); + +static int format_ext4(char *fs_blkdev, char *fs_mnt_point, long long fs_length) +{ + unsigned int nr_sec; + int fd, rc = 0; + + if ((fd = open(fs_blkdev, O_WRONLY, 0644)) < 0) { + ERROR("Cannot open block device. %s\n", strerror(errno)); + return -1; + } + + if ((ioctl(fd, BLKGETSIZE, &nr_sec)) == -1) { + ERROR("Cannot get block device size. %s\n", strerror(errno)); + close(fd); + return -1; + } + + /* Format the partition using the calculated length */ + reset_ext4fs_info(); + info.len = ((off64_t)nr_sec * 512); + + if (fs_length > 0) { + info.len = fs_length; + } else if (fs_length < 0) { + info.len += fs_length; + } + + /* Use make_ext4fs_internal to avoid wiping an already-wiped partition. */ + rc = make_ext4fs_internal(fd, NULL, fs_mnt_point, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL); + if (rc) { + ERROR("make_ext4fs returned %d.\n", rc); + } + close(fd); + + return rc; +} + +static int format_f2fs(char *fs_blkdev, long long fs_length) +{ + char * args[5]; + int pid; + int rc = 0; + char buff[65]; + + args[0] = (char *)"/sbin/mkfs.f2fs"; + + if (fs_length >= 0) { + snprintf(buff, sizeof(buff), "%lld", fs_length / 512); + args[1] = fs_blkdev; + args[2] = buff; + args[3] = (char *)0; + } else if (fs_length < 0) { + snprintf(buff, sizeof(buff), "%lld", -fs_length); + args[1] = "-r"; + args[2] = buff; + args[3] = fs_blkdev; + args[4] = (char *)0; + } + + pid = fork(); + if (pid < 0) { + return pid; + } + if (!pid) { + /* This doesn't return */ + execv("/sbin/mkfs.f2fs", args); + exit(1); + } + for(;;) { + pid_t p = waitpid(pid, &rc, 0); + if (p != pid) { + ERROR("Error waiting for child process - %d\n", p); + rc = -1; + break; + } + if (WIFEXITED(rc)) { + rc = WEXITSTATUS(rc); + INFO("%s done, status %d\n", args[0], rc); + if (rc) { + rc = -1; + } + break; + } + ERROR("Still waiting for %s...\n", args[0]); + } + + return rc; +} + +int fs_mgr_do_format(struct fstab_rec *fstab) +{ + int rc = -EINVAL; + + ERROR("%s: Format %s as '%s'.\n", __func__, fstab->blk_device, fstab->fs_type); + + if (!strncmp(fstab->fs_type, "f2fs", 4)) { + rc = format_f2fs(fstab->blk_device, fstab->length); + } else if (!strncmp(fstab->fs_type, "ext4", 4)) { + rc = format_ext4(fstab->blk_device, fstab->mount_point, fstab->length); + } else { + ERROR("File system type '%s' is not supported\n", fstab->fs_type); + } + + return rc; +} diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c index ab8f128c..77580621 100644 --- a/fs_mgr/fs_mgr_fstab.c +++ b/fs_mgr/fs_mgr_fstab.c @@ -29,6 +29,7 @@ struct fs_mgr_flag_values { int partnum; int swap_prio; unsigned int zram_size; + unsigned int zram_streams; }; struct flag_list { @@ -68,6 +69,8 @@ static struct flag_list fs_mgr_flags[] = { { "zramsize=", MF_ZRAMSIZE }, { "verify", MF_VERIFY }, { "noemulatedsd", MF_NOEMULATEDSD }, + { "formattable", MF_FORMATTABLE }, + { "zramstreams=",MF_ZRAMSTREAMS }, { "defaults", 0 }, { 0, 0 }, }; @@ -87,6 +90,7 @@ static int parse_flags(char *flags, struct flag_list *fl, memset(flag_vals, 0, sizeof(*flag_vals)); flag_vals->partnum = -1; flag_vals->swap_prio = -1; /* negative means it wasn't specified. */ + flag_vals->zram_streams = 1; } /* initialize fs_options to the null string */ @@ -146,6 +150,8 @@ static int parse_flags(char *flags, struct flag_list *fl, flag_vals->swap_prio = strtoll(strchr(p, '=') + 1, NULL, 0); } else if ((fl[i].flag == MF_ZRAMSIZE) && flag_vals) { flag_vals->zram_size = strtoll(strchr(p, '=') + 1, NULL, 0); + } else if ((fl[i].flag == MF_ZRAMSTREAMS) && flag_vals) { + flag_vals->zram_streams = strtoll(strchr(p, '=') + 1, NULL, 0); } break; } @@ -296,6 +302,7 @@ struct fstab *fs_mgr_read_fstab(const char *fstab_path) fstab->recs[cnt].partnum = flag_vals.partnum; fstab->recs[cnt].swap_prio = flag_vals.swap_prio; fstab->recs[cnt].zram_size = flag_vals.zram_size; + fstab->recs[cnt].zram_streams = flag_vals.zram_streams; cnt++; } fclose(fstab_file); @@ -432,3 +439,8 @@ int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab) { return fstab->fs_mgr_flags & MF_NOEMULATEDSD; } + +int fs_mgr_is_formattable(struct fstab_rec *fstab) +{ + return fstab->fs_mgr_flags & (MF_FORMATTABLE); +} diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h index 34938fad..081d9c3d 100644 --- a/fs_mgr/fs_mgr_priv.h +++ b/fs_mgr/fs_mgr_priv.h @@ -21,6 +21,7 @@ #include #define INFO(x...) KLOG_INFO("fs_mgr", x) +#define WARNING(x...) KLOG_WARNING("fs_mgr", x) #define ERROR(x...) KLOG_ERROR("fs_mgr", x) #define CRYPTO_TMPFS_OPTIONS "size=256m,mode=0771,uid=1000,gid=1000" @@ -75,6 +76,8 @@ #define MF_FORCECRYPT 0x400 #define MF_NOEMULATEDSD 0x800 /* no emulated sdcard daemon, sd card is the only external storage */ +#define MF_FORMATTABLE 0x1000 +#define MF_ZRAMSTREAMS 0x2000 #define DM_BUF_SIZE 4096 diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h index 5e2ff416..0d92c562 100644 --- a/fs_mgr/include/fs_mgr.h +++ b/fs_mgr/include/fs_mgr.h @@ -56,6 +56,7 @@ struct fstab_rec { int partnum; int swap_prio; unsigned int zram_size; + unsigned int zram_streams; }; struct fstab *fs_mgr_read_fstab(const char *fstab_path); @@ -79,12 +80,17 @@ int fs_mgr_add_entry(struct fstab *fstab, const char *mount_point, const char *fs_type, const char *blk_device); struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path); +struct fstab_rec *fs_mgr_get_entry_for_mount_point_after(struct fstab_rec *start_rec, 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_verified(struct fstab_rec *fstab); int fs_mgr_is_encryptable(struct fstab_rec *fstab); int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab); +int fs_mgr_is_formattable(struct fstab_rec *fstab); int fs_mgr_swapon_all(struct fstab *fstab); + +int fs_mgr_do_format(struct fstab_rec *fstab); + #ifdef __cplusplus } #endif diff --git a/healthd/Android.mk b/healthd/Android.mk index 1d238b1e..37e5490c 100644 --- a/healthd/Android.mk +++ b/healthd/Android.mk @@ -5,7 +5,7 @@ ifneq ($(BUILD_TINY_ANDROID),true) LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -LOCAL_SRC_FILES := healthd_board_default.cpp +LOCAL_SRC_FILES := healthd_board_default.cpp healthd_msm_alarm.cpp LOCAL_MODULE := libhealthd.default LOCAL_CFLAGS := -Werror include $(BUILD_STATIC_LIBRARY) @@ -15,10 +15,15 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := \ healthd.cpp \ healthd_mode_android.cpp \ - healthd_mode_charger.cpp \ BatteryMonitor.cpp \ BatteryPropertiesRegistrar.cpp +ifeq ($(strip $(BOARD_HEALTHD_CUSTOM_CHARGER)),) + LOCAL_SRC_FILES += healthd_mode_charger.cpp +else + LOCAL_SRC_FILES += ../../../$(BOARD_HEALTHD_CUSTOM_CHARGER) +endif + LOCAL_MODULE := healthd LOCAL_MODULE_TAGS := optional LOCAL_FORCE_STATIC_EXECUTABLE := true @@ -27,6 +32,19 @@ LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED) LOCAL_CFLAGS := -D__STDC_LIMIT_MACROS -Werror +HEALTHD_CHARGER_DEFINES := RED_LED_PATH \ + GREEN_LED_PATH \ + BLUE_LED_PATH \ + BACKLIGHT_PATH \ + SECONDARY_BACKLIGHT_PATH \ + CHARGING_ENABLED_PATH + +$(foreach healthd_charger_define,$(HEALTHD_CHARGER_DEFINES), \ + $(if $($(healthd_charger_define)), \ + $(eval LOCAL_CFLAGS += -D$(healthd_charger_define)=\"$($(healthd_charger_define))\") \ + ) \ +) + ifeq ($(strip $(BOARD_CHARGER_DISABLE_INIT_BLANK)),true) LOCAL_CFLAGS += -DCHARGER_DISABLE_INIT_BLANK endif @@ -35,7 +53,11 @@ ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true) LOCAL_CFLAGS += -DCHARGER_ENABLE_SUSPEND endif -LOCAL_C_INCLUDES := bootable/recovery +ifeq ($(strip $(BOARD_CHARGER_SHOW_PERCENTAGE)),true) +LOCAL_CFLAGS += -DCHARGER_SHOW_PERCENTAGE +endif + +LOCAL_C_INCLUDES := $(call project-path-for,recovery) LOCAL_STATIC_LIBRARIES := libbatteryservice libbinder libminui libpng libz libutils libstdc++ libcutils liblog libm libc @@ -47,7 +69,7 @@ LOCAL_HAL_STATIC_LIBRARIES := libhealthd # Symlink /charger to /sbin/healthd LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT) \ - && ln -sf /sbin/healthd $(TARGET_ROOT_OUT)/charger + && rm -f $(TARGET_ROOT_OUT)/charger && ln -sf /sbin/healthd $(TARGET_ROOT_OUT)/charger include $(BUILD_EXECUTABLE) @@ -65,8 +87,13 @@ include $$(BUILD_PREBUILT) endef _img_modules := +ifeq ($(strip $(BOARD_HEALTHD_CUSTOM_CHARGER_RES)),) +IMAGES_DIR := images +else +IMAGES_DIR := ../../../$(BOARD_HEALTHD_CUSTOM_CHARGER_RES) +endif _images := -$(foreach _img, $(call find-subdir-subdir-files, "images", "*.png"), \ +$(foreach _img, $(call find-subdir-subdir-files, "$(IMAGES_DIR)", "*.png"), \ $(eval $(call _add-charger-image,$(_img)))) include $(CLEAR_VARS) diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp index 9388ed0c..66c4e8e4 100644 --- a/healthd/BatteryMonitor.cpp +++ b/healthd/BatteryMonitor.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2013 The Android Open Source Project + * Copyright (C) 2015 The CyanogenMod Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -135,6 +136,10 @@ BatteryMonitor::PowerSupplyType BatteryMonitor::readPowerSupplyType(const String { "USB_CDP", ANDROID_POWER_SUPPLY_TYPE_AC }, { "USB_ACA", ANDROID_POWER_SUPPLY_TYPE_AC }, { "Wireless", ANDROID_POWER_SUPPLY_TYPE_WIRELESS }, + { "Wipower", ANDROID_POWER_SUPPLY_TYPE_WIRELESS }, + { "DockBattery", ANDROID_POWER_SUPPLY_TYPE_DOCK_BATTERY }, + { "DockAC", ANDROID_POWER_SUPPLY_TYPE_DOCK_AC }, + { "USB_HVDCP", ANDROID_POWER_SUPPLY_TYPE_AC }, { NULL, 0 }, }; @@ -179,8 +184,11 @@ bool BatteryMonitor::update(void) { props.chargerAcOnline = false; props.chargerUsbOnline = false; props.chargerWirelessOnline = false; + props.chargerDockAcOnline = false; props.batteryStatus = BATTERY_STATUS_UNKNOWN; props.batteryHealth = BATTERY_HEALTH_UNKNOWN; + props.dockBatteryStatus = BATTERY_STATUS_UNKNOWN; + props.dockBatteryHealth = BATTERY_HEALTH_UNKNOWN; if (!mHealthdConfig->batteryPresentPath.isEmpty()) props.batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath); @@ -209,44 +217,100 @@ bool BatteryMonitor::update(void) { if (readFromFile(mHealthdConfig->batteryTechnologyPath, buf, SIZE) > 0) props.batteryTechnology = String8(buf); - unsigned int i; + props.dockBatterySupported = mHealthdConfig->dockBatterySupported; + if (props.dockBatterySupported) { + if (!mHealthdConfig->dockBatteryPresentPath.isEmpty()) + props.dockBatteryPresent = getBooleanField(mHealthdConfig->dockBatteryPresentPath); + else + props.dockBatteryPresent = mDockBatteryDevicePresent; - for (i = 0; i < mChargerNames.size(); i++) { - String8 path; - path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, - mChargerNames[i].string()); + props.dockBatteryLevel = mBatteryFixedCapacity ? + mBatteryFixedCapacity : + getIntField(mHealthdConfig->dockBatteryCapacityPath); + props.dockBatteryVoltage = getIntField(mHealthdConfig->dockBatteryVoltagePath) / 1000; - if (readFromFile(path, buf, SIZE) > 0) { - if (buf[0] != '0') { + props.dockBatteryTemperature = mBatteryFixedTemperature ? + mBatteryFixedTemperature : + getIntField(mHealthdConfig->dockBatteryTemperaturePath); + + if (readFromFile(mHealthdConfig->dockBatteryStatusPath, buf, SIZE) > 0) + props.dockBatteryStatus = getBatteryStatus(buf); + + if (readFromFile(mHealthdConfig->dockBatteryHealthPath, buf, SIZE) > 0) + props.dockBatteryHealth = getBatteryHealth(buf); + + if (readFromFile(mHealthdConfig->dockBatteryTechnologyPath, buf, SIZE) > 0) + props.dockBatteryTechnology = String8(buf); + } + + // reinitialize the mChargerNames vector everytime there is an update + String8 path; + DIR* dir = opendir(POWER_SUPPLY_SYSFS_PATH); + if (dir == NULL) { + KLOG_ERROR(LOG_TAG, "Could not open %s\n", POWER_SUPPLY_SYSFS_PATH); + } else { + struct dirent* entry; + // reconstruct the charger strings + mChargerNames.clear(); + while ((entry = readdir(dir))) { + const char* name = entry->d_name; + + if (!strcmp(name, ".") || !strcmp(name, "..")) + continue; + + // Look for "type" file in each subdirectory + path.clear(); + path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, name); + switch(readPowerSupplyType(path)) { + case ANDROID_POWER_SUPPLY_TYPE_BATTERY: + case ANDROID_POWER_SUPPLY_TYPE_DOCK_BATTERY: + break; + default: path.clear(); - path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, - mChargerNames[i].string()); - switch(readPowerSupplyType(path)) { - case ANDROID_POWER_SUPPLY_TYPE_AC: - props.chargerAcOnline = true; - break; - case ANDROID_POWER_SUPPLY_TYPE_USB: - props.chargerUsbOnline = true; - break; - case ANDROID_POWER_SUPPLY_TYPE_WIRELESS: - props.chargerWirelessOnline = true; - break; - default: - KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n", - mChargerNames[i].string()); + path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name); + if (access(path.string(), R_OK) == 0) { + mChargerNames.add(String8(name)); + if (readFromFile(path, buf, SIZE) > 0) { + if (buf[0] != '0') { + path.clear(); + path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH, + name); + switch(readPowerSupplyType(path)) { + case ANDROID_POWER_SUPPLY_TYPE_AC: + props.chargerAcOnline = true; + break; + case ANDROID_POWER_SUPPLY_TYPE_USB: + props.chargerUsbOnline = true; + break; + case ANDROID_POWER_SUPPLY_TYPE_WIRELESS: + props.chargerWirelessOnline = true; + break; + case ANDROID_POWER_SUPPLY_TYPE_DOCK_AC: + if (mHealthdConfig->dockBatterySupported) { + props.chargerDockAcOnline = true; + } + default: + KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n", + name); + } + } + } } - } - } - } + break; + } //switch + } //while + closedir(dir); + }//else logthis = !healthd_board_battery_update(&props); if (logthis) { char dmesgline[256]; + char dmesglinedock[256]; if (props.batteryPresent) { snprintf(dmesgline, sizeof(dmesgline), - "battery l=%d v=%d t=%s%d.%d h=%d st=%d", + "battery [l=%d v=%d t=%s%d.%d h=%d st=%d]", props.batteryLevel, props.batteryVoltage, props.batteryTemperature < 0 ? "-" : "", abs(props.batteryTemperature / 10), @@ -265,15 +329,37 @@ bool BatteryMonitor::update(void) { "battery none"); } - KLOG_WARNING(LOG_TAG, "%s chg=%s%s%s\n", dmesgline, + if (props.dockBatteryPresent) { + snprintf(dmesglinedock, sizeof(dmesglinedock), + "dock-battery [l=%d v=%d t=%s%d.%d h=%d st=%d]", + props.dockBatteryLevel, props.dockBatteryVoltage, + props.dockBatteryTemperature < 0 ? "-" : "", + abs(props.dockBatteryTemperature / 10), + abs(props.dockBatteryTemperature % 10), props.dockBatteryHealth, + props.dockBatteryStatus); + + if (!mHealthdConfig->dockBatteryCurrentNowPath.isEmpty()) { + int c = getIntField(mHealthdConfig->dockBatteryCurrentNowPath); + char b[20]; + + snprintf(b, sizeof(b), " c=%d", c / 1000); + strlcat(dmesglinedock, b, sizeof(dmesglinedock)); + } + } else { + snprintf(dmesglinedock, sizeof(dmesglinedock), + "dock-battery none"); + } + + KLOG_WARNING(LOG_TAG, "%s %s chg=%s%s%s%s\n", dmesgline, dmesglinedock, props.chargerAcOnline ? "a" : "", props.chargerUsbOnline ? "u" : "", - props.chargerWirelessOnline ? "w" : ""); + props.chargerWirelessOnline ? "w" : "", + props.chargerDockAcOnline ? "d" : ""); } healthd_mode_ops->battery_update(&props); return props.chargerAcOnline | props.chargerUsbOnline | - props.chargerWirelessOnline; + props.chargerWirelessOnline | props.chargerDockAcOnline; } status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) { @@ -337,13 +423,77 @@ status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) { return ret; } +status_t BatteryMonitor::getDockProperty(int id, struct BatteryProperty *val) { + status_t ret = BAD_VALUE; + if (!mHealthdConfig->dockBatterySupported) { + return ret; + } + + val->valueInt64 = LONG_MIN; + + switch(id) { + case BATTERY_PROP_CHARGE_COUNTER: + if (!mHealthdConfig->dockBatteryChargeCounterPath.isEmpty()) { + val->valueInt64 = + getIntField(mHealthdConfig->dockBatteryChargeCounterPath); + ret = NO_ERROR; + } else { + ret = NAME_NOT_FOUND; + } + break; + + case BATTERY_PROP_CURRENT_NOW: + if (!mHealthdConfig->dockBatteryCurrentNowPath.isEmpty()) { + val->valueInt64 = + getIntField(mHealthdConfig->dockBatteryCurrentNowPath); + ret = NO_ERROR; + } else { + ret = NAME_NOT_FOUND; + } + break; + + case BATTERY_PROP_CURRENT_AVG: + if (!mHealthdConfig->dockBatteryCurrentAvgPath.isEmpty()) { + val->valueInt64 = + getIntField(mHealthdConfig->dockBatteryCurrentAvgPath); + ret = NO_ERROR; + } else { + ret = NAME_NOT_FOUND; + } + break; + + case BATTERY_PROP_CAPACITY: + if (!mHealthdConfig->dockBatteryCapacityPath.isEmpty()) { + val->valueInt64 = + getIntField(mHealthdConfig->dockBatteryCapacityPath); + ret = NO_ERROR; + } else { + ret = NAME_NOT_FOUND; + } + break; + + case BATTERY_PROP_ENERGY_COUNTER: + if (mHealthdConfig->dockEnergyCounter) { + ret = mHealthdConfig->dockEnergyCounter(&val->valueInt64); + } else { + ret = NAME_NOT_FOUND; + } + break; + + default: + break; + } + + return ret; +} + void BatteryMonitor::dumpState(int fd) { int v; char vs[128]; - snprintf(vs, sizeof(vs), "ac: %d usb: %d wireless: %d\n", + snprintf(vs, sizeof(vs), "ac: %d usb: %d wireless: %d dock-ac: %d\n", props.chargerAcOnline, props.chargerUsbOnline, - props.chargerWirelessOnline); + props.chargerWirelessOnline, props.chargerDockAcOnline); write(fd, vs, strlen(vs)); snprintf(vs, sizeof(vs), "status: %d health: %d present: %d\n", props.batteryStatus, props.batteryHealth, props.batteryPresent); @@ -370,6 +520,34 @@ void BatteryMonitor::dumpState(int fd) { snprintf(vs, sizeof(vs), "charge counter: %d\n", v); write(fd, vs, strlen(vs)); } + + if (mHealthdConfig->dockBatterySupported) { + snprintf(vs, sizeof(vs), "dock-status: %d dock-health: %d dock-present: %d\n", + props.dockBatteryStatus, props.dockBatteryHealth, props.dockBatteryPresent); + write(fd, vs, strlen(vs)); + snprintf(vs, sizeof(vs), "dock-level: %d dock-voltage: %d dock-temp: %d\n", + props.dockBatteryLevel, props.dockBatteryVoltage, + props.dockBatteryTemperature); + write(fd, vs, strlen(vs)); + + if (!mHealthdConfig->dockBatteryCurrentNowPath.isEmpty()) { + v = getIntField(mHealthdConfig->dockBatteryCurrentNowPath); + snprintf(vs, sizeof(vs), "dock-current now: %d\n", v); + write(fd, vs, strlen(vs)); + } + + if (!mHealthdConfig->dockBatteryCurrentAvgPath.isEmpty()) { + v = getIntField(mHealthdConfig->dockBatteryCurrentAvgPath); + snprintf(vs, sizeof(vs), "dock-current avg: %d\n", v); + write(fd, vs, strlen(vs)); + } + + if (!mHealthdConfig->dockBatteryChargeCounterPath.isEmpty()) { + v = getIntField(mHealthdConfig->dockBatteryChargeCounterPath); + snprintf(vs, sizeof(vs), "dock-charge counter: %d\n", v); + write(fd, vs, strlen(vs)); + } + } } void BatteryMonitor::init(struct healthd_config *hc) { @@ -397,6 +575,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { case ANDROID_POWER_SUPPLY_TYPE_AC: case ANDROID_POWER_SUPPLY_TYPE_USB: case ANDROID_POWER_SUPPLY_TYPE_WIRELESS: + case ANDROID_POWER_SUPPLY_TYPE_DOCK_AC: path.clear(); path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH, name); if (access(path.string(), R_OK) == 0) @@ -502,6 +681,107 @@ void BatteryMonitor::init(struct healthd_config *hc) { break; + case ANDROID_POWER_SUPPLY_TYPE_DOCK_BATTERY: + if (mHealthdConfig->dockBatterySupported) { + mDockBatteryDevicePresent = true; + + if (mHealthdConfig->dockBatteryStatusPath.isEmpty()) { + path.clear(); + path.appendFormat("%s/%s/status", POWER_SUPPLY_SYSFS_PATH, + name); + if (access(path, R_OK) == 0) + mHealthdConfig->dockBatteryStatusPath = path; + } + + if (mHealthdConfig->dockBatteryHealthPath.isEmpty()) { + path.clear(); + path.appendFormat("%s/%s/health", POWER_SUPPLY_SYSFS_PATH, + name); + if (access(path, R_OK) == 0) + mHealthdConfig->dockBatteryHealthPath = path; + } + + if (mHealthdConfig->dockBatteryPresentPath.isEmpty()) { + path.clear(); + path.appendFormat("%s/%s/present", POWER_SUPPLY_SYSFS_PATH, + name); + if (access(path, R_OK) == 0) + mHealthdConfig->dockBatteryPresentPath = path; + } + + if (mHealthdConfig->dockBatteryCapacityPath.isEmpty()) { + path.clear(); + path.appendFormat("%s/%s/capacity", POWER_SUPPLY_SYSFS_PATH, + name); + if (access(path, R_OK) == 0) + mHealthdConfig->dockBatteryCapacityPath = path; + } + + if (mHealthdConfig->dockBatteryVoltagePath.isEmpty()) { + path.clear(); + path.appendFormat("%s/%s/voltage_now", + POWER_SUPPLY_SYSFS_PATH, name); + if (access(path, R_OK) == 0) { + mHealthdConfig->dockBatteryVoltagePath = path; + } else { + path.clear(); + path.appendFormat("%s/%s/batt_vol", + POWER_SUPPLY_SYSFS_PATH, name); + if (access(path, R_OK) == 0) + mHealthdConfig->dockBatteryVoltagePath = path; + } + } + + if (mHealthdConfig->dockBatteryCurrentNowPath.isEmpty()) { + path.clear(); + path.appendFormat("%s/%s/current_now", + POWER_SUPPLY_SYSFS_PATH, name); + if (access(path, R_OK) == 0) + mHealthdConfig->dockBatteryCurrentNowPath = path; + } + + if (mHealthdConfig->dockBatteryCurrentAvgPath.isEmpty()) { + path.clear(); + path.appendFormat("%s/%s/current_avg", + POWER_SUPPLY_SYSFS_PATH, name); + if (access(path, R_OK) == 0) + mHealthdConfig->dockBatteryCurrentAvgPath = path; + } + + if (mHealthdConfig->dockBatteryChargeCounterPath.isEmpty()) { + path.clear(); + path.appendFormat("%s/%s/charge_counter", + POWER_SUPPLY_SYSFS_PATH, name); + if (access(path, R_OK) == 0) + mHealthdConfig->dockBatteryChargeCounterPath = path; + } + + if (mHealthdConfig->dockBatteryTemperaturePath.isEmpty()) { + path.clear(); + path.appendFormat("%s/%s/temp", POWER_SUPPLY_SYSFS_PATH, + name); + if (access(path, R_OK) == 0) { + mHealthdConfig->dockBatteryTemperaturePath = path; + } else { + path.clear(); + path.appendFormat("%s/%s/batt_temp", + POWER_SUPPLY_SYSFS_PATH, name); + if (access(path, R_OK) == 0) + mHealthdConfig->dockBatteryTemperaturePath = path; + } + } + + if (mHealthdConfig->dockBatteryTechnologyPath.isEmpty()) { + path.clear(); + path.appendFormat("%s/%s/technology", + POWER_SUPPLY_SYSFS_PATH, name); + if (access(path, R_OK) == 0) + mHealthdConfig->dockBatteryTechnologyPath = path; + } + } + + break; + case ANDROID_POWER_SUPPLY_TYPE_UNKNOWN: break; } @@ -511,7 +791,7 @@ void BatteryMonitor::init(struct healthd_config *hc) { if (!mChargerNames.size()) KLOG_ERROR(LOG_TAG, "No charger supplies found\n"); - if (!mBatteryDevicePresent) { + if (!mBatteryDevicePresent && !mDockBatteryDevicePresent) { KLOG_WARNING(LOG_TAG, "No battery devices found\n"); hc->periodic_chores_interval_fast = -1; hc->periodic_chores_interval_slow = -1; @@ -530,6 +810,23 @@ void BatteryMonitor::init(struct healthd_config *hc) { KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n"); if (mHealthdConfig->batteryTechnologyPath.isEmpty()) KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n"); + + if (mHealthdConfig->dockBatterySupported) { + if (mHealthdConfig->dockBatteryStatusPath.isEmpty()) + KLOG_WARNING(LOG_TAG, "DockBatteryStatusPath not found\n"); + if (mHealthdConfig->dockBatteryHealthPath.isEmpty()) + KLOG_WARNING(LOG_TAG, "DockBatteryHealthPath not found\n"); + if (mHealthdConfig->dockBatteryPresentPath.isEmpty()) + KLOG_WARNING(LOG_TAG, "DockBatteryPresentPath not found\n"); + if (mHealthdConfig->dockBatteryCapacityPath.isEmpty()) + KLOG_WARNING(LOG_TAG, "DockBatteryCapacityPath not found\n"); + if (mHealthdConfig->dockBatteryVoltagePath.isEmpty()) + KLOG_WARNING(LOG_TAG, "DockBatteryVoltagePath not found\n"); + if (mHealthdConfig->dockBatteryTemperaturePath.isEmpty()) + KLOG_WARNING(LOG_TAG, "DockBatteryTemperaturePath not found\n"); + if (mHealthdConfig->dockBatteryTechnologyPath.isEmpty()) + KLOG_WARNING(LOG_TAG, "DockBatteryTechnologyPath not found\n"); + } } if (property_get("ro.boot.fake_battery", pval, NULL) > 0 diff --git a/healthd/BatteryMonitor.h b/healthd/BatteryMonitor.h index 3425f277..6e3ec987 100644 --- a/healthd/BatteryMonitor.h +++ b/healthd/BatteryMonitor.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2013 The Android Open Source Project + * Copyright (C) 2015 The CyanogenMod Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,18 +35,22 @@ class BatteryMonitor { ANDROID_POWER_SUPPLY_TYPE_AC, ANDROID_POWER_SUPPLY_TYPE_USB, ANDROID_POWER_SUPPLY_TYPE_WIRELESS, - ANDROID_POWER_SUPPLY_TYPE_BATTERY + ANDROID_POWER_SUPPLY_TYPE_BATTERY, + ANDROID_POWER_SUPPLY_TYPE_DOCK_AC, + ANDROID_POWER_SUPPLY_TYPE_DOCK_BATTERY }; void init(struct healthd_config *hc); bool update(void); status_t getProperty(int id, struct BatteryProperty *val); + status_t getDockProperty(int id, struct BatteryProperty *val); void dumpState(int fd); private: struct healthd_config *mHealthdConfig; Vector mChargerNames; bool mBatteryDevicePresent; + bool mDockBatteryDevicePresent; int mBatteryFixedCapacity; int mBatteryFixedTemperature; struct BatteryProperties props; diff --git a/healthd/BatteryPropertiesRegistrar.cpp b/healthd/BatteryPropertiesRegistrar.cpp index 74bcbfde..6152b165 100644 --- a/healthd/BatteryPropertiesRegistrar.cpp +++ b/healthd/BatteryPropertiesRegistrar.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2013 The Android Open Source Project + * Copyright (C) 2015 The CyanogenMod Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -76,6 +77,10 @@ status_t BatteryPropertiesRegistrar::getProperty(int id, struct BatteryProperty return healthd_get_property(id, val); } +status_t BatteryPropertiesRegistrar::getDockProperty(int id, struct BatteryProperty *val) { + return healthd_get_dock_property(id, val); +} + status_t BatteryPropertiesRegistrar::dump(int fd, const Vector& /*args*/) { IPCThreadState* self = IPCThreadState::self(); const int pid = self->getCallingPid(); diff --git a/healthd/BatteryPropertiesRegistrar.h b/healthd/BatteryPropertiesRegistrar.h index 88538744..5ca4fc1c 100644 --- a/healthd/BatteryPropertiesRegistrar.h +++ b/healthd/BatteryPropertiesRegistrar.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2013 The Android Open Source Project + * Copyright (C) 2015 The CyanogenMod Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,6 +41,7 @@ class BatteryPropertiesRegistrar : public BnBatteryPropertiesRegistrar, void registerListener(const sp& listener); void unregisterListener(const sp& listener); status_t getProperty(int id, struct BatteryProperty *val); + status_t getDockProperty(int id, struct BatteryProperty *val); status_t dump(int fd, const Vector& args); void binderDied(const wp& who); }; diff --git a/healthd/healthd.cpp b/healthd/healthd.cpp index f4171bd4..e172e254 100644 --- a/healthd/healthd.cpp +++ b/healthd/healthd.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2013 The Android Open Source Project + * Copyright (C) 2015 The CyanogenMod Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,12 +33,20 @@ #include #include #include +#include using namespace android; // Periodic chores intervals in seconds +#ifdef QCOM_HARDWARE +#define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (60 * 10) +//For the designs without low battery detection,need to enable +//the default 60*10s wakeup timer to periodic check. +#define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW -1 +#else #define DEFAULT_PERIODIC_CHORES_INTERVAL_FAST (60 * 1) #define DEFAULT_PERIODIC_CHORES_INTERVAL_SLOW (60 * 10) +#endif static struct healthd_config healthd_config = { .periodic_chores_interval_fast = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST, @@ -54,6 +63,18 @@ static struct healthd_config healthd_config = { .batteryChargeCounterPath = String8(String8::kEmptyString), .energyCounter = NULL, .screen_on = NULL, + .dockBatterySupported = false, + .dockBatteryStatusPath = String8(String8::kEmptyString), + .dockBatteryHealthPath = String8(String8::kEmptyString), + .dockBatteryPresentPath = String8(String8::kEmptyString), + .dockBatteryCapacityPath = String8(String8::kEmptyString), + .dockBatteryVoltagePath = String8(String8::kEmptyString), + .dockBatteryTemperaturePath = String8(String8::kEmptyString), + .dockBatteryTechnologyPath = String8(String8::kEmptyString), + .dockBatteryCurrentNowPath = String8(String8::kEmptyString), + .dockBatteryCurrentAvgPath = String8(String8::kEmptyString), + .dockBatteryChargeCounterPath = String8(String8::kEmptyString), + .dockEnergyCounter = NULL, }; static int eventct; @@ -91,6 +112,13 @@ extern void healthd_mode_charger_heartbeat(void); extern void healthd_mode_charger_battery_update( struct android::BatteryProperties *props); +static const struct option OPTIONS[] = { + { "mode", required_argument, NULL, 'm' }, + { NULL, 0, NULL, 0 }, +}; + +int mode = NORMAL; + // NOPs for modes that need no special action static void healthd_mode_nop_init(struct healthd_config *config); @@ -173,6 +201,10 @@ status_t healthd_get_property(int id, struct BatteryProperty *val) { return gBatteryMonitor->getProperty(id, val); } +status_t healthd_get_dock_property(int id, struct BatteryProperty *val) { + return gBatteryMonitor->getDockProperty(id, val); +} + void healthd_battery_update(void) { // Fast wake interval when on charger (watch for overheat); // slow wake interval when on battery (watch for drained battery). @@ -333,6 +365,18 @@ int main(int argc, char **argv) { if (!strcmp(basename(argv[0]), "charger")) { healthd_mode_ops = &charger_ops; + int arg; + while ((arg=getopt_long(argc, argv,"m:" , OPTIONS, NULL))!=-1) { + switch (arg) { + case 'm': + mode = atoi(optarg); + break; + case '?': + default: + KLOG_ERROR(LOG_TAG, "Unrecognized charger option\n"); + continue; + } + } } else { while ((ch = getopt(argc, argv, "cr")) != -1) { switch (ch) { @@ -357,6 +401,9 @@ int main(int argc, char **argv) { exit(2); } + periodic_chores(); + healthd_mode_ops->heartbeat(); + healthd_mainloop(); KLOG_ERROR("Main loop terminated, exiting\n"); return 3; diff --git a/healthd/healthd.h b/healthd/healthd.h index 4704f0b4..2cbdabf3 100644 --- a/healthd/healthd.h +++ b/healthd/healthd.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2013 The Android Open Source Project + * Copyright (C) 2015 The CyanogenMod Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -48,8 +49,25 @@ // batteryTemperaturePath: battery temperature (POWER_SUPPLY_PROP_TEMP) // batteryTechnologyPath: battery technology (POWER_SUPPLY_PROP_TECHNOLOGY) // batteryCurrentNowPath: battery current (POWER_SUPPLY_PROP_CURRENT_NOW) +// batteryCurrentAvgPath: battery average (POWER_SUPPLY_PROP_CURRENT_AVG) // batteryChargeCounterPath: battery accumulated charge // (POWER_SUPPLY_PROP_CHARGE_COUNTER) +// +// dockBatteryStatusPath: dock charging status (POWER_SUPPLY_PROP_STATUS) +// dockBatteryHealthPath: dock battery health (POWER_SUPPLY_PROP_HEALTH) +// dockBatteryPresentPath: dock battery present (POWER_SUPPLY_PROP_PRESENT) +// dockBatteryCapacityPath: remaining dock capacity (POWER_SUPPLY_PROP_CAPACITY) +// dockBatteryVoltagePath: dock battery voltage (POWER_SUPPLY_PROP_VOLTAGE_NOW) +// dockBatteryTemperaturePath: dock battery temperature (POWER_SUPPLY_PROP_TEMP) +// dockBatteryTechnologyPath: dock battery technology (POWER_SUPPLY_PROP_TECHNOLOGY) +// dockBatteryCurrentNowPath: dock battery current (POWER_SUPPLY_PROP_CURRENT_NOW) +// dockBatteryCurrentAvgPath: dock battery average (POWER_SUPPLY_PROP_CURRENT_AVG) +// dockBatteryChargeCounterPath: dock battery accumulated charge +// (POWER_SUPPLY_PROP_CHARGE_COUNTER) +// +// The dockBatterySupported property indicates whether a dock battery is supported +// by the device, and whether this module should fetch dock battery values. +// Defaults is to false. struct healthd_config { int periodic_chores_interval_fast; @@ -68,6 +86,20 @@ struct healthd_config { int (*energyCounter)(int64_t *); bool (*screen_on)(android::BatteryProperties *props); + + bool dockBatterySupported; + android::String8 dockBatteryStatusPath; + android::String8 dockBatteryHealthPath; + android::String8 dockBatteryPresentPath; + android::String8 dockBatteryCapacityPath; + android::String8 dockBatteryVoltagePath; + android::String8 dockBatteryTemperaturePath; + android::String8 dockBatteryTechnologyPath; + android::String8 dockBatteryCurrentNowPath; + android::String8 dockBatteryCurrentAvgPath; + android::String8 dockBatteryChargeCounterPath; + + int (*dockEnergyCounter)(int64_t *); }; // Global helper functions @@ -76,6 +108,8 @@ int healthd_register_event(int fd, void (*handler)(uint32_t)); void healthd_battery_update(); android::status_t healthd_get_property(int id, struct android::BatteryProperty *val); +android::status_t healthd_get_dock_property(int id, + struct android::BatteryProperty *val); void healthd_dump_battery_state(int fd); struct healthd_mode_ops { @@ -87,6 +121,11 @@ struct healthd_mode_ops { extern struct healthd_mode_ops *healthd_mode_ops; +enum MODE { + NORMAL = 0, + QUICKBOOT, +}; + // Charger mode void healthd_mode_charger_init(struct healthd_config *config); diff --git a/healthd/healthd_board_default.cpp b/healthd/healthd_board_default.cpp index ed4ddb41..3d073627 100644 --- a/healthd/healthd_board_default.cpp +++ b/healthd/healthd_board_default.cpp @@ -15,15 +15,17 @@ */ #include +#include "healthd_msm.h" void healthd_board_init(struct healthd_config*) { // use defaults + power_off_alarm_init(); } int healthd_board_battery_update(struct android::BatteryProperties*) { // return 0 to log periodic polled battery status to kernel log - return 0; + return 1; } diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp index 50396498..4e6586d0 100644 --- a/healthd/healthd_mode_charger.cpp +++ b/healthd/healthd_mode_charger.cpp @@ -72,11 +72,28 @@ char *locale; #define LAST_KMSG_PATH "/proc/last_kmsg" #define LAST_KMSG_PSTORE_PATH "/sys/fs/pstore/console-ramoops" #define LAST_KMSG_MAX_SZ (32 * 1024) +#ifndef RED_LED_PATH +#define RED_LED_PATH "/sys/class/leds/red/brightness" +#endif +#ifndef GREEN_LED_PATH +#define GREEN_LED_PATH "/sys/class/leds/green/brightness" +#endif +#ifndef BLUE_LED_PATH +#define BLUE_LED_PATH "/sys/class/leds/blue/brightness" +#endif +#ifndef BACKLIGHT_PATH +#define BACKLIGHT_PATH "/sys/class/leds/lcd-backlight/brightness" +#endif +#ifndef CHARGING_ENABLED_PATH +#define CHARGING_ENABLED_PATH "/sys/class/power_supply/battery/charging_enabled" +#endif #define LOGE(x...) do { KLOG_ERROR("charger", x); } while (0) #define LOGW(x...) do { KLOG_WARNING("charger", x); } while (0) #define LOGV(x...) do { KLOG_DEBUG("charger", x); } while (0) +extern int mode; + struct key_state { bool pending; bool down; @@ -167,6 +184,33 @@ static struct animation battery_animation = { .capacity = 0, }; +enum { + RED_LED = 0x01 << 0, + GREEN_LED = 0x01 << 1, + BLUE_LED = 0x01 << 2, +}; + +struct led_ctl { + int color; + const char *path; +}; + +struct led_ctl leds[3] = + {{RED_LED, RED_LED_PATH}, + {GREEN_LED, GREEN_LED_PATH}, + {BLUE_LED, BLUE_LED_PATH}}; + +struct soc_led_color_mapping { + int soc; + int color; +}; + +struct soc_led_color_mapping soc_leds[3] = { + {15, RED_LED}, + {90, RED_LED | GREEN_LED}, + {100, GREEN_LED}, +}; + static struct charger charger_state; static struct healthd_config *healthd_config; static struct android::BatteryProperties *batt_prop; @@ -174,6 +218,99 @@ static int char_width; static int char_height; static bool minui_inited; +static int set_tricolor_led(int on, int color) +{ + int fd, i; + char buffer[10]; + + for (i = 0; i < (int)ARRAY_SIZE(leds); i++) { + if ((color & leds[i].color) && (access(leds[i].path, R_OK | W_OK) == 0)) { + fd = open(leds[i].path, O_RDWR); + if (fd < 0) { + LOGE("Could not open led node %d\n", i); + continue; + } + if (on) + snprintf(buffer, sizeof(int), "%d\n", 255); + else + snprintf(buffer, sizeof(int), "%d\n", 0); + + if (write(fd, buffer, strlen(buffer)) < 0) + LOGE("Could not write to led node\n"); + close(fd); + } + } + + return 0; +} + +static int set_battery_soc_leds(int soc) +{ + int i, color; + static int old_color = 0; + + for (i = 0; i < (int)ARRAY_SIZE(soc_leds); i++) { + if (soc <= soc_leds[i].soc) + break; + } + color = soc_leds[i].color; + if (old_color != color) { + set_tricolor_led(0, old_color); + set_tricolor_led(1, color); + old_color = color; + LOGV("soc = %d, set led color 0x%x\n", soc, soc_leds[i].color); + } + + return 0; +} + +#define BACKLIGHT_ON_LEVEL 100 +static int set_backlight(bool on) +{ + int fd; + char buffer[10]; + + if (access(BACKLIGHT_PATH, R_OK | W_OK) != 0) + { + LOGW("Backlight control not support\n"); + return 0; + } + + memset(buffer, '\0', sizeof(buffer)); + fd = open(BACKLIGHT_PATH, O_RDWR); + if (fd < 0) { + LOGE("Could not open backlight node : %s\n", strerror(errno)); + return 0; + } + LOGV("Enabling backlight\n"); + snprintf(buffer, sizeof(buffer), "%d\n", on ? BACKLIGHT_ON_LEVEL : 0); + if (write(fd, buffer,strlen(buffer)) < 0) { + LOGE("Could not write to backlight node : %s\n", strerror(errno)); + } + close(fd); + +#ifdef SECONDARY_BACKLIGHT_PATH + if (access(SECONDARY_BACKLIGHT_PATH, R_OK | W_OK) != 0) + { + LOGW("Secondary Backlight control not support\n"); + return 0; + } + + fd = open(SECONDARY_BACKLIGHT_PATH, O_RDWR); + if (fd < 0) { + LOGE("Could not open secondary backlight node : %s\n", strerror(errno)); + return 0; + } + LOGV("Enabling secondary backlight\n"); + if (write(fd, buffer,strlen(buffer)) < 0) { + LOGE("Could not write to secondary backlight node : %s\n", strerror(errno)); + } + close(fd); +#endif + + return 0; +} + /* current time in milliseconds */ static int64_t curr_time_ms(void) { @@ -239,6 +376,56 @@ static void dump_last_kmsg(void) LOGW("\n"); } +static int read_file(const char *path, char *buf, size_t sz) +{ + int fd; + size_t cnt; + + fd = open(path, O_RDONLY, 0); + if (fd < 0) + goto err; + + cnt = read(fd, buf, sz - 1); + if (cnt <= 0) + goto err; + buf[cnt] = '\0'; + if (buf[cnt - 1] == '\n') { + cnt--; + buf[cnt] = '\0'; + } + + close(fd); + return cnt; + +err: + if (fd >= 0) + close(fd); + return -1; +} + +static int read_file_int(const char *path, int *val) +{ + char buf[32]; + int ret; + int tmp; + char *end; + + ret = read_file(path, buf, sizeof(buf)); + if (ret < 0) + return -1; + + tmp = strtol(buf, &end, 0); + if (end == buf || + ((end < buf+sizeof(buf)) && (*end != '\n' && *end != '\0'))) + goto err; + + *val = tmp; + return 0; + +err: + return -1; +} + #ifdef CHARGER_ENABLE_SUSPEND static int request_suspend(bool enable) { @@ -315,6 +502,23 @@ static void draw_battery(struct charger *charger) } } +#ifdef CHARGER_SHOW_PERCENTAGE +#define STR_LEN 64 +static void draw_capacity(struct charger *charger) +{ + char cap_str[STR_LEN]; + int x, y; + int str_len_px; + + snprintf(cap_str, (STR_LEN - 1), "%d%%", charger->batt_anim->capacity); + str_len_px = gr_measure(cap_str); + x = (gr_fb_width() - str_len_px) / 2; + y = (gr_fb_height() + char_height) / 2; + android_green(); + gr_text(x, y, cap_str, 0); +} +#endif + static void redraw_screen(struct charger *charger) { struct animation *batt_anim = charger->batt_anim; @@ -322,10 +526,14 @@ static void redraw_screen(struct charger *charger) clear_screen(); /* try to display *something* */ - if (batt_anim->capacity < 0 || batt_anim->num_frames == 0) + if (batt_anim->capacity < 0 || batt_anim->num_frames == 0) { draw_unknown(charger); - else + } else { draw_battery(charger); +#ifdef CHARGER_SHOW_PERCENTAGE + draw_capacity(charger); +#endif + } gr_flip(); } @@ -376,6 +584,7 @@ static void update_screen_state(struct charger *charger, int64_t now) if (batt_anim->cur_cycle == batt_anim->num_cycles) { reset_animation(batt_anim); charger->next_screen_transition = -1; + set_backlight(false); gr_fb_blank(true); LOGV("[%" PRId64 "] animation done\n", now); if (charger->charger_connected) @@ -407,9 +616,11 @@ static void update_screen_state(struct charger *charger, int64_t now) batt_anim->capacity = batt_prop->batteryLevel; } - /* unblank the screen on first cycle */ - if (batt_anim->cur_cycle == 0) + /* unblank the screen on first cycle */ + if (batt_anim->cur_cycle == 0) { gr_fb_blank(false); + set_backlight(true); + } /* draw the new frame (@ cur_frame) */ redraw_screen(charger); @@ -509,6 +720,7 @@ static void set_next_key_check(struct charger *charger, static void process_key(struct charger *charger, int code, int64_t now) { + struct animation *batt_anim = charger->batt_anim; struct key_state *key = &charger->keys[code]; int64_t next_key_check; @@ -535,10 +747,24 @@ static void process_key(struct charger *charger, int code, int64_t now) } else { /* if the power key got released, force screen state cycle */ if (key->pending) { - request_suspend(false); - kick_animation(charger->batt_anim); + if (!batt_anim->run) { + request_suspend(false); + kick_animation(batt_anim); + } else { + reset_animation(batt_anim); + charger->next_screen_transition = -1; + set_backlight(false); + gr_fb_blank(true); + if (charger->charger_connected) + request_suspend(true); + } } } + } else { + if (key->pending) { + request_suspend(false); + kick_animation(charger->batt_anim); + } } key->pending = false; @@ -547,6 +773,7 @@ static void process_key(struct charger *charger, int code, int64_t now) static void handle_input_state(struct charger *charger, int64_t now) { process_key(charger, KEY_POWER, now); + process_key(charger, KEY_HOME, now); if (charger->next_key_check != -1 && now > charger->next_key_check) charger->next_key_check = -1; @@ -554,12 +781,33 @@ static void handle_input_state(struct charger *charger, int64_t now) static void handle_power_supply_state(struct charger *charger, int64_t now) { + static int old_soc = 0; + int soc = 0; + if (!charger->have_battery_state) return; + if (batt_prop && batt_prop->batteryLevel >= 0) { + soc = batt_prop->batteryLevel; + } + + if (old_soc != soc) { + old_soc = soc; + set_battery_soc_leds(soc); + } + if (!charger->charger_connected) { request_suspend(false); if (charger->next_pwr_check == -1) { + if (mode == QUICKBOOT) { + set_backlight(false); + gr_fb_blank(true); + request_suspend(true); + /* exit here. There is no need to keep running when charger + * unplugged under QuickBoot mode + */ + exit(0); + } charger->next_pwr_check = now + UNPLUGGED_SHUTDOWN_TIME; LOGW("[%" PRId64 "] device unplugged: shutting down in %" PRId64 " (@ %" PRId64 ")\n", now, (int64_t)UNPLUGGED_SHUTDOWN_TIME, charger->next_pwr_check); @@ -665,6 +913,7 @@ static void charger_event_handler(uint32_t /*epevents*/) void healthd_mode_charger_init(struct healthd_config* config) { int ret; + int charging_enabled = 1; struct charger *charger = &charger_state; int i; int epollfd; @@ -673,6 +922,16 @@ void healthd_mode_charger_init(struct healthd_config* config) LOGW("--------------- STARTING CHARGER MODE ---------------\n"); + if (mode == NORMAL) { + /* check the charging is enabled or not */ + ret = read_file_int(CHARGING_ENABLED_PATH, &charging_enabled); + if (!ret && !charging_enabled) { + /* if charging is disabled, reboot and exit power off charging */ + LOGW("android charging is disabled, exit!\n"); + android_reboot(ANDROID_RB_RESTART, 0, 0); + } + } + ret = ev_init(input_callback, charger); if (!ret) { epollfd = ev_get_epollfd(); diff --git a/healthd/healthd_msm.h b/healthd/healthd_msm.h new file mode 100644 index 00000000..6c46b207 --- /dev/null +++ b/healthd/healthd_msm.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _HEALTHD_MSM_H_ +#define _HEALTHD_MSM_H_ +void power_off_alarm_init(void); +#endif /* _HEALTHD_MSM_H_ */ diff --git a/healthd/healthd_msm_alarm.cpp b/healthd/healthd_msm_alarm.cpp new file mode 100644 index 00000000..cbe809aa --- /dev/null +++ b/healthd/healthd_msm_alarm.cpp @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "healthd_msm.h" + +#define LOGE(x...) do { KLOG_ERROR("charger", x); } while (0) +#define LOGI(x...) do { KLOG_INFO("charger", x); } while (0) +#define LOGV(x...) do { KLOG_DEBUG("charger", x); } while (0) + +enum alarm_time_type { + ALARM_TIME, + RTC_TIME, +}; + +/* + * shouldn't be changed after + * reading from alarm register + */ +static time_t alm_secs; + +static int alarm_get_time(enum alarm_time_type time_type, + time_t *secs) +{ + struct tm tm; + unsigned int cmd; + int rc, fd = -1; + + if (!secs) + return -1; + + fd = open("/dev/rtc0", O_RDWR); + if (fd < 0) { + LOGE("Can't open rtc devfs node\n"); + return -1; + } + + switch (time_type) { + case ALARM_TIME: + cmd = RTC_ALM_READ; + break; + case RTC_TIME: + cmd = RTC_RD_TIME; + break; + default: + LOGE("Invalid time type\n"); + goto err; + } + + rc = ioctl(fd, cmd, &tm); + if (rc < 0) { + LOGE("Unable to get time\n"); + goto err; + } + + *secs = mktime(&tm) + tm.tm_gmtoff; + if (*secs < 0) { + LOGE("Invalid seconds = %ld\n", *secs); + goto err; + } + + close(fd); + return 0; + +err: + close(fd); + return -1; +} + +#define ERR_SECS 2 +static int alarm_is_alm_expired() +{ + int rc; + time_t rtc_secs; + + rc = alarm_get_time(RTC_TIME, &rtc_secs); + if (rc < 0) + return 0; + + return (alm_secs >= rtc_secs - ERR_SECS && + alm_secs <= rtc_secs + ERR_SECS) ? 1 : 0; +} + +static int alarm_set_reboot_time_and_wait(time_t secs) +{ + int rc, fd; + struct timespec ts; + + fd = open("/dev/alarm", O_RDWR); + if (fd < 0) { + LOGE("Can't open alarm devfs node\n"); + goto err; + } + + /* get the elapsed realtime from boot time to now */ + rc = ioctl(fd, ANDROID_ALARM_GET_TIME( + ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP), &ts); + if (rc < 0) { + LOGE("Unable to get elapsed realtime\n"); + goto err; + } + + /* calculate the elapsed time from boot time to reboot time */ + ts.tv_sec += secs; + ts.tv_nsec = 0; + + rc = ioctl(fd, ANDROID_ALARM_SET( + ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP), &ts); + if (rc < 0) { + LOGE("Unable to set reboot time to %ld\n", secs); + goto err; + } + + do { + rc = ioctl(fd, ANDROID_ALARM_WAIT); + } while ((rc < 0 && errno == EINTR) || !alarm_is_alm_expired()); + + if (rc <= 0) { + LOGE("Unable to wait on alarm\n"); + goto err; + } + + close(fd); + return 0; + +err: + if (fd >= 0) + close(fd); + return -1; +} + +static void *alarm_thread(void *) +{ + time_t rtc_secs, rb_secs; + int rc; + + /* + * to support power off alarm, the time + * stored in alarm register at latest + * shutdown time should be some time + * earlier than the actual alarm time + * set by user + */ + rc = alarm_get_time(ALARM_TIME, &alm_secs); + if (rc < 0 || !alm_secs) + goto err; + + rc = alarm_get_time(RTC_TIME, &rtc_secs); + if (rc < 0) + goto err; + + /* + * calculate the reboot time after which + * the phone will reboot + */ + rb_secs = alm_secs - rtc_secs; + if (rb_secs <= 0) + goto err; + + rc = alarm_set_reboot_time_and_wait(rb_secs); + if (rc < 0) + goto err; + + LOGI("Exit from power off charging, reboot the phone!\n"); + android_reboot(ANDROID_RB_RESTART2, 0, (char *)"rtc"); + +err: + LOGE("Exit from alarm thread\n"); + return NULL; +} + +void power_off_alarm_init(void) +{ + pthread_t tid; + int rc; + char value[PROP_VALUE_MAX]; + + property_get("ro.bootmode", value, ""); + if (!strcmp("charger", value)) { + rc = pthread_create(&tid, NULL, alarm_thread, NULL); + if (rc < 0) + LOGE("Create alarm thread failed\n"); + } +} diff --git a/include/cutils/iosched_policy.h b/include/cutils/iosched_policy.h index 07c5d1fc..25b87bac 100644 --- a/include/cutils/iosched_policy.h +++ b/include/cutils/iosched_policy.h @@ -31,6 +31,8 @@ typedef enum { extern int android_set_ioprio(int pid, IoSchedClass clazz, int ioprio); extern int android_get_ioprio(int pid, IoSchedClass *clazz, int *ioprio); +extern int android_set_rt_ioprio(int pid, int rt); + #ifdef __cplusplus } #endif diff --git a/include/log/logprint.h b/include/log/logprint.h index 481c96e2..a7a9cd6e 100644 --- a/include/log/logprint.h +++ b/include/log/logprint.h @@ -38,6 +38,11 @@ typedef enum { FORMAT_LONG, } AndroidLogPrintFormat; +typedef enum { + OUTPUT_COLOR_ON = 0, + OUTPUT_COLOR_OFF, +} AndroidLogColoredOutput; + typedef struct AndroidLogFormat_t AndroidLogFormat; typedef struct AndroidLogEntry_t { @@ -58,6 +63,8 @@ void android_log_format_free(AndroidLogFormat *p_format); void android_log_setPrintFormat(AndroidLogFormat *p_format, AndroidLogPrintFormat format); +void android_log_setColoredOutput(AndroidLogFormat *p_format); + /** * Returns FORMAT_OFF on invalid string */ diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h index 2f528b95..44cb4ba0 100644 --- a/include/private/android_filesystem_config.h +++ b/include/private/android_filesystem_config.h @@ -79,6 +79,8 @@ #define AID_LOGD 1036 /* log daemon */ #define AID_SHARED_RELRO 1037 /* creator of shared GNU RELRO files */ +#define AID_AUDIT 1049 /* audit daemon */ + #define AID_SHELL 2000 /* adb and debug shell user */ #define AID_CACHE 2001 /* cache access */ #define AID_DIAG 2002 /* access to diagnostic resources */ @@ -93,8 +95,19 @@ #define AID_NET_BW_STATS 3006 /* read bandwidth statistics */ #define AID_NET_BW_ACCT 3007 /* change bandwidth statistics accounting */ #define AID_NET_BT_STACK 3008 /* bluetooth: access config files */ +#if defined(QCOM_LEGACY_UIDS) +#define AID_QCOM_ONCRPC 3009 /* can read/write /dev/oncrpc files */ +#define AID_QCOM_DIAG 3010 /* can read/write /dev/diag */ +#else +#define AID_QCOM_DIAG 3009 /* can read/write /dev/diag */ +#define AID_IMS 3010 /* can read/write /dev/socket/imsrtp */ +#define AID_SENSORS 3011 /* access to /dev/socket/sensor_ctl_socket & QCCI/QCSI */ +#define AID_RFS 3012 /* Remote Filesystem for peripheral processors */ +#define AID_RFS_SHARED 3013 /* Shared files for Remote Filesystem for peripheral processors */ +#endif #define AID_EVERYBODY 9997 /* shared between all apps in the same profile */ + #define AID_MISC 9998 /* access to misc storage */ #define AID_NOBODY 9999 @@ -149,6 +162,9 @@ static const struct android_id_info android_ids[] = { { "sdcard_r", AID_SDCARD_R, }, { "clat", AID_CLAT, }, { "loop_radio", AID_LOOP_RADIO, }, +#if defined(QCOM_LEGACY_UIDS) + { "qcom_oncrpc", AID_QCOM_ONCRPC, }, +#endif { "mediadrm", AID_MEDIA_DRM, }, { "package_info", AID_PACKAGE_INFO, }, { "sdcard_pics", AID_SDCARD_PICS, }, @@ -157,6 +173,8 @@ static const struct android_id_info android_ids[] = { { "logd", AID_LOGD, }, { "shared_relro", AID_SHARED_RELRO, }, + { "audit", AID_AUDIT, }, + { "shell", AID_SHELL, }, { "cache", AID_CACHE, }, { "diag", AID_DIAG, }, @@ -167,9 +185,18 @@ static const struct android_id_info android_ids[] = { { "net_raw", AID_NET_RAW, }, { "net_admin", AID_NET_ADMIN, }, { "net_bw_stats", AID_NET_BW_STATS, }, + { "qcom_diag", AID_QCOM_DIAG, }, +#if !defined(QCOM_LEGACY_UIDS) + { "ims", AID_IMS, }, +#endif { "net_bw_acct", AID_NET_BW_ACCT, }, { "net_bt_stack", AID_NET_BT_STACK, }, - + { "qcom_diag", AID_QCOM_DIAG, }, +#if !defined(QCOM_LEGACY_UIDS) + { "sensors", AID_SENSORS, }, + { "rfs", AID_RFS, }, + { "rfs_shared", AID_RFS_SHARED, }, +#endif { "everybody", AID_EVERYBODY, }, { "misc", AID_MISC, }, { "nobody", AID_NOBODY, }, @@ -211,6 +238,7 @@ static const struct fs_path_config android_dirs[] = { { 00755, AID_ROOT, AID_SHELL, 0, "system/vendor" }, { 00755, AID_ROOT, AID_SHELL, 0, "system/xbin" }, { 00755, AID_ROOT, AID_ROOT, 0, "system/etc/ppp" }, + { 00755, AID_ROOT, AID_SHELL, 0, "system/etc" }, { 00755, AID_ROOT, AID_SHELL, 0, "vendor" }, { 00777, AID_ROOT, AID_ROOT, 0, "sdcard" }, { 00755, AID_ROOT, AID_ROOT, 0, 0 }, @@ -242,9 +270,10 @@ static const struct fs_path_config android_files[] = { * Do not change. */ { 02750, AID_ROOT, AID_INET, 0, "system/bin/netcfg" }, + /* CM's daemonized su doesn't need the setuid bit */ + { 00755, AID_ROOT, AID_SHELL, 0, "system/xbin/su" }, /* the following five files are INTENTIONALLY set-uid, but they * are NOT included on user builds. */ - { 04750, AID_ROOT, AID_SHELL, 0, "system/xbin/su" }, { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/librank" }, { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procrank" }, { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procmem" }, @@ -256,6 +285,7 @@ static const struct fs_path_config android_files[] = { { 00750, AID_ROOT, AID_ROOT, 0, "system/bin/uncrypt" }, { 00750, AID_ROOT, AID_ROOT, 0, "system/bin/install-recovery.sh" }, { 00755, AID_ROOT, AID_SHELL, 0, "system/bin/*" }, + { 00755, AID_ROOT, AID_SHELL, 0, "system/etc/init.d/*" }, { 00755, AID_ROOT, AID_ROOT, 0, "system/lib/valgrind/*" }, { 00755, AID_ROOT, AID_ROOT, 0, "system/lib64/valgrind/*" }, { 00755, AID_ROOT, AID_SHELL, 0, "system/xbin/*" }, @@ -266,6 +296,7 @@ static const struct fs_path_config android_files[] = { { 00750, AID_ROOT, AID_SHELL, 0, "init*" }, { 00750, AID_ROOT, AID_SHELL, 0, "sbin/fs_mgr" }, { 00640, AID_ROOT, AID_SHELL, 0, "fstab.*" }, + { 00755, AID_ROOT, AID_SHELL, 0, "system/etc/init.d/*" }, { 00644, AID_ROOT, AID_ROOT, 0, 0 }, }; diff --git a/include/system/audio.h b/include/system/audio.h index 181a1713..50ca957c 100644 --- a/include/system/audio.h +++ b/include/system/audio.h @@ -36,6 +36,13 @@ __BEGIN_DECLS #define AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS "0" /* AudioFlinger and AudioPolicy services use I/O handles to identify audio sources and sinks */ + +#define AMR_FRAMESIZE 32 +#define QCELP_FRAMESIZE 35 +#define EVRC_FRAMESIZE 23 +#define AMR_WB_FRAMESIZE 61 +#define AAC_FRAMESIZE 2048 + typedef int audio_io_handle_t; #define AUDIO_IO_HANDLE_NONE 0 @@ -64,7 +71,12 @@ typedef enum { AUDIO_STREAM_REROUTING = 11, /* For dynamic policy output mixes */ AUDIO_STREAM_PATCH = 12, /* For internal audio flinger tracks. Fixed volume */ AUDIO_STREAM_PUBLIC_CNT = AUDIO_STREAM_TTS + 1, +#if defined(QCOM_HARDWARE) && !defined(QCOM_DIRECTTRACK) + AUDIO_STREAM_INCALL_MUSIC = 13, + AUDIO_STREAM_CNT = AUDIO_STREAM_INCALL_MUSIC + 1, +#else AUDIO_STREAM_CNT = AUDIO_STREAM_PATCH + 1, +#endif } audio_stream_type_t; /* Do not change these values without updating their counterparts @@ -138,6 +150,10 @@ typedef enum { /* An example of remote presentation is Wifi Display */ /* where a dongle attached to a TV can be used to */ /* play the mix captured by this audio source. */ +#ifdef QCOM_HARDWARE + AUDIO_SOURCE_FM_RX = 10, + AUDIO_SOURCE_FM_RX_A2DP = 11, +#endif AUDIO_SOURCE_CNT, AUDIO_SOURCE_MAX = AUDIO_SOURCE_CNT - 1, AUDIO_SOURCE_FM_TUNER = 1998, @@ -234,6 +250,14 @@ typedef enum { AUDIO_FORMAT_VORBIS_SUB_NONE = 0x0, } audio_format_vorbis_sub_fmt_t; +#ifdef QCOM_HARDWARE +/* DOLBY (AC3/EAC3) sub format field definition: specify dual-mono acmod... */ +typedef enum { + AUDIO_FORMAT_DOLBY_SUB_NONE = 0x0, + AUDIO_FORMAT_DOLBY_SUB_DM = 0x1, /* Clips with the Dual Mono content*/ +} audio_format_dolby_sub_fmt_t; +#endif + /* Audio format consists of a main format field (upper 8 bits) and a sub format * field (lower 24 bits). * @@ -257,6 +281,24 @@ typedef enum { AUDIO_FORMAT_OPUS = 0x08000000UL, AUDIO_FORMAT_AC3 = 0x09000000UL, AUDIO_FORMAT_E_AC3 = 0x0A000000UL, + +#ifdef QCOM_HARDWARE + AUDIO_FORMAT_EVRC = 0x10000000UL, + AUDIO_FORMAT_QCELP = 0x11000000UL, + AUDIO_FORMAT_DTS = 0x12000000UL, + AUDIO_FORMAT_WMA = 0x13000000UL, + AUDIO_FORMAT_WMA_PRO = 0x14000000UL, + AUDIO_FORMAT_AAC_ADIF = 0x15000000UL, + AUDIO_FORMAT_EVRCB = 0x16000000UL, + AUDIO_FORMAT_EVRCWB = 0x17000000UL, + AUDIO_FORMAT_DTS_LBR = 0x18000000UL, + AUDIO_FORMAT_AMR_WB_PLUS = 0x19000000UL, + AUDIO_FORMAT_MP2 = 0x1A000000UL, + AUDIO_FORMAT_EVRCNW = 0x1B000000UL, +#endif + AUDIO_FORMAT_PCM_OFFLOAD = 0x1C000000UL, + AUDIO_FORMAT_FLAC = 0x1D000000UL, + AUDIO_FORMAT_E_AC3_JOC = 0x1E000000UL, AUDIO_FORMAT_MAIN_MASK = 0xFF000000UL, AUDIO_FORMAT_SUB_MASK = 0x00FFFFFFUL, @@ -273,6 +315,12 @@ typedef enum { AUDIO_FORMAT_PCM_SUB_8_24_BIT), AUDIO_FORMAT_PCM_FLOAT = (AUDIO_FORMAT_PCM | AUDIO_FORMAT_PCM_SUB_FLOAT), +#ifdef QCOM_HARDWARE + AUDIO_FORMAT_AC3_DM = (AUDIO_FORMAT_AC3 | + AUDIO_FORMAT_DOLBY_SUB_DM), + AUDIO_FORMAT_E_AC3_DM = (AUDIO_FORMAT_E_AC3 | + AUDIO_FORMAT_DOLBY_SUB_DM), +#endif AUDIO_FORMAT_PCM_24_BIT_PACKED = (AUDIO_FORMAT_PCM | AUDIO_FORMAT_PCM_SUB_24_BIT_PACKED), AUDIO_FORMAT_AAC_MAIN = (AUDIO_FORMAT_AAC | @@ -295,6 +343,11 @@ typedef enum { AUDIO_FORMAT_AAC_SUB_HE_V2), AUDIO_FORMAT_AAC_ELD = (AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_ELD), + /*Offload PCM formats*/ + AUDIO_FORMAT_PCM_16_BIT_OFFLOAD = (AUDIO_FORMAT_PCM_OFFLOAD | + AUDIO_FORMAT_PCM_SUB_16_BIT), + AUDIO_FORMAT_PCM_24_BIT_OFFLOAD = (AUDIO_FORMAT_PCM_OFFLOAD | + AUDIO_FORMAT_PCM_SUB_8_24_BIT), } audio_format_t; /* For the channel mask for position assignment representation */ @@ -335,6 +388,11 @@ enum { AUDIO_CHANNEL_OUT_MONO = AUDIO_CHANNEL_OUT_FRONT_LEFT, AUDIO_CHANNEL_OUT_STEREO = (AUDIO_CHANNEL_OUT_FRONT_LEFT | AUDIO_CHANNEL_OUT_FRONT_RIGHT), +#ifdef QCOM_HARDWARE + AUDIO_CHANNEL_OUT_2POINT1 = (AUDIO_CHANNEL_OUT_FRONT_LEFT | + AUDIO_CHANNEL_OUT_FRONT_RIGHT | + AUDIO_CHANNEL_OUT_FRONT_CENTER), +#endif AUDIO_CHANNEL_OUT_QUAD = (AUDIO_CHANNEL_OUT_FRONT_LEFT | AUDIO_CHANNEL_OUT_FRONT_RIGHT | AUDIO_CHANNEL_OUT_BACK_LEFT | @@ -345,6 +403,14 @@ enum { AUDIO_CHANNEL_OUT_FRONT_RIGHT | AUDIO_CHANNEL_OUT_SIDE_LEFT | AUDIO_CHANNEL_OUT_SIDE_RIGHT), +#ifdef QCOM_HARDWARE + AUDIO_CHANNEL_OUT_SURROUND = (AUDIO_CHANNEL_OUT_FRONT_LEFT | + AUDIO_CHANNEL_OUT_FRONT_RIGHT | + AUDIO_CHANNEL_OUT_FRONT_CENTER | + AUDIO_CHANNEL_OUT_BACK_CENTER), + AUDIO_CHANNEL_OUT_PENTA = (AUDIO_CHANNEL_OUT_QUAD | + AUDIO_CHANNEL_OUT_FRONT_CENTER), +#endif AUDIO_CHANNEL_OUT_5POINT1 = (AUDIO_CHANNEL_OUT_FRONT_LEFT | AUDIO_CHANNEL_OUT_FRONT_RIGHT | AUDIO_CHANNEL_OUT_FRONT_CENTER | @@ -359,6 +425,15 @@ enum { AUDIO_CHANNEL_OUT_LOW_FREQUENCY | AUDIO_CHANNEL_OUT_SIDE_LEFT | AUDIO_CHANNEL_OUT_SIDE_RIGHT), +#ifdef QCOM_HARDWARE + AUDIO_CHANNEL_OUT_6POINT1 = (AUDIO_CHANNEL_OUT_FRONT_LEFT | + AUDIO_CHANNEL_OUT_FRONT_RIGHT | + AUDIO_CHANNEL_OUT_FRONT_CENTER | + AUDIO_CHANNEL_OUT_LOW_FREQUENCY | + AUDIO_CHANNEL_OUT_BACK_LEFT | + AUDIO_CHANNEL_OUT_BACK_RIGHT | + AUDIO_CHANNEL_OUT_BACK_CENTER), +#endif // matches the correct AudioFormat.CHANNEL_OUT_7POINT1_SURROUND definition for 7.1 AUDIO_CHANNEL_OUT_7POINT1 = (AUDIO_CHANNEL_OUT_FRONT_LEFT | AUDIO_CHANNEL_OUT_FRONT_RIGHT | @@ -410,6 +485,17 @@ 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), +#ifdef QCOM_HARDWARE + AUDIO_CHANNEL_IN_5POINT1 = (AUDIO_CHANNEL_IN_LEFT | + AUDIO_CHANNEL_IN_RIGHT | + AUDIO_CHANNEL_IN_FRONT | + AUDIO_CHANNEL_IN_BACK | + AUDIO_CHANNEL_IN_LEFT_PROCESSED | + AUDIO_CHANNEL_IN_RIGHT_PROCESSED), + AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO = (AUDIO_CHANNEL_IN_VOICE_UPLINK | AUDIO_CHANNEL_IN_MONO), + AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO = (AUDIO_CHANNEL_IN_VOICE_DNLINK | AUDIO_CHANNEL_IN_MONO), + AUDIO_CHANNEL_IN_VOICE_CALL_MONO = (AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO | AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO), +#endif AUDIO_CHANNEL_IN_ALL = (AUDIO_CHANNEL_IN_LEFT | AUDIO_CHANNEL_IN_RIGHT | AUDIO_CHANNEL_IN_FRONT | @@ -594,6 +680,10 @@ enum { AUDIO_DEVICE_OUT_AUX_LINE = 0x200000, /* limited-output speaker device for acoustic safety */ AUDIO_DEVICE_OUT_SPEAKER_SAFE = 0x400000, +#ifdef QCOM_HARDWARE + AUDIO_DEVICE_OUT_FM_TX = 0x1000000, + AUDIO_DEVICE_OUT_PROXY = 0x2000000, +#endif AUDIO_DEVICE_OUT_DEFAULT = AUDIO_DEVICE_BIT_DEFAULT, AUDIO_DEVICE_OUT_ALL = (AUDIO_DEVICE_OUT_EARPIECE | AUDIO_DEVICE_OUT_SPEAKER | @@ -618,6 +708,10 @@ enum { AUDIO_DEVICE_OUT_FM | AUDIO_DEVICE_OUT_AUX_LINE | AUDIO_DEVICE_OUT_SPEAKER_SAFE | +#ifdef QCOM_HARDWARE + AUDIO_DEVICE_OUT_FM_TX | + AUDIO_DEVICE_OUT_PROXY | +#endif AUDIO_DEVICE_OUT_DEFAULT), AUDIO_DEVICE_OUT_ALL_A2DP = (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP | AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | @@ -655,6 +749,11 @@ enum { AUDIO_DEVICE_IN_SPDIF = AUDIO_DEVICE_BIT_IN | 0x10000, AUDIO_DEVICE_IN_BLUETOOTH_A2DP = AUDIO_DEVICE_BIT_IN | 0x20000, AUDIO_DEVICE_IN_LOOPBACK = AUDIO_DEVICE_BIT_IN | 0x40000, +#ifdef QCOM_HARDWARE + AUDIO_DEVICE_IN_PROXY = AUDIO_DEVICE_BIT_IN | 0x100000, + AUDIO_DEVICE_IN_FM_RX = AUDIO_DEVICE_BIT_IN | 0x200000, + AUDIO_DEVICE_IN_FM_RX_A2DP = AUDIO_DEVICE_BIT_IN | 0x400000, +#endif AUDIO_DEVICE_IN_DEFAULT = AUDIO_DEVICE_BIT_IN | AUDIO_DEVICE_BIT_DEFAULT, AUDIO_DEVICE_IN_ALL = (AUDIO_DEVICE_IN_COMMUNICATION | @@ -676,6 +775,11 @@ enum { AUDIO_DEVICE_IN_SPDIF | AUDIO_DEVICE_IN_BLUETOOTH_A2DP | AUDIO_DEVICE_IN_LOOPBACK | +#ifdef QCOM_HARDWARE + AUDIO_DEVICE_IN_FM_RX | + AUDIO_DEVICE_IN_FM_RX_A2DP | + AUDIO_DEVICE_IN_PROXY | +#endif AUDIO_DEVICE_IN_DEFAULT), AUDIO_DEVICE_IN_ALL_SCO = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, AUDIO_DEVICE_IN_ALL_USB = (AUDIO_DEVICE_IN_USB_ACCESSORY | @@ -708,7 +812,17 @@ typedef enum { AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD = 0x10, // offload playback of compressed // streams to hardware codec AUDIO_OUTPUT_FLAG_NON_BLOCKING = 0x20, // use non-blocking write - AUDIO_OUTPUT_FLAG_HW_AV_SYNC = 0x40 // output uses a hardware A/V synchronization source + AUDIO_OUTPUT_FLAG_HW_AV_SYNC = 0x40, // output uses a hardware A/V synchronization source +#ifdef QCOM_HARDWARE + AUDIO_OUTPUT_FLAG_VOIP_RX = 0x1000, // use this flag in combination with DIRECT to + // indicate HAL to activate EC & NS + // path for VOIP calls + AUDIO_OUTPUT_FLAG_INCALL_MUSIC = 0x2000, //use this flag for incall music delivery + // flag for HDMI compressed passthrough + AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH = 0x4000, + AUDIO_OUTPUT_FLAG_LPA = 0x8000, + AUDIO_OUTPUT_FLAG_TUNNEL = 0x10000 +#endif } audio_output_flags_t; /* The audio input flags are analogous to audio output flags. @@ -738,6 +852,8 @@ typedef struct { int64_t duration_us; // duration in microseconds, -1 if unknown bool has_video; // true if stream is tied to a video stream bool is_streaming; // true if streaming, false if local playback + uint16_t bit_width; // bits per sample + bool use_small_bufs; // true if offloading audio track } audio_offload_info_t; #define AUDIO_MAKE_OFFLOAD_INFO_VERSION(maj,min) \ @@ -756,7 +872,9 @@ static const audio_offload_info_t AUDIO_INFO_INITIALIZER = { bit_rate: 0, duration_us: 0, has_video: false, - is_streaming: false + is_streaming: false, + bit_width: 16, + use_small_bufs: false, }; /* common audio stream configuration parameters @@ -1102,8 +1220,10 @@ static inline bool audio_is_usb_device(audio_devices_t device) static inline bool audio_is_remote_submix_device(audio_devices_t device) { - if ((device & AUDIO_DEVICE_OUT_REMOTE_SUBMIX) == AUDIO_DEVICE_OUT_REMOTE_SUBMIX - || (device & AUDIO_DEVICE_IN_REMOTE_SUBMIX) == AUDIO_DEVICE_IN_REMOTE_SUBMIX) + if ((audio_is_output_devices(device) && + (device & AUDIO_DEVICE_OUT_REMOTE_SUBMIX) == AUDIO_DEVICE_OUT_REMOTE_SUBMIX) + || (!audio_is_output_devices(device) && + (device & AUDIO_DEVICE_IN_REMOTE_SUBMIX) == AUDIO_DEVICE_IN_REMOTE_SUBMIX)) return true; else return false; @@ -1249,6 +1369,7 @@ static inline audio_channel_mask_t audio_channel_out_mask_from_count(uint32_t ch * or AUDIO_CHANNEL_INVALID if the channel count exceeds that of the * configurations for which a default input channel mask is defined. */ +/* Similar to above, but for input. Currently handles mono, stereo and 5.1 input. */ static inline audio_channel_mask_t audio_channel_in_mask_from_count(uint32_t channel_count) { uint32_t bits; @@ -1261,6 +1382,11 @@ static inline audio_channel_mask_t audio_channel_in_mask_from_count(uint32_t cha case 2: bits = AUDIO_CHANNEL_IN_STEREO; break; +#ifdef QCOM_HARDWARE + case 6: + bits = AUDIO_CHANNEL_IN_5POINT1; + break; +#endif default: return AUDIO_CHANNEL_INVALID; } @@ -1313,6 +1439,28 @@ static inline bool audio_is_valid_format(audio_format_t format) case AUDIO_FORMAT_OPUS: case AUDIO_FORMAT_AC3: case AUDIO_FORMAT_E_AC3: +#ifdef QCOM_HARDWARE + case AUDIO_FORMAT_QCELP: + case AUDIO_FORMAT_EVRC: + case AUDIO_FORMAT_EVRCB: + case AUDIO_FORMAT_EVRCWB: + case AUDIO_FORMAT_AAC_ADIF: + case AUDIO_FORMAT_WMA: + case AUDIO_FORMAT_WMA_PRO: + case AUDIO_FORMAT_DTS: + case AUDIO_FORMAT_DTS_LBR: + case AUDIO_FORMAT_AMR_WB_PLUS: + case AUDIO_FORMAT_MP2: + case AUDIO_FORMAT_EVRCNW: + case AUDIO_FORMAT_FLAC: + case AUDIO_FORMAT_E_AC3_JOC: + return true; + case AUDIO_FORMAT_PCM_OFFLOAD: + if (format != AUDIO_FORMAT_PCM_16_BIT_OFFLOAD && + format != AUDIO_FORMAT_PCM_24_BIT_OFFLOAD) { + return false; + } +#endif return true; default: return false; @@ -1324,6 +1472,39 @@ static inline bool audio_is_linear_pcm(audio_format_t format) return ((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM); } +static inline bool audio_is_offload_pcm(audio_format_t format) +{ +#ifdef QCOM_HARDWARE + return ((format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_PCM_OFFLOAD); +#endif + return false; +} + +static inline bool audio_is_compress_capture_format(audio_format_t format) +{ +#ifdef QCOM_HARDWARE + if (format == AUDIO_FORMAT_AMR_WB) + return true; + else +#endif + return false; +} + +static inline bool audio_is_compress_voip_format(audio_format_t format) +{ +#ifdef QCOM_HARDWARE + if (format == AUDIO_FORMAT_AMR_NB || + format == AUDIO_FORMAT_AMR_WB || + format == AUDIO_FORMAT_EVRC || + format == AUDIO_FORMAT_EVRCB || + format == AUDIO_FORMAT_EVRCWB || + format == AUDIO_FORMAT_EVRCNW) + return true; + else +#endif + return false; +} + static inline size_t audio_bytes_per_sample(audio_format_t format) { size_t size = 0; @@ -1331,12 +1512,14 @@ static inline size_t audio_bytes_per_sample(audio_format_t format) switch (format) { case AUDIO_FORMAT_PCM_32_BIT: case AUDIO_FORMAT_PCM_8_24_BIT: + case AUDIO_FORMAT_PCM_24_BIT_OFFLOAD: size = sizeof(int32_t); break; case AUDIO_FORMAT_PCM_24_BIT_PACKED: size = sizeof(uint8_t) * 3; break; case AUDIO_FORMAT_PCM_16_BIT: + case AUDIO_FORMAT_PCM_16_BIT_OFFLOAD: size = sizeof(int16_t); break; case AUDIO_FORMAT_PCM_8_BIT: @@ -1345,7 +1528,27 @@ static inline size_t audio_bytes_per_sample(audio_format_t format) case AUDIO_FORMAT_PCM_FLOAT: size = sizeof(float); break; +#ifdef QCOM_HARDWARE + case AUDIO_FORMAT_AMR_NB: + size = 32; + break; + case AUDIO_FORMAT_EVRC: + size = 23; + break; + case AUDIO_FORMAT_QCELP: + size = 35; + break; + case AUDIO_FORMAT_AAC: + size = 2048; + break; + case AUDIO_FORMAT_AMR_WB: + size = 61; + break; +#endif default: +#ifdef QCOM_HARDWARE + size = sizeof(uint8_t); +#endif break; } return size; diff --git a/include/system/camera.h b/include/system/camera.h index 7a4dd534..bfaf210c 100644 --- a/include/system/camera.h +++ b/include/system/camera.h @@ -88,9 +88,18 @@ enum { // Notify on autofocus start and stop. This is useful in continuous // autofocus - FOCUS_MODE_CONTINUOUS_VIDEO and FOCUS_MODE_CONTINUOUS_PICTURE. CAMERA_MSG_FOCUS_MOVE = 0x0800, // notifyCallback + CAMERA_MSG_STATS_DATA = 0x1000, + CAMERA_MSG_META_DATA = 0x2000, CAMERA_MSG_ALL_MSGS = 0xFFFF }; +/** meta data type in CameraMetaDataCallback */ +enum { + CAMERA_META_DATA_ASD = 0x001, //ASD data + CAMERA_META_DATA_FD = 0x002, //FD/FP data + CAMERA_META_DATA_HDR = 0x003, //Auto HDR data +}; + /** cmdType in sendCommand functions */ enum { CAMERA_CMD_START_SMOOTH_ZOOM = 1, @@ -174,6 +183,22 @@ enum { * count is non-positive or too big to be realized. */ CAMERA_CMD_SET_VIDEO_BUFFER_COUNT = 10, + + /** + * Commands to enable/disable preview histogram + * + * Based on user's input to enable/disable histogram from the camera + * UI, send the appropriate command to the HAL to turn on/off the histogram + * stats and start sending the data to the application. + */ + CAMERA_CMD_HISTOGRAM_ON = 11, + CAMERA_CMD_HISTOGRAM_OFF = 12, + CAMERA_CMD_HISTOGRAM_SEND_DATA = 13, + CAMERA_CMD_LONGSHOT_ON = 14, + CAMERA_CMD_LONGSHOT_OFF = 15, + CAMERA_CMD_STOP_LONGSHOT = 16, + CAMERA_CMD_METADATA_ON = 100, + CAMERA_CMD_METADATA_OFF = 101, }; /** camera fatal errors */ @@ -254,9 +279,33 @@ typedef struct camera_face { * -2000, -2000 if this is not supported. */ int32_t mouth[2]; +#ifdef QCOM_BSP + int32_t smile_degree; + int32_t smile_score; + int32_t blink_detected; + int32_t face_recognised; + int32_t gaze_angle; + int32_t updown_dir; + int32_t leftright_dir; + int32_t roll_dir; + int32_t left_right_gaze; + int32_t top_bottom_gaze; + int32_t leye_blink; + int32_t reye_blink; +#endif } camera_face_t; +/** + * The information of a data type received in a camera frame. + */ +typedef enum { + /** Data buffer */ + CAMERA_FRAME_DATA_BUF = 0x000, + /** File descriptor */ + CAMERA_FRAME_DATA_FD = 0x100 +} camera_frame_data_type_t; + /** * The metadata of the frame data. */ diff --git a/include/system/graphics.h b/include/system/graphics.h index c3fca97b..b207ee82 100644 --- a/include/system/graphics.h +++ b/include/system/graphics.h @@ -54,7 +54,8 @@ enum { HAL_PIXEL_FORMAT_RGB_888 = 3, HAL_PIXEL_FORMAT_RGB_565 = 4, HAL_PIXEL_FORMAT_BGRA_8888 = 5, - + HAL_PIXEL_FORMAT_RGBA_5551 = 6, + HAL_PIXEL_FORMAT_RGBA_4444 = 7, /* * sRGB color pixel formats: * diff --git a/include/system/window.h b/include/system/window.h index bf93b79c..3d832a52 100644 --- a/include/system/window.h +++ b/include/system/window.h @@ -294,6 +294,7 @@ enum { NATIVE_WINDOW_SET_POST_TRANSFORM_CROP = 16, /* private */ NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17,/* private */ NATIVE_WINDOW_SET_SIDEBAND_STREAM = 18, + NATIVE_WINDOW_SET_BUFFERS_SIZE = 19, /* private */ }; /* parameter for NATIVE_WINDOW_[API_][DIS]CONNECT */ diff --git a/include/utils/Compat.h b/include/utils/Compat.h index fb7748ea..eb8fa46d 100644 --- a/include/utils/Compat.h +++ b/include/utils/Compat.h @@ -47,6 +47,17 @@ static inline ssize_t pread64(int fd, void* buf, size_t nbytes, off64_t offset) # define ZD_TYPE long #endif +/* + * Needed for cases where something should be constexpr if possible, but not + * being constexpr is fine if in pre-C++11 code (such as a const static float + * member variable). + */ +#if __cplusplus >= 201103L +#define CONSTEXPR constexpr +#else +#define CONSTEXPR +#endif + /* * TEMP_FAILURE_RETRY is defined by some, but not all, versions of * . (Alas, it is not as standard as we'd hoped!) So, if it's diff --git a/include/utils/Mutex.h b/include/utils/Mutex.h index dd201c89..4fdd27ff 100644 --- a/include/utils/Mutex.h +++ b/include/utils/Mutex.h @@ -26,6 +26,7 @@ #endif #include +#include // --------------------------------------------------------------------------- namespace android { @@ -45,7 +46,7 @@ class Mutex { PRIVATE = 0, SHARED = 1 }; - + Mutex(); Mutex(const char* name); Mutex(int type, const char* name = NULL); @@ -58,6 +59,16 @@ class Mutex { // lock if possible; returns 0 on success, error otherwise status_t tryLock(); +#if HAVE_ANDROID_OS + // lock the mutex, but don't wait longer than timeoutMilliseconds. + // Returns 0 on success, TIMED_OUT for failure due to timeout expiration. + // + // OSX doesn't have pthread_mutex_timedlock() or equivalent. To keep + // capabilities consistent across host OSes, this method is only available + // when building Android binaries. + status_t timedLock(nsecs_t timeoutMilliseconds); +#endif + // Manages the mutex automatically. It'll be locked when Autolock is // constructed and released when Autolock goes out of scope. class Autolock { @@ -71,11 +82,11 @@ class Mutex { private: friend class Condition; - + // A mutex cannot be copied Mutex(const Mutex&); Mutex& operator = (const Mutex&); - + #if defined(HAVE_PTHREADS) pthread_mutex_t mMutex; #else @@ -117,6 +128,15 @@ inline void Mutex::unlock() { inline status_t Mutex::tryLock() { return -pthread_mutex_trylock(&mMutex); } +#if HAVE_ANDROID_OS +inline status_t Mutex::timedLock(nsecs_t timeoutNs) { + const struct timespec ts = { + /* .tv_sec = */ timeoutNs / 1000000000, + /* .tv_nsec = */ timeoutNs % 1000000000, + }; + return -pthread_mutex_timedlock(&mMutex, &ts); +} +#endif #endif // HAVE_PTHREADS @@ -127,7 +147,7 @@ inline status_t Mutex::tryLock() { * When the function returns, it will go out of scope, and release the * mutex. */ - + typedef Mutex::Autolock AutoMutex; // --------------------------------------------------------------------------- diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h index 8e15c190..5afdf927 100644 --- a/include/utils/RefBase.h +++ b/include/utils/RefBase.h @@ -53,6 +53,15 @@ inline bool operator _op_ (const U* o) const { \ // --------------------------------------------------------------------------- +#ifdef REFBASE_JB_MR1_COMPAT_SYMBOLS +class ReferenceConverterBase { +public: + virtual size_t getReferenceTypeSize() const = 0; + virtual void* getReferenceBase(void const*) const = 0; + inline virtual ~ReferenceConverterBase() { } +}; +#endif + class ReferenceRenamer { protected: // destructor is purposedly not virtual so we avoid code overhead from diff --git a/include/utils/VectorImpl.h b/include/utils/VectorImpl.h index 21ad71ce..88c3a05d 100644 --- a/include/utils/VectorImpl.h +++ b/include/utils/VectorImpl.h @@ -105,7 +105,19 @@ class VectorImpl virtual void do_splat(void* dest, const void* item, size_t num) const = 0; virtual void do_move_forward(void* dest, const void* from, size_t num) const = 0; virtual void do_move_backward(void* dest, const void* from, size_t num) const = 0; - + +#ifdef NEEDS_VECTORIMPL_SYMBOLS + // take care of FBC... + virtual void reservedVectorImpl1(); + virtual void reservedVectorImpl2(); + virtual void reservedVectorImpl3(); + virtual void reservedVectorImpl4(); + virtual void reservedVectorImpl5(); + virtual void reservedVectorImpl6(); + virtual void reservedVectorImpl7(); + virtual void reservedVectorImpl8(); +#endif + private: void* _grow(size_t where, size_t amount); void _shrink(size_t where, size_t amount); @@ -156,6 +168,18 @@ class SortedVectorImpl : public VectorImpl protected: virtual int do_compare(const void* lhs, const void* rhs) const = 0; +#ifdef NEEDS_VECTORIMPL_SYMBOLS + // take care of FBC... + virtual void reservedSortedVectorImpl1(); + virtual void reservedSortedVectorImpl2(); + virtual void reservedSortedVectorImpl3(); + virtual void reservedSortedVectorImpl4(); + virtual void reservedSortedVectorImpl5(); + virtual void reservedSortedVectorImpl6(); + virtual void reservedSortedVectorImpl7(); + virtual void reservedSortedVectorImpl8(); +#endif + private: ssize_t _indexOrderOf(const void* item, size_t* order = 0) const; diff --git a/init/Android.mk b/init/Android.mk old mode 100644 new mode 100755 index 489dc93e..1c01cbe3 --- a/init/Android.mk +++ b/init/Android.mk @@ -15,7 +15,8 @@ LOCAL_SRC_FILES:= \ init_parser.c \ ueventd.c \ ueventd_parser.c \ - watchdogd.c + watchdogd.c \ + vendor_init.c LOCAL_CFLAGS += -Wno-unused-parameter @@ -24,13 +25,25 @@ LOCAL_SRC_FILES += bootchart.c LOCAL_CFLAGS += -DBOOTCHART=1 endif -ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT))) -LOCAL_CFLAGS += -DALLOW_LOCAL_PROP_OVERRIDE=1 -DALLOW_DISABLE_SELINUX=1 -endif +LOCAL_CFLAGS += -DALLOW_LOCAL_PROP_OVERRIDE=1 # Enable ueventd logging #LOCAL_CFLAGS += -DLOG_UEVENTS=1 +SYSTEM_CORE_INIT_DEFINES := BOARD_CHARGING_MODE_BOOTING_LPM \ + BOARD_CHARGING_CMDLINE_NAME \ + BOARD_CHARGING_CMDLINE_VALUE + +$(foreach system_core_init_define,$(SYSTEM_CORE_INIT_DEFINES), \ + $(if $($(system_core_init_define)), \ + $(eval LOCAL_CFLAGS += -D$(system_core_init_define)=\"$($(system_core_init_define))\") \ + ) \ +) + +ifneq ($(TARGET_NR_SVC_SUPP_GIDS),) +LOCAL_CFLAGS += -DNR_SVC_SUPP_GIDS=$(TARGET_NR_SVC_SUPP_GIDS) +endif + LOCAL_MODULE:= init LOCAL_FORCE_STATIC_EXECUTABLE := true @@ -45,9 +58,25 @@ LOCAL_STATIC_LIBRARIES := \ libc \ libselinux \ libmincrypt \ - libext4_utils_static + libext4_utils_static \ + libext2_blkid \ + libext2_uuid_static \ + liblz4-static \ + libsparse_static \ + libz LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk +ifneq ($(strip $(TARGET_PLATFORM_DEVICE_BASE)),) +LOCAL_CFLAGS += -D_PLATFORM_BASE="\"$(TARGET_PLATFORM_DEVICE_BASE)\"" +endif +ifneq ($(strip $(TARGET_INIT_VENDOR_LIB)),) +LOCAL_WHOLE_STATIC_LIBRARIES += $(TARGET_INIT_VENDOR_LIB) +endif +ifneq ($(strip $(TARGET_PROP_PATH_FACTORY)),) +LOCAL_CFLAGS += -DOVERRIDE_PROP_PATH_FACTORY=\"$(TARGET_PROP_PATH_FACTORY)\" +endif + +LOCAL_C_INCLUDES += external/zlib include $(BUILD_EXECUTABLE) diff --git a/init/NOTICE b/init/NOTICE index c5b1efa7..d93146db 100644 --- a/init/NOTICE +++ b/init/NOTICE @@ -188,3 +188,30 @@ END OF TERMS AND CONDITIONS + +Copyright (c) 2013, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation 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 "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +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. diff --git a/init/builtins.c b/init/builtins.c index c1925514..8bf124d4 100644 --- a/init/builtins.c +++ b/init/builtins.c @@ -15,6 +15,7 @@ */ #include +#include #include #include #include @@ -51,6 +52,7 @@ int add_environment(const char *name, const char *value); extern int init_module(void *, unsigned long, const char *); +extern int init_export_rc_file(const char *); static int write_file(const char *path, const char *value) { @@ -75,61 +77,47 @@ static int write_file(const char *path, const char *value) } } -static int _open(const char *path) -{ - int fd; - - fd = open(path, O_RDONLY | O_NOFOLLOW); - if (fd < 0) - fd = open(path, O_WRONLY | O_NOFOLLOW); - - return fd; -} static int _chown(const char *path, unsigned int uid, unsigned int gid) { - int fd; int ret; - fd = _open(path); - if (fd < 0) { + struct stat p_statbuf; + + ret = lstat(path, &p_statbuf); + if (ret < 0) { return -1; } - ret = fchown(fd, uid, gid); - if (ret < 0) { - int errno_copy = errno; - close(fd); - errno = errno_copy; + if (S_ISLNK(p_statbuf.st_mode) == 1) { + errno = EINVAL; return -1; } - close(fd); + ret = chown(path, uid, gid); - return 0; + return ret; } static int _chmod(const char *path, mode_t mode) { - int fd; int ret; - fd = _open(path); - if (fd < 0) { + struct stat p_statbuf; + + ret = lstat(path, &p_statbuf); + if (ret < 0) { return -1; } - ret = fchmod(fd, mode); - if (ret < 0) { - int errno_copy = errno; - close(fd); - errno = errno_copy; + if (S_ISLNK(p_statbuf.st_mode) == 1) { + errno = EINVAL; return -1; } - close(fd); + ret = chmod(path, mode); - return 0; + return ret; } static int insmod(const char *filename, char *options) @@ -214,26 +202,55 @@ int do_chroot(int nargs, char **args) int do_class_start(int nargs, char **args) { - /* Starting a class does not start services - * which are explicitly disabled. They must - * be started individually. - */ + char prop[PROP_NAME_MAX]; + snprintf(prop, PROP_NAME_MAX, "class_start:%s", args[1]); + + /* Starting a class does not start services + * which are explicitly disabled. They must + * be started individually. + */ service_for_each_class(args[1], service_start_if_not_disabled); + action_for_each_trigger(prop, action_add_queue_tail); return 0; } int do_class_stop(int nargs, char **args) { + char prop[PROP_NAME_MAX]; + snprintf(prop, PROP_NAME_MAX, "class_stop:%s", args[1]); + service_for_each_class(args[1], service_stop); + action_for_each_trigger(prop, action_add_queue_tail); return 0; } int do_class_reset(int nargs, char **args) { + char prop[PROP_NAME_MAX]; + snprintf(prop, PROP_NAME_MAX, "class_reset:%s", args[1]); + service_for_each_class(args[1], service_reset); + action_for_each_trigger(prop, action_add_queue_tail); return 0; } +int do_export_rc(int nargs, char **args) +{ + /* Import environments from a specified file. + * The file content is of the form: + * export + * e.g. + * export LD_PRELOAD /system/lib/xyz.so + * export PROMPT abcde + * Differences between "import" and "export_rc": + * 1) export_rc can only import environment vars + * 2) export_rc is performed when the command + * is executed rather than at the time the + * command is parsed (i.e. "import") + */ + return init_export_rc_file(args[1]); +} + int do_domainname(int nargs, char **args) { return write_file("/proc/sys/kernel/domainname", args[1]); @@ -254,9 +271,60 @@ int do_enable(int nargs, char **args) return 0; } +#define MAX_PARAMETERS 64 int do_exec(int nargs, char **args) { - return -1; + pid_t pid; + int status, i, j; + char *par[MAX_PARAMETERS]; + char prop_val[PROP_VALUE_MAX]; + int len; + + if (nargs > MAX_PARAMETERS) + { + return -1; + } + + for(i=0, j=1; i<(nargs-1) ;i++,j++) + { + if ((args[j]) + && + (!expand_props(prop_val, args[j], sizeof(prop_val)))) + + { + len = strlen(args[j]); + if (strlen(prop_val) <= len) { + /* Overwrite arg with expansion. + * + * For now, only allow an expansion length that + * can fit within the original arg length to + * avoid extra allocations. + * On failure, use original argument. + */ + strncpy(args[j], prop_val, len + 1); + } + } + par[i] = args[j]; + } + + par[i] = (char*)0; + pid = fork(); + if (!pid) + { + char tmp[32]; + int fd, sz; + get_property_workspace(&fd, &sz); + sprintf(tmp, "%d,%d", dup(fd), sz); + setenv("ANDROID_PROPERTY_WORKSPACE", tmp, 1); + execve(par[0], par, environ); + exit(0); + } + else + { + while(wait(&status)!=pid); + } + + return 0; } int do_export(int nargs, char **args) @@ -433,6 +501,7 @@ int do_mount(int nargs, char **args) sprintf(tmp, "/dev/block/loop%d", n); loop = open(tmp, mode); if (loop < 0) { + close(fd); return -1; } @@ -500,6 +569,7 @@ int do_mount_all(int nargs, char **args) int ret = -1; int child_ret = -1; int status; + char boot_mode[PROP_VALUE_MAX]; const char *prop; struct fstab *fstab; @@ -549,10 +619,12 @@ int do_mount_all(int nargs, char **args) property_set("vold.decrypt", "trigger_default_encryption"); } else if (ret == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) { property_set("ro.crypto.state", "unencrypted"); - /* If fs_mgr determined this is an unencrypted device, then trigger - * that action. + /* If fs_mgr determined this is an unencrypted device and we are + * not booting into ffbm then trigger that action. */ - action_for_each_trigger("nonencrypted", action_add_queue_tail); + property_get("ro.bootmode", boot_mode); + if (strncmp(boot_mode, "ffbm", 4)) + action_for_each_trigger("nonencrypted", action_add_queue_tail); } else if (ret == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) { /* Setup a wipe via recovery, and reboot into recovery */ ERROR("fs_mgr_mount_all suggested recovery, so wiping data via recovery.\n"); @@ -895,6 +967,14 @@ int do_setsebool(int nargs, char **args) { return 0; } +int do_log(int nargs, char **args) { + int i; + for (i = 1; i < nargs; i++) { + ERROR("%s", args[i]); + } + return 0; +} + int do_loglevel(int nargs, char **args) { int log_level; char log_level_str[PROP_VALUE_MAX] = ""; @@ -941,3 +1021,8 @@ int do_wait(int nargs, char **args) } else return -1; } + +int do_umount(int nargs, char **args) { + return umount(args[1]); +} + diff --git a/init/devices.c b/init/devices.c index 1012fee4..5dfe2536 100644 --- a/init/devices.c +++ b/init/devices.c @@ -47,6 +47,7 @@ #include "ueventd_parser.h" #include "util.h" #include "log.h" +#include #define UNUSED __attribute__((__unused__)) @@ -54,8 +55,10 @@ #define FIRMWARE_DIR1 "/etc/firmware" #define FIRMWARE_DIR2 "/vendor/firmware" #define FIRMWARE_DIR3 "/firmware/image" +#define DEVICES_BASE "/devices/soc.0" extern struct selabel_handle *sehandle; +extern char bootdevice[32]; static int device_fd = -1; @@ -168,7 +171,14 @@ void fixup_sys_perms(const char *upath) } if (access(buf, F_OK) == 0) { INFO("restorecon_recursive: %s\n", buf); +#ifdef _PLATFORM_BASE + if(!strcmp(upath, DEVICES_BASE)) + restorecon(buf); + else + restorecon_recursive(buf); +#else restorecon_recursive(buf); +#endif } } @@ -273,11 +283,18 @@ static void add_platform_device(const char *path) struct platform_node *bus; const char *name = path; +#ifdef _PLATFORM_BASE + if (!strncmp(path, _PLATFORM_BASE, strlen(_PLATFORM_BASE))) + name += strlen(_PLATFORM_BASE); + else + return; +#else if (!strncmp(path, "/devices/", 9)) { name += 9; if (!strncmp(name, "platform/", 9)) name += 9; } +#endif list_for_each_reverse(node, &platform_names) { bus = node_to_item(node, struct platform_node, list); @@ -336,6 +353,35 @@ static void remove_platform_device(const char *path) } } +/* Given a path that may start with an MTD device (/devices/virtual/mtd/mtd8/mtdblock8), + * populate the supplied buffer with the MTD partition number and return 0. + * If it doesn't start with an MTD device, or there is some error, return -1 */ +static int find_mtd_device_prefix(const char *path, char *buf, ssize_t buf_sz) +{ + const char *start, *end; + + if (strncmp(path, "/devices/virtual/mtd", 20)) + return -1; + + /* Beginning of the prefix is the initial "mtdXX" after "/devices/virtual/mtd/" */ + start = path + 21; + + /* End of the prefix is one path '/' later, capturing the partition number + * Example: mtd8 */ + end = strchr(start, '/'); + if (!end) { + return -1; + } + + /* Make sure we have enough room for the string plus null terminator */ + if (end - start + 1 > buf_sz) + return -1; + + strncpy(buf, start, end - start); + buf[end - start] = '\0'; + return 0; +} + /* Given a path that may start with a PCI device, populate the supplied buffer * with the PCI domain/bus number and the peripheral ID and return 0. * If it doesn't start with a PCI device, or there is some error, return -1 */ @@ -438,6 +484,41 @@ static void parse_event(const char *msg, struct uevent *uevent) uevent->firmware, uevent->major, uevent->minor); } +static char **get_v4l_device_symlinks(struct uevent *uevent) +{ + char **links; + int fd = -1; + int nr; + char link_name_path[256]; + char link_name[64]; + + if (strncmp(uevent->path, "/devices/virtual/video4linux/video", 34)) + return NULL; + + links = malloc(sizeof(char *) * 2); + if (!links) + return NULL; + memset(links, 0, sizeof(char *) * 2); + + snprintf(link_name_path, sizeof(link_name_path), "%s%s%s", + SYSFS_PREFIX, uevent->path, "/link_name"); + fd = open(link_name_path, O_RDONLY); + if (fd < 0) + goto err; + nr = read(fd, link_name, sizeof(link_name) - 1); + close(fd); + if (nr <= 0) + goto err; + link_name[nr] = '\0'; + if (asprintf(&links[0], "/dev/video/%s", link_name) <= 0) + links[0] = NULL; + + return links; +err: + free(links); + return NULL; +} + static char **get_character_device_symlinks(struct uevent *uevent) { const char *parent; @@ -458,7 +539,7 @@ static char **get_character_device_symlinks(struct uevent *uevent) /* skip "/devices/platform/" */ parent = strchr(uevent->path + pdev->path_len, '/'); - if (!*parent) + if (!parent) goto err; if (!strncmp(parent, "/usb", 4)) { @@ -505,7 +586,12 @@ static char **get_block_device_symlinks(struct uevent *uevent) int ret; char *p; unsigned int size; + int is_bootdevice = -1; struct stat info; + int mtd_fd = -1; + int nr; + char mtd_name_path[256]; + char mtd_name[64]; pdev = find_platform_device(uevent->path); if (pdev) { @@ -514,19 +600,52 @@ static char **get_block_device_symlinks(struct uevent *uevent) } else if (!find_pci_device_prefix(uevent->path, buf, sizeof(buf))) { device = buf; type = "pci"; + } else if (!find_mtd_device_prefix(uevent->path, buf, sizeof(buf))) { + device = buf; + type = "mtd"; } else { return NULL; } - char **links = malloc(sizeof(char *) * 4); + char **links = malloc(sizeof(char *) * 6); if (!links) return NULL; - memset(links, 0, sizeof(char *) * 4); + memset(links, 0, sizeof(char *) * 6); INFO("found %s device %s\n", type, device); snprintf(link_path, sizeof(link_path), "/dev/block/%s/%s", type, device); + if(!strcmp(type, "mtd")) { + snprintf(mtd_name_path, sizeof(mtd_name_path), + "/sys/devices/virtual/%s/%s/name", type, device); + mtd_fd = open(mtd_name_path, O_RDONLY); + if(mtd_fd < 0) { + ERROR("Unable to open %s for reading", mtd_name_path); + return NULL; + } + nr = read(mtd_fd, mtd_name, sizeof(mtd_name) - 1); + if (nr <= 0) + return NULL; + close(mtd_fd); + mtd_name[nr - 1] = '\0'; + + p = strdup(mtd_name); + sanitize(p); + if (asprintf(&links[link_num], "/dev/block/%s/by-name/%s", type, p) > 0) + link_num++; + else + links[link_num] = NULL; + free(p); + } + + if (bootdevice[0] == '\0') + is_bootdevice = 0; + else if (!strncmp(device, bootdevice, sizeof(bootdevice))) { + make_link_init(link_path, "/dev/block/bootdevice"); + is_bootdevice = 1; + } + if (uevent->partition_name) { p = strdup(uevent->partition_name); sanitize(p); @@ -536,6 +655,13 @@ static char **get_block_device_symlinks(struct uevent *uevent) link_num++; else links[link_num] = NULL; + + if (is_bootdevice >= 0) { + if (asprintf(&links[link_num], "/dev/block/bootdevice/by-name/%s", p) > 0) + link_num++; + else + links[link_num] = NULL; + } free(p); } @@ -544,6 +670,13 @@ static char **get_block_device_symlinks(struct uevent *uevent) link_num++; else links[link_num] = NULL; + + if (is_bootdevice >= 0) { + if (asprintf(&links[link_num], "/dev/block/bootdevice/by-num/p%d", uevent->partition_num) > 0) + link_num++; + else + links[link_num] = NULL; + } } slash = strrchr(uevent->path, '/'); @@ -564,7 +697,7 @@ static void handle_device(const char *action, const char *devpath, make_device(devpath, path, block, major, minor, (const char **)links); if (links) { for (i = 0; links[i]; i++) - make_link(devpath, links[i]); + make_link_init(devpath, links[i]); } } @@ -762,9 +895,32 @@ static void handle_generic_device_event(struct uevent *uevent) base = "/dev/log/"; make_dir(base, 0755); name += 4; + } else if (!strncmp(uevent->subsystem, "dvb", 3)) { + /* This imitates the file system that would be created + * if we were using devfs instead to preserve backward compatibility + * for users of dvb devices + */ + int adapter_id; + char dev_name[20] = {0}; + + sscanf(name, "dvb%d.%s", &adapter_id, dev_name); + + /* build dvb directory */ + base = "/dev/dvb"; + mkdir(base, 0755); + + /* build adapter directory */ + snprintf(devpath, sizeof(devpath), "/dev/dvb/adapter%d", adapter_id); + mkdir(devpath, 0755); + + /* build actual device directory */ + snprintf(devpath, sizeof(devpath), "/dev/dvb/adapter%d/%s", + adapter_id, dev_name); } else base = "/dev/"; links = get_character_device_symlinks(uevent); + if (!links) + links = get_v4l_device_symlinks(uevent); if (!devpath[0]) snprintf(devpath, sizeof(devpath), "%s%s", base, name); @@ -787,23 +943,20 @@ static void handle_device_event(struct uevent *uevent) } } -static int load_firmware(int fw_fd, int loading_fd, int data_fd) +static int load_firmware(int fw_fd, gzFile gz_fd, int loading_fd, int data_fd) { - struct stat st; - long len_to_copy; int ret = 0; - if(fstat(fw_fd, &st) < 0) - return -1; - len_to_copy = st.st_size; - write(loading_fd, "1", 1); /* start transfer */ - while (len_to_copy > 0) { + while (1) { char buf[PAGE_SIZE]; ssize_t nr; - nr = read(fw_fd, buf, sizeof(buf)); + if (gz_fd) + nr = gzread(gz_fd, buf, sizeof(buf)); + else + nr = read(fw_fd, buf, sizeof(buf)); if(!nr) break; if(nr < 0) { @@ -811,7 +964,6 @@ static int load_firmware(int fw_fd, int loading_fd, int data_fd) break; } - len_to_copy -= nr; while (nr > 0) { ssize_t nw = 0; @@ -827,8 +979,10 @@ static int load_firmware(int fw_fd, int loading_fd, int data_fd) out: if(!ret) write(loading_fd, "0", 1); /* successful end of transfer */ - else + else { + ERROR("%s: aborted transfer\n", __func__); write(loading_fd, "-1", 2); /* abort transfer */ + } return ret; } @@ -838,11 +992,47 @@ static int is_booting(void) return access("/dev/.booting", F_OK) == 0; } +gzFile fw_gzopen(const char *fname, const char *mode) +{ + char *file1 = NULL, *file2 = NULL, *file3 = NULL; + int l; + gzFile gz_fd = NULL; + + l = asprintf(&file1, FIRMWARE_DIR1"/%s.gz", fname); + if (l == -1) + goto out; + + l = asprintf(&file2, FIRMWARE_DIR2"/%s.gz", fname); + if (l == -1) + goto file1_free_out; + + l = asprintf(&file3, FIRMWARE_DIR3"/%s.gz", fname); + if (l == -1) + goto file2_free_out; + + gz_fd = gzopen(file1, mode); + if(!gz_fd) { + gz_fd = gzopen(file2, mode); + if (!gz_fd) { + gz_fd = gzopen(file3, mode); + } + } + + free(file3); +file2_free_out: + free(file2); +file1_free_out: + free(file1); +out: + return gz_fd; +} + static void process_firmware_event(struct uevent *uevent) { char *root, *loading, *data, *file1 = NULL, *file2 = NULL, *file3 = NULL; int l, loading_fd, data_fd, fw_fd; int booting = is_booting(); + gzFile gz_fd = NULL; INFO("firmware: loading '%s' for '%s'\n", uevent->firmware, uevent->path); @@ -886,27 +1076,33 @@ static void process_firmware_event(struct uevent *uevent) if (fw_fd < 0) { fw_fd = open(file3, O_RDONLY); if (fw_fd < 0) { - if (booting) { - /* If we're not fully booted, we may be missing - * filesystems needed for firmware, wait and retry. - */ - usleep(100000); - booting = is_booting(); - goto try_loading_again; + gz_fd = fw_gzopen(uevent->firmware, "rb"); + if (!gz_fd) { + if (booting || (access("/system/etc/firmware", F_OK) != 0)) { + /* If we're not fully booted, we may be missing + * filesystems needed for firmware, wait and retry. + */ + usleep(100000); + booting = is_booting(); + goto try_loading_again; + } + INFO("firmware: could not open '%s' %d\n", uevent->firmware, errno); + write(loading_fd, "-1", 2); + goto data_close_out; } - INFO("firmware: could not open '%s' %d\n", uevent->firmware, errno); - write(loading_fd, "-1", 2); - goto data_close_out; } } } - if(!load_firmware(fw_fd, loading_fd, data_fd)) + if(!load_firmware(fw_fd, gz_fd, loading_fd, data_fd)) INFO("firmware: copy success { '%s', '%s' }\n", root, uevent->firmware); else INFO("firmware: copy failure { '%s', '%s' }\n", root, uevent->firmware); - close(fw_fd); + if (gz_fd) + gzclose(gz_fd); + else + close(fw_fd); data_close_out: close(data_fd); loading_close_out: diff --git a/init/init.c b/init/init.c index bd1db7a5..86e2861a 100644 --- a/init/init.c +++ b/init/init.c @@ -67,11 +67,17 @@ static int property_triggers_enabled = 0; static int bootchart_count; #endif +#ifndef BOARD_CHARGING_CMDLINE_NAME +#define BOARD_CHARGING_CMDLINE_NAME "androidboot.battchg_pause" +#define BOARD_CHARGING_CMDLINE_VALUE "true" +#endif + static char console[32]; static char bootmode[32]; static char hardware[32]; static unsigned revision = 0; static char qemu[32]; +static char battchg_pause[32]; static struct action *cur_action = NULL; static struct command *cur_command = NULL; @@ -93,6 +99,8 @@ static time_t process_needs_restart; static const char *ENV[32]; +static unsigned charging_mode = 0; + /* add_environment - add "key=value" to the current environment */ int add_environment(const char *key, const char *val) { @@ -248,6 +256,9 @@ void service_start(struct service *svc, const char *dynamic_args) NOTICE("starting '%s'\n", svc->name); + if (properties_inited()) + notify_service_state(svc->name, "starting"); + pid = fork(); if (pid == 0) { @@ -578,7 +589,7 @@ static int wait_for_coldboot_done_action(int nargs, char **args) { int ret; INFO("wait for %s\n", coldboot_done); - ret = wait_for_file(coldboot_done, COMMAND_RETRY_TIMEOUT); + ret = wait_for_file(coldboot_done, COLDBOOT_RETRY_TIMEOUT); if (ret) ERROR("Timed out waiting for %s\n", coldboot_done); return ret; @@ -728,6 +739,8 @@ static void import_kernel_nv(char *name, int for_emulator) if (!strcmp(name,"qemu")) { strlcpy(qemu, value, sizeof(qemu)); + } else if (!strcmp(name,BOARD_CHARGING_CMDLINE_NAME)) { + strlcpy(battchg_pause, value, sizeof(battchg_pause)); } else if (!strncmp(name, "androidboot.", 12) && name_len > 12) { const char *boot_prop_name = name + 12; char prop[PROP_NAME_MAX]; @@ -907,29 +920,6 @@ static bool selinux_is_disabled(void) return false; } -static bool selinux_is_enforcing(void) -{ -#ifdef ALLOW_DISABLE_SELINUX - char tmp[PROP_VALUE_MAX]; - - if (property_get("ro.boot.selinux", tmp) == 0) { - /* Property is not set. Assume enforcing */ - return true; - } - - if (strcmp(tmp, "permissive") == 0) { - /* SELinux is in the kernel, but we've been told to go into permissive mode */ - return false; - } - - if (strcmp(tmp, "enforcing") != 0) { - ERROR("SELinux: Unknown value of ro.boot.selinux. Got: \"%s\". Assuming enforcing.\n", tmp); - } - -#endif - return true; -} - int selinux_reload_policy(void) { if (selinux_is_disabled()) { @@ -993,11 +983,30 @@ static void selinux_initialize(void) } selinux_init_all_handles(); - bool is_enforcing = selinux_is_enforcing(); + bool is_enforcing = false; INFO("SELinux: security_setenforce(%d)\n", is_enforcing); security_setenforce(is_enforcing); } +static int charging_mode_booting(void) +{ +#ifndef BOARD_CHARGING_MODE_BOOTING_LPM + return 0; +#else + int f; + char cmb; + f = open(BOARD_CHARGING_MODE_BOOTING_LPM, O_RDONLY); + if (f < 0) + return 0; + + if (1 != read(f, (void *)&cmb,1)) + return 0; + + close(f); + return ('1' == cmb); +#endif +} + int main(int argc, char **argv) { int fd_count = 0; @@ -1009,6 +1018,7 @@ int main(int argc, char **argv) int signal_fd_init = 0; int keychord_fd_init = 0; bool is_charger = false; + bool is_ffbm = false; if (!strcmp(basename(argv[0]), "ueventd")) return ueventd_main(argc, argv); @@ -1068,7 +1078,9 @@ int main(int argc, char **argv) restorecon("/dev/__properties__"); restorecon_recursive("/sys"); - is_charger = !strcmp(bootmode, "charger"); + is_ffbm = !strncmp(bootmode, "ffbm", 4); + if (!is_ffbm) + is_charger = !strcmp(bootmode, "charger") || charging_mode_booting(); INFO("property init\n"); property_load_boot_defaults(); @@ -1093,13 +1105,21 @@ int main(int argc, char **argv) queue_builtin_action(property_service_init_action, "property_service_init"); queue_builtin_action(signal_init_action, "signal_init"); + /* Older bootloaders use non-standard charging modes. Check for + * those now, after mounting the filesystems */ + if (strcmp(battchg_pause, BOARD_CHARGING_CMDLINE_VALUE) == 0) + is_charger = 1; + /* Don't mount filesystems or start core system services if in charger mode. */ if (is_charger) { action_for_each_trigger("charger", action_add_queue_tail); } else { - action_for_each_trigger("late-init", action_add_queue_tail); + if (is_ffbm) { + action_for_each_trigger("ffbm", action_add_queue_tail); + } else { + action_for_each_trigger("late-init", action_add_queue_tail); + } } - /* run all property triggers based on current state of the properties */ queue_builtin_action(queue_property_triggers_action, "queue_property_triggers"); diff --git a/init/init.h b/init/init.h index a7615a36..48ac12f8 100644 --- a/init/init.h +++ b/init/init.h @@ -80,10 +80,14 @@ struct svcenvinfo { #define SVC_RESTART 0x100 /* Use to safely restart (stop, wait, start) a service */ #define SVC_DISABLED_START 0x200 /* a start was requested but it was disabled at the time */ +#ifndef NR_SVC_SUPP_GIDS #define NR_SVC_SUPP_GIDS 12 /* twelve supplementary groups */ +#endif #define COMMAND_RETRY_TIMEOUT 5 +#define COLDBOOT_RETRY_TIMEOUT 10 + struct service { /* list of all services */ struct listnode slist; diff --git a/init/init_parser.c b/init/init_parser.c index 6466db21..eec90902 100644 --- a/init/init_parser.c +++ b/init/init_parser.c @@ -42,12 +42,14 @@ struct import { const char *filename; }; -static void *parse_service(struct parse_state *state, int nargs, char **args); +static void *parse_service(struct parse_state *state, int nargs, char **args, bool redefine); static void parse_line_service(struct parse_state *state, int nargs, char **args); static void *parse_action(struct parse_state *state, int nargs, char **args); static void parse_line_action(struct parse_state *state, int nargs, char **args); +void add_environment(const char *name, const char *value); + #define SECTION 0x01 #define COMMAND 0x02 #define OPTION 0x04 @@ -98,6 +100,7 @@ static int lookup_keyword(const char *s) if (!strcmp(s, "nable")) return K_enable; if (!strcmp(s, "xec")) return K_exec; if (!strcmp(s, "xport")) return K_export; + if (!strcmp(s, "xport_rc")) return K_export_rc; break; case 'g': if (!strcmp(s, "roup")) return K_group; @@ -115,6 +118,7 @@ static int lookup_keyword(const char *s) if (!strcmp(s, "eycodes")) return K_keycodes; break; case 'l': + if (!strcmp(s, "og")) return K_log; if (!strcmp(s, "oglevel")) return K_loglevel; if (!strcmp(s, "oad_persist_props")) return K_load_persist_props; if (!strcmp(s, "oad_all_props")) return K_load_all_props; @@ -141,6 +145,7 @@ static int lookup_keyword(const char *s) case 's': if (!strcmp(s, "eclabel")) return K_seclabel; if (!strcmp(s, "ervice")) return K_service; + if (!strcmp(s, "ervice_redefine")) return K_service_redefine; if (!strcmp(s, "etcon")) return K_setcon; if (!strcmp(s, "etenforce")) return K_setenforce; if (!strcmp(s, "etenv")) return K_setenv; @@ -160,6 +165,7 @@ static int lookup_keyword(const char *s) break; case 'u': if (!strcmp(s, "ser")) return K_user; + if (!strcmp(s, "mount")) return K_umount; break; case 'w': if (!strcmp(s, "rite")) return K_write; @@ -324,7 +330,8 @@ static void parse_new_section(struct parse_state *state, int kw, nargs > 1 ? args[1] : ""); switch(kw) { case K_service: - state->context = parse_service(state, nargs, args); + case K_service_redefine: + state->context = parse_service(state, nargs, args, (kw == K_service_redefine)); if (state->context) { state->parse_line = parse_line_service; return; @@ -412,6 +419,63 @@ int init_parse_config_file(const char *fn) return 0; } +typedef enum { + ENV_NOTREADY, + ENV_NAME, + ENV_VALUE, + ENV_WAITFORNEXTLINE, +} export_rc_state_t; + +int init_export_rc_file(const char *fn) +{ + char *data; + struct parse_state state; + char *env = NULL; + export_rc_state_t env_state = ENV_NOTREADY; + + data = read_file(fn, 0); + if (!data) return -1; + + state.filename = fn; + state.line = 0; + state.ptr = data; + state.nexttoken = 0; + state.parse_line = parse_line_no_op; + for (;;) { + switch (next_token(&state)) { + case T_EOF: + free(data); + return 0; + case T_NEWLINE: + env_state = ENV_NOTREADY; + break; + case T_TEXT: + switch (env_state) { + case ENV_NOTREADY: + if (strcmp(state.text, "export") == 0) { + env_state = ENV_NAME; + } else { + env_state = ENV_WAITFORNEXTLINE; + } + break; + case ENV_NAME: + env = state.text; + env_state = ENV_VALUE; + break; + case ENV_VALUE: + add_environment(env, state.text); + env_state = ENV_WAITFORNEXTLINE; + break; + default: + break; + } + break; + } + } + + return 0; +} + static int valid_name(const char *name) { if (strlen(name) > 16) { @@ -613,7 +677,7 @@ int action_queue_empty() return list_empty(&action_queue); } -static void *parse_service(struct parse_state *state, int nargs, char **args) +static void *parse_service(struct parse_state *state, int nargs, char **args, bool redefine) { struct service *svc; if (nargs < 3) { @@ -626,13 +690,18 @@ static void *parse_service(struct parse_state *state, int nargs, char **args) } svc = service_find_by_name(args[1]); - if (svc) { + if (svc && !redefine) { parse_error(state, "ignored duplicate definition of service '%s'\n", args[1]); return 0; } nargs -= 2; - svc = calloc(1, sizeof(*svc) + sizeof(char*) * nargs); + + if (!svc) { + svc = calloc(1, sizeof(*svc) + sizeof(char*) * nargs); + redefine = false; + } + if (!svc) { parse_error(state, "out of memory\n"); return 0; @@ -644,7 +713,8 @@ static void *parse_service(struct parse_state *state, int nargs, char **args) svc->nargs = nargs; svc->onrestart.name = "onrestart"; list_init(&svc->onrestart.commands); - list_add_tail(&service_list, &svc->slist); + if (!redefine) + list_add_tail(&service_list, &svc->slist); return svc; } diff --git a/init/keywords.h b/init/keywords.h index 2d97e5b9..224a505d 100644 --- a/init/keywords.h +++ b/init/keywords.h @@ -9,6 +9,7 @@ int do_domainname(int nargs, char **args); int do_enable(int nargs, char **args); int do_exec(int nargs, char **args); int do_export(int nargs, char **args); +int do_export_rc(int nargs, char **args); int do_hostname(int nargs, char **args); int do_ifup(int nargs, char **args); int do_insmod(int nargs, char **args); @@ -37,10 +38,12 @@ int do_write(int nargs, char **args); int do_copy(int nargs, char **args); int do_chown(int nargs, char **args); int do_chmod(int nargs, char **args); +int do_log(int nargs, char **args); int do_loglevel(int nargs, char **args); int do_load_persist_props(int nargs, char **args); int do_load_all_props(int nargs, char **args); int do_wait(int nargs, char **args); +int do_umount(int nargs, char **args); #define __MAKE_KEYWORD_ENUM__ #define KEYWORD(symbol, flags, nargs, func) K_##symbol, enum { @@ -60,6 +63,7 @@ enum { KEYWORD(enable, COMMAND, 1, do_enable) KEYWORD(exec, COMMAND, 1, do_exec) KEYWORD(export, COMMAND, 2, do_export) + KEYWORD(export_rc, COMMAND, 1, do_export_rc) KEYWORD(group, OPTION, 0, 0) KEYWORD(hostname, COMMAND, 1, do_hostname) KEYWORD(ifup, COMMAND, 1, do_ifup) @@ -80,6 +84,7 @@ enum { KEYWORD(rmdir, COMMAND, 1, do_rmdir) KEYWORD(seclabel, OPTION, 0, 0) KEYWORD(service, SECTION, 0, 0) + KEYWORD(service_redefine, SECTION, 0, 0) KEYWORD(setcon, COMMAND, 1, do_setcon) KEYWORD(setenforce, COMMAND, 1, do_setenforce) KEYWORD(setenv, OPTION, 2, 0) @@ -100,10 +105,12 @@ enum { KEYWORD(copy, COMMAND, 2, do_copy) KEYWORD(chown, COMMAND, 2, do_chown) KEYWORD(chmod, COMMAND, 2, do_chmod) + KEYWORD(log, COMMAND, 1, do_log) KEYWORD(loglevel, COMMAND, 1, do_loglevel) KEYWORD(load_persist_props, COMMAND, 0, do_load_persist_props) KEYWORD(load_all_props, COMMAND, 0, do_load_all_props) KEYWORD(ioprio, OPTION, 0, 0) + KEYWORD(umount, COMMAND, 1, do_umount) #ifdef __MAKE_KEYWORD_ENUM__ KEYWORD_COUNT, }; diff --git a/init/log.h b/init/log.h index e9cb65a6..66b95e34 100644 --- a/init/log.h +++ b/init/log.h @@ -20,7 +20,7 @@ #include #define ERROR(x...) KLOG_ERROR("init", x) -#define NOTICE(x...) KLOG_NOTICE("init", x) +#define NOTICE(x...) KLOG_INFO("init", x) #define INFO(x...) KLOG_INFO("init", x) extern int log_callback(int type, const char *fmt, ...); diff --git a/init/property_service.c b/init/property_service.c index 91ef2518..322f4d8b 100644 --- a/init/property_service.c +++ b/init/property_service.c @@ -48,6 +48,7 @@ #include "init.h" #include "util.h" #include "log.h" +#include "vendor_init.h" #define PERSISTENT_PROPERTY_DIR "/data/property" @@ -56,6 +57,68 @@ static int property_area_inited = 0; static int property_set_fd = -1; +/* White list of permissions for setting property services. */ +struct { + const char *prefix; + unsigned int uid; + unsigned int gid; +} property_perms[] = { + { "net.rmnet0.", AID_RADIO, 0 }, + { "net.gprs.", AID_RADIO, 0 }, + { "net.ppp", AID_RADIO, 0 }, + { "net.qmi", AID_RADIO, 0 }, + { "net.lte", AID_RADIO, 0 }, + { "net.cdma", AID_RADIO, 0 }, + { "ril.", AID_RADIO, 0 }, + { "gsm.", AID_RADIO, 0 }, + { "persist.radio", AID_RADIO, 0 }, + { "net.dns", AID_RADIO, 0 }, + { "sys.usb.config", AID_RADIO, 0 }, + { "net.", AID_SYSTEM, 0 }, + { "dev.", AID_SYSTEM, 0 }, + { "runtime.", AID_SYSTEM, 0 }, + { "hw.", AID_SYSTEM, 0 }, + { "sys.", AID_SYSTEM, 0 }, + { "sys.powerctl", AID_SHELL, 0 }, + { "service.", AID_SYSTEM, 0 }, + { "wlan.", AID_SYSTEM, 0 }, + { "gps.", AID_GPS, 0 }, + { "bluetooth.", AID_BLUETOOTH, 0 }, + { "dhcp.", AID_SYSTEM, 0 }, + { "dhcp.", AID_DHCP, 0 }, + { "debug.", AID_SYSTEM, 0 }, + { "debug.", AID_SHELL, 0 }, + { "log.", AID_SHELL, 0 }, + { "service.adb.root", AID_SHELL, 0 }, + { "service.adb.tcp.port", AID_SHELL, 0 }, + { "persist.logd.size",AID_SYSTEM, 0 }, + { "persist.sys.", AID_SYSTEM, 0 }, + { "persist.service.", AID_SYSTEM, 0 }, + { "persist.security.", AID_SYSTEM, 0 }, + { "persist.gps.", AID_GPS, 0 }, + { "persist.service.bdroid.", AID_BLUETOOTH, 0 }, + { "selinux." , AID_SYSTEM, 0 }, + { "wc_transport.", AID_BLUETOOTH, AID_SYSTEM }, + { "build.fingerprint", AID_SYSTEM, 0 }, + { "partition." , AID_SYSTEM, 0}, + { NULL, 0, 0 } +}; + +/* + * White list of UID that are allowed to start/stop services. + * Currently there are no user apps that require. + */ +struct { + const char *service; + unsigned int uid; + unsigned int gid; +} control_perms[] = { + { "dumpstate",AID_SHELL, AID_LOG }, + { "ril-daemon",AID_RADIO, AID_RADIO }, + { "pre-recovery", AID_SYSTEM, AID_SYSTEM }, + {NULL, 0, 0 } +}; + typedef struct { size_t size; int fd; @@ -543,6 +606,12 @@ void load_all_props(void) load_properties_from_file(PROP_PATH_VENDOR_BUILD, NULL); load_properties_from_file(PROP_PATH_FACTORY, "ro.*"); + /* ensure ro.boot.ftm gets set */ + property_set("ro.boot.ftm", "0"); + + /* Read vendor-specific property runtime overrides. */ + vendor_load_properties(); + load_override_properties(); /* Read persistent properties after all default values have been loaded. */ diff --git a/init/ueventd.c b/init/ueventd.c index 833e4fd0..1e580525 100644 --- a/init/ueventd.c +++ b/init/ueventd.c @@ -33,6 +33,7 @@ static char hardware[32]; static unsigned revision = 0; +char bootdevice[32]; static void import_kernel_nv(char *name, int in_qemu) { @@ -44,6 +45,10 @@ static void import_kernel_nv(char *name, int in_qemu) { strlcpy(hardware, value, sizeof(hardware)); } + else if (!strcmp(name,"androidboot.bootdevice")) + { + strlcpy(bootdevice, value, sizeof(bootdevice)); + } } } } diff --git a/init/util.c b/init/util.c index e1a3ee33..f5c84864 100644 --- a/init/util.c +++ b/init/util.c @@ -335,7 +335,7 @@ void sanitize(char *s) } } -void make_link(const char *oldpath, const char *newpath) +void make_link_init(const char *oldpath, const char *newpath) { int ret; char buf[256]; @@ -530,7 +530,11 @@ int restorecon(const char* pathname) return selinux_android_restorecon(pathname, 0); } +#define RESTORECON_RECURSIVE_FLAGS \ + (SELINUX_ANDROID_RESTORECON_FORCE | \ + SELINUX_ANDROID_RESTORECON_RECURSE) + int restorecon_recursive(const char* pathname) { - return selinux_android_restorecon(pathname, SELINUX_ANDROID_RESTORECON_RECURSE); + return selinux_android_restorecon(pathname, RESTORECON_RECURSIVE_FLAGS); } diff --git a/init/util.h b/init/util.h index 04b8129b..a7e7c8b2 100644 --- a/init/util.h +++ b/init/util.h @@ -33,7 +33,7 @@ unsigned int decode_uid(const char *s); int mkdir_recursive(const char *pathname, mode_t mode); void sanitize(char *p); -void make_link(const char *oldpath, const char *newpath); +void make_link_init(const char *oldpath, const char *newpath); void remove_link(const char *oldpath, const char *newpath); int wait_for_file(const char *filename, int timeout); void open_devnull_stdio(void); diff --git a/init/vendor_init.c b/init/vendor_init.c new file mode 100644 index 00000000..d3fd5ffe --- /dev/null +++ b/init/vendor_init.c @@ -0,0 +1,37 @@ +/* +Copyright (c) 2013, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation 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 "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +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 "vendor_init.h" + +/* init vendor override stubs */ + +__attribute__ ((weak)) +void vendor_load_properties() +{ +} diff --git a/init/vendor_init.h b/init/vendor_init.h new file mode 100644 index 00000000..9afb449b --- /dev/null +++ b/init/vendor_init.h @@ -0,0 +1,33 @@ +/* +Copyright (c) 2013, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation 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 "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +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. + */ + +#ifndef __INIT_VENDOR__H__ +#define __INIT_VENDOR__H__ +extern void vendor_load_properties(void); +#endif /* __INIT_VENDOR__H__ */ diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk index 9588dd6d..81d15dc0 100755 --- a/libbacktrace/Android.mk +++ b/libbacktrace/Android.mk @@ -194,6 +194,8 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := \ BacktraceMap.cpp \ +LOCAL_MULTILIB := both + include $(BUILD_HOST_SHARED_LIBRARY) # Don't build for unbundled branches diff --git a/libcutils/Android.mk b/libcutils/Android.mk index b016a423..5a803f83 100644 --- a/libcutils/Android.mk +++ b/libcutils/Android.mk @@ -79,7 +79,7 @@ LOCAL_SRC_FILES := $(commonSources) $(commonHostSources) dlmalloc_stubs.c LOCAL_STATIC_LIBRARIES := liblog LOCAL_CFLAGS += $(hostSmpFlag) ifneq ($(HOST_OS),windows) -LOCAL_CFLAGS += -Werror +LOCAL_CFLAGS += -std=gnu89 endif LOCAL_MULTILIB := both LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk @@ -92,7 +92,7 @@ include $(CLEAR_VARS) LOCAL_MODULE := tst_str_parms LOCAL_CFLAGS += -DTEST_STR_PARMS ifneq ($(HOST_OS),windows) -LOCAL_CFLAGS += -Werror +LOCAL_CFLAGS += -std=gnu89 endif LOCAL_SRC_FILES := str_parms.c hashmap.c memory.c LOCAL_STATIC_LIBRARIES := liblog @@ -141,9 +141,17 @@ LOCAL_CFLAGS_mips += -DHAVE_MEMSET16 -DHAVE_MEMSET32 LOCAL_CFLAGS_x86 += -DHAVE_MEMSET16 -DHAVE_MEMSET32 LOCAL_CFLAGS_x86_64 += -DHAVE_MEMSET16 -DHAVE_MEMSET32 +ifneq ($(TARGET_RECOVERY_PRE_COMMAND),) + LOCAL_CFLAGS += -DRECOVERY_PRE_COMMAND='$(TARGET_RECOVERY_PRE_COMMAND)' +endif + +ifeq ($(TARGET_RECOVERY_PRE_COMMAND_CLEAR_REASON),true) + LOCAL_CFLAGS += -DRECOVERY_PRE_COMMAND_CLEAR_REASON +endif + LOCAL_C_INCLUDES := $(libcutils_c_includes) LOCAL_STATIC_LIBRARIES := liblog -LOCAL_CFLAGS += $(targetSmpFlag) -Werror +LOCAL_CFLAGS += $(targetSmpFlag) -std=gnu89 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk include $(BUILD_STATIC_LIBRARY) @@ -153,14 +161,14 @@ LOCAL_MODULE := libcutils # liblog symbols present in libcutils. LOCAL_WHOLE_STATIC_LIBRARIES := libcutils liblog LOCAL_SHARED_LIBRARIES := liblog -LOCAL_CFLAGS += $(targetSmpFlag) -Werror +LOCAL_CFLAGS += $(targetSmpFlag) -std=gnu89 LOCAL_C_INCLUDES := $(libcutils_c_includes) LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk include $(BUILD_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := tst_str_parms -LOCAL_CFLAGS += -DTEST_STR_PARMS -Werror +LOCAL_CFLAGS += -DTEST_STR_PARMS -std=gnu89 LOCAL_SRC_FILES := str_parms.c hashmap.c memory.c LOCAL_SHARED_LIBRARIES := liblog LOCAL_MODULE_TAGS := optional diff --git a/libcutils/android_reboot.c b/libcutils/android_reboot.c index 5d982958..30738d78 100644 --- a/libcutils/android_reboot.c +++ b/libcutils/android_reboot.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -95,7 +96,7 @@ static void remount_ro(void) /* Now poll /proc/mounts till it's done */ - while (!remount_ro_done() && (cnt < 50)) { + while (!remount_ro_done() && (cnt < 3600)) { usleep(100000); cnt++; } @@ -106,29 +107,49 @@ static void remount_ro(void) int android_reboot(int cmd, int flags UNUSED, char *arg) { - int ret; + int ret = 0; + int reason = -1; + +#ifdef RECOVERY_PRE_COMMAND + if (cmd == (int) ANDROID_RB_RESTART2) { + if (arg && strlen(arg) > 0) { + char cmd[PATH_MAX]; + sprintf(cmd, RECOVERY_PRE_COMMAND " %s", arg); + system(cmd); + } + } +#endif sync(); remount_ro(); switch (cmd) { case ANDROID_RB_RESTART: - ret = reboot(RB_AUTOBOOT); + reason = RB_AUTOBOOT; break; case ANDROID_RB_POWEROFF: ret = reboot(RB_POWER_OFF); - break; + return ret; case ANDROID_RB_RESTART2: - ret = syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, - LINUX_REBOOT_CMD_RESTART2, arg); + // REBOOT_MAGIC break; default: - ret = -1; + return -1; } +#ifdef RECOVERY_PRE_COMMAND_CLEAR_REASON + reason = RB_AUTOBOOT; +#endif + + if (reason != -1) + ret = reboot(reason); + else + ret = syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, + LINUX_REBOOT_CMD_RESTART2, arg); + return ret; } diff --git a/libcutils/iosched_policy.c b/libcutils/iosched_policy.c index a6da9cac..e1f1b1d8 100644 --- a/libcutils/iosched_policy.c +++ b/libcutils/iosched_policy.c @@ -1,9 +1,10 @@ /* ** Copyright 2007-2014, The Android Open Source Project +** Copyright 2015, The CyanogenMod 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 +** 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 ** @@ -22,26 +23,27 @@ #include #include +#define LOG_TAG "iosched_policy" +#include + +#define __android_unused __attribute__((__unused__)) #ifdef HAVE_ANDROID_OS #include #include -#define __android_unused -#else -#define __android_unused __attribute__((__unused__)) -#endif +#include + +static int __rtio_cgroup_supported = -1; +static pthread_once_t __rtio_init_once = PTHREAD_ONCE_INIT; int android_set_ioprio(int pid __android_unused, IoSchedClass clazz __android_unused, int ioprio __android_unused) { -#ifdef HAVE_ANDROID_OS if (syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, pid, ioprio | (clazz << IOPRIO_CLASS_SHIFT))) { return -1; } -#endif return 0; } int android_get_ioprio(int pid __android_unused, IoSchedClass *clazz, int *ioprio) { -#ifdef HAVE_ANDROID_OS int rc; if ((rc = syscall(SYS_ioprio_get, IOPRIO_WHO_PROCESS, pid)) < 0) { @@ -50,9 +52,83 @@ int android_get_ioprio(int pid __android_unused, IoSchedClass *clazz, int *iopri *clazz = (rc >> IOPRIO_CLASS_SHIFT); *ioprio = (rc & 0xff); + return 0; +} + +static void __initialize_rtio(void) { + if (!access("/sys/fs/cgroup/bfqio/tasks", W_OK) || + !access("/sys/fs/cgroup/bfqio/rt-display/tasks", W_OK)) { + __rtio_cgroup_supported = 1; + } else { + __rtio_cgroup_supported = 0; + } +} + +int android_set_rt_ioprio(int tid, int rt) { + int fd = -1, rc = -1; + + pthread_once(&__rtio_init_once, __initialize_rtio); + if (__rtio_cgroup_supported != 1) { + return -1; + } + + if (rt) { + fd = open("/sys/fs/cgroup/bfqio/rt-display/tasks", O_WRONLY | O_CLOEXEC); + } else { + fd = open("/sys/fs/cgroup/bfqio/tasks", O_WRONLY | O_CLOEXEC); + } + + if (fd < 0) { + return -1; + } + +#ifdef HAVE_GETTID + if (tid == 0) { + tid = gettid(); + } +#endif + + // specialized itoa -- works for tid > 0 + char text[22]; + char *end = text + sizeof(text) - 1; + char *ptr = end; + *ptr = '\0'; + while (tid > 0) { + *--ptr = '0' + (tid % 10); + tid = tid / 10; + } + + rc = write(fd, ptr, end - ptr); + if (rc < 0) { + /* + * If the thread is in the process of exiting, + * don't flag an error + */ + if (errno == ESRCH) { + rc = 0; + } else { + SLOGV("android_set_rt_ioprio failed to write '%s' (%s); fd=%d\n", + ptr, strerror(errno), fd); + } + } + + close(fd); + return rc; +} + #else +int android_set_ioprio(int pid __android_unused, IoSchedClass clazz __android_unused, int ioprio __android_unused) { + return 0; +} + +int android_get_ioprio(int pid __android_unused, IoSchedClass *clazz, int *ioprio) { *clazz = IoSchedClass_NONE; *ioprio = 0; -#endif return 0; } + +int android_set_rt_ioprio(int tid __android_unused, int rt __android_unused) +{ + return 0; +} +#endif diff --git a/libcutils/klog.c b/libcutils/klog.c index fbb7b724..66d5aeef 100644 --- a/libcutils/klog.c +++ b/libcutils/klog.c @@ -25,6 +25,11 @@ #include +#ifdef AMAZON_LOG +extern int lab126_log_write(int bufID, int prio, const char *tag, const char *fmt, ...); +extern int __vitals_log_print(int bufID, int prio, const char *tag, const char *fmt, ...); +#endif // AMAZON_LOG + static int klog_fd = -1; static int klog_level = KLOG_DEFAULT_LEVEL; diff --git a/libcutils/native_handle.c b/libcutils/native_handle.c index 9a4a5bb3..61fa38ed 100644 --- a/libcutils/native_handle.c +++ b/libcutils/native_handle.c @@ -25,11 +25,17 @@ #include #include +static const int kMaxNativeFds = 1024; +static const int kMaxNativeInts = 1024; + native_handle_t* native_handle_create(int numFds, int numInts) { - native_handle_t* h = malloc( - sizeof(native_handle_t) + sizeof(int)*(numFds+numInts)); + if (numFds < 0 || numInts < 0 || numFds > kMaxNativeFds || numInts > kMaxNativeInts) { + return NULL; + } + size_t mallocSize = sizeof(native_handle_t) + (sizeof(int) * (numFds + numInts)); + native_handle_t* h = malloc(mallocSize); if (h) { h->version = sizeof(native_handle_t); h->numFds = numFds; diff --git a/libdiskconfig/Android.mk b/libdiskconfig/Android.mk index 624e3852..5e7400e1 100644 --- a/libdiskconfig/Android.mk +++ b/libdiskconfig/Android.mk @@ -15,6 +15,13 @@ LOCAL_SYSTEM_SHARED_LIBRARIES := libcutils liblog libc LOCAL_CFLAGS := -Werror include $(BUILD_SHARED_LIBRARY) +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(commonSources) +LOCAL_MODULE := libdiskconfig +LOCAL_MODULE_TAGS := optional +#LOCAL_STATIC_LIBRARIES := libcutils liblog libc +include $(BUILD_STATIC_LIBRARY) + ifeq ($(HOST_OS),linux) include $(CLEAR_VARS) LOCAL_SRC_FILES := $(commonSources) diff --git a/liblog/Android.mk b/liblog/Android.mk index a4e5f5eb..bbcae54f 100644 --- a/liblog/Android.mk +++ b/liblog/Android.mk @@ -70,19 +70,22 @@ endif LOCAL_MULTILIB := both include $(BUILD_HOST_SHARED_LIBRARY) +ifeq ($(TARGET_USES_MOTOROLA_LOG),true) +LIBLOG_CFLAGS := -DMOTOROLA_LOG +endif # Shared and static library for target # ======================================================== include $(CLEAR_VARS) LOCAL_MODULE := liblog LOCAL_SRC_FILES := $(liblog_target_sources) -LOCAL_CFLAGS := -Werror +LOCAL_CFLAGS := $(LIBLOG_CFLAGS) -Werror include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := liblog LOCAL_WHOLE_STATIC_LIBRARIES := liblog -LOCAL_CFLAGS := -Werror +LOCAL_CFLAGS := $(LIBLOG_CFLAGS) -Werror include $(BUILD_SHARED_LIBRARY) include $(call first-makefiles-under,$(LOCAL_PATH)) diff --git a/liblog/logd_write.c b/liblog/logd_write.c index b2668ced..4b9c7c7f 100644 --- a/liblog/logd_write.c +++ b/liblog/logd_write.c @@ -35,6 +35,12 @@ #include #endif +#if defined(MOTOROLA_LOG) || defined(MTK_HARDWARE) +#if HAVE_LIBC_SYSTEM_PROPERTIES +#include +#endif +#endif + #include #include #include @@ -83,6 +89,95 @@ int __android_log_dev_available(void) return (g_log_status == kLogAvailable); } +#ifdef MOTOROLA_LOG +/* Fallback when there is neither log.tag. nor log.tag.DEFAULT. + * this is compile-time defaulted to "info". The log startup code + * looks at the build tags to see about whether it should be DEBUG... + * -- just as is done in frameworks/base/core/jni/android_util_Log.cpp + */ +static int prio_fallback = ANDROID_LOG_INFO; + +/* + * public interface so native code can see "should i log this" + * and behave similar to java Log.isLoggable() calls. + * + * NB: we have (level,tag) here to match the other __android_log entries. + * The Java side uses (tag,level) for its ordering. + * since the args are (int,char*) vs (char*,char*) we won't get strange + * swapped-the-strings errors. + */ + +#define LOGGING_PREFIX "log.tag." +#define LOGGING_DEFAULT "log.tag.DEFAULT" + +int __android_log_loggable(int prio, const char *tag) +{ + int nprio; + +#if HAVE_LIBC_SYSTEM_PROPERTIES + char keybuf[PROP_NAME_MAX]; + char results[PROP_VALUE_MAX]; + int n; + + /* we can NOT cache the log.tag. and log.tag.DEFAULT + * values because either one can be changed dynamically. + * + * damn, says the performance compulsive. + */ + + n = 0; + results[0] = '\0'; + if (tag) { + memcpy (keybuf, LOGGING_PREFIX, strlen (LOGGING_PREFIX) + 1); + /* watch out for buffer overflow */ + strncpy (keybuf + strlen (LOGGING_PREFIX), tag, + sizeof (keybuf) - strlen (LOGGING_PREFIX)); + keybuf[sizeof (keybuf) - 1] = '\0'; + n = __system_property_get (keybuf, results); + } + if (n == 0) { + /* nothing yet, look for the global */ + memcpy (keybuf, LOGGING_DEFAULT, sizeof (LOGGING_DEFAULT)); + n = __system_property_get (keybuf, results); + } + + if (n == 0) { + nprio = prio_fallback; + } else { + switch (results[0]) { + case 'E': + nprio = ANDROID_LOG_ERROR; + break; + case 'W': + nprio = ANDROID_LOG_WARN; + break; + case 'I': + nprio = ANDROID_LOG_INFO; + break; + case 'D': + nprio = ANDROID_LOG_DEBUG; + break; + case 'V': + nprio = ANDROID_LOG_VERBOSE; + break; + case 'S': + nprio = ANDROID_LOG_SILENT; + break; + default: + /* unspecified or invalid */ + nprio = prio_fallback; + break; + } + } +#else + /* no system property routines, fallback to a default */ + nprio = prio_fallback; +#endif + + return ((prio >= nprio) ? 1 : 0); +} +#endif + #if !FAKE_LOG_DEVICE /* give up, resources too limited */ static int __write_to_log_null(log_id_t log_fd __unused, struct iovec *vec __unused, @@ -309,6 +404,50 @@ static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr) return write_to_log(log_id, vec, nr); } +#ifdef AMAZON_LOG +int lab126_log_write(int bufID, int prio, const char *tag, const char *fmt, ...) +{ + va_list ap; + char buf[LOG_BUF_SIZE]; + int _a = bufID; + int _b = prio; + + // skip flooding logs + if (!tag) + { + tag = ""; + } + if( strncmp(tag, "Sensors", 7) == 0 + || strncmp(tag, "qcom_se", 7) == 0 ) + { + return 0; + } + // skip flooding logs + + va_start(ap, fmt); + vsnprintf(buf, LOG_BUF_SIZE, fmt, ap); + va_end(ap); + + char new_tag[128]; + snprintf(new_tag, sizeof(new_tag), "AMZ-%s", tag); + + return __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_DEBUG, new_tag, buf); +} + +int __vitals_log_print(int bufID, int prio, const char *tag, const char *fmt, ...) +{ + va_list ap; + char buf[LOG_BUF_SIZE]; + int _a = bufID; + int _b = prio; + + va_start(ap, fmt); + va_end(ap); + + return __android_log_write(ANDROID_LOG_DEBUG, tag, "__vitals_log_print not implemented"); +} +#endif + int __android_log_write(int prio, const char *tag, const char *msg) { struct iovec vec[3]; @@ -497,3 +636,44 @@ int __android_log_bswrite(int32_t tag, const char *payload) return write_to_log(LOG_ID_EVENTS, vec, 4); } + +#ifdef MTK_HARDWARE +struct xlog_record { + const char *tag_str; + const char *fmt_str; + int prio; +}; + +void __attribute__((weak)) __xlog_buf_printf(int bufid, const struct xlog_record *xlog_record, ...) { + va_list args; + va_start(args, xlog_record); +#if HAVE_LIBC_SYSTEM_PROPERTIES + int len = 0; + int do_xlog = 0; + char results[PROP_VALUE_MAX]; + + + // MobileLog + len = __system_property_get ("debug.MB.running", results); + if (len && atoi(results)) + do_xlog = 1; + + // ModemLog + len = __system_property_get ("debug.mdlogger.Running", results); + if (len && atoi(results)) + do_xlog = 1; + + // Manual + len = __system_property_get ("persist.debug.xlog.enable", results); + if (len && atoi(results)) + do_xlog = 1; + + if (do_xlog > 0) +#endif + __android_log_vprint(xlog_record->prio, xlog_record->tag_str, xlog_record->fmt_str, args); + + // get rid of "unused parameter 'bufid'" + bufid = bufid; + return; +} +#endif diff --git a/liblog/logd_write_kern.c b/liblog/logd_write_kern.c index ae621cb1..a7bd61c1 100644 --- a/liblog/logd_write_kern.c +++ b/liblog/logd_write_kern.c @@ -32,6 +32,12 @@ #include #endif +#ifdef MOTOROLA_LOG +#if HAVE_LIBC_SYSTEM_PROPERTIES +#include +#endif +#endif + #include #include #include @@ -87,6 +93,95 @@ int __android_log_dev_available(void) return (g_log_status == kLogAvailable); } +#ifdef MOTOROLA_LOG +/* Fallback when there is neither log.tag. nor log.tag.DEFAULT. + * this is compile-time defaulted to "info". The log startup code + * looks at the build tags to see about whether it should be DEBUG... + * -- just as is done in frameworks/base/core/jni/android_util_Log.cpp + */ +static int prio_fallback = ANDROID_LOG_INFO; + +/* + * public interface so native code can see "should i log this" + * and behave similar to java Log.isLoggable() calls. + * + * NB: we have (level,tag) here to match the other __android_log entries. + * The Java side uses (tag,level) for its ordering. + * since the args are (int,char*) vs (char*,char*) we won't get strange + * swapped-the-strings errors. + */ + +#define LOGGING_PREFIX "log.tag." +#define LOGGING_DEFAULT "log.tag.DEFAULT" + +int __android_log_loggable(int prio, const char *tag) +{ + int nprio; + +#if HAVE_LIBC_SYSTEM_PROPERTIES + char keybuf[PROP_NAME_MAX]; + char results[PROP_VALUE_MAX]; + int n; + + /* we can NOT cache the log.tag. and log.tag.DEFAULT + * values because either one can be changed dynamically. + * + * damn, says the performance compulsive. + */ + + n = 0; + results[0] = '\0'; + if (tag) { + memcpy (keybuf, LOGGING_PREFIX, strlen (LOGGING_PREFIX) + 1); + /* watch out for buffer overflow */ + strncpy (keybuf + strlen (LOGGING_PREFIX), tag, + sizeof (keybuf) - strlen (LOGGING_PREFIX)); + keybuf[sizeof (keybuf) - 1] = '\0'; + n = __system_property_get (keybuf, results); + } + if (n == 0) { + /* nothing yet, look for the global */ + memcpy (keybuf, LOGGING_DEFAULT, sizeof (LOGGING_DEFAULT)); + n = __system_property_get (keybuf, results); + } + + if (n == 0) { + nprio = prio_fallback; + } else { + switch (results[0]) { + case 'E': + nprio = ANDROID_LOG_ERROR; + break; + case 'W': + nprio = ANDROID_LOG_WARN; + break; + case 'I': + nprio = ANDROID_LOG_INFO; + break; + case 'D': + nprio = ANDROID_LOG_DEBUG; + break; + case 'V': + nprio = ANDROID_LOG_VERBOSE; + break; + case 'S': + nprio = ANDROID_LOG_SILENT; + break; + default: + /* unspecified or invalid */ + nprio = prio_fallback; + break; + } + } +#else + /* no system property routines, fallback to a default */ + nprio = prio_fallback; +#endif + + return ((prio >= nprio) ? 1 : 0); +} +#endif + static int __write_to_log_null(log_id_t log_fd __unused, struct iovec *vec __unused, size_t nr __unused) { diff --git a/liblog/logprint.c b/liblog/logprint.c index 08e830ac..8851b11a 100644 --- a/liblog/logprint.c +++ b/liblog/logprint.c @@ -17,8 +17,16 @@ #define _GNU_SOURCE /* for asprintf */ +#define COLOR_BLUE 75 +#define COLOR_DEFAULT 231 +#define COLOR_GREEN 40 +#define COLOR_ORANGE 166 +#define COLOR_RED 196 +#define COLOR_YELLOW 226 + #include #include + #include #include #include @@ -39,6 +47,7 @@ struct AndroidLogFormat_t { android_LogPriority global_pri; FilterInfo *filters; AndroidLogPrintFormat format; + AndroidLogColoredOutput colored_output; }; static FilterInfo * filterinfo_new(const char * tag, android_LogPriority pri) @@ -110,6 +119,23 @@ static char filterPriToChar (android_LogPriority pri) } } +static int colorFromPri (android_LogPriority pri) +{ + switch (pri) { + case ANDROID_LOG_VERBOSE: return COLOR_DEFAULT; + case ANDROID_LOG_DEBUG: return COLOR_BLUE; + case ANDROID_LOG_INFO: return COLOR_GREEN; + case ANDROID_LOG_WARN: return COLOR_ORANGE; + case ANDROID_LOG_ERROR: return COLOR_RED; + case ANDROID_LOG_FATAL: return COLOR_RED; + case ANDROID_LOG_SILENT: return COLOR_DEFAULT; + + case ANDROID_LOG_DEFAULT: + case ANDROID_LOG_UNKNOWN: + default: return COLOR_DEFAULT; + } +} + static android_LogPriority filterPriForTag( AndroidLogFormat *p_format, const char *tag) { @@ -149,6 +175,7 @@ AndroidLogFormat *android_log_format_new() p_ret->global_pri = ANDROID_LOG_VERBOSE; p_ret->format = FORMAT_BRIEF; + p_ret->colored_output = OUTPUT_COLOR_OFF; return p_ret; } @@ -177,6 +204,11 @@ void android_log_setPrintFormat(AndroidLogFormat *p_format, p_format->format=format; } +void android_log_setColoredOutput(AndroidLogFormat *p_format) +{ + p_format->colored_output = OUTPUT_COLOR_ON; +} + /** * Returns FORMAT_OFF on invalid string */ @@ -721,20 +753,32 @@ char *android_log_formatLogLine ( */ size_t prefixLen, suffixLen; + size_t prefixColorLen = 0; + char * prefixBufTmp = prefixBuf; + size_t prefixBufTmpRemainLen = sizeof(prefixBuf); + + if (p_format->colored_output == OUTPUT_COLOR_ON) { + prefixColorLen = snprintf(prefixBufTmp, prefixBufTmpRemainLen, "%c[%d;%d;%dm", 0x1B, 38, 5, colorFromPri(entry->priority)); + if(prefixColorLen >= prefixBufTmpRemainLen) + prefixColorLen = prefixBufTmpRemainLen - 1; + prefixBufTmp += prefixColorLen; + prefixBufTmpRemainLen -= prefixColorLen; + } + switch (p_format->format) { case FORMAT_TAG: - prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), + prefixLen = snprintf(prefixBufTmp, prefixBufTmpRemainLen, "%c/%-8s: ", priChar, entry->tag); strcpy(suffixBuf, "\n"); suffixLen = 1; break; case FORMAT_PROCESS: - prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), + prefixLen = snprintf(prefixBufTmp, prefixBufTmpRemainLen, "%c(%5d) ", priChar, entry->pid); suffixLen = snprintf(suffixBuf, sizeof(suffixBuf), " (%s)\n", entry->tag); break; case FORMAT_THREAD: - prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), + prefixLen = snprintf(prefixBufTmp, prefixBufTmpRemainLen, "%c(%5d:%5d) ", priChar, entry->pid, entry->tid); strcpy(suffixBuf, "\n"); suffixLen = 1; @@ -746,21 +790,21 @@ char *android_log_formatLogLine ( suffixLen = 1; break; case FORMAT_TIME: - prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), + prefixLen = snprintf(prefixBufTmp, prefixBufTmpRemainLen, "%s.%03ld %c/%-8s(%5d): ", timeBuf, entry->tv_nsec / 1000000, priChar, entry->tag, entry->pid); strcpy(suffixBuf, "\n"); suffixLen = 1; break; case FORMAT_THREADTIME: - prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), + prefixLen = snprintf(prefixBufTmp, prefixBufTmpRemainLen, "%s.%03ld %5d %5d %c %-8s: ", timeBuf, entry->tv_nsec / 1000000, entry->pid, entry->tid, priChar, entry->tag); strcpy(suffixBuf, "\n"); suffixLen = 1; break; case FORMAT_LONG: - prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), + prefixLen = snprintf(prefixBufTmp, prefixBufTmpRemainLen, "[ %s.%03ld %5d:%5d %c/%-8s ]\n", timeBuf, entry->tv_nsec / 1000000, entry->pid, entry->tid, priChar, entry->tag); @@ -770,7 +814,7 @@ char *android_log_formatLogLine ( break; case FORMAT_BRIEF: default: - prefixLen = snprintf(prefixBuf, sizeof(prefixBuf), + prefixLen = snprintf(prefixBufTmp, prefixBufTmpRemainLen, "%c/%-8s(%5d): ", priChar, entry->tag, entry->pid); strcpy(suffixBuf, "\n"); suffixLen = 1; @@ -782,11 +826,22 @@ char *android_log_formatLogLine ( * possibly causing heap corruption. To avoid this we double check and * set the length at the maximum (size minus null byte) */ - if(prefixLen >= sizeof(prefixBuf)) - prefixLen = sizeof(prefixBuf) - 1; + if(prefixLen >= prefixBufTmpRemainLen) + prefixLen = prefixBufTmpRemainLen - 1; if(suffixLen >= sizeof(suffixBuf)) suffixLen = sizeof(suffixBuf) - 1; + size_t suffixColorLen = 0; + char * suffixBufTmp = suffixBuf + suffixLen; + size_t suffixBufTmpRemainLen = sizeof(suffixBuf) - suffixLen; + + if (p_format->colored_output == OUTPUT_COLOR_ON) { + suffixColorLen = snprintf(suffixBufTmp, suffixBufTmpRemainLen, "%c[%dm", 0x1B, 0); + if(suffixColorLen >= suffixBufTmpRemainLen) + suffixColorLen = suffixBufTmpRemainLen - 1; + } + + /* the following code is tragically unreadable */ size_t numLines; @@ -812,7 +867,7 @@ char *android_log_formatLogLine ( // this is an upper bound--newlines in message may be counted // extraneously - bufferSize = (numLines * (prefixLen + suffixLen)) + entry->messageLen + 1; + bufferSize = (numLines * (prefixColorLen + prefixLen + suffixLen + suffixColorLen)) + entry->messageLen + 1; if (defaultBufferSize >= bufferSize) { ret = defaultBuffer; @@ -831,11 +886,11 @@ char *android_log_formatLogLine ( if (prefixSuffixIsHeaderFooter) { strcat(p, prefixBuf); - p += prefixLen; + p += prefixColorLen + prefixLen; strncat(p, entry->message, entry->messageLen); p += entry->messageLen; strcat(p, suffixBuf); - p += suffixLen; + p += suffixLen + suffixColorLen; } else { while(pm < (entry->message + entry->messageLen)) { const char *lineStart; @@ -848,11 +903,11 @@ char *android_log_formatLogLine ( lineLen = pm - lineStart; strcat(p, prefixBuf); - p += prefixLen; + p += prefixColorLen + prefixLen; strncat(p, lineStart, lineLen); p += lineLen; strcat(p, suffixBuf); - p += suffixLen; + p += suffixLen + suffixColorLen; if (*pm == '\n') pm++; } diff --git a/libmincrypt/Android.mk b/libmincrypt/Android.mk index 79069862..796ce9d1 100644 --- a/libmincrypt/Android.mk +++ b/libmincrypt/Android.mk @@ -8,6 +8,13 @@ LOCAL_SRC_FILES := dsa_sig.c p256.c p256_ec.c p256_ecdsa.c rsa.c sha.c sha256.c LOCAL_CFLAGS := -Wall -Werror include $(BUILD_STATIC_LIBRARY) +## Crippled version without an RSA implementation +## to coexist with libcrypto_static and provide SHA_hash +include $(CLEAR_VARS) +LOCAL_MODULE := libminshacrypt +LOCAL_SRC_FILES := sha.c sha256.c +include $(BUILD_STATIC_LIBRARY) + include $(CLEAR_VARS) LOCAL_MODULE := libmincrypt LOCAL_SRC_FILES := dsa_sig.c p256.c p256_ec.c p256_ecdsa.c rsa.c sha.c sha256.c diff --git a/libnetutils/ifc_utils.c b/libnetutils/ifc_utils.c index 913f51e8..cb3722d8 100644 --- a/libnetutils/ifc_utils.c +++ b/libnetutils/ifc_utils.c @@ -598,23 +598,26 @@ int ifc_disable(const char *ifname) int ifc_reset_connections(const char *ifname, const int reset_mask) { #ifdef HAVE_ANDROID_OS - int result, success; + int result = 0, success; in_addr_t myaddr = 0; struct ifreq ifr; struct in6_ifreq ifr6; + int ctl_sock = -1; if (reset_mask & RESET_IPV4_ADDRESSES) { /* IPv4. Clear connections on the IP address. */ - ifc_init(); - if (!(reset_mask & RESET_IGNORE_INTERFACE_ADDRESS)) { - ifc_get_info(ifname, &myaddr, NULL, NULL); + ctl_sock = socket(AF_INET, SOCK_DGRAM, 0); + if (ctl_sock >= 0) { + if (!(reset_mask & RESET_IGNORE_INTERFACE_ADDRESS)) { + ifc_get_info(ifname, &myaddr, NULL, NULL); + } + ifc_init_ifr(ifname, &ifr); + init_sockaddr_in(&ifr.ifr_addr, myaddr); + result = ioctl(ctl_sock, SIOCKILLADDR, &ifr); + close(ctl_sock); + } else { + result = -1; } - ifc_init_ifr(ifname, &ifr); - init_sockaddr_in(&ifr.ifr_addr, myaddr); - result = ioctl(ifc_ctl_sock, SIOCKILLADDR, &ifr); - ifc_close(); - } else { - result = 0; } if (reset_mask & RESET_IPV6_ADDRESSES) { @@ -624,14 +627,18 @@ int ifc_reset_connections(const char *ifname, const int reset_mask) * So we clear all unused IPv6 connections on the device by specifying an * empty IPv6 address. */ - ifc_init6(); + ctl_sock = socket(AF_INET6, SOCK_DGRAM, 0); // This implicitly specifies an address of ::, i.e., kill all IPv6 sockets. memset(&ifr6, 0, sizeof(ifr6)); - success = ioctl(ifc_ctl_sock6, SIOCKILLADDR, &ifr6); - if (result == 0) { - result = success; + if (ctl_sock >= 0) { + success = ioctl(ctl_sock, SIOCKILLADDR, &ifr6); + if (result == 0) { + result = success; + } + close(ctl_sock); + } else { + result = -1; } - ifc_close6(); } return result; @@ -699,6 +706,8 @@ ifc_configure(const char *ifname, property_set(dns_prop_name, dns1 ? ipaddr_to_string(dns1) : ""); snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.dns2", ifname); property_set(dns_prop_name, dns2 ? ipaddr_to_string(dns2) : ""); + snprintf(dns_prop_name, sizeof(dns_prop_name), "net.%s.gw", ifname); + property_set(dns_prop_name, gateway ? ipaddr_to_string(gateway) : ""); return 0; } diff --git a/libsysutils/Android.mk b/libsysutils/Android.mk index 246f954c..3fdad320 100644 --- a/libsysutils/Android.mk +++ b/libsysutils/Android.mk @@ -2,9 +2,7 @@ ifneq ($(BUILD_TINY_ANDROID),true) LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ +common_src_files := \ src/SocketListener.cpp \ src/FrameworkListener.cpp \ src/NetlinkListener.cpp \ @@ -14,14 +12,18 @@ LOCAL_SRC_FILES:= \ src/ServiceManager.cpp \ EventLogTags.logtags -LOCAL_MODULE:= libsysutils - -LOCAL_C_INCLUDES := +include $(CLEAR_VARS) +LOCAL_SRC_FILES:= $(common_src_files) +LOCAL_MODULE:= libsysutils LOCAL_CFLAGS := -Werror - LOCAL_SHARED_LIBRARIES := libcutils liblog - include $(BUILD_SHARED_LIBRARY) +include $(CLEAR_VARS) +LOCAL_SRC_FILES:= $(common_src_files) +LOCAL_MODULE:= libsysutils +LOCAL_CFLAGS := -Werror +include $(BUILD_STATIC_LIBRARY) + endif diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp index 9d596ef5..bd381ee4 100644 --- a/libsysutils/src/NetlinkEvent.cpp +++ b/libsysutils/src/NetlinkEvent.cpp @@ -584,6 +584,10 @@ bool NetlinkEvent::parseAsciiNetlinkMessage(char *buffer, int size) { } s += strlen(s) + 1; } + if(findParam("ALERT_NAME") !=NULL ) { + mSubsystem = strdup("qlog"); + mAction = NlActionChange; + } return true; } @@ -597,12 +601,15 @@ bool NetlinkEvent::decode(char *buffer, int size, int format) { const char *NetlinkEvent::findParam(const char *paramName) { size_t len = strlen(paramName); + if (len == 0) { + return NULL; + } for (int i = 0; i < NL_PARAMS_MAX && mParams[i] != NULL; ++i) { const char *ptr = mParams[i] + len; if (!strncmp(mParams[i], paramName, len) && *ptr == '=') return ++ptr; } - SLOGE("NetlinkEvent::FindParam(): Parameter '%s' not found", paramName); + SLOGV("NetlinkEvent::FindParam(): Parameter '%s' not found", paramName); return NULL; } diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c index 684f4013..f625198d 100644 --- a/libusbhost/usbhost.c +++ b/libusbhost/usbhost.c @@ -37,6 +37,7 @@ #include #include +#include #include #include #include @@ -189,6 +190,7 @@ int usb_host_load(struct usb_host_context *context, { int done = 0; int i; + struct stat usbfsdir; context->cb_added = added_cb; context->cb_removed = removed_cb; @@ -197,17 +199,23 @@ int usb_host_load(struct usb_host_context *context, D("Created device discovery thread\n"); /* watch for files added and deleted within USB_FS_DIR */ + context->wdd = -1; context->wddbus = -1; for (i = 0; i < MAX_USBFS_WD_COUNT; i++) context->wds[i] = -1; - /* watch the root for new subdirectories */ - context->wdd = inotify_add_watch(context->fd, DEV_DIR, IN_CREATE | IN_DELETE); - if (context->wdd < 0) { - fprintf(stderr, "inotify_add_watch failed\n"); - if (discovery_done_cb) - discovery_done_cb(client_data); - return done; + /* watch the root for new subdirectories; skip if final USB_FS_DIR + path already exist + */ + if (stat(USB_FS_DIR, &usbfsdir) == -1) { + context->wdd = inotify_add_watch(context->fd, DEV_DIR, IN_CREATE | IN_DELETE); + if (context->wdd < 0) + goto failed; + } else { + /* Final USB_FS_DIR already exists; watch base bus dir in case of bus/usb removal */ + context->wddbus = inotify_add_watch(context->fd, DEV_BUS_DIR, IN_CREATE | IN_DELETE); + if (context->wddbus < 0) + goto failed; } watch_existing_subdirs(context, context->wds, MAX_USBFS_WD_COUNT); @@ -218,6 +226,12 @@ int usb_host_load(struct usb_host_context *context, done |= discovery_done_cb(client_data); return done; + +failed: + fprintf(stderr, "inotify_add_watch failed\n"); + if (discovery_done_cb) + discovery_done_cb(client_data); + return done; } /* usb_host_load() */ int usb_host_read_event(struct usb_host_context *context) diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp index 02907ad6..b0ca12e4 100644 --- a/libutils/RefBase.cpp +++ b/libutils/RefBase.cpp @@ -630,6 +630,13 @@ void RefBase::onLastWeakRef(const void* /*id*/) // --------------------------------------------------------------------------- +#ifdef REFBASE_JB_MR1_COMPAT_SYMBOLS +extern "C" void _ZN7android7RefBase14moveReferencesEPvPKvjRKNS_22ReferenceConverterBaseE(void* /*dst*/, void const* /*src*/, size_t /*n*/, + const ReferenceConverterBase& /*caster*/) +{ +} +#endif + #if DEBUG_REFS void RefBase::renameRefs(size_t n, const ReferenceRenamer& renamer) { for (size_t i=0 ; i -1) { + result = ioctl(s_fd, + ANDROID_ALARM_GET_TIME(ANDROID_ALARM_ELAPSED_REALTIME), &ts); + + if (result == 0) { + timestamp = seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec; + checkTimeStamps(timestamp, &prevTimestamp, &prevMethod, METHOD_IOCTL); + if (clock_method < 0) { + clock_method = METHOD_IOCTL; + pthread_mutex_unlock(&clock_lock); + } + return timestamp; + } + } } // /dev/alarm doesn't exist, fallback to CLOCK_BOOTTIME - result = clock_gettime(CLOCK_BOOTTIME, &ts); - if (result == 0) { - timestamp = seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec; - checkTimeStamps(timestamp, &prevTimestamp, &prevMethod, - METHOD_CLOCK_GETTIME); - return timestamp; + if (clock_method < 0 || clock_method == METHOD_CLOCK_GETTIME) { + result = clock_gettime(CLOCK_BOOTTIME, &ts); + if (result == 0) { + timestamp = seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec; + checkTimeStamps(timestamp, &prevTimestamp, &prevMethod, + METHOD_CLOCK_GETTIME); + if (clock_method < 0) { + clock_method = METHOD_CLOCK_GETTIME; + pthread_mutex_unlock(&clock_lock); + } + return timestamp; + } } // XXX: there was an error, probably because the driver didn't @@ -150,6 +171,10 @@ int64_t elapsedRealtimeNano() timestamp = systemTime(SYSTEM_TIME_MONOTONIC); checkTimeStamps(timestamp, &prevTimestamp, &prevMethod, METHOD_SYSTEMTIME); + if (clock_method < 0) { + clock_method = METHOD_SYSTEMTIME; + pthread_mutex_unlock(&clock_lock); + } return timestamp; #else return systemTime(SYSTEM_TIME_MONOTONIC); diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp index b09d5106..ab5f3c5f 100644 --- a/libutils/Threads.cpp +++ b/libutils/Threads.cpp @@ -98,6 +98,7 @@ struct thread_data_t { androidSetThreadName(name); free(name); } + return f(u); } }; @@ -339,7 +340,7 @@ int androidSetThreadPriority(pid_t tid, int pri) errno = lasterr; } #endif - + return rc; } @@ -727,7 +728,7 @@ status_t Thread::run(const char* name, int32_t priority, size_t stack) return UNKNOWN_ERROR; } - + // Do not refer to mStatus here: The thread is already running (may, in fact // already have exited with a valid mStatus result). The NO_ERROR indication // here merely indicates successfully starting the thread and does not diff --git a/libutils/VectorImpl.cpp b/libutils/VectorImpl.cpp index 30ca6635..8886f781 100644 --- a/libutils/VectorImpl.cpp +++ b/libutils/VectorImpl.cpp @@ -198,7 +198,10 @@ status_t VectorImpl::sort(VectorImpl::compar_r_t cmp, void* state) _do_copy(next, curr, 1); next = curr; --j; - curr = reinterpret_cast(array) + mItemSize*(j); + curr = NULL; + if (j >= 0) { + curr = reinterpret_cast(array) + mItemSize*(j); + } } while (j>=0 && (cmp(curr, temp, state) > 0)); _do_destroy(next, 1); @@ -516,6 +519,17 @@ void VectorImpl::_do_move_backward(void* dest, const void* from, size_t num) con do_move_backward(dest, from, num); } +#ifdef NEEDS_VECTORIMPL_SYMBOLS +void VectorImpl::reservedVectorImpl1() { } +void VectorImpl::reservedVectorImpl2() { } +void VectorImpl::reservedVectorImpl3() { } +void VectorImpl::reservedVectorImpl4() { } +void VectorImpl::reservedVectorImpl5() { } +void VectorImpl::reservedVectorImpl6() { } +void VectorImpl::reservedVectorImpl7() { } +void VectorImpl::reservedVectorImpl8() { } +#endif + /*****************************************************************************/ SortedVectorImpl::SortedVectorImpl(size_t itemSize, uint32_t flags) @@ -631,6 +645,17 @@ ssize_t SortedVectorImpl::remove(const void* item) return i; } +#ifdef NEEDS_VECTORIMPL_SYMBOLS +void SortedVectorImpl::reservedSortedVectorImpl1() { }; +void SortedVectorImpl::reservedSortedVectorImpl2() { }; +void SortedVectorImpl::reservedSortedVectorImpl3() { }; +void SortedVectorImpl::reservedSortedVectorImpl4() { }; +void SortedVectorImpl::reservedSortedVectorImpl5() { }; +void SortedVectorImpl::reservedSortedVectorImpl6() { }; +void SortedVectorImpl::reservedSortedVectorImpl7() { }; +void SortedVectorImpl::reservedSortedVectorImpl8() { }; +#endif + /*****************************************************************************/ }; // namespace android diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc index 87dac0e7..7ecab04a 100644 --- a/libziparchive/zip_archive.cc +++ b/libziparchive/zip_archive.cc @@ -1124,7 +1124,22 @@ int32_t ExtractEntryToFile(ZipArchiveHandle handle, return kIoError; } - int result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset)); + int result = 0; +#if defined(__linux__) + // Make sure we have enough space on the volume to extract the compressed + // entry. Note that the call to ftruncate below will change the file size but + // will not allocate space on disk. + if (declared_length > 0) { + result = TEMP_FAILURE_RETRY(fallocate(fd, 0, current_offset, declared_length)); + if (result == -1) { + ALOGW("Zip: unable to allocate space for file to %" PRId64 ": %s", + static_cast(declared_length + current_offset), strerror(errno)); + return kIoError; + } + } +#endif // defined(__linux__) + + result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset)); if (result == -1) { ALOGW("Zip: unable to truncate file to %" PRId64 ": %s", (int64_t)(declared_length + current_offset), strerror(errno)); diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp index 858e56c2..14e7ee3b 100644 --- a/logcat/logcat.cpp +++ b/logcat/logcat.cpp @@ -242,6 +242,7 @@ static void show_help(const char *cmd) " other pruning activity is oldest first. Special case ~!\n" " represents an automatic quicker pruning for the noisiest\n" " UID as determined by the current statistics.\n" + " -C colored output\n" " -P ' ...' set prune white and ~black list, using same format as\n" " printed above. Must be quoted.\n"); @@ -308,6 +309,11 @@ static const char *multiplier_of_size(unsigned long value) return multipliers[i]; } +static void setColoredOutput() +{ + android_log_setColoredOutput(g_logformat); +} + int main(int argc, char **argv) { int err; @@ -339,7 +345,7 @@ int main(int argc, char **argv) for (;;) { int ret; - ret = getopt(argc, argv, "cdt:T:gG:sQf:r:n:v:b:BSpP:"); + ret = getopt(argc, argv, "cdt:T:gG:sQf:r:n:v:b:BSpCP:"); if (ret < 0) { break; @@ -441,6 +447,10 @@ int main(int argc, char **argv) setPruneList = optarg; break; + case 'C': + setColoredOutput(); + break; + case 'b': { if (strcmp(optarg, "all") == 0) { while (devices) { diff --git a/logd/Android.mk b/logd/Android.mk index 188511f0..8bdaf186 100644 --- a/logd/Android.mk +++ b/logd/Android.mk @@ -27,6 +27,10 @@ LOCAL_SHARED_LIBRARIES := \ libutils LOCAL_CFLAGS := -Werror $(shell sed -n 's/^\([0-9]*\)[ \t]*auditd[ \t].*/-DAUDITD_LOG_TAG=\1/p' $(LOCAL_PATH)/event.logtags) +LOCAL_CFLAGS += -Os + +LOCAL_CONLYFLAGS += -std=gnu89 +LOCAL_CPPFLAGS += -std=gnu++03 include $(BUILD_EXECUTABLE) diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp index 8c1c3447..c9b979d6 100644 --- a/logd/LogBuffer.cpp +++ b/logd/LogBuffer.cpp @@ -444,7 +444,24 @@ log_time LogBuffer::flushTo( uid_t uid = reader->getUid(); pthread_mutex_lock(&mLogElementsLock); - for (it = mLogElements.begin(); it != mLogElements.end(); ++it) { + + if (start == LogTimeEntry::EPOCH) { + // client wants to start from the beginning + it = mLogElements.begin(); + } else { + // Client wants to start from some specified time. Chances are + // we are better off starting from the end of the time sorted list. + for (it = mLogElements.end(); it != mLogElements.begin(); /* do nothing */) { + --it; + LogBufferElement *element = *it; + if (element->getMonotonicTime() <= start) { + it++; + break; + } + } + } + + for (; it != mLogElements.end(); ++it) { LogBufferElement *element = *it; if (!privileged && (element->getUid() != uid)) { diff --git a/logd/libaudit.c b/logd/libaudit.c index d00d5795..cf76305d 100644 --- a/logd/libaudit.c +++ b/logd/libaudit.c @@ -177,7 +177,7 @@ int audit_setup(int fd, uint32_t pid) */ status.pid = pid; status.mask = AUDIT_STATUS_PID | AUDIT_STATUS_RATE_LIMIT; - status.rate_limit = 20; // audit entries per second + status.rate_limit = 5; // audit entries per second /* Let the kernel know this pid will be registering for audit events */ rc = audit_send(fd, AUDIT_SET, &status, sizeof(status)); diff --git a/mkbootimg/Android.mk b/mkbootimg/Android.mk index 0c9b0c65..dd42459c 100644 --- a/mkbootimg/Android.mk +++ b/mkbootimg/Android.mk @@ -10,4 +10,34 @@ LOCAL_MODULE := mkbootimg include $(BUILD_HOST_EXECUTABLE) +include $(CLEAR_VARS) +LOCAL_SRC_FILES := unpackbootimg.c +LOCAL_MODULE := unpackbootimg +include $(BUILD_HOST_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := mkbootimg.c +LOCAL_STATIC_LIBRARIES := libmincrypt libcutils libc +LOCAL_MODULE := utility_mkbootimg +LOCAL_MODULE_TAGS := eng +LOCAL_MODULE_STEM := mkbootimg +LOCAL_MODULE_CLASS := UTILITY_EXECUTABLES +LOCAL_UNSTRIPPED_PATH := $(PRODUCT_OUT)/symbols/utilities +LOCAL_MODULE_PATH := $(PRODUCT_OUT)/utilities +LOCAL_FORCE_STATIC_EXECUTABLE := true +include $(BUILD_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := unpackbootimg.c +LOCAL_STATIC_LIBRARIES := libcutils libc +LOCAL_MODULE := utility_unpackbootimg +LOCAL_MODULE_TAGS := eng +LOCAL_MODULE_STEM := unpackbootimg +LOCAL_MODULE_CLASS := UTILITY_EXECUTABLES +LOCAL_UNSTRIPPED_PATH := $(PRODUCT_OUT)/symbols/utilities +LOCAL_MODULE_PATH := $(PRODUCT_OUT)/utilities +LOCAL_FORCE_STATIC_EXECUTABLE := true +include $(BUILD_EXECUTABLE) + $(call dist-for-goals,dist_files,$(LOCAL_BUILT_MODULE)) + diff --git a/mkbootimg/bootimg.h b/mkbootimg/bootimg.h index 9171d85a..308c537d 100644 --- a/mkbootimg/bootimg.h +++ b/mkbootimg/bootimg.h @@ -41,8 +41,8 @@ struct boot_img_hdr unsigned tags_addr; /* physical addr for kernel tags */ unsigned page_size; /* flash page size we assume */ - unsigned unused[2]; /* future expansion: should be 0 */ - + unsigned dt_size; /* device tree in bytes */ + unsigned unused; /* future expansion: should be 0 */ unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */ unsigned char cmdline[BOOT_ARGS_SIZE]; @@ -64,10 +64,13 @@ struct boot_img_hdr ** +-----------------+ ** | second stage | o pages ** +-----------------+ +** | device tree | p pages +** +-----------------+ ** ** n = (kernel_size + page_size - 1) / page_size ** m = (ramdisk_size + page_size - 1) / page_size ** o = (second_size + page_size - 1) / page_size +** p = (dt_size + page_size - 1) / page_size ** ** 0. all entities are page_size aligned in flash ** 1. kernel and ramdisk are required (size != 0) diff --git a/mkbootimg/mkbootimg.c b/mkbootimg/mkbootimg.c index fc92b4dc..38b4b37f 100644 --- a/mkbootimg/mkbootimg.c +++ b/mkbootimg/mkbootimg.c @@ -65,6 +65,9 @@ int usage(void) " [ --board ]\n" " [ --base
]\n" " [ --pagesize ]\n" + " [ --dt ]\n" + " [ --ramdisk_offset
]\n" + " [ --tags_offset
]\n" " -o|--output \n" ); return 1; @@ -72,7 +75,7 @@ int usage(void) -static unsigned char padding[16384] = { 0, }; +static unsigned char padding[131072] = { 0, }; int write_padding(int fd, unsigned pagesize, unsigned itemsize) { @@ -105,6 +108,8 @@ int main(int argc, char **argv) char *cmdline = ""; char *bootimg = 0; char *board = ""; + char *dt_fn = 0; + void *dt_data = 0; unsigned pagesize = 2048; int fd; SHA_CTX ctx; @@ -154,10 +159,14 @@ int main(int argc, char **argv) } else if(!strcmp(arg,"--pagesize")) { pagesize = strtoul(val, 0, 10); if ((pagesize != 2048) && (pagesize != 4096) - && (pagesize != 8192) && (pagesize != 16384)) { + && (pagesize != 8192) && (pagesize != 16384) + && (pagesize != 32768) && (pagesize != 65536) + && (pagesize != 131072)) { fprintf(stderr,"error: unsupported page size %d\n", pagesize); return -1; } + } else if(!strcmp(arg, "--dt")) { + dt_fn = val; } else { return usage(); } @@ -232,6 +241,14 @@ int main(int argc, char **argv) } } + if(dt_fn) { + dt_data = load_file(dt_fn, &hdr.dt_size); + if (dt_data == 0) { + fprintf(stderr,"error: could not load device tree image '%s'\n", dt_fn); + return 1; + } + } + /* put a hash of the contents in the header so boot images can be * differentiated based on their first 2k. */ @@ -242,6 +259,10 @@ int main(int argc, char **argv) SHA_update(&ctx, &hdr.ramdisk_size, sizeof(hdr.ramdisk_size)); SHA_update(&ctx, second_data, hdr.second_size); SHA_update(&ctx, &hdr.second_size, sizeof(hdr.second_size)); + if(dt_data) { + SHA_update(&ctx, dt_data, hdr.dt_size); + SHA_update(&ctx, &hdr.dt_size, sizeof(hdr.dt_size)); + } sha = SHA_final(&ctx); memcpy(hdr.id, sha, SHA_DIGEST_SIZE > sizeof(hdr.id) ? sizeof(hdr.id) : SHA_DIGEST_SIZE); @@ -266,6 +287,10 @@ int main(int argc, char **argv) if(write_padding(fd, pagesize, hdr.second_size)) goto fail; } + if(dt_data) { + if(write(fd, dt_data, hdr.dt_size) != (ssize_t) hdr.dt_size) goto fail; + if(write_padding(fd, pagesize, hdr.dt_size)) goto fail; + } return 0; fail: diff --git a/mkbootimg/unpackbootimg.c b/mkbootimg/unpackbootimg.c new file mode 100644 index 00000000..3d2fda73 --- /dev/null +++ b/mkbootimg/unpackbootimg.c @@ -0,0 +1,211 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mincrypt/sha.h" +#include "bootimg.h" + +typedef unsigned char byte; + +int read_padding(FILE* f, unsigned itemsize, int pagesize) +{ + byte* buf = (byte*)malloc(sizeof(byte) * pagesize); + unsigned pagemask = pagesize - 1; + unsigned count; + + if((itemsize & pagemask) == 0) { + free(buf); + return 0; + } + + count = pagesize - (itemsize & pagemask); + + fread(buf, count, 1, f); + free(buf); + return count; +} + +void write_string_to_file(char* file, char* string) +{ + FILE* f = fopen(file, "w"); + fwrite(string, strlen(string), 1, f); + fwrite("\n", 1, 1, f); + fclose(f); +} + +int usage() { + printf("usage: unpackbootimg\n"); + printf("\t-i|--input boot.img\n"); + printf("\t[ -o|--output output_directory]\n"); + printf("\t[ -p|--pagesize ]\n"); + return 0; +} + +int main(int argc, char** argv) +{ + char tmp[PATH_MAX]; + char* directory = "./"; + char* filename = NULL; + int pagesize = 0; + + argc--; + argv++; + while(argc > 0){ + char *arg = argv[0]; + char *val = argv[1]; + argc -= 2; + argv += 2; + if(!strcmp(arg, "--input") || !strcmp(arg, "-i")) { + filename = val; + } else if(!strcmp(arg, "--output") || !strcmp(arg, "-o")) { + directory = val; + } else if(!strcmp(arg, "--pagesize") || !strcmp(arg, "-p")) { + pagesize = strtoul(val, 0, 16); + } else { + return usage(); + } + } + + if (filename == NULL) { + return usage(); + } + + int total_read = 0; + FILE* f = fopen(filename, "rb"); + boot_img_hdr header; + + //printf("Reading header...\n"); + int i; + for (i = 0; i <= 512; i++) { + fseek(f, i, SEEK_SET); + fread(tmp, BOOT_MAGIC_SIZE, 1, f); + if (memcmp(tmp, BOOT_MAGIC, BOOT_MAGIC_SIZE) == 0) + break; + } + total_read = i; + if (i > 512) { + printf("Android boot magic not found.\n"); + return 1; + } + fseek(f, i, SEEK_SET); + printf("Android magic found at: %d\n", i); + + fread(&header, sizeof(header), 1, f); + printf("BOARD_KERNEL_CMDLINE %s\n", header.cmdline); + printf("BOARD_KERNEL_BASE %08x\n", header.kernel_addr - 0x00008000); + printf("BOARD_RAMDISK_OFFSET %08x\n", header.ramdisk_addr - header.kernel_addr + 0x00008000); + printf("BOARD_SECOND_OFFSET %08x\n", header.second_addr - header.kernel_addr + 0x00008000); + printf("BOARD_TAGS_OFFSET %08x\n",header.tags_addr - header.kernel_addr + 0x00008000); + printf("BOARD_PAGE_SIZE %d\n", header.page_size); + printf("BOARD_SECOND_SIZE %d\n", header.second_size); + printf("BOARD_DT_SIZE %d\n", header.dt_size); + + if (pagesize == 0) { + pagesize = header.page_size; + } + + //printf("cmdline...\n"); + sprintf(tmp, "%s/%s", directory, basename(filename)); + strcat(tmp, "-cmdline"); + write_string_to_file(tmp, header.cmdline); + + //printf("base...\n"); + sprintf(tmp, "%s/%s", directory, basename(filename)); + strcat(tmp, "-base"); + char basetmp[200]; + sprintf(basetmp, "%08x", header.kernel_addr - 0x00008000); + write_string_to_file(tmp, basetmp); + + //printf("ramdisk_offset...\n"); + sprintf(tmp, "%s/%s", directory, basename(filename)); + strcat(tmp, "-ramdisk_offset"); + char ramdisktmp[200]; + sprintf(ramdisktmp, "%08x", header.ramdisk_addr - header.kernel_addr + 0x00008000); + write_string_to_file(tmp, ramdisktmp); + + //printf("second_offset...\n"); + sprintf(tmp, "%s/%s", directory, basename(filename)); + strcat(tmp, "-second_offset"); + char secondtmp[200]; + sprintf(secondtmp, "%08x", header.second_addr - header.kernel_addr + 0x00008000); + write_string_to_file(tmp, secondtmp); + + //printf("tags_offset...\n"); + sprintf(tmp, "%s/%s", directory, basename(filename)); + strcat(tmp, "-tags_offset"); + char tagstmp[200]; + sprintf(tagstmp, "%08x", header.tags_addr - header.kernel_addr + 0x00008000); + write_string_to_file(tmp, tagstmp); + + //printf("pagesize...\n"); + sprintf(tmp, "%s/%s", directory, basename(filename)); + strcat(tmp, "-pagesize"); + char pagesizetmp[200]; + sprintf(pagesizetmp, "%d", header.page_size); + write_string_to_file(tmp, pagesizetmp); + + total_read += sizeof(header); + //printf("total read: %d\n", total_read); + total_read += read_padding(f, sizeof(header), pagesize); + + sprintf(tmp, "%s/%s", directory, basename(filename)); + strcat(tmp, "-zImage"); + FILE *k = fopen(tmp, "wb"); + byte* kernel = (byte*)malloc(header.kernel_size); + //printf("Reading kernel...\n"); + fread(kernel, header.kernel_size, 1, f); + total_read += header.kernel_size; + fwrite(kernel, header.kernel_size, 1, k); + fclose(k); + + //printf("total read: %d\n", header.kernel_size); + total_read += read_padding(f, header.kernel_size, pagesize); + + + byte* ramdisk = (byte*)malloc(header.ramdisk_size); + //printf("Reading ramdisk...\n"); + fread(ramdisk, header.ramdisk_size, 1, f); + total_read += header.ramdisk_size; + sprintf(tmp, "%s/%s", directory, basename(filename)); + if(ramdisk[0] == 0x02 && ramdisk[1]== 0x21) + strcat(tmp, "-ramdisk.lz4"); + else + strcat(tmp, "-ramdisk.gz"); + FILE *r = fopen(tmp, "wb"); + fwrite(ramdisk, header.ramdisk_size, 1, r); + fclose(r); + + total_read += read_padding(f, header.ramdisk_size, pagesize); + + sprintf(tmp, "%s/%s", directory, basename(filename)); + strcat(tmp, "-second"); + FILE *s = fopen(tmp, "wb"); + byte* second = (byte*)malloc(header.second_size); + //printf("Reading second...\n"); + fread(second, header.second_size, 1, f); + total_read += header.second_size; + fwrite(second, header.second_size, 1, r); + fclose(s); + + total_read += read_padding(f, header.second_size, pagesize); + + sprintf(tmp, "%s/%s", directory, basename(filename)); + strcat(tmp, "-dt"); + FILE *d = fopen(tmp, "wb"); + byte* dt = (byte*)malloc(header.dt_size); + //printf("Reading dt...\n"); + fread(dt, header.dt_size, 1, f); + total_read += header.dt_size; + fwrite(dt, header.dt_size, 1, r); + fclose(d); + + fclose(f); + + //printf("Total Read: %d\n", total_read); + return 0; +} diff --git a/rootdir/Android.mk b/rootdir/Android.mk index 3ecb1db8..38f1b56e 100644 --- a/rootdir/Android.mk +++ b/rootdir/Android.mk @@ -30,16 +30,21 @@ LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \ include $(BUILD_SYSTEM)/base_rules.mk -# Regenerate init.environ.rc if PRODUCT_BOOTCLASSPATH has changed. -bcp_md5 := $(word 1, $(shell echo $(PRODUCT_BOOTCLASSPATH) $(PRODUCT_SYSTEM_SERVER_CLASSPATH) | $(MD5SUM))) +# Regenerate init.environ.rc if PRODUCT_BOOTCLASSPATH or TARGET_LDPRELOAD has changed. +bcp_md5 := $(word 1, $(shell echo $(PRODUCT_BOOTCLASSPATH) $(PRODUCT_SYSTEM_SERVER_CLASSPATH) $(TARGET_LDPRELOAD) | $(MD5SUM))) bcp_dep := $(intermediates)/$(bcp_md5).bcp.dep $(bcp_dep) : $(hide) mkdir -p $(dir $@) && rm -rf $(dir $@)*.bcp.dep && touch $@ +ifneq ($(strip $(TARGET_LDPRELOAD)),) + TARGET_LDPRELOAD_STR := :$(TARGET_LDPRELOAD) +endif + $(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/init.environ.rc.in $(bcp_dep) @echo "Generate: $< -> $@" @mkdir -p $(dir $@) - $(hide) sed -e 's?%BOOTCLASSPATH%?$(PRODUCT_BOOTCLASSPATH)?g' $< >$@ + $(hide) sed -e 's?%BOOTCLASSPATH%?$(PRODUCT_BOOTCLASSPATH)?g'\ + -e 's?%TARGET_LDPRELOAD%?$(TARGET_LDPRELOAD_STR)?g' $< >$@ $(hide) sed -i -e 's?%SYSTEMSERVERCLASSPATH%?$(PRODUCT_SYSTEM_SERVER_CLASSPATH)?g' $@ bcp_md5 := diff --git a/rootdir/init.environ.rc.in b/rootdir/init.environ.rc.in index 30bef463..c32337a6 100644 --- a/rootdir/init.environ.rc.in +++ b/rootdir/init.environ.rc.in @@ -10,3 +10,4 @@ on init export LOOP_MOUNTPOINT /mnt/obb export BOOTCLASSPATH %BOOTCLASSPATH% export SYSTEMSERVERCLASSPATH %SYSTEMSERVERCLASSPATH% + export LD_PRELOAD libsigchain.so%TARGET_LDPRELOAD% diff --git a/rootdir/init.rc b/rootdir/init.rc index cbcb8427..c4f0d505 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -9,6 +9,9 @@ import /init.usb.rc import /init.${ro.hardware}.rc import /init.${ro.zygote}.rc import /init.trace.rc +# Include RADIUM's extra init file +import /init.radium.rc + on early-init # Set init and its forked children's oom_adj. @@ -59,6 +62,7 @@ on init write /sys/fs/cgroup/memory/sw/memory.move_charge_at_immigrate 1 chown root system /sys/fs/cgroup/memory/sw/tasks chmod 0660 /sys/fs/cgroup/memory/sw/tasks + chmod 0220 /sys/fs/cgroup/memory/cgroup.event_control mkdir /system mkdir /data 0771 system system @@ -250,6 +254,7 @@ on post-fs-data # create basic filesystem structure mkdir /data/misc 01771 system misc mkdir /data/misc/adb 02750 system shell + mkdir /data/misc/audit 02750 audit system mkdir /data/misc/bluedroid 0770 bluetooth net_bt_stack mkdir /data/misc/bluetooth 0770 system system mkdir /data/misc/keystore 0700 keystore keystore @@ -281,6 +286,7 @@ on post-fs-data mkdir /data/app-lib 0771 system system mkdir /data/app 0771 system system mkdir /data/property 0700 root root + mkdir /data/tombstones 0771 system system # create dalvik-cache, so as to enforce our permissions mkdir /data/dalvik-cache 0771 root root @@ -315,6 +321,9 @@ on post-fs-data # Set SELinux security contexts on upgrade or policy update. restorecon_recursive /data + restorecon /data/data + restorecon /data/user + restorecon /data/user/0 # If there is no fs-post-data action in the init..rc file, you # must uncomment this line, otherwise encrypted filesystems @@ -391,6 +400,7 @@ on boot chown system system /sys/class/timed_output/vibrator/enable chown system system /sys/class/leds/keyboard-backlight/brightness chown system system /sys/class/leds/lcd-backlight/brightness + chown system system /sys/class/leds/torch-light/brightness chown system system /sys/class/leds/button-backlight/brightness chown system system /sys/class/leds/jogball-backlight/brightness chown system system /sys/class/leds/red/brightness @@ -492,6 +502,10 @@ service console /system/bin/sh group shell log seclabel u:r:shell:s0 +service auditd /system/bin/auditd -k + seclabel u:r:logd:s0 + class main + on property:ro.debuggable=1 start console @@ -545,7 +559,7 @@ service ril-daemon /system/bin/rild socket rild stream 660 root radio socket rild-debug stream 660 radio system user root - group radio cache inet misc audio log + group radio cache inet misc audio sdcard_rw qcom_diag log service surfaceflinger /system/bin/surfaceflinger class core @@ -561,7 +575,7 @@ service drm /system/bin/drmserver service media /system/bin/mediaserver class main user media - group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm + group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm qcom_diag ioprio rt 4 # One shot invocation to deal with encrypted volume. @@ -589,10 +603,15 @@ service installd /system/bin/installd class main socket installd stream 600 system system -service flash_recovery /system/bin/install-recovery.sh - class main - seclabel u:r:install_recovery:s0 - oneshot +#service flash_recovery /system/bin/install-recovery.sh +# class main +# seclabel u:r:install_recovery:s0 +# oneshot +# disabled + +# update recovery if enabled +#on property:persist.sys.recovery_update=true +# start flash_recovery service racoon /system/bin/racoon class main diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc index 474f6306..9b9bbcbf 100644 --- a/rootdir/ueventd.rc +++ b/rootdir/ueventd.rc @@ -17,9 +17,12 @@ subsystem adf # group, then they'll only see log entries for their UID. /dev/log/* 0666 root log -# the msm hw3d client device node is world writable/readable. +# the msm hw3d client device node is world writable/readable /dev/msm_hw3dc 0666 root root +# the DIAG device node is not world writable/readable. +/dev/diag 0660 system qcom_diag + # gpu driver for adreno200 is globally accessible /dev/kgsl 0666 root root @@ -27,7 +30,6 @@ subsystem adf /dev/dri/* 0666 root graphics # these should not be world writable -/dev/diag 0660 radio radio /dev/diag_arm9 0660 radio radio /dev/android_adb 0660 adb adb /dev/android_adb_enable 0660 adb adb @@ -35,9 +37,10 @@ subsystem adf /dev/uhid 0660 system net_bt_stack /dev/uinput 0660 system net_bt_stack /dev/alarm 0664 system radio +/dev/hidg* 0777 system system /dev/rtc0 0640 system system /dev/tty0 0660 root system -/dev/graphics/* 0660 root graphics +/dev/graphics/* 0660 system graphics /dev/msm_hw3dm 0660 system graphics /dev/input/* 0660 root input /dev/eac 0660 root audio @@ -94,3 +97,41 @@ subsystem adf /sys/devices/virtual/usb_composite/* enable 0664 root system /sys/devices/system/cpu/cpu* cpufreq/scaling_max_freq 0664 system system /sys/devices/system/cpu/cpu* cpufreq/scaling_min_freq 0664 system system +/sys/devices/system/cpu/cpu* cpufreq/scaling_governor 0664 system system + +/sys/devices/system/cpu/cpufreq ondemand/boostfreq 0664 system system +/sys/devices/system/cpu/cpufreq ondemand/boostpulse 0664 system system +/sys/devices/system/cpu/cpufreq ondemand/boosttime 0664 system system +/sys/devices/system/cpu/cpufreq ondemand/down_differential 0664 system system +/sys/devices/system/cpu/cpufreq ondemand/down_differential_multi_core 0664 system system +/sys/devices/system/cpu/cpufreq ondemand/ignore_nice_load 0664 system system +/sys/devices/system/cpu/cpufreq ondemand/input_boost 0664 system system +/sys/devices/system/cpu/cpufreq ondemand/io_is_busy 0664 system system +/sys/devices/system/cpu/cpufreq ondemand/optimal_freq 0664 system system +/sys/devices/system/cpu/cpufreq ondemand/powersave_bias 0664 system system +/sys/devices/system/cpu/cpufreq ondemand/sampling_down_factor 0664 system system +/sys/devices/system/cpu/cpufreq ondemand/sampling_rate 0664 system system +/sys/devices/system/cpu/cpufreq ondemand/sampling_rate_min 0664 system system +/sys/devices/system/cpu/cpufreq ondemand/sync_freq 0664 system system +/sys/devices/system/cpu/cpufreq ondemand/up_threshold 0664 system system +/sys/devices/system/cpu/cpufreq ondemand/up_threshold_any_cpu_load 0664 system system +/sys/devices/system/cpu/cpufreq ondemand/up_threshold_multi_core 0664 system system + +/sys/devices/system/cpu/cpufreq interactive/above_hispeed_delay 0664 system system +/sys/devices/system/cpu/cpufreq interactive/align_windows 0664 system system +/sys/devices/system/cpu/cpufreq interactive/boost 0664 system system +/sys/devices/system/cpu/cpufreq interactive/boostpulse 0664 system system +/sys/devices/system/cpu/cpufreq interactive/boostpulse_duration 0664 system system +/sys/devices/system/cpu/cpufreq interactive/go_hispeed_load 0664 system system +/sys/devices/system/cpu/cpufreq interactive/hispeed_freq 0664 system system +/sys/devices/system/cpu/cpufreq interactive/io_is_busy 0664 system system +/sys/devices/system/cpu/cpufreq interactive/max_freq_hysteresis 0664 system system +/sys/devices/system/cpu/cpufreq interactive/min_sample_rate 0664 system system +/sys/devices/system/cpu/cpufreq interactive/min_sample_time 0664 system system +/sys/devices/system/cpu/cpufreq interactive/sampling_down_factor 0664 system system +/sys/devices/system/cpu/cpufreq interactive/sync_freq 0664 system system +/sys/devices/system/cpu/cpufreq interactive/target_loads 0664 system system +/sys/devices/system/cpu/cpufreq interactive/timer_rate 0664 system system +/sys/devices/system/cpu/cpufreq interactive/timer_slack 0664 system system +/sys/devices/system/cpu/cpufreq interactive/up_threshold_any_cpu_freq 0664 system system +/sys/devices/system/cpu/cpufreq interactive/up_threshold_any_cpu_load 0664 system system diff --git a/sdcard/Android.mk b/sdcard/Android.mk index 63b0f414..0ea83cc9 100644 --- a/sdcard/Android.mk +++ b/sdcard/Android.mk @@ -1,11 +1,16 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) - LOCAL_SRC_FILES := sdcard.c -LOCAL_MODULE := sdcard +LOCAL_MODULE := libsdcard LOCAL_CFLAGS := -Wall -Wno-unused-parameter -Werror +LOCAL_MODULE_TAGS := optional +include $(BUILD_STATIC_LIBRARY) +include $(CLEAR_VARS) +LOCAL_SRC_FILES := main.c +LOCAL_MODULE := sdcard +LOCAL_CFLAGS := -Wall -Wno-unused-parameter -Werror +LOCAL_STATIC_LIBRARIES := libsdcard LOCAL_SHARED_LIBRARIES := libc libcutils - include $(BUILD_EXECUTABLE) diff --git a/adb/usb_vendors.h b/sdcard/main.c similarity index 74% rename from adb/usb_vendors.h rename to sdcard/main.c index cee23a15..ad2405bd 100644 --- a/adb/usb_vendors.h +++ b/sdcard/main.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 The Android Open Source Project + * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,12 +14,8 @@ * limitations under the License. */ -#ifndef __USB_VENDORS_H -#define __USB_VENDORS_H +extern int sdcard_main(int argc, char **argv); -extern int vendorIds[]; -extern unsigned vendorIdCount; - -void usb_vendors_init(void); - -#endif +int main(int argc, char **argv) { + return sdcard_main(argc, argv); +} diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c index 9cfb0408..586d4d12 100644 --- a/sdcard/sdcard.c +++ b/sdcard/sdcard.c @@ -198,6 +198,8 @@ struct node { * position. Used to support things like OBB. */ char* graft_path; size_t graft_pathlen; + + bool deleted; }; static int str_hash(void *key) { @@ -630,6 +632,8 @@ struct node *create_node_locked(struct fuse* fuse, node->ino = fuse->inode_ctr++; node->gen = fuse->next_generation++; + node->deleted = false; + derive_permissions_locked(fuse, parent, node); acquire_node_locked(node); add_node_to_parent_locked(node, parent); @@ -703,7 +707,7 @@ static struct node *lookup_child_by_name_locked(struct node *node, const char *n * must be considered distinct even if they refer to the same * underlying file as otherwise operations such as "mv x x" * will not work because the source and target nodes are the same. */ - if (!strcmp(name, node->name)) { + if (!strcmp(name, node->name) && !node->deleted) { return node; } } @@ -936,7 +940,9 @@ static int handle_setattr(struct fuse* fuse, struct fuse_handler* handler, if (!node) { return -ENOENT; } - if (!check_caller_access_to_node(fuse, hdr, node, W_OK, has_rw)) { + + if (!(req->valid & FATTR_FH) && + !check_caller_access_to_node(fuse, hdr, node, W_OK, has_rw)) { return -EACCES; } @@ -1067,6 +1073,7 @@ static int handle_unlink(struct fuse* fuse, struct fuse_handler* handler, { bool has_rw; struct node* parent_node; + struct node* child_node; char parent_path[PATH_MAX]; char child_path[PATH_MAX]; @@ -1088,6 +1095,12 @@ static int handle_unlink(struct fuse* fuse, struct fuse_handler* handler, if (unlink(child_path) < 0) { return -errno; } + pthread_mutex_lock(&fuse->lock); + child_node = lookup_child_by_name_locked(parent_node, name); + if (child_node) { + child_node->deleted = true; + } + pthread_mutex_unlock(&fuse->lock); return 0; } @@ -1095,6 +1108,7 @@ static int handle_rmdir(struct fuse* fuse, struct fuse_handler* handler, const struct fuse_in_header* hdr, const char* name) { bool has_rw; + struct node* child_node; struct node* parent_node; char parent_path[PATH_MAX]; char child_path[PATH_MAX]; @@ -1117,6 +1131,12 @@ static int handle_rmdir(struct fuse* fuse, struct fuse_handler* handler, if (rmdir(child_path) < 0) { return -errno; } + pthread_mutex_lock(&fuse->lock); + child_node = lookup_child_by_name_locked(parent_node, name); + if (child_node) { + child_node->deleted = true; + } + pthread_mutex_unlock(&fuse->lock); return 0; } @@ -1301,6 +1321,7 @@ static int handle_write(struct fuse* fuse, struct fuse_handler* handler, return -errno; } out.size = res; + out.padding = 0; fuse_reply(fuse, hdr->unique, &out, sizeof(out)); return NO_STATUS; } @@ -1840,7 +1861,8 @@ static int run(const char* source_path, const char* dest_path, uid_t uid, "fd=%i,rootmode=40000,default_permissions,allow_other,user_id=%d,group_id=%d", fd, uid, gid); - res = mount("/dev/fuse", dest_path, "fuse", MS_NOSUID | MS_NODEV | MS_NOEXEC, opts); + res = mount("/dev/fuse", dest_path, "fuse", MS_NOSUID | MS_NODEV | MS_NOEXEC | + MS_NOATIME, opts); if (res < 0) { ERROR("cannot mount fuse filesystem: %s\n", strerror(errno)); goto error; @@ -1877,7 +1899,7 @@ static int run(const char* source_path, const char* dest_path, uid_t uid, return res; } -int main(int argc, char **argv) +int sdcard_main(int argc, char **argv) { int res; const char *source_path = NULL; diff --git a/toolbox/Android.mk b/toolbox/Android.mk index 84714cf7..18726414 100644 --- a/toolbox/Android.mk +++ b/toolbox/Android.mk @@ -175,6 +175,7 @@ OUR_TOOLS := \ ps \ readlink \ renice \ + restart \ restorecon \ prlimit \ rmmod \ @@ -202,6 +203,8 @@ ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT))) OUR_TOOLS += r endif +OUR_TOOLS += setfattr + ALL_TOOLS = $(BSD_TOOLS) $(OUR_TOOLS) LOCAL_SRC_FILES := \ diff --git a/toolbox/chmod.c b/toolbox/chmod.c index 2a524e99..96d1fda4 100644 --- a/toolbox/chmod.c +++ b/toolbox/chmod.c @@ -9,16 +9,20 @@ #include #include +#include +#include -void recurse_chmod(char* path, int mode) +void recurse_chmod(char* path, int mode, unsigned int flag) { struct dirent *dp; DIR *dir = opendir(path); + int fd = 0; if (dir == NULL) { // not a directory, carry on return; } - char *subpath = malloc(sizeof(char)*PATH_MAX); + int maxpathlen = sizeof(char)*PATH_MAX; + char *subpath = malloc(maxpathlen); int pathlen = strlen(path); while ((dp = readdir(dir)) != NULL) { @@ -30,16 +34,23 @@ void recurse_chmod(char* path, int mode) exit(1); } - strcpy(subpath, path); - strcat(subpath, "/"); - strcat(subpath, dp->d_name); - - if (chmod(subpath, mode) < 0) { - fprintf(stderr, "Unable to chmod %s: %s\n", subpath, strerror(errno)); + strlcpy(subpath, path, maxpathlen); + strlcat(subpath, "/", maxpathlen); + strlcat(subpath, dp->d_name, maxpathlen); + + if(((fd = open(subpath, flag|O_RDONLY)) != -1) || ((fd = open(subpath, flag|O_WRONLY)) != -1)) { + if (fchmod(fd, mode) < 0){ + fprintf(stderr, "Unable to chmod %s: %s\n", subpath, strerror(errno)); + close(fd); + exit(1); + } + close(fd); + } else { + fprintf(stderr, "Unable to open %s: %s\n", subpath, strerror(errno)); exit(1); } - recurse_chmod(subpath, mode); + recurse_chmod(subpath, mode, flag); } free(subpath); closedir(dir); @@ -49,6 +60,7 @@ static int usage() { fprintf(stderr, "Usage: chmod [OPTION] \n"); fprintf(stderr, " -R, --recursive change files and directories recursively\n"); + fprintf(stderr, " -h, --no-dereference do not follow symlink\n"); fprintf(stderr, " --help display this help and exit\n"); return 10; @@ -57,15 +69,37 @@ static int usage() int chmod_main(int argc, char **argv) { int i; + int noFollow = 0; + int fd = 0; + int ch = 0; + int recursive = 0; + unsigned int flag =0; + int help = 0; + static struct option long_options[] = + { + {"help", no_argument, 0, 'H'}, + {"recursive", no_argument, 0, 'R'}, + {"no-dereference", no_argument, 0, 'h'} + }; + /* getopt_long stores the option index here. */ + int option_index = 0; + while((ch = getopt_long(argc, argv, "HhR",long_options,&option_index)) != -1) + switch(ch){ + case 'H': + help = 1; + break; + case 'R': + recursive = 1; + break; + case 'h': + noFollow = 1; + break; + default: + break; - if (argc < 3 || strcmp(argv[1], "--help") == 0) { - return usage(); } - int recursive = (strcmp(argv[1], "-R") == 0 || - strcmp(argv[1], "--recursive") == 0) ? 1 : 0; - - if (recursive && argc < 4) { + if (argc < 3 || help || (recursive && argc < 4)) { return usage(); } @@ -73,7 +107,15 @@ int chmod_main(int argc, char **argv) argc--; argv++; } + if (noFollow && argc < 4) { + return usage(); + } + if(noFollow) { + flag = O_NOFOLLOW; + argc--; + argv++; + } int mode = 0; const char* s = argv[1]; while (*s) { @@ -88,14 +130,20 @@ int chmod_main(int argc, char **argv) } for (i = 2; i < argc; i++) { - if (chmod(argv[i], mode) < 0) { - fprintf(stderr, "Unable to chmod %s: %s\n", argv[i], strerror(errno)); + if(((fd = open(argv[i], flag|O_RDONLY )) != -1)||((fd = open(argv[i], flag|O_WRONLY )) != -1)) { + if (fchmod(fd, mode) < 0){ + fprintf(stderr, "Unable to chmod %s: %s\n", argv[i], strerror(errno)); + close(fd); + return 10; + } + close(fd); + } else { + fprintf(stderr, "Unable to open %s: %s\n", argv[i], strerror(errno)); return 10; } if (recursive) { - recurse_chmod(argv[i], mode); + recurse_chmod(argv[i], mode, flag); } } return 0; } - diff --git a/toolbox/notify.c b/toolbox/notify.c index c983ed56..8ce346c5 100644 --- a/toolbox/notify.c +++ b/toolbox/notify.c @@ -101,14 +101,17 @@ int notify_main(int argc, char *argv[]) else if(verbose >= 1) printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : ""); if(print_files && (event->mask & IN_MODIFY)) { - char filename[512]; + char* filename = file_names[event->wd + id_offset]; + char* alloc_buf = NULL; ssize_t read_len; char *display_name; int buflen; - strcpy(filename, file_names[event->wd + id_offset]); if(event->len) { - strcat(filename, "/"); - strcat(filename, event->name); + if(asprintf(&alloc_buf, "%s/%s", filename, event->name) < 0) { + fprintf(stderr, "asprintf failed, %s\n", strerror(errno)); + return 1; + } + filename = alloc_buf; } ffd = open(filename, O_RDONLY); display_name = (verbose >= 2 || event->len == 0) ? filename : event->name; @@ -132,6 +135,7 @@ int notify_main(int argc, char *argv[]) printf("%s: %s", display_name, buf); } close(ffd); + free(alloc_buf); } if(event_count && --event_count == 0) return 0; diff --git a/toolbox/restart.c b/toolbox/restart.c new file mode 100644 index 00000000..9d803dea --- /dev/null +++ b/toolbox/restart.c @@ -0,0 +1,27 @@ +#include +#include +#include + +#include + +int restart_main(int argc, char *argv[]) +{ + char buf[1024]; + + if(argc > 1) { + property_set("ctl.stop", argv[1]); + property_set("ctl.start", argv[1]); + } else { + /* defaults to stopping and starting the common services */ + property_set("ctl.stop", "zygote_secondary"); + property_set("ctl.stop", "zygote"); + property_set("ctl.stop", "surfaceflinger"); + property_set("ctl.stop", "netd"); + property_set("ctl.start", "netd"); + property_set("ctl.start", "surfaceflinger"); + property_set("ctl.start", "zygote"); + property_set("ctl.start", "zygote_secondary"); + } + + return 0; +} diff --git a/toolbox/setfattr.c b/toolbox/setfattr.c new file mode 100644 index 00000000..b71ede8c --- /dev/null +++ b/toolbox/setfattr.c @@ -0,0 +1,66 @@ +#include +#include +#include +#include + +extern int setxattr(const char *, const char *, const void *, size_t, int); + +static int usage(const char *s) +{ + fprintf(stderr, "Usage: %s -n name -v value pathname\n", s); + fprintf(stderr, " -n name name of the extended attribute to set\n"); + fprintf(stderr, " -v value new value of the attribute\n"); + fprintf(stderr, " -h display this help and exit\n"); + + exit(10); +} + +int setfattr_main(int argc, char **argv) +{ + int i; + char *name = NULL; + char *valuestr = NULL; + unsigned long long value = 0; + size_t valuelen = 0; + + for (;;) { + int ret; + + ret = getopt(argc, argv, "hn:v:"); + + if (ret < 0) + break; + + switch(ret) { + case 'h': + usage(argv[0]); + break; + case 'n': + name = optarg; + break; + case 'v': + valuestr = optarg; + break; + } + } + + if (!name || !valuestr || optind == argc) + usage(argv[0]); + + /* + * We are being super lazy here, since setxattr can take an arbitrary + * amount of binary data. We assume that the value is numerical and + * not longer than 8 bytes. strtoull() detects the numeric base from + * the string prefix (0x for hexidecimal or 0 for octal). We also + * ignore endianness problems because it all works out fine on little + * endian. Hey, it's toolbox! + */ + value = strtoull(valuestr, NULL, 0); + while ((value >> (valuelen * 8))) + valuelen++; + + for (i = optind ; i < argc ; i++) + setxattr(argv[i], name, &value, valuelen, 0); + + return 0; +} diff --git a/toolbox/toolbox.c b/toolbox/toolbox.c index 0eac390e..915da440 100644 --- a/toolbox/toolbox.c +++ b/toolbox/toolbox.c @@ -1,6 +1,8 @@ +#include #include #include #include +#include int main(int, char **); @@ -31,11 +33,24 @@ static struct { 0, 0 }, }; +static void SIGPIPE_handler(int signal) { + // Those desktop Linux tools that catch SIGPIPE seem to agree that it's + // a successful way to exit, not a failure. (Which makes sense --- we were + // told to stop by a reader, rather than failing to continue ourselves.) + _exit(0); +} + int main(int argc, char **argv) { int i; char *name = argv[0]; + // Let's assume that none of this code handles broken pipes. At least ls, + // ps, and top were broken (though I'd previously added this fix locally + // to top). We exit rather than use SIG_IGN because tools like top will + // just keep on writing to nowhere forever if we don't stop them. + signal(SIGPIPE, SIGPIPE_handler); + if((argc > 1) && (argv[1][0] == '@')) { name = argv[1] + 1; argc--; diff --git a/toolbox/top.c b/toolbox/top.c index b1a275c1..1e99d4cc 100644 --- a/toolbox/top.c +++ b/toolbox/top.c @@ -109,15 +109,9 @@ static int proc_thr_cmp(const void *a, const void *b); static int numcmp(long long a, long long b); static void usage(char *cmd); -static void exit_top(int signal) { - exit(EXIT_FAILURE); -} - int top_main(int argc, char *argv[]) { num_used_procs = num_free_procs = 0; - signal(SIGPIPE, exit_top); - max_procs = 0; delay = 3; iterations = -1;