diff options
58 files changed, 2260 insertions, 1056 deletions
diff --git a/adb/commandline.c b/adb/commandline.c index e0345a8..5df5796 100644 --- a/adb/commandline.c +++ b/adb/commandline.c @@ -110,9 +110,10 @@ void help() " adb push [-p] <local> <remote>\n" " - copy file/dir to device\n" " ('-p' to display the transfer progress)\n" - " adb pull [-p] <remote> [<local>]\n" + " adb pull [-p] [-a] <remote> [<local>]\n" " - copy file/dir from device\n" " ('-p' to display the transfer progress)\n" + " ('-a' means copy timestamp and mode)\n" " adb sync [ <directory> ] - copy host->device only if changed\n" " (-l means list but don't copy)\n" " (see 'adb help all')\n" @@ -927,12 +928,19 @@ static const char *find_product_out_path(const char *hint) } -static void parse_push_pull_args(char** arg, int narg, char const** path1, char const** path2, - int* show_progress) { +static void parse_push_pull_args(char **arg, int narg, char const **path1, char const **path2, + int *show_progress, int *copy_attrs) { *show_progress = 0; + *copy_attrs = 0; - if ((narg > 0) && !strcmp(*arg, "-p")) { - *show_progress = 1; + while (narg > 0) { + if (!strcmp(*arg, "-p")) { + *show_progress = 1; + } else if (!strcmp(*arg, "-a")) { + *copy_attrs = 1; + } else { + break; + } ++arg; --narg; } @@ -1396,9 +1404,10 @@ top: if(!strcmp(argv[0], "push")) { int show_progress = 0; + int copy_attrs = 0; // unused const char* lpath = NULL, *rpath = NULL; - parse_push_pull_args(&argv[1], argc - 1, &lpath, &rpath, &show_progress); + parse_push_pull_args(&argv[1], argc - 1, &lpath, &rpath, &show_progress, ©_attrs); if ((lpath != NULL) && (rpath != NULL)) { return do_sync_push(lpath, rpath, 0 /* no verify APK */, show_progress); @@ -1409,12 +1418,13 @@ top: if(!strcmp(argv[0], "pull")) { int show_progress = 0; + int copy_attrs = 0; const char* rpath = NULL, *lpath = "."; - parse_push_pull_args(&argv[1], argc - 1, &rpath, &lpath, &show_progress); + parse_push_pull_args(&argv[1], argc - 1, &rpath, &lpath, &show_progress, ©_attrs); if (rpath != NULL) { - return do_sync_pull(rpath, lpath, show_progress); + return do_sync_pull(rpath, lpath, show_progress, copy_attrs); } return usage(); diff --git a/adb/file_sync_client.c b/adb/file_sync_client.c index 8fad50e..3da54c4 100644 --- a/adb/file_sync_client.c +++ b/adb/file_sync_client.c @@ -25,6 +25,7 @@ #include <limits.h> #include <sys/types.h> #include <zipfile/zipfile.h> +#include <utime.h> #include "sysdeps.h" #include "adb.h" @@ -139,7 +140,8 @@ struct syncsendbuf { static syncsendbuf send_buffer; -int sync_readtime(int fd, const char *path, unsigned *timestamp) +int sync_readtime(int fd, const char *path, unsigned int *timestamp, + unsigned int *mode) { syncmsg msg; int len = strlen(path); @@ -161,6 +163,7 @@ int sync_readtime(int fd, const char *path, unsigned *timestamp) } *timestamp = ltohl(msg.stat.time); + *mode = ltohl(msg.stat.mode); return 0; } @@ -237,7 +240,7 @@ static int write_data_file(int fd, const char *path, syncsendbuf *sbuf, int show if (show_progress) { // Determine local file size. struct stat st; - if (lstat(path, &st)) { + if (fstat(lfd, &st)) { fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno)); return -1; } @@ -931,8 +934,21 @@ static int remote_build_list(int syncfd, copyinfo **filelist, return 0; } +static int set_time_and_mode(const char *lpath, unsigned int time, unsigned int mode) +{ + struct utimbuf times = { time, time }; + int r1 = utime(lpath, ×); + + /* use umask for permissions */ + mode_t mask=umask(0000); + umask(mask); + int r2 = chmod(lpath, mode & ~mask); + + return r1 ? : r2; +} + static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath, - int checktimestamps) + int copy_attrs) { copyinfo *filelist = 0; copyinfo *ci, *next; @@ -962,26 +978,6 @@ static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath, return -1; } -#if 0 - if (checktimestamps) { - for (ci = filelist; ci != 0; ci = ci->next) { - if (sync_start_readtime(fd, ci->dst)) { - return 1; - } - } - for (ci = filelist; ci != 0; ci = ci->next) { - unsigned int timestamp, mode, size; - if (sync_finish_readtime(fd, ×tamp, &mode, &size)) - return 1; - if (size == ci->size) { - /* for links, we cannot update the atime/mtime */ - if ((S_ISREG(ci->mode & mode) && timestamp == ci->time) || - (S_ISLNK(ci->mode & mode) && timestamp >= ci->time)) - ci->flag = 1; - } - } - } -#endif for (ci = filelist; ci != 0; ci = next) { next = ci->next; if (ci->flag == 0) { @@ -989,6 +985,10 @@ static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath, if (sync_recv(fd, ci->src, ci->dst, 0 /* no show progress */)) { return 1; } + + if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) { + return 1; + } pulled++; } else { skipped++; @@ -1003,9 +1003,9 @@ static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath, return 0; } -int do_sync_pull(const char *rpath, const char *lpath, int show_progress) +int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int copy_attrs) { - unsigned mode; + unsigned mode, time; struct stat st; int fd; @@ -1016,7 +1016,7 @@ int do_sync_pull(const char *rpath, const char *lpath, int show_progress) return 1; } - if(sync_readmode(fd, rpath, &mode)) { + if(sync_readtime(fd, rpath, &time, &mode)) { return 1; } if(mode == 0) { @@ -1047,13 +1047,15 @@ int do_sync_pull(const char *rpath, const char *lpath, int show_progress) if (sync_recv(fd, rpath, lpath, show_progress)) { return 1; } else { + if (copy_attrs && set_time_and_mode(lpath, time, mode)) + return 1; END(); sync_quit(fd); return 0; } } else if(S_ISDIR(mode)) { BEGIN(); - if (copy_remote_dir_local(fd, rpath, lpath, 0)) { + if (copy_remote_dir_local(fd, rpath, lpath, copy_attrs)) { return 1; } else { END(); diff --git a/adb/file_sync_service.h b/adb/file_sync_service.h index 3e7e096..8ea239e 100644 --- a/adb/file_sync_service.h +++ b/adb/file_sync_service.h @@ -80,7 +80,7 @@ void file_sync_service(int fd, void *cookie); int do_sync_ls(const char *path); int do_sync_push(const char *lpath, const char *rpath, int verifyApk, int show_progress); int do_sync_sync(const char *lpath, const char *rpath, int listonly); -int do_sync_pull(const char *rpath, const char *lpath, int show_progress); +int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int pullTime); #define SYNC_DATA_MAX (64*1024) diff --git a/charger/Android.mk b/charger/Android.mk deleted file mode 100644 index 40c7d78..0000000 --- a/charger/Android.mk +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright 2011 The Android Open Source Project - -ifneq ($(BUILD_TINY_ANDROID),true) - -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - charger.c - -ifeq ($(strip $(BOARD_CHARGER_DISABLE_INIT_BLANK)),true) -LOCAL_CFLAGS := -DCHARGER_DISABLE_INIT_BLANK -endif - -ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true) -LOCAL_CFLAGS += -DCHARGER_ENABLE_SUSPEND -endif - -LOCAL_MODULE := charger -LOCAL_MODULE_TAGS := optional -LOCAL_FORCE_STATIC_EXECUTABLE := true -LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT) -LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED) - -LOCAL_C_INCLUDES := bootable/recovery - -LOCAL_STATIC_LIBRARIES := libminui libpng -ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true) -LOCAL_STATIC_LIBRARIES += libsuspend -endif -LOCAL_STATIC_LIBRARIES += libz libstdc++ libcutils liblog libm libc - -include $(BUILD_EXECUTABLE) - -define _add-charger-image -include $$(CLEAR_VARS) -LOCAL_MODULE := system_core_charger_$(notdir $(1)) -LOCAL_MODULE_STEM := $(notdir $(1)) -_img_modules += $$(LOCAL_MODULE) -LOCAL_SRC_FILES := $1 -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_CLASS := ETC -LOCAL_MODULE_PATH := $$(TARGET_ROOT_OUT)/res/images/charger -include $$(BUILD_PREBUILT) -endef - -_img_modules := -_images := -$(foreach _img, $(call find-subdir-subdir-files, "images", "*.png"), \ - $(eval $(call _add-charger-image,$(_img)))) - -include $(CLEAR_VARS) -LOCAL_MODULE := charger_res_images -LOCAL_MODULE_TAGS := optional -LOCAL_REQUIRED_MODULES := $(_img_modules) -include $(BUILD_PHONY_PACKAGE) - -_add-charger-image := -_img_modules := - -endif diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp index d0cefc7..749752b 100755 --- a/debuggerd/tombstone.cpp +++ b/debuggerd/tombstone.cpp @@ -458,14 +458,14 @@ static bool dump_sibling_thread_report( // Reads the contents of the specified log device, filters out the entries // that don't match the specified pid, and writes them to the tombstone file. // -// If "tail" is set, we only print the last few lines. -static void dump_log_file(log_t* log, pid_t pid, const char* filename, - unsigned int tail) { +// If "tail" is non-zero, log the last "tail" number of lines. +static void dump_log_file( + log_t* log, pid_t pid, const char* filename, unsigned int tail) { bool first = true; - struct logger_list *logger_list; + struct logger_list* logger_list; logger_list = android_logger_list_open( - android_name_to_log_id(filename), O_RDONLY | O_NONBLOCK, tail, pid); + android_name_to_log_id(filename), O_RDONLY | O_NONBLOCK, tail, pid); if (!logger_list) { XLOG("Unable to open %s: %s\n", filename, strerror(errno)); @@ -476,6 +476,7 @@ static void dump_log_file(log_t* log, pid_t pid, const char* filename, while (true) { ssize_t actual = android_logger_list_read(logger_list, &log_entry); + struct logger_entry* entry; if (actual < 0) { if (actual == -EINTR) { @@ -485,8 +486,7 @@ static void dump_log_file(log_t* log, pid_t pid, const char* filename, // non-blocking EOF; we're done break; } else { - _LOG(log, 0, "Error while reading log: %s\n", - strerror(-actual)); + _LOG(log, 0, "Error while reading log: %s\n", strerror(-actual)); break; } } else if (actual == 0) { @@ -499,16 +499,11 @@ static void dump_log_file(log_t* log, pid_t pid, const char* filename, // because you will be writing as fast as you're reading. Any // high-frequency debug diagnostics should just be written to // the tombstone file. - struct logger_entry* entry = &log_entry.entry_v1; - if (entry->pid != static_cast<int32_t>(pid)) { - // wrong pid, ignore - continue; - } + entry = &log_entry.entry_v1; if (first) { - _LOG(log, 0, "--------- %slog %s\n", - tail ? "tail end of " : "", filename); + _LOG(log, 0, "--------- %slog %s\n", tail ? "tail end of " : "", filename); first = false; } @@ -521,7 +516,7 @@ static void dump_log_file(log_t* log, pid_t pid, const char* filename, if (!hdr_size) { hdr_size = sizeof(log_entry.entry_v1); } - char* msg = (char *)log_entry.buf + hdr_size; + char* msg = reinterpret_cast<char*>(log_entry.buf) + hdr_size; unsigned char prio = msg[0]; char* tag = msg + 1; msg = tag + strlen(tag) + 1; @@ -529,7 +524,7 @@ static void dump_log_file(log_t* log, pid_t pid, const char* filename, // consume any trailing newlines char* nl = msg + strlen(msg) - 1; while (nl >= msg && *nl == '\n') { - *nl-- = '\0'; + *nl-- = '\0'; } char prioChar = (prio < strlen(kPrioChars) ? kPrioChars[prio] : '?'); @@ -553,7 +548,6 @@ static void dump_log_file(log_t* log, pid_t pid, const char* filename, _LOG(log, 0, "%s.%03d %5d %5d %c %-8s: %s\n", timeBuf, entry->nsec / 1000000, entry->pid, entry->tid, prioChar, tag, msg); - } while ((msg = nl)); } @@ -562,7 +556,7 @@ static void dump_log_file(log_t* log, pid_t pid, const char* filename, // Dumps the logs generated by the specified pid to the tombstone, from both // "system" and "main" log devices. Ideally we'd interleave the output. -static void dump_logs(log_t* log, pid_t pid, unsigned tail) { +static void dump_logs(log_t* log, pid_t pid, unsigned int tail) { dump_log_file(log, pid, "system", tail); dump_log_file(log, pid, "main", tail); } diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c index dcda005..ee3cbf9 100644 --- a/fs_mgr/fs_mgr.c +++ b/fs_mgr/fs_mgr.c @@ -208,16 +208,25 @@ static int fs_match(char *in1, char *in2) return ret; } +static int device_is_debuggable() { + int ret = -1; + char value[PROP_VALUE_MAX]; + ret = __system_property_get("ro.debuggable", value); + if (ret < 0) + return ret; + return strcmp(value, "1") ? 0 : 1; +} + int fs_mgr_mount_all(struct fstab *fstab) { int i = 0; - int encrypted = 0; - int ret = -1; + int encryptable = 0; + int error_count = 0; int mret; int mount_errno; if (!fstab) { - return ret; + return -1; } for (i = 0; i < fstab->num_entries; i++) { @@ -242,7 +251,8 @@ int fs_mgr_mount_all(struct fstab *fstab) fstab->recs[i].mount_point); } - if (fstab->recs[i].fs_mgr_flags & MF_VERIFY) { + if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && + !device_is_debuggable()) { if (fs_mgr_setup_verity(&fstab->recs[i]) < 0) { ERROR("Could not set up verified partition, skipping!"); continue; @@ -250,47 +260,62 @@ int fs_mgr_mount_all(struct fstab *fstab) } mret = __mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point, - fstab->recs[i].fs_type, fstab->recs[i].flags, - fstab->recs[i].fs_options); + fstab->recs[i].fs_type, fstab->recs[i].flags, + fstab->recs[i].fs_options); if (!mret) { + /* If this is encryptable, need to trigger encryption */ + if ((fstab->recs[i].fs_mgr_flags & MF_FORCECRYPT)) { + if (umount(fstab->recs[i].mount_point) == 0) { + if (!encryptable) { + encryptable = 2; + } else { + ERROR("Only one encryptable/encrypted partition supported"); + encryptable = 1; + } + } else { + INFO("Could not umount %s - allow continue unencrypted", + fstab->recs[i].mount_point); + continue; + } + } + /* Success! Go get the next one */ continue; } /* back up errno as partition_wipe clobbers the value */ mount_errno = errno; - - /* mount(2) returned an error, check if it's encrypted and deal with it */ - if ((fstab->recs[i].fs_mgr_flags & MF_CRYPT) && + /* mount(2) returned an error, check if it's encryptable and deal with it */ + if (mount_errno != EBUSY && mount_errno != EACCES && + (fstab->recs[i].fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT)) && !partition_wiped(fstab->recs[i].blk_device)) { /* Need to mount a tmpfs at this mountpoint for now, and set * properties that vold will query later for decrypting */ if (mount("tmpfs", fstab->recs[i].mount_point, "tmpfs", - MS_NOATIME | MS_NOSUID | MS_NODEV, CRYPTO_TMPFS_OPTIONS) < 0) { - ERROR("Cannot mount tmpfs filesystem for encrypted fs at %s error: %s\n", - fstab->recs[i].mount_point, strerror(errno)); - goto out; + MS_NOATIME | MS_NOSUID | MS_NODEV, CRYPTO_TMPFS_OPTIONS) < 0) { + ERROR("Cannot mount tmpfs filesystem for encryptable fs at %s error: %s\n", + fstab->recs[i].mount_point, strerror(errno)); + ++error_count; + continue; } - encrypted = 1; + encryptable = 1; } else { ERROR("Failed to mount an un-encryptable or wiped partition on" - "%s at %s options: %s error: %s\n", - fstab->recs[i].blk_device, fstab->recs[i].mount_point, - fstab->recs[i].fs_options, strerror(mount_errno)); - goto out; + "%s at %s options: %s error: %s\n", + fstab->recs[i].blk_device, fstab->recs[i].mount_point, + fstab->recs[i].fs_options, strerror(mount_errno)); + ++error_count; + continue; } } - if (encrypted) { - ret = 1; + if (error_count) { + return -1; } else { - ret = 0; + return encryptable; } - -out: - return ret; } /* If tmp_mount_point is non-null, mount the filesystem there. This is for the @@ -332,7 +357,8 @@ int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device, fstab->recs[i].mount_point); } - if (fstab->recs[i].fs_mgr_flags & MF_VERIFY) { + if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && + !device_is_debuggable()) { if (fs_mgr_setup_verity(&fstab->recs[i]) < 0) { ERROR("Could not set up verified partition, skipping!"); continue; @@ -504,7 +530,7 @@ int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc, char *real_blk_dev if (fstab->recs[i].fs_mgr_flags & MF_VOLDMANAGED) { continue; } - if (!(fstab->recs[i].fs_mgr_flags & MF_CRYPT)) { + if (!(fstab->recs[i].fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT))) { continue; } diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c index 45bbfdc..98a2af4 100644 --- a/fs_mgr/fs_mgr_fstab.c +++ b/fs_mgr/fs_mgr_fstab.c @@ -59,6 +59,7 @@ static struct flag_list fs_mgr_flags[] = { { "wait", MF_WAIT }, { "check", MF_CHECK }, { "encryptable=",MF_CRYPT }, + { "forceencrypt=",MF_FORCECRYPT }, { "nonremovable",MF_NONREMOVABLE }, { "voldmanaged=",MF_VOLDMANAGED}, { "length=", MF_LENGTH }, @@ -106,6 +107,11 @@ static int parse_flags(char *flags, struct flag_list *fl, * location of the keys. Get it and return it. */ flag_vals->key_loc = strdup(strchr(p, '=') + 1); + } else if ((fl[i].flag == MF_FORCECRYPT) && flag_vals) { + /* The forceencrypt flag is followed by an = and the + * location of the keys. Get it and return it. + */ + flag_vals->key_loc = strdup(strchr(p, '=') + 1); } else if ((fl[i].flag == MF_LENGTH) && flag_vals) { /* The length flag is followed by an = and the * size of the partition. Get it and return it. @@ -394,7 +400,7 @@ int fs_mgr_is_nonremovable(struct fstab_rec *fstab) int fs_mgr_is_encryptable(struct fstab_rec *fstab) { - return fstab->fs_mgr_flags & MF_CRYPT; + return fstab->fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT); } int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab) diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h index 59ffd78..6bb568a 100644 --- a/fs_mgr/fs_mgr_priv.h +++ b/fs_mgr/fs_mgr_priv.h @@ -72,6 +72,7 @@ #define MF_SWAPPRIO 0x80 #define MF_ZRAMSIZE 0x100 #define MF_VERIFY 0x200 +#define MF_FORCECRYPT 0x400 /* * There is no emulated sdcard daemon running on /data/media on this device, * so treat the physical SD card as the only external storage device, diff --git a/fs_mgr/fs_mgr_verity.c b/fs_mgr/fs_mgr_verity.c index 40bc2ec..aa3b1dd 100644 --- a/fs_mgr/fs_mgr_verity.c +++ b/fs_mgr/fs_mgr_verity.c @@ -30,6 +30,7 @@ #include <time.h> #include <private/android_filesystem_config.h> +#include <cutils/properties.h> #include <logwrap/logwrap.h> #include "mincrypt/rsa.h" @@ -335,6 +336,26 @@ static int test_access(char *device) { return -1; } +static int set_verified_property(char *name) { + int ret; + char *key; + ret = asprintf(&key, "partition.%s.verified", name); + if (ret < 0) { + ERROR("Error formatting verified property"); + return ret; + } + ret = PROP_NAME_MAX - strlen(key); + if (ret < 0) { + ERROR("Verified property name is too long"); + return -1; + } + ret = property_set(key, "1"); + if (ret < 0) + ERROR("Error setting verified property %s: %d", key, ret); + free(key); + return ret; +} + int fs_mgr_setup_verity(struct fstab_rec *fstab) { int retval = -1; @@ -351,6 +372,13 @@ int fs_mgr_setup_verity(struct fstab_rec *fstab) { io->flags |= 1; io->target_count = 1; + // check to ensure that the verity device is ext4 + // TODO: support non-ext4 filesystems + if (strcmp(fstab->fs_type, "ext4")) { + ERROR("Cannot verify non-ext4 device (%s)", fstab->fs_type); + return retval; + } + // get the device mapper fd int fd; if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) { @@ -403,7 +431,8 @@ int fs_mgr_setup_verity(struct fstab_rec *fstab) { goto out; } - retval = 0; + // set the property indicating that the partition is verified + retval = set_verified_property(mount_point); out: close(fd); diff --git a/healthd/Android.mk b/healthd/Android.mk index 473d375..715c2ed 100644 --- a/healthd/Android.mk +++ b/healthd/Android.mk @@ -13,6 +13,8 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := \ healthd.cpp \ + healthd_mode_android.cpp \ + healthd_mode_charger.cpp \ BatteryMonitor.cpp \ BatteryPropertiesRegistrar.cpp @@ -22,9 +24,57 @@ LOCAL_FORCE_STATIC_EXECUTABLE := true LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN) LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED) -LOCAL_STATIC_LIBRARIES := libbatteryservice libbinder libz libutils libstdc++ libcutils liblog libm libc +LOCAL_CFLAGS := -D__STDC_LIMIT_MACROS + +ifeq ($(strip $(BOARD_CHARGER_DISABLE_INIT_BLANK)),true) +LOCAL_CFLAGS += -DCHARGER_DISABLE_INIT_BLANK +endif + +ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true) +LOCAL_CFLAGS += -DCHARGER_ENABLE_SUSPEND +endif + +LOCAL_C_INCLUDES := bootable/recovery + +LOCAL_STATIC_LIBRARIES := libbatteryservice libbinder libminui libpng libz libutils libstdc++ libcutils liblog libm libc + +ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true) +LOCAL_STATIC_LIBRARIES += libsuspend +endif + 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 + include $(BUILD_EXECUTABLE) + +define _add-charger-image +include $$(CLEAR_VARS) +LOCAL_MODULE := system_core_charger_$(notdir $(1)) +LOCAL_MODULE_STEM := $(notdir $(1)) +_img_modules += $$(LOCAL_MODULE) +LOCAL_SRC_FILES := $1 +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $$(TARGET_ROOT_OUT)/res/images/charger +include $$(BUILD_PREBUILT) +endef + +_img_modules := +_images := +$(foreach _img, $(call find-subdir-subdir-files, "images", "*.png"), \ + $(eval $(call _add-charger-image,$(_img)))) + +include $(CLEAR_VARS) +LOCAL_MODULE := charger_res_images +LOCAL_MODULE_TAGS := optional +LOCAL_REQUIRED_MODULES := $(_img_modules) +include $(BUILD_PHONY_PACKAGE) + +_add-charger-image := +_img_modules := + endif diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp index 688c7ff..9368225 100644 --- a/healthd/BatteryMonitor.cpp +++ b/healthd/BatteryMonitor.cpp @@ -18,7 +18,6 @@ #include "healthd.h" #include "BatteryMonitor.h" -#include "BatteryPropertiesRegistrar.h" #include <dirent.h> #include <errno.h> @@ -28,6 +27,7 @@ #include <unistd.h> #include <batteryservice/BatteryService.h> #include <cutils/klog.h> +#include <utils/Errors.h> #include <utils/String8.h> #include <utils/Vector.h> @@ -170,7 +170,6 @@ int BatteryMonitor::getIntField(const String8& path) { } bool BatteryMonitor::update(void) { - struct BatteryProperties props; bool logthis; props.chargerAcOnline = false; @@ -178,23 +177,15 @@ bool BatteryMonitor::update(void) { props.chargerWirelessOnline = false; props.batteryStatus = BATTERY_STATUS_UNKNOWN; props.batteryHealth = BATTERY_HEALTH_UNKNOWN; - props.batteryCurrentNow = INT_MIN; - props.batteryChargeCounter = INT_MIN; if (!mHealthdConfig->batteryPresentPath.isEmpty()) props.batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath); else - props.batteryPresent = true; + props.batteryPresent = mBatteryDevicePresent; props.batteryLevel = getIntField(mHealthdConfig->batteryCapacityPath); props.batteryVoltage = getIntField(mHealthdConfig->batteryVoltagePath) / 1000; - if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) - props.batteryCurrentNow = getIntField(mHealthdConfig->batteryCurrentNowPath); - - if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) - props.batteryChargeCounter = getIntField(mHealthdConfig->batteryChargeCounterPath); - props.batteryTemperature = getIntField(mHealthdConfig->batteryTemperaturePath); const int SIZE = 128; @@ -244,7 +235,9 @@ bool BatteryMonitor::update(void) { if (logthis) { char dmesgline[256]; - snprintf(dmesgline, sizeof(dmesgline), + + if (props.batteryPresent) { + snprintf(dmesgline, sizeof(dmesgline), "battery l=%d v=%d t=%s%d.%d h=%d st=%d", props.batteryLevel, props.batteryVoltage, props.batteryTemperature < 0 ? "-" : "", @@ -252,11 +245,16 @@ bool BatteryMonitor::update(void) { abs(props.batteryTemperature % 10), props.batteryHealth, props.batteryStatus); - if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) { - char b[20]; + if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) { + int c = getIntField(mHealthdConfig->batteryCurrentNowPath); + char b[20]; - snprintf(b, sizeof(b), " c=%d", props.batteryCurrentNow / 1000); - strlcat(dmesgline, b, sizeof(dmesgline)); + snprintf(b, sizeof(b), " c=%d", c / 1000); + strlcat(dmesgline, b, sizeof(dmesgline)); + } + } else { + snprintf(dmesgline, sizeof(dmesgline), + "battery none"); } KLOG_INFO(LOG_TAG, "%s chg=%s%s%s\n", dmesgline, @@ -265,14 +263,101 @@ bool BatteryMonitor::update(void) { props.chargerWirelessOnline ? "w" : ""); } - if (mBatteryPropertiesRegistrar != NULL) - mBatteryPropertiesRegistrar->notifyListeners(props); - + healthd_mode_ops->battery_update(&props); return props.chargerAcOnline | props.chargerUsbOnline | props.chargerWirelessOnline; } -void BatteryMonitor::init(struct healthd_config *hc, bool nosvcmgr) { +status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) { + status_t ret = BAD_VALUE; + + switch(id) { + case BATTERY_PROP_CHARGE_COUNTER: + if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) { + val->valueInt = + getIntField(mHealthdConfig->batteryChargeCounterPath); + ret = NO_ERROR; + } else { + ret = NAME_NOT_FOUND; + } + break; + + case BATTERY_PROP_CURRENT_NOW: + if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) { + val->valueInt = + getIntField(mHealthdConfig->batteryCurrentNowPath); + ret = NO_ERROR; + } else { + ret = NAME_NOT_FOUND; + } + break; + + case BATTERY_PROP_CURRENT_AVG: + if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) { + val->valueInt = + getIntField(mHealthdConfig->batteryCurrentAvgPath); + ret = NO_ERROR; + } else { + ret = NAME_NOT_FOUND; + } + break; + + case BATTERY_PROP_CAPACITY: + if (!mHealthdConfig->batteryCapacityPath.isEmpty()) { + val->valueInt = + getIntField(mHealthdConfig->batteryCapacityPath); + ret = NO_ERROR; + } else { + ret = NAME_NOT_FOUND; + } + break; + + default: + break; + } + + if (ret != NO_ERROR) + val->valueInt = INT_MIN; + + return ret; +} + +void BatteryMonitor::dumpState(int fd) { + int v; + char vs[128]; + + snprintf(vs, sizeof(vs), "ac: %d usb: %d wireless: %d\n", + props.chargerAcOnline, props.chargerUsbOnline, + props.chargerWirelessOnline); + write(fd, vs, strlen(vs)); + snprintf(vs, sizeof(vs), "status: %d health: %d present: %d\n", + props.batteryStatus, props.batteryHealth, props.batteryPresent); + write(fd, vs, strlen(vs)); + snprintf(vs, sizeof(vs), "level: %d voltage: %d temp: %d\n", + props.batteryLevel, props.batteryVoltage, + props.batteryTemperature); + write(fd, vs, strlen(vs)); + + if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) { + v = getIntField(mHealthdConfig->batteryCurrentNowPath); + snprintf(vs, sizeof(vs), "current now: %d\n", v); + write(fd, vs, strlen(vs)); + } + + if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) { + v = getIntField(mHealthdConfig->batteryCurrentAvgPath); + snprintf(vs, sizeof(vs), "current avg: %d\n", v); + write(fd, vs, strlen(vs)); + } + + if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) { + v = getIntField(mHealthdConfig->batteryChargeCounterPath); + snprintf(vs, sizeof(vs), "charge counter: %d\n", v); + write(fd, vs, strlen(vs)); + } +} + +void BatteryMonitor::init(struct healthd_config *hc) { String8 path; mHealthdConfig = hc; @@ -303,6 +388,8 @@ void BatteryMonitor::init(struct healthd_config *hc, bool nosvcmgr) { break; case ANDROID_POWER_SUPPLY_TYPE_BATTERY: + mBatteryDevicePresent = true; + if (mHealthdConfig->batteryStatusPath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/status", POWER_SUPPLY_SYSFS_PATH, @@ -358,6 +445,14 @@ void BatteryMonitor::init(struct healthd_config *hc, bool nosvcmgr) { mHealthdConfig->batteryCurrentNowPath = path; } + if (mHealthdConfig->batteryCurrentAvgPath.isEmpty()) { + path.clear(); + path.appendFormat("%s/%s/current_avg", + POWER_SUPPLY_SYSFS_PATH, name); + if (access(path, R_OK) == 0) + mHealthdConfig->batteryCurrentAvgPath = path; + } + if (mHealthdConfig->batteryChargeCounterPath.isEmpty()) { path.clear(); path.appendFormat("%s/%s/charge_counter", @@ -400,24 +495,25 @@ void BatteryMonitor::init(struct healthd_config *hc, bool nosvcmgr) { if (!mChargerNames.size()) KLOG_ERROR(LOG_TAG, "No charger supplies found\n"); - if (mHealthdConfig->batteryStatusPath.isEmpty()) - KLOG_WARNING(LOG_TAG, "BatteryStatusPath not found\n"); - if (mHealthdConfig->batteryHealthPath.isEmpty()) - KLOG_WARNING(LOG_TAG, "BatteryHealthPath not found\n"); - if (mHealthdConfig->batteryPresentPath.isEmpty()) - KLOG_WARNING(LOG_TAG, "BatteryPresentPath not found\n"); - if (mHealthdConfig->batteryCapacityPath.isEmpty()) - KLOG_WARNING(LOG_TAG, "BatteryCapacityPath not found\n"); - if (mHealthdConfig->batteryVoltagePath.isEmpty()) - KLOG_WARNING(LOG_TAG, "BatteryVoltagePath not found\n"); - if (mHealthdConfig->batteryTemperaturePath.isEmpty()) - KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n"); - if (mHealthdConfig->batteryTechnologyPath.isEmpty()) - KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n"); - - if (nosvcmgr == false) { - mBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar(this); - mBatteryPropertiesRegistrar->publish(); + if (!mBatteryDevicePresent) { + KLOG_INFO(LOG_TAG, "No battery devices found\n"); + hc->periodic_chores_interval_fast = -1; + hc->periodic_chores_interval_slow = -1; + } else { + if (mHealthdConfig->batteryStatusPath.isEmpty()) + KLOG_WARNING(LOG_TAG, "BatteryStatusPath not found\n"); + if (mHealthdConfig->batteryHealthPath.isEmpty()) + KLOG_WARNING(LOG_TAG, "BatteryHealthPath not found\n"); + if (mHealthdConfig->batteryPresentPath.isEmpty()) + KLOG_WARNING(LOG_TAG, "BatteryPresentPath not found\n"); + if (mHealthdConfig->batteryCapacityPath.isEmpty()) + KLOG_WARNING(LOG_TAG, "BatteryCapacityPath not found\n"); + if (mHealthdConfig->batteryVoltagePath.isEmpty()) + KLOG_WARNING(LOG_TAG, "BatteryVoltagePath not found\n"); + if (mHealthdConfig->batteryTemperaturePath.isEmpty()) + KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n"); + if (mHealthdConfig->batteryTechnologyPath.isEmpty()) + KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n"); } } diff --git a/healthd/BatteryMonitor.h b/healthd/BatteryMonitor.h index ba291af..4866cc2 100644 --- a/healthd/BatteryMonitor.h +++ b/healthd/BatteryMonitor.h @@ -17,17 +17,15 @@ #ifndef HEALTHD_BATTERYMONITOR_H #define HEALTHD_BATTERYMONITOR_H +#include <batteryservice/BatteryService.h> #include <binder/IInterface.h> #include <utils/String8.h> #include <utils/Vector.h> #include "healthd.h" -#include "BatteryPropertiesRegistrar.h" namespace android { -class BatteryPropertiesRegistrar; - class BatteryMonitor { public: @@ -39,14 +37,16 @@ class BatteryMonitor { ANDROID_POWER_SUPPLY_TYPE_BATTERY }; - void init(struct healthd_config *hc, bool nosvcmgr); + void init(struct healthd_config *hc); bool update(void); + status_t getProperty(int id, struct BatteryProperty *val); + void dumpState(int fd); private: struct healthd_config *mHealthdConfig; Vector<String8> mChargerNames; - - sp<BatteryPropertiesRegistrar> mBatteryPropertiesRegistrar; + bool mBatteryDevicePresent; + struct BatteryProperties props; int getBatteryStatus(const char* status); int getBatteryHealth(const char* status); diff --git a/healthd/BatteryPropertiesRegistrar.cpp b/healthd/BatteryPropertiesRegistrar.cpp index 6a33ad8..272b6d7 100644 --- a/healthd/BatteryPropertiesRegistrar.cpp +++ b/healthd/BatteryPropertiesRegistrar.cpp @@ -18,19 +18,20 @@ #include <batteryservice/BatteryService.h> #include <batteryservice/IBatteryPropertiesListener.h> #include <batteryservice/IBatteryPropertiesRegistrar.h> +#include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> +#include <binder/PermissionCache.h> +#include <private/android_filesystem_config.h> #include <utils/Errors.h> #include <utils/Mutex.h> #include <utils/String16.h> -namespace android { +#include "healthd.h" -BatteryPropertiesRegistrar::BatteryPropertiesRegistrar(BatteryMonitor* monitor) { - mBatteryMonitor = monitor; -} +namespace android { void BatteryPropertiesRegistrar::publish() { - defaultServiceManager()->addService(String16("batterypropreg"), this); + defaultServiceManager()->addService(String16("batteryproperties"), this); } void BatteryPropertiesRegistrar::notifyListeners(struct BatteryProperties props) { @@ -42,6 +43,8 @@ void BatteryPropertiesRegistrar::notifyListeners(struct BatteryProperties props) void BatteryPropertiesRegistrar::registerListener(const sp<IBatteryPropertiesListener>& listener) { { + if (listener == NULL) + return; Mutex::Autolock _l(mRegistrationLock); // check whether this is a duplicate for (size_t i = 0; i < mListeners.size(); i++) { @@ -53,10 +56,12 @@ void BatteryPropertiesRegistrar::registerListener(const sp<IBatteryPropertiesLis mListeners.add(listener); listener->asBinder()->linkToDeath(this); } - mBatteryMonitor->update(); + healthd_battery_update(); } void BatteryPropertiesRegistrar::unregisterListener(const sp<IBatteryPropertiesListener>& listener) { + if (listener == NULL) + return; Mutex::Autolock _l(mRegistrationLock); for (size_t i = 0; i < mListeners.size(); i++) { if (mListeners[i]->asBinder() == listener->asBinder()) { @@ -67,6 +72,23 @@ void BatteryPropertiesRegistrar::unregisterListener(const sp<IBatteryPropertiesL } } +status_t BatteryPropertiesRegistrar::getProperty(int id, struct BatteryProperty *val) { + return healthd_get_property(id, val); +} + +status_t BatteryPropertiesRegistrar::dump(int fd, const Vector<String16>& args) { + IPCThreadState* self = IPCThreadState::self(); + const int pid = self->getCallingPid(); + const int uid = self->getCallingUid(); + if ((uid != AID_SHELL) && + !PermissionCache::checkPermission( + String16("android.permission.DUMP"), pid, uid)) + return PERMISSION_DENIED; + + healthd_dump_battery_state(fd); + return OK; +} + void BatteryPropertiesRegistrar::binderDied(const wp<IBinder>& who) { Mutex::Autolock _l(mRegistrationLock); diff --git a/healthd/BatteryPropertiesRegistrar.h b/healthd/BatteryPropertiesRegistrar.h index 793ddad..8853874 100644 --- a/healthd/BatteryPropertiesRegistrar.h +++ b/healthd/BatteryPropertiesRegistrar.h @@ -17,10 +17,9 @@ #ifndef HEALTHD_BATTERYPROPERTIES_REGISTRAR_H #define HEALTHD_BATTERYPROPERTIES_REGISTRAR_H -#include "BatteryMonitor.h" - #include <binder/IBinder.h> #include <utils/Mutex.h> +#include <utils/String16.h> #include <utils/Vector.h> #include <batteryservice/BatteryService.h> #include <batteryservice/IBatteryPropertiesListener.h> @@ -28,22 +27,20 @@ namespace android { -class BatteryMonitor; - class BatteryPropertiesRegistrar : public BnBatteryPropertiesRegistrar, public IBinder::DeathRecipient { public: - BatteryPropertiesRegistrar(BatteryMonitor* monitor); void publish(); void notifyListeners(struct BatteryProperties props); private: - BatteryMonitor* mBatteryMonitor; Mutex mRegistrationLock; Vector<sp<IBatteryPropertiesListener> > mListeners; void registerListener(const sp<IBatteryPropertiesListener>& listener); void unregisterListener(const sp<IBatteryPropertiesListener>& listener); + status_t getProperty(int id, struct BatteryProperty *val); + status_t dump(int fd, const Vector<String16>& args); void binderDied(const wp<IBinder>& who); }; diff --git a/healthd/healthd.cpp b/healthd/healthd.cpp index 9b84c3e..8363c41 100644 --- a/healthd/healthd.cpp +++ b/healthd/healthd.cpp @@ -21,16 +21,17 @@ #include "BatteryMonitor.h" #include <errno.h> +#include <libgen.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <unistd.h> #include <batteryservice/BatteryService.h> -#include <binder/IPCThreadState.h> -#include <binder/ProcessState.h> #include <cutils/klog.h> #include <cutils/uevent.h> #include <sys/epoll.h> #include <sys/timerfd.h> +#include <utils/Errors.h> using namespace android; @@ -49,13 +50,17 @@ static struct healthd_config healthd_config = { .batteryTemperaturePath = String8(String8::kEmptyString), .batteryTechnologyPath = String8(String8::kEmptyString), .batteryCurrentNowPath = String8(String8::kEmptyString), + .batteryCurrentAvgPath = String8(String8::kEmptyString), .batteryChargeCounterPath = String8(String8::kEmptyString), }; +static int eventct; +static int epollfd; + #define POWER_SUPPLY_SUBSYSTEM "power_supply" -// epoll events: uevent, wakealarm, binder -#define MAX_EPOLL_EVENTS 3 +// epoll_create() parameter is actually unused +#define MAX_EPOLL_EVENTS 40 static int uevent_fd; static int wakealarm_fd; static int binder_fd; @@ -67,7 +72,80 @@ static int wakealarm_wake_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST; static BatteryMonitor* gBatteryMonitor; -static bool nosvcmgr; +struct healthd_mode_ops *healthd_mode_ops; + +// Android mode + +extern void healthd_mode_android_init(struct healthd_config *config); +extern int healthd_mode_android_preparetowait(void); +extern void healthd_mode_android_battery_update( + struct android::BatteryProperties *props); + +// Charger mode + +extern void healthd_mode_charger_init(struct healthd_config *config); +extern int healthd_mode_charger_preparetowait(void); +extern void healthd_mode_charger_heartbeat(void); +extern void healthd_mode_charger_battery_update( + struct android::BatteryProperties *props); + +// NOPs for modes that need no special action + +static void healthd_mode_nop_init(struct healthd_config *config); +static int healthd_mode_nop_preparetowait(void); +static void healthd_mode_nop_heartbeat(void); +static void healthd_mode_nop_battery_update( + struct android::BatteryProperties *props); + +static struct healthd_mode_ops android_ops = { + .init = healthd_mode_android_init, + .preparetowait = healthd_mode_android_preparetowait, + .heartbeat = healthd_mode_nop_heartbeat, + .battery_update = healthd_mode_android_battery_update, +}; + +static struct healthd_mode_ops charger_ops = { + .init = healthd_mode_charger_init, + .preparetowait = healthd_mode_charger_preparetowait, + .heartbeat = healthd_mode_charger_heartbeat, + .battery_update = healthd_mode_charger_battery_update, +}; + +static struct healthd_mode_ops recovery_ops = { + .init = healthd_mode_nop_init, + .preparetowait = healthd_mode_nop_preparetowait, + .heartbeat = healthd_mode_nop_heartbeat, + .battery_update = healthd_mode_nop_battery_update, +}; + +static void healthd_mode_nop_init(struct healthd_config *config) { +} + +static int healthd_mode_nop_preparetowait(void) { + return -1; +} + +static void healthd_mode_nop_heartbeat(void) { +} + +static void healthd_mode_nop_battery_update( + struct android::BatteryProperties *props) { +} + +int healthd_register_event(int fd, void (*handler)(uint32_t)) { + struct epoll_event ev; + + ev.events = EPOLLIN | EPOLLWAKEUP; + ev.data.ptr = (void *)handler; + if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) { + KLOG_ERROR(LOG_TAG, + "epoll_ctl failed; errno=%d\n", errno); + return -1; + } + + eventct++; + return 0; +} static void wakealarm_set_interval(int interval) { struct itimerspec itval; @@ -89,7 +167,11 @@ static void wakealarm_set_interval(int interval) { KLOG_ERROR(LOG_TAG, "wakealarm_set_interval: timerfd_settime failed\n"); } -static void battery_update(void) { +status_t healthd_get_property(int id, struct BatteryProperty *val) { + return gBatteryMonitor->getProperty(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). @@ -113,21 +195,17 @@ static void battery_update(void) { -1 : healthd_config.periodic_chores_interval_fast * 1000; } -static void periodic_chores() { - battery_update(); +void healthd_dump_battery_state(int fd) { + gBatteryMonitor->dumpState(fd); + fsync(fd); } -static void uevent_init(void) { - uevent_fd = uevent_open_socket(64*1024, true); - - if (uevent_fd >= 0) - fcntl(uevent_fd, F_SETFL, O_NONBLOCK); - else - KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n"); +static void periodic_chores() { + healthd_battery_update(); } #define UEVENT_MSG_LEN 1024 -static void uevent_event(void) { +static void uevent_event(uint32_t epevents) { char msg[UEVENT_MSG_LEN+2]; char *cp; int n; @@ -144,7 +222,7 @@ static void uevent_event(void) { while (*cp) { if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) { - battery_update(); + healthd_battery_update(); break; } @@ -154,89 +232,56 @@ static void uevent_event(void) { } } -static void wakealarm_init(void) { - wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK); - if (wakealarm_fd == -1) { - KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n"); +static void uevent_init(void) { + uevent_fd = uevent_open_socket(64*1024, true); + + if (uevent_fd < 0) { + KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n"); return; } - wakealarm_set_interval(healthd_config.periodic_chores_interval_fast); + fcntl(uevent_fd, F_SETFL, O_NONBLOCK); + if (healthd_register_event(uevent_fd, uevent_event)) + KLOG_ERROR(LOG_TAG, + "register for uevent events failed\n"); } -static void wakealarm_event(void) { +static void wakealarm_event(uint32_t epevents) { unsigned long long wakeups; if (read(wakealarm_fd, &wakeups, sizeof(wakeups)) == -1) { - KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm_fd failed\n"); + KLOG_ERROR(LOG_TAG, "wakealarm_event: read wakealarm fd failed\n"); return; } periodic_chores(); } -static void binder_init(void) { - ProcessState::self()->setThreadPoolMaxThreadCount(0); - IPCThreadState::self()->disableBackgroundScheduling(true); - IPCThreadState::self()->setupPolling(&binder_fd); -} - -static void binder_event(void) { - IPCThreadState::self()->handlePolledCommands(); -} - -static void healthd_mainloop(void) { - struct epoll_event ev; - int epollfd; - int maxevents = 0; - - epollfd = epoll_create(MAX_EPOLL_EVENTS); - if (epollfd == -1) { - KLOG_ERROR(LOG_TAG, - "healthd_mainloop: epoll_create failed; errno=%d\n", - errno); +static void wakealarm_init(void) { + wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK); + if (wakealarm_fd == -1) { + KLOG_ERROR(LOG_TAG, "wakealarm_init: timerfd_create failed\n"); return; } - if (uevent_fd >= 0) { - ev.events = EPOLLIN | EPOLLWAKEUP; - ev.data.ptr = (void *)uevent_event; - if (epoll_ctl(epollfd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1) - KLOG_ERROR(LOG_TAG, - "healthd_mainloop: epoll_ctl for uevent_fd failed; errno=%d\n", - errno); - else - maxevents++; - } + if (healthd_register_event(wakealarm_fd, wakealarm_event)) + KLOG_ERROR(LOG_TAG, + "Registration of wakealarm event failed\n"); - if (wakealarm_fd >= 0) { - ev.events = EPOLLIN | EPOLLWAKEUP; - ev.data.ptr = (void *)wakealarm_event; - if (epoll_ctl(epollfd, EPOLL_CTL_ADD, wakealarm_fd, &ev) == -1) - KLOG_ERROR(LOG_TAG, - "healthd_mainloop: epoll_ctl for wakealarm_fd failed; errno=%d\n", - errno); - else - maxevents++; - } - - if (binder_fd >= 0) { - ev.events = EPOLLIN | EPOLLWAKEUP; - ev.data.ptr= (void *)binder_event; - if (epoll_ctl(epollfd, EPOLL_CTL_ADD, binder_fd, &ev) == -1) - KLOG_ERROR(LOG_TAG, - "healthd_mainloop: epoll_ctl for binder_fd failed; errno=%d\n", - errno); - else - maxevents++; - } + wakealarm_set_interval(healthd_config.periodic_chores_interval_fast); +} +static void healthd_mainloop(void) { while (1) { - struct epoll_event events[maxevents]; + struct epoll_event events[eventct]; int nevents; + int timeout = awake_poll_interval; + int mode_timeout; - IPCThreadState::self()->flushCommands(); - nevents = epoll_wait(epollfd, events, maxevents, awake_poll_interval); + mode_timeout = healthd_mode_ops->preparetowait(); + if (timeout < 0 || (mode_timeout > 0 && mode_timeout < timeout)) + timeout = mode_timeout; + nevents = epoll_wait(epollfd, events, eventct, timeout); if (nevents == -1) { if (errno == EINTR) @@ -247,39 +292,70 @@ static void healthd_mainloop(void) { for (int n = 0; n < nevents; ++n) { if (events[n].data.ptr) - (*(void (*)())events[n].data.ptr)(); + (*(void (*)(int))events[n].data.ptr)(events[n].events); } if (!nevents) periodic_chores(); + + healthd_mode_ops->heartbeat(); } return; } +static int healthd_init() { + epollfd = epoll_create(MAX_EPOLL_EVENTS); + if (epollfd == -1) { + KLOG_ERROR(LOG_TAG, + "epoll_create failed; errno=%d\n", + errno); + return -1; + } + + healthd_mode_ops->init(&healthd_config); + healthd_board_init(&healthd_config); + wakealarm_init(); + uevent_init(); + gBatteryMonitor = new BatteryMonitor(); + gBatteryMonitor->init(&healthd_config); + return 0; +} + int main(int argc, char **argv) { int ch; + int ret; klog_set_level(KLOG_LEVEL); - - while ((ch = getopt(argc, argv, "n")) != -1) { - switch (ch) { - case 'n': - nosvcmgr = true; - break; - case '?': - default: - KLOG_WARNING(LOG_TAG, "Unrecognized healthd option: %c\n", ch); + healthd_mode_ops = &android_ops; + + if (!strcmp(basename(argv[0]), "charger")) { + healthd_mode_ops = &charger_ops; + } else { + while ((ch = getopt(argc, argv, "cr")) != -1) { + switch (ch) { + case 'c': + healthd_mode_ops = &charger_ops; + break; + case 'r': + healthd_mode_ops = &recovery_ops; + break; + case '?': + default: + KLOG_ERROR(LOG_TAG, "Unrecognized healthd option: %c\n", + optopt); + exit(1); + } } } - healthd_board_init(&healthd_config); - wakealarm_init(); - uevent_init(); - binder_init(); - gBatteryMonitor = new BatteryMonitor(); - gBatteryMonitor->init(&healthd_config, nosvcmgr); + ret = healthd_init(); + if (ret) { + KLOG_ERROR("Initialization failed, exiting\n"); + exit(2); + } healthd_mainloop(); - return 0; + KLOG_ERROR("Main loop terminated, exiting\n"); + return 3; } diff --git a/healthd/healthd.h b/healthd/healthd.h index 5374fb1..23a54bf 100644 --- a/healthd/healthd.h +++ b/healthd/healthd.h @@ -18,6 +18,7 @@ #define _HEALTHD_H_ #include <batteryservice/BatteryService.h> +#include <utils/Errors.h> #include <utils/String8.h> // periodic_chores_interval_fast, periodic_chores_interval_slow: intervals at @@ -61,9 +62,35 @@ struct healthd_config { android::String8 batteryTemperaturePath; android::String8 batteryTechnologyPath; android::String8 batteryCurrentNowPath; + android::String8 batteryCurrentAvgPath; android::String8 batteryChargeCounterPath; }; +// Global helper functions + +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); +void healthd_dump_battery_state(int fd); + +struct healthd_mode_ops { + void (*init)(struct healthd_config *config); + int (*preparetowait)(void); + void (*heartbeat)(void); + void (*battery_update)(struct android::BatteryProperties *props); +}; + +extern struct healthd_mode_ops *healthd_mode_ops; + +// Charger mode + +void healthd_mode_charger_init(struct healthd_config *config); +int healthd_mode_charger_preparetowait(void); +void healthd_mode_charger_heartbeat(void); +void healthd_mode_charger_battery_update( + struct android::BatteryProperties *props); + // The following are implemented in libhealthd_board to handle board-specific // behavior. // diff --git a/healthd/healthd_mode_android.cpp b/healthd/healthd_mode_android.cpp new file mode 100644 index 0000000..4887c8c --- /dev/null +++ b/healthd/healthd_mode_android.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "healthd-android" + +#include "healthd.h" +#include "BatteryPropertiesRegistrar.h" + +#include <binder/IPCThreadState.h> +#include <binder/ProcessState.h> +#include <cutils/klog.h> +#include <sys/epoll.h> + +using namespace android; + +static int gBinderFd; +static sp<BatteryPropertiesRegistrar> gBatteryPropertiesRegistrar; + +void healthd_mode_android_battery_update( + struct android::BatteryProperties *props) { + if (gBatteryPropertiesRegistrar != NULL) + gBatteryPropertiesRegistrar->notifyListeners(*props); + + return; +} + +int healthd_mode_android_preparetowait(void) { + IPCThreadState::self()->flushCommands(); + return -1; +} + +static void binder_event(uint32_t epevents) { + IPCThreadState::self()->handlePolledCommands(); +} + +void healthd_mode_android_init(struct healthd_config *config) { + ProcessState::self()->setThreadPoolMaxThreadCount(0); + IPCThreadState::self()->disableBackgroundScheduling(true); + IPCThreadState::self()->setupPolling(&gBinderFd); + + if (gBinderFd >= 0) { + if (healthd_register_event(gBinderFd, binder_event)) + KLOG_ERROR(LOG_TAG, + "Register for binder events failed\n"); + } + + gBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar(); + gBatteryPropertiesRegistrar->publish(); +} diff --git a/charger/charger.c b/healthd/healthd_mode_charger.cpp index e3cadb1..710f5b6 100644 --- a/charger/charger.c +++ b/healthd/healthd_mode_charger.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Android Open Source Project + * Copyright (C) 2011-2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,9 +14,6 @@ * limitations under the License. */ -//#define DEBUG_UEVENTS -#define CHARGER_KLOG_LEVEL 6 - #include <dirent.h> #include <errno.h> #include <fcntl.h> @@ -25,7 +22,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sys/poll.h> +#include <sys/epoll.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/un.h> @@ -35,11 +32,10 @@ #include <sys/socket.h> #include <linux/netlink.h> +#include <batteryservice/BatteryService.h> #include <cutils/android_reboot.h> #include <cutils/klog.h> -#include <cutils/list.h> #include <cutils/misc.h> -#include <cutils/uevent.h> #ifdef CHARGER_ENABLE_SUSPEND #include <suspend/autosuspend.h> @@ -47,6 +43,8 @@ #include "minui/minui.h" +#include "healthd.h" + char *locale; #ifndef max @@ -69,6 +67,7 @@ char *locale; #define BATTERY_FULL_THRESH 95 #define LAST_KMSG_PATH "/proc/last_kmsg" +#define LAST_KMSG_PSTORE_PATH "/sys/fs/pstore/console-ramoops" #define LAST_KMSG_MAX_SZ (32 * 1024) #define LOGE(x...) do { KLOG_ERROR("charger", x); } while (0) @@ -81,15 +80,6 @@ struct key_state { int64_t timestamp; }; -struct power_supply { - struct listnode list; - char name[256]; - char type[32]; - bool online; - bool valid; - char cap_path[PATH_MAX]; -}; - struct frame { int disp_time; int min_capacity; @@ -113,69 +103,69 @@ struct animation { }; struct charger { + bool have_battery_state; + bool charger_connected; + int capacity; int64_t next_screen_transition; int64_t next_key_check; int64_t next_pwr_check; struct key_state keys[KEY_MAX + 1]; - int uevent_fd; - - struct listnode supplies; - int num_supplies; - int num_supplies_online; struct animation *batt_anim; gr_surface surf_unknown; - - struct power_supply *battery; -}; - -struct uevent { - const char *action; - const char *path; - const char *subsystem; - const char *ps_name; - const char *ps_type; - const char *ps_online; }; static struct frame batt_anim_frames[] = { { .disp_time = 750, .min_capacity = 0, + .level_only = false, + .surface = NULL, }, { .disp_time = 750, .min_capacity = 20, + .level_only = false, + .surface = NULL, }, { .disp_time = 750, .min_capacity = 40, + .level_only = false, + .surface = NULL, }, { .disp_time = 750, .min_capacity = 60, + .level_only = false, + .surface = NULL, }, { .disp_time = 750, .min_capacity = 80, .level_only = true, + .surface = NULL, }, { .disp_time = 750, .min_capacity = BATTERY_FULL_THRESH, + .level_only = false, + .surface = NULL, }, }; static struct animation battery_animation = { + .run = false, .frames = batt_anim_frames, + .cur_frame = 0, .num_frames = ARRAY_SIZE(batt_anim_frames), + .cur_cycle = 0, .num_cycles = 3, + .capacity = 0, }; -static struct charger charger_state = { - .batt_anim = &battery_animation, -}; +static struct charger charger_state; static int char_width; static int char_height; @@ -206,10 +196,14 @@ static void dump_last_kmsg(void) LOGI("\n"); LOGI("*************** LAST KMSG ***************\n"); LOGI("\n"); - buf = load_file(LAST_KMSG_PATH, &sz); + buf = (char *)load_file(LAST_KMSG_PSTORE_PATH, &sz); + if (!buf || !sz) { - LOGI("last_kmsg not found. Cold reset?\n"); - goto out; + buf = (char *)load_file(LAST_KMSG_PATH, &sz); + if (!buf || !sz) { + LOGI("last_kmsg not found. Cold reset?\n"); + goto out; + } } len = min(sz, LAST_KMSG_MAX_SZ); @@ -220,7 +214,7 @@ static void dump_last_kmsg(void) char yoink; char *nl; - nl = memrchr(ptr, '\n', cnt - 1); + nl = (char *)memrchr(ptr, '\n', cnt - 1); if (nl) cnt = nl - ptr + 1; @@ -241,114 +235,9 @@ out: LOGI("\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) +static int get_battery_capacity() { - 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; -} - -static int get_battery_capacity(struct charger *charger) -{ - int ret; - int batt_cap = -1; - - if (!charger->battery) - return -1; - - ret = read_file_int(charger->battery->cap_path, &batt_cap); - if (ret < 0 || batt_cap > 100) { - batt_cap = -1; - } - - return batt_cap; -} - -static struct power_supply *find_supply(struct charger *charger, - const char *name) -{ - struct listnode *node; - struct power_supply *supply; - - list_for_each(node, &charger->supplies) { - supply = node_to_item(node, struct power_supply, list); - if (!strncmp(name, supply->name, sizeof(supply->name))) - return supply; - } - return NULL; -} - -static struct power_supply *add_supply(struct charger *charger, - const char *name, const char *type, - const char *path, bool online) -{ - struct power_supply *supply; - - supply = calloc(1, sizeof(struct power_supply)); - if (!supply) - return NULL; - - strlcpy(supply->name, name, sizeof(supply->name)); - strlcpy(supply->type, type, sizeof(supply->type)); - snprintf(supply->cap_path, sizeof(supply->cap_path), - "/sys/%s/capacity", path); - supply->online = online; - list_add_tail(&charger->supplies, &supply->list); - charger->num_supplies++; - LOGV("... added %s %s %d\n", supply->name, supply->type, online); - return supply; -} - -static void remove_supply(struct charger *charger, struct power_supply *supply) -{ - if (!supply) - return; - list_remove(&supply->list); - charger->num_supplies--; - free(supply); + return charger_state.capacity; } #ifdef CHARGER_ENABLE_SUSPEND @@ -366,237 +255,6 @@ static int request_suspend(bool enable) } #endif -static void parse_uevent(const char *msg, struct uevent *uevent) -{ - uevent->action = ""; - uevent->path = ""; - uevent->subsystem = ""; - uevent->ps_name = ""; - uevent->ps_online = ""; - uevent->ps_type = ""; - - /* currently ignoring SEQNUM */ - while (*msg) { -#ifdef DEBUG_UEVENTS - LOGV("uevent str: %s\n", msg); -#endif - if (!strncmp(msg, "ACTION=", 7)) { - msg += 7; - uevent->action = msg; - } else if (!strncmp(msg, "DEVPATH=", 8)) { - msg += 8; - uevent->path = msg; - } else if (!strncmp(msg, "SUBSYSTEM=", 10)) { - msg += 10; - uevent->subsystem = msg; - } else if (!strncmp(msg, "POWER_SUPPLY_NAME=", 18)) { - msg += 18; - uevent->ps_name = msg; - } else if (!strncmp(msg, "POWER_SUPPLY_ONLINE=", 20)) { - msg += 20; - uevent->ps_online = msg; - } else if (!strncmp(msg, "POWER_SUPPLY_TYPE=", 18)) { - msg += 18; - uevent->ps_type = msg; - } - - /* advance to after the next \0 */ - while (*msg++) - ; - } - - LOGV("event { '%s', '%s', '%s', '%s', '%s', '%s' }\n", - uevent->action, uevent->path, uevent->subsystem, - uevent->ps_name, uevent->ps_type, uevent->ps_online); -} - -static void process_ps_uevent(struct charger *charger, struct uevent *uevent) -{ - int online; - char ps_type[32]; - struct power_supply *supply = NULL; - int i; - bool was_online = false; - bool battery = false; - - if (uevent->ps_type[0] == '\0') { - char *path; - int ret; - - if (uevent->path[0] == '\0') - return; - ret = asprintf(&path, "/sys/%s/type", uevent->path); - if (ret <= 0) - return; - ret = read_file(path, ps_type, sizeof(ps_type)); - free(path); - if (ret < 0) - return; - } else { - strlcpy(ps_type, uevent->ps_type, sizeof(ps_type)); - } - - if (!strncmp(ps_type, "Battery", 7)) - battery = true; - - online = atoi(uevent->ps_online); - supply = find_supply(charger, uevent->ps_name); - if (supply) { - was_online = supply->online; - supply->online = online; - } - - if (!strcmp(uevent->action, "add")) { - if (!supply) { - supply = add_supply(charger, uevent->ps_name, ps_type, uevent->path, - online); - if (!supply) { - LOGE("cannot add supply '%s' (%s %d)\n", uevent->ps_name, - uevent->ps_type, online); - return; - } - /* only pick up the first battery for now */ - if (battery && !charger->battery) - charger->battery = supply; - } else { - LOGE("supply '%s' already exists..\n", uevent->ps_name); - } - } else if (!strcmp(uevent->action, "remove")) { - if (supply) { - if (charger->battery == supply) - charger->battery = NULL; - remove_supply(charger, supply); - supply = NULL; - } - } else if (!strcmp(uevent->action, "change")) { - if (!supply) { - LOGE("power supply '%s' not found ('%s' %d)\n", - uevent->ps_name, ps_type, online); - return; - } - } else { - return; - } - - /* allow battery to be managed in the supply list but make it not - * contribute to online power supplies. */ - if (!battery) { - if (was_online && !online) - charger->num_supplies_online--; - else if (supply && !was_online && online) - charger->num_supplies_online++; - } - - LOGI("power supply %s (%s) %s (action=%s num_online=%d num_supplies=%d)\n", - uevent->ps_name, ps_type, battery ? "" : online ? "online" : "offline", - uevent->action, charger->num_supplies_online, charger->num_supplies); -} - -static void process_uevent(struct charger *charger, struct uevent *uevent) -{ - if (!strcmp(uevent->subsystem, "power_supply")) - process_ps_uevent(charger, uevent); -} - -#define UEVENT_MSG_LEN 1024 -static int handle_uevent_fd(struct charger *charger, int fd) -{ - char msg[UEVENT_MSG_LEN+2]; - int n; - - if (fd < 0) - return -1; - - while (true) { - struct uevent uevent; - - n = uevent_kernel_multicast_recv(fd, msg, UEVENT_MSG_LEN); - if (n <= 0) - break; - if (n >= UEVENT_MSG_LEN) /* overflow -- discard */ - continue; - - msg[n] = '\0'; - msg[n+1] = '\0'; - - parse_uevent(msg, &uevent); - process_uevent(charger, &uevent); - } - - return 0; -} - -static int uevent_callback(int fd, short revents, void *data) -{ - struct charger *charger = data; - - if (!(revents & POLLIN)) - return -1; - return handle_uevent_fd(charger, fd); -} - -/* force the kernel to regenerate the change events for the existing - * devices, if valid */ -static void do_coldboot(struct charger *charger, DIR *d, const char *event, - bool follow_links, int max_depth) -{ - struct dirent *de; - int dfd, fd; - - dfd = dirfd(d); - - fd = openat(dfd, "uevent", O_WRONLY); - if (fd >= 0) { - write(fd, event, strlen(event)); - close(fd); - handle_uevent_fd(charger, charger->uevent_fd); - } - - while ((de = readdir(d)) && max_depth > 0) { - DIR *d2; - - LOGV("looking at '%s'\n", de->d_name); - - if ((de->d_type != DT_DIR && !(de->d_type == DT_LNK && follow_links)) || - de->d_name[0] == '.') { - LOGV("skipping '%s' type %d (depth=%d follow=%d)\n", - de->d_name, de->d_type, max_depth, follow_links); - continue; - } - LOGV("can descend into '%s'\n", de->d_name); - - fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY); - if (fd < 0) { - LOGE("cannot openat %d '%s' (%d: %s)\n", dfd, de->d_name, - errno, strerror(errno)); - continue; - } - - d2 = fdopendir(fd); - if (d2 == 0) - close(fd); - else { - LOGV("opened '%s'\n", de->d_name); - do_coldboot(charger, d2, event, follow_links, max_depth - 1); - closedir(d2); - } - } -} - -static void coldboot(struct charger *charger, const char *path, - const char *event) -{ - char str[256]; - - LOGV("doing coldboot '%s' in '%s'\n", event, path); - DIR *d = opendir(path); - if (d) { - snprintf(str, sizeof(str), "%s\n", event); - do_coldboot(charger, d, str, true, 1); - closedir(d); - } -} - static int draw_text(const char *str, int x, int y) { int str_len_px = gr_measure(str); @@ -699,7 +357,7 @@ static void update_screen_state(struct charger *charger, int64_t now) charger->next_screen_transition = -1; gr_fb_blank(true); LOGV("[%lld] animation done\n", now); - if (charger->num_supplies_online > 0) + if (!charger->charger_connected) request_suspend(true); return; } @@ -712,7 +370,7 @@ static void update_screen_state(struct charger *charger, int64_t now) int ret; LOGV("[%lld] animation starting\n", now); - batt_cap = get_battery_capacity(charger); + batt_cap = get_battery_capacity(); if (batt_cap >= 0 && batt_anim->num_frames != 0) { int i; @@ -773,7 +431,7 @@ static void update_screen_state(struct charger *charger, int64_t now) static int set_key_callback(int code, int value, void *data) { - struct charger *charger = data; + struct charger *charger = (struct charger *)data; int64_t now = curr_time_ms(); int down = !!value; @@ -860,7 +518,10 @@ static void handle_input_state(struct charger *charger, int64_t now) static void handle_power_supply_state(struct charger *charger, int64_t now) { - if (charger->num_supplies_online == 0) { + if (!charger->have_battery_state) + return; + + if (!charger->charger_connected) { request_suspend(false); if (charger->next_pwr_check == -1) { charger->next_pwr_check = now + UNPLUGGED_SHUTDOWN_TIME; @@ -882,8 +543,43 @@ static void handle_power_supply_state(struct charger *charger, int64_t now) } } -static void wait_next_event(struct charger *charger, int64_t now) +void healthd_mode_charger_heartbeat() +{ + struct charger *charger = &charger_state; + int64_t now = curr_time_ms(); + int ret; + + handle_input_state(charger, now); + handle_power_supply_state(charger, now); + + /* do screen update last in case any of the above want to start + * screen transitions (animations, etc) + */ + update_screen_state(charger, now); +} + +void healthd_mode_charger_battery_update( + struct android::BatteryProperties *props) +{ + struct charger *charger = &charger_state; + + charger->charger_connected = + props->chargerAcOnline || props->chargerUsbOnline || + props->chargerWirelessOnline; + charger->capacity = props->batteryLevel; + + if (!charger->have_battery_state) { + charger->have_battery_state = true; + charger->next_screen_transition = curr_time_ms() - 1; + reset_animation(charger->batt_anim); + kick_animation(charger->batt_anim); + } +} + +int healthd_mode_charger_preparetowait(void) { + struct charger *charger = &charger_state; + int64_t now = curr_time_ms(); int64_t next_event = INT64_MAX; int64_t timeout; struct input_event ev; @@ -904,57 +600,38 @@ static void wait_next_event(struct charger *charger, int64_t now) timeout = max(0, next_event - now); else timeout = -1; - LOGV("[%lld] blocking (%lld)\n", now, timeout); - ret = ev_wait((int)timeout); - if (!ret) - ev_dispatch(); + + return (int)timeout; } -static int input_callback(int fd, short revents, void *data) +static int input_callback(int fd, unsigned int epevents, void *data) { - struct charger *charger = data; + struct charger *charger = (struct charger *)data; struct input_event ev; int ret; - ret = ev_get_input(fd, revents, &ev); + ret = ev_get_input(fd, epevents, &ev); if (ret) return -1; update_input_state(charger, &ev); return 0; } -static void event_loop(struct charger *charger) +static void charger_event_handler(uint32_t epevents) { int ret; - while (true) { - int64_t now = curr_time_ms(); - - LOGV("[%lld] event_loop()\n", now); - handle_input_state(charger, now); - handle_power_supply_state(charger, now); - - /* do screen update last in case any of the above want to start - * screen transitions (animations, etc) - */ - update_screen_state(charger, now); - - wait_next_event(charger, now); - } + ret = ev_wait(-1); + if (!ret) + ev_dispatch(); } -int main(int argc, char **argv) +void healthd_mode_charger_init(struct healthd_config *config) { int ret; struct charger *charger = &charger_state; - int64_t now = curr_time_ms() - 1; - int fd; int i; - - list_init(&charger->supplies); - - klog_init(); - klog_set_level(CHARGER_KLOG_LEVEL); + int epollfd; dump_last_kmsg(); @@ -963,15 +640,11 @@ int main(int argc, char **argv) gr_init(); gr_font_size(&char_width, &char_height); - ev_init(input_callback, charger); - - fd = uevent_open_socket(64*1024, true); - if (fd >= 0) { - fcntl(fd, F_SETFL, O_NONBLOCK); - ev_add_fd(fd, uevent_callback, charger); + ret = ev_init(input_callback, charger); + if (!ret) { + epollfd = ev_get_epollfd(); + healthd_register_event(epollfd, charger_event_handler); } - charger->uevent_fd = fd; - coldboot(charger, "/sys/class/power_supply", "add"); ret = res_create_display_surface("charger/battery_fail", &charger->surf_unknown); if (ret < 0) { @@ -1005,13 +678,7 @@ int main(int argc, char **argv) gr_fb_blank(true); #endif - charger->next_screen_transition = now - 1; + charger->next_screen_transition = -1; charger->next_key_check = -1; charger->next_pwr_check = -1; - reset_animation(charger->batt_anim); - kick_animation(charger->batt_anim); - - event_loop(charger); - - return 0; } diff --git a/charger/images/battery_fail.png b/healthd/images/battery_fail.png Binary files differindex aded88a..aded88a 100644 --- a/charger/images/battery_fail.png +++ b/healthd/images/battery_fail.png diff --git a/charger/images/battery_scale.png b/healthd/images/battery_scale.png Binary files differindex 2ae8f0f..2ae8f0f 100644 --- a/charger/images/battery_scale.png +++ b/healthd/images/battery_scale.png diff --git a/include/cutils/klog.h b/include/cutils/klog.h index 3635e89..d5ae6d7 100644 --- a/include/cutils/klog.h +++ b/include/cutils/klog.h @@ -25,7 +25,7 @@ __BEGIN_DECLS void klog_init(void); int klog_get_level(void); void klog_set_level(int level); -void klog_close(void); +/* TODO: void klog_close(void); - and make klog_fd users thread safe. */ void klog_write(int level, const char *fmt, ...) __attribute__ ((format(printf, 2, 3))); void klog_vwrite(int level, const char *fmt, va_list ap); diff --git a/include/cutils/properties.h b/include/cutils/properties.h index 2c70165..798db8b 100644 --- a/include/cutils/properties.h +++ b/include/cutils/properties.h @@ -20,6 +20,7 @@ #include <sys/cdefs.h> #include <stddef.h> #include <sys/system_properties.h> +#include <stdint.h> #ifdef __cplusplus extern "C" { @@ -44,6 +45,64 @@ extern "C" { */ int property_get(const char *key, char *value, const char *default_value); +/* property_get_bool: returns the value of key coerced into a +** boolean. If the property is not set, then the default value is returned. +** +* The following is considered to be true (1): +** "1", "true", "y", "yes", "on" +** +** The following is considered to be false (0): +** "0", "false", "n", "no", "off" +** +** The conversion is whitespace-sensitive (e.g. " off" will not be false). +** +** If no property with this key is set (or the key is NULL) or the boolean +** conversion fails, the default value is returned. +**/ +int8_t property_get_bool(const char *key, int8_t default_value); + +/* property_get_int64: returns the value of key truncated and coerced into a +** int64_t. If the property is not set, then the default value is used. +** +** The numeric conversion is identical to strtoimax with the base inferred: +** - All digits up to the first non-digit characters are read +** - The longest consecutive prefix of digits is converted to a long +** +** Valid strings of digits are: +** - An optional sign character + or - +** - An optional prefix indicating the base (otherwise base 10 is assumed) +** -- 0 prefix is octal +** -- 0x / 0X prefix is hex +** +** Leading/trailing whitespace is ignored. Overflow/underflow will cause +** numeric conversion to fail. +** +** If no property with this key is set (or the key is NULL) or the numeric +** conversion fails, the default value is returned. +**/ +int64_t property_get_int64(const char *key, int64_t default_value); + +/* property_get_int32: returns the value of key truncated and coerced into an +** int32_t. If the property is not set, then the default value is used. +** +** The numeric conversion is identical to strtoimax with the base inferred: +** - All digits up to the first non-digit characters are read +** - The longest consecutive prefix of digits is converted to a long +** +** Valid strings of digits are: +** - An optional sign character + or - +** - An optional prefix indicating the base (otherwise base 10 is assumed) +** -- 0 prefix is octal +** -- 0x / 0X prefix is hex +** +** Leading/trailing whitespace is ignored. Overflow/underflow will cause +** numeric conversion to fail. +** +** If no property with this key is set (or the key is NULL) or the numeric +** conversion fails, the default value is returned. +**/ +int32_t property_get_int32(const char *key, int32_t default_value); + /* property_set: returns 0 on success, < 0 on failure */ int property_set(const char *key, const char *value); diff --git a/include/cutils/str_parms.h b/include/cutils/str_parms.h index 247c996..66f3637 100644 --- a/include/cutils/str_parms.h +++ b/include/cutils/str_parms.h @@ -34,6 +34,12 @@ int str_parms_add_int(struct str_parms *str_parms, const char *key, int value); int str_parms_add_float(struct str_parms *str_parms, const char *key, float value); +// Returns non-zero if the str_parms contains the specified key. +int str_parms_has_key(struct str_parms *str_parms, const char *key); + +// Gets value associated with the specified key (if present), placing it in the buffer +// pointed to by the out_val parameter. Returns the length of the returned string value. +// If 'key' isn't in the parms, then return -ENOENT (-2) and leave 'out_val' untouched. int str_parms_get_str(struct str_parms *str_parms, const char *key, char *out_val, int len); int str_parms_get_int(struct str_parms *str_parms, const char *key, diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h index d662107..baa012d 100644 --- a/include/private/android_filesystem_config.h +++ b/include/private/android_filesystem_config.h @@ -249,6 +249,8 @@ static const struct fs_path_config android_files[] = { /* the following files have enhanced capabilities and ARE included in user builds. */ { 00750, AID_ROOT, AID_SHELL, (1 << CAP_SETUID) | (1 << CAP_SETGID), "system/bin/run-as" }, + { 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_ROOT, 0, "system/lib/valgrind/*" }, { 00755, AID_ROOT, AID_ROOT, 0, "system/lib64/valgrind/*" }, @@ -258,7 +260,6 @@ static const struct fs_path_config android_files[] = { { 00750, AID_ROOT, AID_SHELL, 0, "sbin/*" }, { 00755, AID_ROOT, AID_ROOT, 0, "bin/*" }, { 00750, AID_ROOT, AID_SHELL, 0, "init*" }, - { 00750, AID_ROOT, AID_SHELL, 0, "charger*" }, { 00750, AID_ROOT, AID_SHELL, 0, "sbin/fs_mgr" }, { 00640, AID_ROOT, AID_SHELL, 0, "fstab.*" }, { 00644, AID_ROOT, AID_ROOT, 0, 0 }, diff --git a/include/system/audio.h b/include/system/audio.h index f36befb..1b7d81a 100644 --- a/include/system/audio.h +++ b/include/system/audio.h @@ -34,11 +34,17 @@ __BEGIN_DECLS /* device address used to refer to the standard remote submix */ #define AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS "0" +/* AudioFlinger and AudioPolicy services use I/O handles to identify audio sources and sinks */ typedef int audio_io_handle_t; +#define AUDIO_IO_HANDLE_NONE 0 /* Audio stream types */ typedef enum { + /* These values must kept in sync with + * frameworks/base/media/java/android/media/AudioSystem.java + */ AUDIO_STREAM_DEFAULT = -1, + AUDIO_STREAM_MIN = 0, AUDIO_STREAM_VOICE_CALL = 0, AUDIO_STREAM_SYSTEM = 1, AUDIO_STREAM_RING = 2, @@ -55,7 +61,9 @@ typedef enum { } audio_stream_type_t; /* Do not change these values without updating their counterparts - * in media/java/android/media/MediaRecorder.java! + * in frameworks/base/media/java/android/media/MediaRecorder.java, + * frameworks/av/services/audioflinger/AudioPolicyService.cpp, + * and system/media/audio_effects/include/audio_effects/audio_effects_conf.h! */ typedef enum { AUDIO_SOURCE_DEFAULT = 0, @@ -93,18 +101,30 @@ typedef enum { * (value must be 0) */ AUDIO_SESSION_OUTPUT_MIX = 0, + + /* application does not specify an explicit session ID to be used, + * and requests a new session ID to be allocated + * TODO use unique values for AUDIO_SESSION_OUTPUT_MIX and AUDIO_SESSION_ALLOCATE, + * after all uses have been updated from 0 to the appropriate symbol, and have been tested. + */ + AUDIO_SESSION_ALLOCATE = 0, } audio_session_t; /* Audio sub formats (see enum audio_format). */ /* PCM sub formats */ typedef enum { + /* All of these are in native byte order */ AUDIO_FORMAT_PCM_SUB_16_BIT = 0x1, /* DO NOT CHANGE - PCM signed 16 bits */ AUDIO_FORMAT_PCM_SUB_8_BIT = 0x2, /* DO NOT CHANGE - PCM unsigned 8 bits */ AUDIO_FORMAT_PCM_SUB_32_BIT = 0x3, /* PCM signed .31 fixed point */ AUDIO_FORMAT_PCM_SUB_8_24_BIT = 0x4, /* PCM signed 7.24 fixed point */ + AUDIO_FORMAT_PCM_SUB_FLOAT = 0x5, /* PCM single-precision floating point */ + AUDIO_FORMAT_PCM_SUB_24_BIT_PACKED = 0x6, /* PCM signed .23 fixed point packed in 3 bytes */ } audio_format_pcm_sub_fmt_t; +/* The audio_format_*_sub_fmt_t declarations are not currently used */ + /* MP3 sub format field definition : can use 11 LSBs in the same way as MP3 * frame header to specify bit rate, stereo mode, version... */ @@ -129,7 +149,7 @@ typedef enum { AUDIO_FORMAT_VORBIS_SUB_NONE = 0x0, } audio_format_vorbis_sub_fmt_t; -/* Audio format consists in a main format field (upper 8 bits) and a sub format +/* Audio format consists of a main format field (upper 8 bits) and a sub format * field (lower 24 bits). * * The main format indicates the main codec type. The sub format field @@ -149,18 +169,25 @@ typedef enum { AUDIO_FORMAT_HE_AAC_V1 = 0x05000000UL, AUDIO_FORMAT_HE_AAC_V2 = 0x06000000UL, AUDIO_FORMAT_VORBIS = 0x07000000UL, + AUDIO_FORMAT_OPUS = 0x08000000UL, AUDIO_FORMAT_MAIN_MASK = 0xFF000000UL, AUDIO_FORMAT_SUB_MASK = 0x00FFFFFFUL, /* Aliases */ + /* note != AudioFormat.ENCODING_PCM_16BIT */ AUDIO_FORMAT_PCM_16_BIT = (AUDIO_FORMAT_PCM | AUDIO_FORMAT_PCM_SUB_16_BIT), + /* note != AudioFormat.ENCODING_PCM_8BIT */ AUDIO_FORMAT_PCM_8_BIT = (AUDIO_FORMAT_PCM | AUDIO_FORMAT_PCM_SUB_8_BIT), AUDIO_FORMAT_PCM_32_BIT = (AUDIO_FORMAT_PCM | AUDIO_FORMAT_PCM_SUB_32_BIT), AUDIO_FORMAT_PCM_8_24_BIT = (AUDIO_FORMAT_PCM | AUDIO_FORMAT_PCM_SUB_8_24_BIT), + AUDIO_FORMAT_PCM_FLOAT = (AUDIO_FORMAT_PCM | + AUDIO_FORMAT_PCM_SUB_FLOAT), + AUDIO_FORMAT_PCM_24_BIT_PACKED = (AUDIO_FORMAT_PCM | + AUDIO_FORMAT_PCM_SUB_24_BIT_PACKED), } audio_format_t; enum { @@ -191,16 +218,26 @@ enum { AUDIO_CHANNEL_OUT_FRONT_RIGHT | AUDIO_CHANNEL_OUT_BACK_LEFT | AUDIO_CHANNEL_OUT_BACK_RIGHT), - AUDIO_CHANNEL_OUT_SURROUND = (AUDIO_CHANNEL_OUT_FRONT_LEFT | + AUDIO_CHANNEL_OUT_QUAD_BACK = AUDIO_CHANNEL_OUT_QUAD, + /* like AUDIO_CHANNEL_OUT_QUAD_BACK with *_SIDE_* instead of *_BACK_* */ + AUDIO_CHANNEL_OUT_QUAD_SIDE = (AUDIO_CHANNEL_OUT_FRONT_LEFT | AUDIO_CHANNEL_OUT_FRONT_RIGHT | - AUDIO_CHANNEL_OUT_FRONT_CENTER | - AUDIO_CHANNEL_OUT_BACK_CENTER), + AUDIO_CHANNEL_OUT_SIDE_LEFT | + AUDIO_CHANNEL_OUT_SIDE_RIGHT), AUDIO_CHANNEL_OUT_5POINT1 = (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_5POINT1_BACK = AUDIO_CHANNEL_OUT_5POINT1, + /* like AUDIO_CHANNEL_OUT_5POINT1_BACK with *_SIDE_* instead of *_BACK_* */ + AUDIO_CHANNEL_OUT_5POINT1_SIDE = (AUDIO_CHANNEL_OUT_FRONT_LEFT | + AUDIO_CHANNEL_OUT_FRONT_RIGHT | + AUDIO_CHANNEL_OUT_FRONT_CENTER | + AUDIO_CHANNEL_OUT_LOW_FREQUENCY | + AUDIO_CHANNEL_OUT_SIDE_LEFT | + AUDIO_CHANNEL_OUT_SIDE_RIGHT), // 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 | @@ -264,8 +301,25 @@ enum { AUDIO_CHANNEL_IN_VOICE_DNLINK), }; +/* A channel mask per se only defines the presence or absence of a channel, not the order. + * But see AUDIO_INTERLEAVE_* below for the platform convention of order. + */ typedef uint32_t audio_channel_mask_t; +/* Expresses the convention when stereo audio samples are stored interleaved + * in an array. This should improve readability by allowing code to use + * symbolic indices instead of hard-coded [0] and [1]. + * + * For multi-channel beyond stereo, the platform convention is that channels + * are interleaved in order from least significant channel mask bit + * to most significant channel mask bit, with unused bits skipped. + * Any exceptions to this convention will be noted at the appropriate API. + */ +enum { + AUDIO_INTERLEAVE_LEFT = 0, + AUDIO_INTERLEAVE_RIGHT = 1, +}; + typedef enum { AUDIO_MODE_INVALID = -2, AUDIO_MODE_CURRENT = -1, @@ -278,7 +332,9 @@ typedef enum { AUDIO_MODE_MAX = AUDIO_MODE_CNT - 1, } audio_mode_t; +/* This enum is deprecated */ typedef enum { + AUDIO_IN_ACOUSTICS_NONE = 0, AUDIO_IN_ACOUSTICS_AGC_ENABLE = 0x0001, AUDIO_IN_ACOUSTICS_AGC_DISABLE = 0, AUDIO_IN_ACOUSTICS_NS_ENABLE = 0x0002, @@ -304,9 +360,12 @@ enum { AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200, AUDIO_DEVICE_OUT_AUX_DIGITAL = 0x400, + /* uses an analog connection (multiplexed over the USB connector pins for instance) */ AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800, AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000, + /* USB accessory mode: your Android device is a USB device and the dock is a USB host */ AUDIO_DEVICE_OUT_USB_ACCESSORY = 0x2000, + /* USB host mode: your Android device is a USB host and the dock is a USB device */ AUDIO_DEVICE_OUT_USB_DEVICE = 0x4000, AUDIO_DEVICE_OUT_REMOTE_SUBMIX = 0x8000, AUDIO_DEVICE_OUT_DEFAULT = AUDIO_DEVICE_BIT_DEFAULT, @@ -367,6 +426,8 @@ enum { AUDIO_DEVICE_IN_USB_DEVICE | 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 | + AUDIO_DEVICE_IN_USB_DEVICE), }; typedef uint32_t audio_devices_t; @@ -483,12 +544,25 @@ static inline bool audio_is_bluetooth_sco_device(audio_devices_t device) return false; } +static inline bool audio_is_usb_out_device(audio_devices_t device) +{ + return ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_ALL_USB)); +} + +static inline bool audio_is_usb_in_device(audio_devices_t device) +{ + if ((device & AUDIO_DEVICE_BIT_IN) != 0) { + device &= ~AUDIO_DEVICE_BIT_IN; + if (popcount(device) == 1 && (device & AUDIO_DEVICE_IN_ALL_USB) != 0) + return true; + } + return false; +} + +/* OBSOLETE - use audio_is_usb_out_device() instead. */ static inline bool audio_is_usb_device(audio_devices_t device) { - if ((popcount(device) == 1) && (device & AUDIO_DEVICE_OUT_ALL_USB)) - return true; - else - return false; + return audio_is_usb_out_device(device); } static inline bool audio_is_remote_submix_device(audio_devices_t device) @@ -526,7 +600,7 @@ static inline bool audio_is_output_channel(audio_channel_mask_t channel) */ static inline audio_channel_mask_t audio_channel_out_mask_from_count(uint32_t channel_count) { - switch(channel_count) { + switch (channel_count) { case 1: return AUDIO_CHANNEL_OUT_MONO; case 2: @@ -565,10 +639,18 @@ static inline bool audio_is_valid_format(audio_format_t format) { switch (format & AUDIO_FORMAT_MAIN_MASK) { case AUDIO_FORMAT_PCM: - if (format != AUDIO_FORMAT_PCM_16_BIT && - format != AUDIO_FORMAT_PCM_8_BIT) { + switch (format) { + case AUDIO_FORMAT_PCM_16_BIT: + case AUDIO_FORMAT_PCM_8_BIT: + case AUDIO_FORMAT_PCM_32_BIT: + case AUDIO_FORMAT_PCM_8_24_BIT: + case AUDIO_FORMAT_PCM_FLOAT: + case AUDIO_FORMAT_PCM_24_BIT_PACKED: + return true; + default: return false; } + /* not reached */ case AUDIO_FORMAT_MP3: case AUDIO_FORMAT_AMR_NB: case AUDIO_FORMAT_AMR_WB: @@ -596,12 +678,18 @@ static inline size_t audio_bytes_per_sample(audio_format_t format) case AUDIO_FORMAT_PCM_8_24_BIT: size = sizeof(int32_t); break; + case AUDIO_FORMAT_PCM_24_BIT_PACKED: + size = sizeof(uint8_t) * 3; + break; case AUDIO_FORMAT_PCM_16_BIT: size = sizeof(int16_t); break; case AUDIO_FORMAT_PCM_8_BIT: size = sizeof(uint8_t); break; + case AUDIO_FORMAT_PCM_FLOAT: + size = sizeof(float); + break; default: break; } diff --git a/include/system/graphics.h b/include/system/graphics.h index be86ae4..82877a0 100644 --- a/include/system/graphics.h +++ b/include/system/graphics.h @@ -165,24 +165,54 @@ enum { /* * Android RAW sensor format: * - * This format is exposed outside of the HAL to applications. + * This format is exposed outside of the camera HAL to applications. * - * RAW_SENSOR is a single-channel 16-bit format, typically representing raw - * Bayer-pattern images from an image sensor, with minimal processing. + * RAW_SENSOR is a single-channel, 16-bit, little endian format, typically + * representing raw Bayer-pattern images from an image sensor, with minimal + * processing. * * The exact pixel layout of the data in the buffer is sensor-dependent, and * needs to be queried from the camera device. * * Generally, not all 16 bits are used; more common values are 10 or 12 - * bits. All parameters to interpret the raw data (black and white points, + * bits. If not all bits are used, the lower-order bits are filled first. + * All parameters to interpret the raw data (black and white points, * color space, etc) must be queried from the camera device. * * This format assumes * - an even width * - an even height - * - a horizontal stride multiple of 16 pixels (32 bytes). + * - a horizontal stride multiple of 16 pixels + * - a vertical stride equal to the height + * - strides are specified in pixels, not in bytes + * + * size = stride * height * 2 + * + * This format must be accepted by the gralloc module when used with the + * following usage flags: + * - GRALLOC_USAGE_HW_CAMERA_* + * - GRALLOC_USAGE_SW_* + * - GRALLOC_USAGE_RENDERSCRIPT */ - HAL_PIXEL_FORMAT_RAW_SENSOR = 0x20, + HAL_PIXEL_FORMAT_RAW16 = 0x20, + HAL_PIXEL_FORMAT_RAW_SENSOR = 0x20, // TODO(rubenbrunk): Remove RAW_SENSOR. + + /* + * Android opaque RAW format: + * + * This format is exposed outside of the camera HAL to applications. + * + * RAW_OPAQUE is a format for unprocessed raw image buffers coming from an + * image sensor. The actual structure of buffers of this format is + * implementation-dependent. + * + * This format must be accepted by the gralloc module when used with the + * following usage flags: + * - GRALLOC_USAGE_HW_CAMERA_* + * - GRALLOC_USAGE_SW_* + * - GRALLOC_USAGE_RENDERSCRIPT + */ + HAL_PIXEL_FORMAT_RAW_OPAQUE = 0x24, /* * Android binary blob graphics buffer format: @@ -297,6 +327,136 @@ enum { HAL_TRANSFORM_RESERVED = 0x08, }; +/** + * Colorspace Definitions + * ====================== + * + * Colorspace is the definition of how pixel values should be interpreted. + * It includes primaries (including white point) and the transfer + * characteristic function, which describes both gamma curve and numeric + * range (within the bit depth). + */ + +enum { + /* + * Arbitrary colorspace with manually defined characteristics. + * Colorspace definition must be communicated separately. + * + * This is used when specifying primaries, transfer characteristics, + * etc. separately. + * + * A typical use case is in video encoding parameters (e.g. for H.264), + * where a colorspace can have separately defined primaries, transfer + * characteristics, etc. + */ + HAL_COLORSPACE_ARBITRARY = 0x1, + + /* + * YCbCr Colorspaces + * ----------------- + * + * Primaries are given using (x,y) coordinates in the CIE 1931 definition + * of x and y specified by ISO 11664-1. + * + * Transfer characteristics are the opto-electronic transfer characteristic + * at the source as a function of linear optical intensity (luminance). + */ + + /* + * JPEG File Interchange Format (JFIF) + * + * Same model as BT.601-625, but all values (Y, Cb, Cr) range from 0 to 255 + * + * Transfer characteristic curve: + * E = 1.099 * L ^ 0.45 - 0.099, 1.00 >= L >= 0.018 + * E = 4.500 L, 0.018 > L >= 0 + * L - luminance of image 0 <= L <= 1 for conventional colorimetry + * E - corresponding electrical signal + * + * Primaries: x y + * green 0.290 0.600 + * blue 0.150 0.060 + * red 0.640 0.330 + * white (D65) 0.3127 0.3290 + */ + HAL_COLORSPACE_JFIF = 0x101, + + /* + * ITU-R Recommendation 601 (BT.601) - 625-line + * + * Standard-definition television, 625 Lines (PAL) + * + * For 8-bit-depth formats: + * Luma (Y) samples should range from 16 to 235, inclusive + * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive + * + * For 10-bit-depth formats: + * Luma (Y) samples should range from 64 to 940, inclusive + * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive + * + * Transfer characteristic curve: + * E = 1.099 * L ^ 0.45 - 0.099, 1.00 >= L >= 0.018 + * E = 4.500 L, 0.018 > L >= 0 + * L - luminance of image 0 <= L <= 1 for conventional colorimetry + * E - corresponding electrical signal + * + * Primaries: x y + * green 0.290 0.600 + * blue 0.150 0.060 + * red 0.640 0.330 + * white (D65) 0.3127 0.3290 + */ + HAL_COLORSPACE_BT601_625 = 0x102, + + /* + * ITU-R Recommendation 601 (BT.601) - 525-line + * + * Standard-definition television, 525 Lines (NTSC) + * + * For 8-bit-depth formats: + * Luma (Y) samples should range from 16 to 235, inclusive + * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive + * + * For 10-bit-depth formats: + * Luma (Y) samples should range from 64 to 940, inclusive + * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive + * + * Transfer characteristic curve: + * E = 1.099 * L ^ 0.45 - 0.099, 1.00 >= L >= 0.018 + * E = 4.500 L, 0.018 > L >= 0 + * L - luminance of image 0 <= L <= 1 for conventional colorimetry + * E - corresponding electrical signal + * + * Primaries: x y + * green 0.310 0.595 + * blue 0.155 0.070 + * red 0.630 0.340 + * white (D65) 0.3127 0.3290 + */ + HAL_COLORSPACE_BT601_525 = 0x103, + + /* + * ITU-R Recommendation 709 (BT.709) + * + * High-definition television + * + * For 8-bit-depth formats: + * Luma (Y) samples should range from 16 to 235, inclusive + * Chroma (Cb, Cr) samples should range from 16 to 240, inclusive + * + * For 10-bit-depth formats: + * Luma (Y) samples should range from 64 to 940, inclusive + * Chroma (Cb, Cr) samples should range from 64 to 960, inclusive + * + * Primaries: x y + * green 0.300 0.600 + * blue 0.150 0.060 + * red 0.640 0.330 + * white (D65) 0.3127 0.3290 + */ + HAL_COLORSPACE_BT709 = 0x104, +}; + #ifdef __cplusplus } #endif diff --git a/include/usbhost/usbhost.h b/include/usbhost/usbhost.h index 1d67c12..d26e931 100644 --- a/include/usbhost/usbhost.h +++ b/include/usbhost/usbhost.h @@ -189,6 +189,13 @@ int usb_device_release_interface(struct usb_device *device, unsigned int interfa int usb_device_connect_kernel_driver(struct usb_device *device, unsigned int interface, int connect); +/* Sets the current configuration for the device to the specified configuration */ +int usb_device_set_configuration(struct usb_device *device, int configuration); + +/* Sets the specified interface of a USB device */ +int usb_device_set_interface(struct usb_device *device, unsigned int interface, + unsigned int alt_setting); + /* Sends a control message to the specified device on endpoint zero */ int usb_device_control_transfer(struct usb_device *device, int requestType, diff --git a/include/utils/BitSet.h b/include/utils/BitSet.h index f1d68a0..8c61293 100644 --- a/include/utils/BitSet.h +++ b/include/utils/BitSet.h @@ -75,19 +75,19 @@ struct BitSet32 { // Result is undefined if all bits are unmarked. inline uint32_t firstMarkedBit() const { return firstMarkedBit(value); } - static uint32_t firstMarkedBit(uint32_t value) { return __builtin_clzl(value); } + static uint32_t firstMarkedBit(uint32_t value) { return clz_checked(value); } // Finds the first unmarked bit in the set. // Result is undefined if all bits are marked. inline uint32_t firstUnmarkedBit() const { return firstUnmarkedBit(value); } - static inline uint32_t firstUnmarkedBit(uint32_t value) { return __builtin_clzl(~ value); } + static inline uint32_t firstUnmarkedBit(uint32_t value) { return clz_checked(~ value); } // Finds the last marked bit in the set. // Result is undefined if all bits are unmarked. inline uint32_t lastMarkedBit() const { return lastMarkedBit(value); } - static inline uint32_t lastMarkedBit(uint32_t value) { return 31 - __builtin_ctzl(value); } + static inline uint32_t lastMarkedBit(uint32_t value) { return 31 - ctz_checked(value); } // Finds the first marked bit in the set and clears it. Returns the bit index. // Result is undefined if all bits are unmarked. @@ -145,6 +145,25 @@ struct BitSet32 { value |= other.value; return *this; } + +private: + // We use these helpers as the signature of __builtin_c{l,t}z has "unsigned int" for the + // input, which is only guaranteed to be 16b, not 32. The compiler should optimize this away. + static inline uint32_t clz_checked(uint32_t value) { + if (sizeof(unsigned int) == sizeof(uint32_t)) { + return __builtin_clz(value); + } else { + return __builtin_clzl(value); + } + } + + static inline uint32_t ctz_checked(uint32_t value) { + if (sizeof(unsigned int) == sizeof(uint32_t)) { + return __builtin_ctz(value); + } else { + return __builtin_ctzl(value); + } + } }; ANDROID_BASIC_TYPES_TRAITS(BitSet32) diff --git a/include/utils/Condition.h b/include/utils/Condition.h index e63ba7e..1c99d1a 100644 --- a/include/utils/Condition.h +++ b/include/utils/Condition.h @@ -60,7 +60,7 @@ public: status_t wait(Mutex& mutex); // same with relative timeout status_t waitRelative(Mutex& mutex, nsecs_t reltime); - // Signal the condition variable, allowing one thread to continue. + // Signal the condition variable, allowing exactly one thread to continue. void signal(); // Signal the condition variable, allowing one or all threads to continue. void signal(WakeUpType type) { @@ -132,6 +132,17 @@ inline status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime) { #endif // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE } inline void Condition::signal() { + /* + * POSIX says pthread_cond_signal wakes up "one or more" waiting threads. + * However bionic follows the glibc guarantee which wakes up "exactly one" + * waiting thread. + * + * man 3 pthread_cond_signal + * pthread_cond_signal restarts one of the threads that are waiting on + * the condition variable cond. If no threads are waiting on cond, + * nothing happens. If several threads are waiting on cond, exactly one + * is restarted, but it is not specified which. + */ pthread_cond_signal(&mCond); } inline void Condition::broadcast() { diff --git a/include/utils/LruCache.h b/include/utils/LruCache.h index 053bfaf..f615a32 100644 --- a/include/utils/LruCache.h +++ b/include/utils/LruCache.h @@ -17,8 +17,8 @@ #ifndef ANDROID_UTILS_LRU_CACHE_H #define ANDROID_UTILS_LRU_CACHE_H +#include <UniquePtr.h> #include <utils/BasicHashtable.h> -#include <utils/UniquePtr.h> namespace android { @@ -48,6 +48,7 @@ public: bool remove(const TKey& key); bool removeOldest(); void clear(); + const TValue& peekOldestValue(); class Iterator { public: @@ -180,6 +181,14 @@ bool LruCache<TKey, TValue>::removeOldest() { } template <typename TKey, typename TValue> +const TValue& LruCache<TKey, TValue>::peekOldestValue() { + if (mOldest) { + return mOldest->value; + } + return mNullValue; +} + +template <typename TKey, typename TValue> void LruCache<TKey, TValue>::clear() { if (mListener) { for (Entry* p = mOldest; p != NULL; p = p->child) { diff --git a/include/utils/NativeHandle.h b/include/utils/NativeHandle.h new file mode 100644 index 0000000..b825168 --- /dev/null +++ b/include/utils/NativeHandle.h @@ -0,0 +1,56 @@ +/* + * Copyright 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 ANDROID_NATIVE_HANDLE_H +#define ANDROID_NATIVE_HANDLE_H + +#include <utils/RefBase.h> +#include <utils/StrongPointer.h> + +typedef struct native_handle native_handle_t; + +namespace android { + +class NativeHandle: public LightRefBase<NativeHandle> { +public: + // Create a refcounted wrapper around a native_handle_t, and declare + // whether the wrapper owns the handle (so that it should clean up the + // handle upon destruction) or not. + // If handle is NULL, no NativeHandle will be created. + static sp<NativeHandle> create(native_handle_t* handle, bool ownsHandle); + + const native_handle_t* handle() const { + return mHandle; + } + +private: + // for access to the destructor + friend class LightRefBase<NativeHandle>; + + NativeHandle(native_handle_t* handle, bool ownsHandle); + virtual ~NativeHandle(); + + native_handle_t* mHandle; + bool mOwnsHandle; + + // non-copyable + NativeHandle(const NativeHandle&); + NativeHandle& operator=(const NativeHandle&); +}; + +} // namespace android + +#endif // ANDROID_NATIVE_HANDLE_H diff --git a/include/utils/UniquePtr.h b/include/utils/UniquePtr.h deleted file mode 100644 index bc62fe6..0000000 --- a/include/utils/UniquePtr.h +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* === NOTE === NOTE === NOTE === NOTE === NOTE === NOTE === NOTE === NOTE === - * - * THIS IS A COPY OF libcore/include/UniquePtr.h AND AS SUCH THAT IS THE - * CANONICAL SOURCE OF THIS FILE. PLEASE KEEP THEM IN SYNC. - * - * === NOTE === NOTE === NOTE === NOTE === NOTE === NOTE === NOTE === NOTE === - */ - -#ifndef UNIQUE_PTR_H_included -#define UNIQUE_PTR_H_included - -#include <cstdlib> // For NULL. - -// Default deleter for pointer types. -template <typename T> -struct DefaultDelete { - enum { type_must_be_complete = sizeof(T) }; - DefaultDelete() {} - void operator()(T* p) const { - delete p; - } -}; - -// Default deleter for array types. -template <typename T> -struct DefaultDelete<T[]> { - enum { type_must_be_complete = sizeof(T) }; - void operator()(T* p) const { - delete[] p; - } -}; - -// A smart pointer that deletes the given pointer on destruction. -// Equivalent to C++0x's std::unique_ptr (a combination of boost::scoped_ptr -// and boost::scoped_array). -// Named to be in keeping with Android style but also to avoid -// collision with any other implementation, until we can switch over -// to unique_ptr. -// Use thus: -// UniquePtr<C> c(new C); -template <typename T, typename D = DefaultDelete<T> > -class UniquePtr { -public: - // Construct a new UniquePtr, taking ownership of the given raw pointer. - explicit UniquePtr(T* ptr = NULL) : mPtr(ptr) { - } - - ~UniquePtr() { - reset(); - } - - // Accessors. - T& operator*() const { return *mPtr; } - T* operator->() const { return mPtr; } - T* get() const { return mPtr; } - - // Returns the raw pointer and hands over ownership to the caller. - // The pointer will not be deleted by UniquePtr. - T* release() __attribute__((warn_unused_result)) { - T* result = mPtr; - mPtr = NULL; - return result; - } - - // Takes ownership of the given raw pointer. - // If this smart pointer previously owned a different raw pointer, that - // raw pointer will be freed. - void reset(T* ptr = NULL) { - if (ptr != mPtr) { - D()(mPtr); - mPtr = ptr; - } - } - -private: - // The raw pointer. - T* mPtr; - - // Comparing unique pointers is probably a mistake, since they're unique. - template <typename T2> bool operator==(const UniquePtr<T2>& p) const; - template <typename T2> bool operator!=(const UniquePtr<T2>& p) const; - - // Disallow copy and assignment. - UniquePtr(const UniquePtr&); - void operator=(const UniquePtr&); -}; - -// Partial specialization for array types. Like std::unique_ptr, this removes -// operator* and operator-> but adds operator[]. -template <typename T, typename D> -class UniquePtr<T[], D> { -public: - explicit UniquePtr(T* ptr = NULL) : mPtr(ptr) { - } - - ~UniquePtr() { - reset(); - } - - T& operator[](size_t i) const { - return mPtr[i]; - } - T* get() const { return mPtr; } - - T* release() __attribute__((warn_unused_result)) { - T* result = mPtr; - mPtr = NULL; - return result; - } - - void reset(T* ptr = NULL) { - if (ptr != mPtr) { - D()(mPtr); - mPtr = ptr; - } - } - -private: - T* mPtr; - - // Disallow copy and assignment. - UniquePtr(const UniquePtr&); - void operator=(const UniquePtr&); -}; - -#if UNIQUE_PTR_TESTS - -// Run these tests with: -// g++ -g -DUNIQUE_PTR_TESTS -x c++ UniquePtr.h && ./a.out - -#include <stdio.h> - -static void assert(bool b) { - if (!b) { - fprintf(stderr, "FAIL\n"); - abort(); - } - fprintf(stderr, "OK\n"); -} -static int cCount = 0; -struct C { - C() { ++cCount; } - ~C() { --cCount; } -}; -static bool freed = false; -struct Freer { - void operator()(int* p) { - assert(*p == 123); - free(p); - freed = true; - } -}; - -int main(int argc, char* argv[]) { - // - // UniquePtr<T> tests... - // - - // Can we free a single object? - { - UniquePtr<C> c(new C); - assert(cCount == 1); - } - assert(cCount == 0); - // Does release work? - C* rawC; - { - UniquePtr<C> c(new C); - assert(cCount == 1); - rawC = c.release(); - } - assert(cCount == 1); - delete rawC; - // Does reset work? - { - UniquePtr<C> c(new C); - assert(cCount == 1); - c.reset(new C); - assert(cCount == 1); - } - assert(cCount == 0); - - // - // UniquePtr<T[]> tests... - // - - // Can we free an array? - { - UniquePtr<C[]> cs(new C[4]); - assert(cCount == 4); - } - assert(cCount == 0); - // Does release work? - { - UniquePtr<C[]> c(new C[4]); - assert(cCount == 4); - rawC = c.release(); - } - assert(cCount == 4); - delete[] rawC; - // Does reset work? - { - UniquePtr<C[]> c(new C[4]); - assert(cCount == 4); - c.reset(new C[2]); - assert(cCount == 2); - } - assert(cCount == 0); - - // - // Custom deleter tests... - // - assert(!freed); - { - UniquePtr<int, Freer> i(reinterpret_cast<int*>(malloc(sizeof(int)))); - *i = 123; - } - assert(freed); - return 0; -} -#endif - -#endif // UNIQUE_PTR_H_included diff --git a/init/builtins.c b/init/builtins.c index d973a6b..a9cd1bd 100644 --- a/init/builtins.c +++ b/init/builtins.c @@ -518,10 +518,14 @@ int do_mount_all(int nargs, char **args) return -1; } - /* ret is 1 if the device is encrypted, 0 if not, and -1 on error */ - if (ret == 1) { + /* ret is 2 if device needs encrypted, 1 if the device appears encrypted, + * 0 if not, and -1 on error */ + if (ret == 2) { + property_set("ro.crypto.state", "unencrypted"); + property_set("vold.decrypt", "trigger_encryption"); + } else if (ret == 1) { property_set("ro.crypto.state", "encrypted"); - property_set("vold.decrypt", "1"); + property_set("vold.decrypt", "trigger_default_encryption"); } else if (ret == 0) { property_set("ro.crypto.state", "unencrypted"); /* If fs_mgr determined this is an unencrypted device, then trigger diff --git a/init/property_service.c b/init/property_service.c index 7e8d79a..8247ef4 100644 --- a/init/property_service.c +++ b/init/property_service.c @@ -24,6 +24,7 @@ #include <dirent.h> #include <limits.h> #include <errno.h> +#include <sys/poll.h> #include <cutils/misc.h> #include <cutils/sockets.h> @@ -96,6 +97,8 @@ struct { { "persist.gps.", AID_GPS, 0 }, { "persist.service.bdroid.", AID_BLUETOOTH, 0 }, { "selinux." , AID_SYSTEM, 0 }, + { "build.fingerprint", AID_SYSTEM, 0 }, + { "partition." , AID_SYSTEM, 0}, { NULL, 0, 0 } }; @@ -110,6 +113,7 @@ struct { } control_perms[] = { { "dumpstate",AID_SHELL, AID_LOG }, { "ril-daemon",AID_RADIO, AID_RADIO }, + { "pre-recovery", AID_SYSTEM, AID_SYSTEM }, {NULL, 0, 0 } }; @@ -282,7 +286,6 @@ static void write_persistent_property(const char *name, const char *value) static bool is_legal_property_name(const char* name, size_t namelen) { size_t i; - bool previous_was_dot = false; if (namelen >= PROP_NAME_MAX) return false; if (namelen < 1) return false; if (name[0] == '.') return false; @@ -292,11 +295,10 @@ static bool is_legal_property_name(const char* name, size_t namelen) /* Don't allow ".." to appear in a property name */ for (i = 0; i < namelen; i++) { if (name[i] == '.') { - if (previous_was_dot == true) return false; - previous_was_dot = true; + // i=0 is guaranteed to never have a dot. See above. + if (name[i-1] == '.') return false; continue; } - previous_was_dot = false; if (name[i] == '_' || name[i] == '-') continue; if (name[i] >= 'a' && name[i] <= 'z') continue; if (name[i] >= 'A' && name[i] <= 'Z') continue; @@ -369,6 +371,9 @@ void handle_property_set_fd() socklen_t addr_size = sizeof(addr); socklen_t cr_size = sizeof(cr); char * source_ctx = NULL; + struct pollfd ufds[1]; + const int timeout_ms = 2 * 1000; /* Default 2 sec timeout for caller to send property. */ + int nr; if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) { return; @@ -381,7 +386,21 @@ void handle_property_set_fd() return; } - r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), 0)); + ufds[0].fd = s; + ufds[0].events = POLLIN; + ufds[0].revents = 0; + nr = TEMP_FAILURE_RETRY(poll(ufds, 1, timeout_ms)); + if (nr == 0) { + ERROR("sys_prop: timeout waiting for uid=%d to send property message.\n", cr.uid); + close(s); + return; + } else if (nr < 0) { + ERROR("sys_prop: error waiting for uid=%d to send property message. err=%d %s\n", cr.uid, errno, strerror(errno)); + close(s); + return; + } + + r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), MSG_DONTWAIT)); if(r != sizeof(prop_msg)) { ERROR("sys_prop: mis-match msg size received: %d expected: %zu errno: %d\n", r, sizeof(prop_msg), errno); diff --git a/libbacktrace/map_info.c b/libbacktrace/map_info.c new file mode 100644 index 0000000..073b24a --- /dev/null +++ b/libbacktrace/map_info.c @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <pthread.h> +#include <unistd.h> +#include <log/log.h> +#include <sys/time.h> + +#include <backtrace/backtrace.h> + +#if defined(__APPLE__) + +// Mac OS vmmap(1) output: +// __TEXT 0009f000-000a1000 [ 8K 8K] r-x/rwx SM=COW /Volumes/android/dalvik-dev/out/host/darwin-x86/bin/libcorkscrew_test\n +// 012345678901234567890123456789012345678901234567890123456789 +// 0 1 2 3 4 5 +static backtrace_map_info_t* parse_vmmap_line(const char* line) { + unsigned long int start; + unsigned long int end; + char permissions[4]; + int name_pos; + if (sscanf(line, "%*21c %lx-%lx [%*13c] %3c/%*3c SM=%*3c %n", + &start, &end, permissions, &name_pos) != 3) { + return NULL; + } + + const char* name = line + name_pos; + size_t name_len = strlen(name); + + backtrace_map_info_t* mi = calloc(1, sizeof(backtrace_map_info_t) + name_len); + if (mi != NULL) { + mi->start = start; + mi->end = end; + mi->is_readable = permissions[0] == 'r'; + mi->is_writable = permissions[1] == 'w'; + mi->is_executable = permissions[2] == 'x'; + memcpy(mi->name, name, name_len); + mi->name[name_len - 1] = '\0'; + ALOGV("Parsed map: start=0x%08x, end=0x%08x, " + "is_readable=%d, is_writable=%d is_executable=%d, name=%s", + mi->start, mi->end, + mi->is_readable, mi->is_writable, mi->is_executable, mi->name); + } + return mi; +} + +backtrace_map_info_t* backtrace_create_map_info_list(pid_t pid) { + char cmd[1024]; + if (pid < 0) { + pid = getpid(); + } + snprintf(cmd, sizeof(cmd), "vmmap -w -resident -submap -allSplitLibs -interleaved %d", pid); + FILE* fp = popen(cmd, "r"); + if (fp == NULL) { + return NULL; + } + + char line[1024]; + backtrace_map_info_t* milist = NULL; + while (fgets(line, sizeof(line), fp) != NULL) { + backtrace_map_info_t* mi = parse_vmmap_line(line); + if (mi != NULL) { + mi->next = milist; + milist = mi; + } + } + pclose(fp); + return milist; +} + +#else + +// Linux /proc/<pid>/maps lines: +// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so\n +// 012345678901234567890123456789012345678901234567890123456789 +// 0 1 2 3 4 5 +static backtrace_map_info_t* parse_maps_line(const char* line) +{ + unsigned long int start; + unsigned long int end; + char permissions[5]; + int name_pos; + if (sscanf(line, "%lx-%lx %4s %*x %*x:%*x %*d%n", &start, &end, + permissions, &name_pos) != 3) { + return NULL; + } + + while (isspace(line[name_pos])) { + name_pos += 1; + } + const char* name = line + name_pos; + size_t name_len = strlen(name); + if (name_len && name[name_len - 1] == '\n') { + name_len -= 1; + } + + backtrace_map_info_t* mi = calloc(1, sizeof(backtrace_map_info_t) + name_len + 1); + if (mi) { + mi->start = start; + mi->end = end; + mi->is_readable = strlen(permissions) == 4 && permissions[0] == 'r'; + mi->is_writable = strlen(permissions) == 4 && permissions[1] == 'w'; + mi->is_executable = strlen(permissions) == 4 && permissions[2] == 'x'; + memcpy(mi->name, name, name_len); + mi->name[name_len] = '\0'; + ALOGV("Parsed map: start=0x%08x, end=0x%08x, " + "is_readable=%d, is_writable=%d, is_executable=%d, name=%s", + mi->start, mi->end, + mi->is_readable, mi->is_writable, mi->is_executable, mi->name); + } + return mi; +} + +backtrace_map_info_t* backtrace_create_map_info_list(pid_t tid) { + char path[PATH_MAX]; + char line[1024]; + FILE* fp; + backtrace_map_info_t* milist = NULL; + + if (tid < 0) { + tid = getpid(); + } + snprintf(path, PATH_MAX, "/proc/%d/maps", tid); + fp = fopen(path, "r"); + if (fp) { + while(fgets(line, sizeof(line), fp)) { + backtrace_map_info_t* mi = parse_maps_line(line); + if (mi) { + mi->next = milist; + milist = mi; + } + } + fclose(fp); + } + return milist; +} + +#endif + +void backtrace_destroy_map_info_list(backtrace_map_info_t* milist) { + while (milist) { + backtrace_map_info_t* next = milist->next; + free(milist); + milist = next; + } +} + +const backtrace_map_info_t* backtrace_find_map_info( + const backtrace_map_info_t* milist, uintptr_t addr) { + const backtrace_map_info_t* mi = milist; + while (mi && !(addr >= mi->start && addr < mi->end)) { + mi = mi->next; + } + return mi; +} diff --git a/libcutils/properties.c b/libcutils/properties.c index 28d8b2f..b283658 100644 --- a/libcutils/properties.c +++ b/libcutils/properties.c @@ -15,17 +15,95 @@ */ #define LOG_TAG "properties" +// #define LOG_NDEBUG 0 #include <stdlib.h> #include <string.h> +#include <ctype.h> #include <unistd.h> #include <cutils/sockets.h> #include <errno.h> #include <assert.h> #include <cutils/properties.h> +#include <stdbool.h> +#include <inttypes.h> #include "loghack.h" +int8_t property_get_bool(const char *key, int8_t default_value) { + if (!key) { + return default_value; + } + + int8_t result = default_value; + char buf[PROPERTY_VALUE_MAX] = {'\0',}; + + int len = property_get(key, buf, ""); + if (len == 1) { + char ch = buf[0]; + if (ch == '0' || ch == 'n') { + result = false; + } else if (ch == '1' || ch == 'y') { + result = true; + } + } else if (len > 1) { + if (!strcmp(buf, "no") || !strcmp(buf, "false") || !strcmp(buf, "off")) { + result = false; + } else if (!strcmp(buf, "yes") || !strcmp(buf, "true") || !strcmp(buf, "on")) { + result = true; + } + } + + return result; +} + +// Convert string property to int (default if fails); return default value if out of bounds +static intmax_t property_get_imax(const char *key, intmax_t lower_bound, intmax_t upper_bound, + intmax_t default_value) { + if (!key) { + return default_value; + } + + intmax_t result = default_value; + char buf[PROPERTY_VALUE_MAX] = {'\0',}; + char *end = NULL; + + int len = property_get(key, buf, ""); + if (len > 0) { + int tmp = errno; + errno = 0; + + // Infer base automatically + result = strtoimax(buf, &end, /*base*/0); + if ((result == INTMAX_MIN || result == INTMAX_MAX) && errno == ERANGE) { + // Over or underflow + result = default_value; + ALOGV("%s(%s,%" PRIdMAX ") - overflow", __FUNCTION__, key, default_value); + } else if (result < lower_bound || result > upper_bound) { + // Out of range of requested bounds + result = default_value; + ALOGV("%s(%s,%" PRIdMAX ") - out of range", __FUNCTION__, key, default_value); + } else if (end == buf) { + // Numeric conversion failed + result = default_value; + ALOGV("%s(%s,%" PRIdMAX ") - numeric conversion failed", + __FUNCTION__, key, default_value); + } + + errno = tmp; + } + + return result; +} + +int64_t property_get_int64(const char *key, int64_t default_value) { + return (int64_t)property_get_imax(key, INT64_MIN, INT64_MAX, default_value); +} + +int32_t property_get_int32(const char *key, int32_t default_value) { + return (int32_t)property_get_imax(key, INT32_MIN, INT32_MAX, default_value); +} + #ifdef HAVE_LIBC_SYSTEM_PROPERTIES #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ @@ -44,10 +122,13 @@ int property_get(const char *key, char *value, const char *default_value) if(len > 0) { return len; } - if(default_value) { len = strlen(default_value); - memcpy(value, default_value, len + 1); + if (len >= PROPERTY_VALUE_MAX) { + len = PROPERTY_VALUE_MAX - 1; + } + memcpy(value, default_value, len); + value[len] = '\0'; } return len; } diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c index 9f092d6..fa0792f 100644 --- a/libcutils/sched_policy.c +++ b/libcutils/sched_policy.c @@ -39,6 +39,7 @@ static inline SchedPolicy _policy(SchedPolicy p) #if defined(HAVE_ANDROID_OS) && defined(HAVE_SCHED_H) && defined(HAVE_PTHREADS) +#include <linux/prctl.h> #include <sched.h> #include <pthread.h> @@ -54,6 +55,9 @@ static inline SchedPolicy _policy(SchedPolicy p) #define CAN_SET_SP_SYSTEM 0 // non-zero means to implement set_sched_policy(tid, SP_SYSTEM) +// timer slack value in nS enforced when the thread moves to background +#define TIMER_SLACK_BG 40000000 + static pthread_once_t the_once = PTHREAD_ONCE_INIT; static int __sys_supports_schedgroups = -1; @@ -325,6 +329,8 @@ int set_sched_policy(int tid, SchedPolicy policy) ¶m); } + prctl(PR_SET_TIMERSLACK_PID, policy == SP_BACKGROUND ? TIMER_SLACK_BG : 0, tid); + return 0; } diff --git a/libcutils/str_parms.c b/libcutils/str_parms.c index 2e3ce9f..dfe8c4b 100644 --- a/libcutils/str_parms.c +++ b/libcutils/str_parms.c @@ -262,6 +262,10 @@ int str_parms_add_float(struct str_parms *str_parms, const char *key, return ret; } +int str_parms_has_key(struct str_parms *str_parms, const char *key) { + return hashmapGet(str_parms->map, (void *)key) != NULL; +} + int str_parms_get_str(struct str_parms *str_parms, const char *key, char *val, int len) { diff --git a/libcutils/tests/Android.mk b/libcutils/tests/Android.mk new file mode 100644 index 0000000..d3e07f8 --- /dev/null +++ b/libcutils/tests/Android.mk @@ -0,0 +1,32 @@ +# Copyright (C) 2014 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +test_src_files := \ + PropertiesTest.cpp \ + +shared_libraries := \ + libutils \ + liblog + +static_libraries := \ + libcutils + +LOCAL_SHARED_LIBRARIES := $(shared_libraries) +LOCAL_STATIC_LIBRARIES := $(static_libraries) +LOCAL_SRC_FILES := $(test_src_files) +LOCAL_MODULE := libcutils_test +include $(BUILD_NATIVE_TEST) diff --git a/libcutils/tests/PropertiesTest.cpp b/libcutils/tests/PropertiesTest.cpp new file mode 100644 index 0000000..659821c --- /dev/null +++ b/libcutils/tests/PropertiesTest.cpp @@ -0,0 +1,309 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "Properties_test" +#include <utils/Log.h> +#include <gtest/gtest.h> + +#include <cutils/properties.h> +#include <limits.h> +#include <string> +#include <sstream> +#include <iostream> + +namespace android { + +#define STRINGIFY_INNER(x) #x +#define STRINGIFY(x) STRINGIFY_INNER(x) +#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) +#define ASSERT_OK(x) ASSERT_EQ(0, (x)) +#define EXPECT_OK(x) EXPECT_EQ(0, (x)) + +#define PROPERTY_TEST_KEY "libcutils.test.key" +#define PROPERTY_TEST_VALUE_DEFAULT "<<<default_value>>>" + +template <typename T> +static std::string HexString(T value) { + std::stringstream ss; + ss << "0x" << std::hex << std::uppercase << value; + return ss.str(); +} + +template <typename T> +static ::testing::AssertionResult AssertEqualHex(const char *mExpr, + const char *nExpr, + T m, + T n) { + if (m == n) { + return ::testing::AssertionSuccess(); + } + + return ::testing::AssertionFailure() + << mExpr << " and " << nExpr << " (expected: " << HexString(m) << + ", actual: " << HexString(n) << ") are not equal"; +} + +class PropertiesTest : public testing::Test { +public: + PropertiesTest() : mValue() {} +protected: + virtual void SetUp() { + EXPECT_OK(property_set(PROPERTY_TEST_KEY, /*value*/NULL)); + } + + virtual void TearDown() { + EXPECT_OK(property_set(PROPERTY_TEST_KEY, /*value*/NULL)); + } + + char mValue[PROPERTY_VALUE_MAX]; + + template <typename T> + static std::string ToString(T value) { + std::stringstream ss; + ss << value; + + return ss.str(); + } + + // Return length of property read; value is written into mValue + int SetAndGetProperty(const char* value, const char* defaultValue = PROPERTY_TEST_VALUE_DEFAULT) { + EXPECT_OK(property_set(PROPERTY_TEST_KEY, value)) << "value: '" << value << "'"; + return property_get(PROPERTY_TEST_KEY, mValue, defaultValue); + } + + void ResetValue(unsigned char c = 0xFF) { + for (size_t i = 0; i < ARRAY_SIZE(mValue); ++i) { + mValue[i] = (char) c; + } + } +}; + +TEST_F(PropertiesTest, SetString) { + + // Null key -> unsuccessful set + { + // Null key -> fails + EXPECT_GT(0, property_set(/*key*/NULL, PROPERTY_TEST_VALUE_DEFAULT)); + } + + // Null value -> returns default value + { + // Null value -> OK , and it clears the value + EXPECT_OK(property_set(PROPERTY_TEST_KEY, /*value*/NULL)); + ResetValue(); + + // Since the value is null, default value will be returned + int len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT); + EXPECT_EQ(strlen(PROPERTY_TEST_VALUE_DEFAULT), len); + EXPECT_STREQ(PROPERTY_TEST_VALUE_DEFAULT, mValue); + } + + // Trivial case => get returns what was set + { + int len = SetAndGetProperty("hello_world"); + EXPECT_EQ(strlen("hello_world"), len) << "hello_world key"; + EXPECT_STREQ("hello_world", mValue); + ResetValue(); + } + + // Set to empty string => get returns default always + { + const char* EMPTY_STRING_DEFAULT = "EMPTY_STRING"; + int len = SetAndGetProperty("", EMPTY_STRING_DEFAULT); + EXPECT_EQ(strlen(EMPTY_STRING_DEFAULT), len) << "empty key"; + EXPECT_STREQ(EMPTY_STRING_DEFAULT, mValue); + ResetValue(); + } + + // Set to max length => get returns what was set + { + std::string maxLengthString = std::string(PROPERTY_VALUE_MAX-1, 'a'); + + int len = SetAndGetProperty(maxLengthString.c_str()); + EXPECT_EQ(PROPERTY_VALUE_MAX-1, len) << "max length key"; + EXPECT_STREQ(maxLengthString.c_str(), mValue); + ResetValue(); + } + + // Set to max length + 1 => set fails + { + const char* VALID_TEST_VALUE = "VALID_VALUE"; + ASSERT_OK(property_set(PROPERTY_TEST_KEY, VALID_TEST_VALUE)); + + std::string oneLongerString = std::string(PROPERTY_VALUE_MAX, 'a'); + + // Expect that the value set fails since it's too long + EXPECT_GT(0, property_set(PROPERTY_TEST_KEY, oneLongerString.c_str())); + int len = property_get(PROPERTY_TEST_KEY, mValue, PROPERTY_TEST_VALUE_DEFAULT); + + EXPECT_EQ(strlen(VALID_TEST_VALUE), len) << "set should've failed"; + EXPECT_STREQ(VALID_TEST_VALUE, mValue); + ResetValue(); + } +} + +TEST_F(PropertiesTest, GetString) { + + // Try to use a default value that's too long => set fails + { + ASSERT_OK(property_set(PROPERTY_TEST_KEY, "")); + + std::string maxLengthString = std::string(PROPERTY_VALUE_MAX-1, 'a'); + std::string oneLongerString = std::string(PROPERTY_VALUE_MAX, 'a'); + + // Expect that the value is truncated since it's too long (by 1) + int len = property_get(PROPERTY_TEST_KEY, mValue, oneLongerString.c_str()); + EXPECT_EQ(PROPERTY_VALUE_MAX-1, len); + EXPECT_STREQ(maxLengthString.c_str(), mValue); + ResetValue(); + } +} + +TEST_F(PropertiesTest, GetBool) { + /** + * TRUE + */ + const char *valuesTrue[] = { "1", "true", "y", "yes", "on", }; + for (size_t i = 0; i < ARRAY_SIZE(valuesTrue); ++i) { + ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesTrue[i])); + bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/false); + EXPECT_TRUE(val) << "Property should've been TRUE for value: '" << valuesTrue[i] << "'"; + } + + /** + * FALSE + */ + const char *valuesFalse[] = { "0", "false", "n", "no", "off", }; + for (size_t i = 0; i < ARRAY_SIZE(valuesFalse); ++i) { + ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesFalse[i])); + bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/true); + EXPECT_FALSE(val) << "Property shoud've been FALSE For string value: '" << valuesFalse[i] << "'"; + } + + /** + * NEITHER + */ + const char *valuesNeither[] = { "x0", "x1", "2", "-2", "True", "False", "garbage", "", " ", + "+1", " 1 ", " true", " true ", " y ", " yes", "yes ", + "+0", "-0", "00", " 00 ", " false", "false ", + }; + for (size_t i = 0; i < ARRAY_SIZE(valuesNeither); ++i) { + ASSERT_OK(property_set(PROPERTY_TEST_KEY, valuesNeither[i])); + + // The default value should always be used + bool val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/true); + EXPECT_TRUE(val) << "Property should've been NEITHER (true) for string value: '" << valuesNeither[i] << "'"; + + val = property_get_bool(PROPERTY_TEST_KEY, /*default_value*/false); + EXPECT_FALSE(val) << "Property should've been NEITHER (false) for string value: '" << valuesNeither[i] << "'"; + } +} + +TEST_F(PropertiesTest, GetInt64) { + const int64_t DEFAULT_VALUE = INT64_C(0xDEADBEEFBEEFDEAD); + + const std::string longMaxString = ToString(INT64_MAX); + const std::string longStringOverflow = longMaxString + "0"; + + const std::string longMinString = ToString(INT64_MIN); + const std::string longStringUnderflow = longMinString + "0"; + + const char* setValues[] = { + // base 10 + "1", "2", "12345", "-1", "-2", "-12345", + // base 16 + "0xFF", "0x0FF", "0xC0FFEE", + // base 8 + "0", "01234", "07", + // corner cases + " 2", "2 ", "+0", "-0", " +0 ", longMaxString.c_str(), longMinString.c_str(), + // failing cases + NULL, "", " ", " ", "hello", " true ", "y", + longStringOverflow.c_str(), longStringUnderflow.c_str(), + }; + + int64_t getValues[] = { + // base 10 + 1, 2, 12345, -1, -2, -12345, + // base 16 + 0xFF, 0x0FF, 0xC0FFEE, + // base 8 + 0, 01234, 07, + // corner cases + 2, 2, 0, 0, 0, INT64_MAX, INT64_MIN, + // failing cases + DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, + DEFAULT_VALUE, DEFAULT_VALUE, + }; + + ASSERT_EQ(ARRAY_SIZE(setValues), ARRAY_SIZE(getValues)); + + for (size_t i = 0; i < ARRAY_SIZE(setValues); ++i) { + ASSERT_OK(property_set(PROPERTY_TEST_KEY, setValues[i])); + + int64_t val = property_get_int64(PROPERTY_TEST_KEY, DEFAULT_VALUE); + EXPECT_PRED_FORMAT2(AssertEqualHex, getValues[i], val) << "Property was set to '" << setValues[i] << "'"; + } +} + +TEST_F(PropertiesTest, GetInt32) { + const int32_t DEFAULT_VALUE = INT32_C(0xDEADBEEF); + + const std::string intMaxString = ToString(INT32_MAX); + const std::string intStringOverflow = intMaxString + "0"; + + const std::string intMinString = ToString(INT32_MIN); + const std::string intStringUnderflow = intMinString + "0"; + + const char* setValues[] = { + // base 10 + "1", "2", "12345", "-1", "-2", "-12345", + // base 16 + "0xFF", "0x0FF", "0xC0FFEE", "0Xf00", + // base 8 + "0", "01234", "07", + // corner cases + " 2", "2 ", "+0", "-0", " +0 ", intMaxString.c_str(), intMinString.c_str(), + // failing cases + NULL, "", " ", " ", "hello", " true ", "y", + intStringOverflow.c_str(), intStringUnderflow.c_str(), + }; + + int32_t getValues[] = { + // base 10 + 1, 2, 12345, -1, -2, -12345, + // base 16 + 0xFF, 0x0FF, 0xC0FFEE, 0Xf00, + // base 8 + 0, 01234, 07, + // corner cases + 2, 2, 0, 0, 0, INT32_MAX, INT32_MIN, + // failing cases + DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, DEFAULT_VALUE, + DEFAULT_VALUE, DEFAULT_VALUE, + }; + + ASSERT_EQ(ARRAY_SIZE(setValues), ARRAY_SIZE(getValues)); + + for (size_t i = 0; i < ARRAY_SIZE(setValues); ++i) { + ASSERT_OK(property_set(PROPERTY_TEST_KEY, setValues[i])); + + int32_t val = property_get_int32(PROPERTY_TEST_KEY, DEFAULT_VALUE); + EXPECT_PRED_FORMAT2(AssertEqualHex, getValues[i], val) << "Property was set to '" << setValues[i] << "'"; + } +} + +} // namespace android diff --git a/libnetutils/packet.c b/libnetutils/packet.c index be4e0db..3cdefb0 100644 --- a/libnetutils/packet.c +++ b/libnetutils/packet.c @@ -230,6 +230,8 @@ int receive_packet(int s, struct dhcp_msg *msg) packet.udp.check = 0; sum = finish_sum(checksum(&packet, nread, 0)); packet.udp.check = temp; + if (!sum) + sum = finish_sum(sum); if (temp != sum) { ALOGW("UDP header checksum failure (0x%x should be 0x%x)", sum, temp); return -1; diff --git a/libsparse/Android.mk b/libsparse/Android.mk index 9025cc0..4aba168 100644 --- a/libsparse/Android.mk +++ b/libsparse/Android.mk @@ -81,14 +81,17 @@ LOCAL_STATIC_LIBRARIES := \ include $(BUILD_EXECUTABLE) +ifneq ($(HOST_OS),windows) + include $(CLEAR_VARS) -LOCAL_SRC_FILES := simg2simg.c -LOCAL_MODULE := simg2simg +LOCAL_SRC_FILES := append2simg.c +LOCAL_MODULE := append2simg LOCAL_STATIC_LIBRARIES := \ libsparse_host \ libz include $(BUILD_HOST_EXECUTABLE) +endif include $(CLEAR_VARS) LOCAL_MODULE := simg_dump.py diff --git a/libsparse/append2simg.c b/libsparse/append2simg.c new file mode 100644 index 0000000..65e6cc2 --- /dev/null +++ b/libsparse/append2simg.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _FILE_OFFSET_BITS 64 +#define _LARGEFILE64_SOURCE 1 +#define _GNU_SOURCE + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <sparse/sparse.h> +#include "sparse_file.h" +#include "backed_block.h" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#if defined(__APPLE__) && defined(__MACH__) +#define lseek64 lseek +#endif +#if defined(__APPLE__) && defined(__MACH__) +#define lseek64 lseek +#define off64_t off_t +#endif + +void usage() +{ + fprintf(stderr, "Usage: append2simg <output> <input>\n"); +} + +int main(int argc, char *argv[]) +{ + int output; + int output_block; + char *output_path; + struct sparse_file *sparse_output; + + int input; + char *input_path; + off64_t input_len; + + int tmp_fd; + char *tmp_path; + + int ret; + + if (argc == 3) { + output_path = argv[1]; + input_path = argv[2]; + } else { + usage(); + exit(-1); + } + + ret = asprintf(&tmp_path, "%s.append2simg", output_path); + if (ret < 0) { + fprintf(stderr, "Couldn't allocate filename\n"); + exit(-1); + } + + output = open(output_path, O_RDWR | O_BINARY); + if (output < 0) { + fprintf(stderr, "Couldn't open output file (%s)\n", strerror(errno)); + exit(-1); + } + + sparse_output = sparse_file_import_auto(output, true); + if (!sparse_output) { + fprintf(stderr, "Couldn't import output file\n"); + exit(-1); + } + + input = open(input_path, O_RDONLY | O_BINARY); + if (input < 0) { + fprintf(stderr, "Couldn't open input file (%s)\n", strerror(errno)); + exit(-1); + } + + input_len = lseek64(input, 0, SEEK_END); + if (input_len < 0) { + fprintf(stderr, "Couldn't get input file length (%s)\n", strerror(errno)); + exit(-1); + } else if (input_len % sparse_output->block_size) { + fprintf(stderr, "Input file is not a multiple of the output file's block size"); + exit(-1); + } + lseek64(input, 0, SEEK_SET); + + output_block = sparse_output->len / sparse_output->block_size; + if (sparse_file_add_fd(sparse_output, input, 0, input_len, output_block) < 0) { + fprintf(stderr, "Couldn't add input file\n"); + exit(-1); + } + sparse_output->len += input_len; + + tmp_fd = open(tmp_path, O_WRONLY | O_CREAT | O_BINARY, 0664); + if (tmp_fd < 0) { + fprintf(stderr, "Couldn't open temporary file (%s)\n", strerror(errno)); + exit(-1); + } + + lseek64(output, 0, SEEK_SET); + if (sparse_file_write(sparse_output, tmp_fd, false, true, false) < 0) { + fprintf(stderr, "Failed to write sparse file\n"); + exit(-1); + } + + sparse_file_destroy(sparse_output); + close(tmp_fd); + close(output); + close(input); + + ret = rename(tmp_path, output_path); + if (ret < 0) { + fprintf(stderr, "Failed to rename temporary file (%s)\n", strerror(errno)); + exit(-1); + } + + free(tmp_path); + + exit(0); +} diff --git a/libsuspend/autosuspend.c b/libsuspend/autosuspend.c index eb1f66e..edd1007 100644 --- a/libsuspend/autosuspend.c +++ b/libsuspend/autosuspend.c @@ -38,10 +38,13 @@ static int autosuspend_init(void) goto out; } +/* Remove autosleep so userspace can manager suspend/resume and keep stats */ +#if 0 autosuspend_ops = autosuspend_autosleep_init(); if (autosuspend_ops) { goto out; } +#endif autosuspend_ops = autosuspend_wakeup_count_init(); if (autosuspend_ops) { diff --git a/libsuspend/autosuspend_wakeup_count.c b/libsuspend/autosuspend_wakeup_count.c index a88e677..7483a8f 100644 --- a/libsuspend/autosuspend_wakeup_count.c +++ b/libsuspend/autosuspend_wakeup_count.c @@ -25,6 +25,7 @@ #include <unistd.h> #define LOG_TAG "libsuspend" +//#define LOG_NDEBUG 0 #include <cutils/log.h> #include "autosuspend_ops.h" @@ -37,6 +38,7 @@ static int wakeup_count_fd; static pthread_t suspend_thread; static sem_t suspend_lockout; static const char *sleep_state = "mem"; +static void (*wakeup_func)(void) = NULL; static void *suspend_thread_func(void *arg __attribute__((unused))) { @@ -80,6 +82,11 @@ static void *suspend_thread_func(void *arg __attribute__((unused))) if (ret < 0) { strerror_r(errno, buf, sizeof(buf)); ALOGE("Error writing to %s: %s\n", SYS_POWER_STATE, buf); + } else { + void (*func)(void) = wakeup_func; + if (func != NULL) { + (*func)(); + } } } @@ -131,6 +138,15 @@ static int autosuspend_wakeup_count_disable(void) return ret; } +void set_wakeup_callback(void (*func)(void)) +{ + if (wakeup_func != NULL) { + ALOGE("Duplicate wakeup callback applied, keeping original"); + return; + } + wakeup_func = func; +} + struct autosuspend_ops autosuspend_wakeup_count_ops = { .enable = autosuspend_wakeup_count_enable, .disable = autosuspend_wakeup_count_disable, diff --git a/libsuspend/include/suspend/autosuspend.h b/libsuspend/include/suspend/autosuspend.h index f56fc6a..10e3d27 100644 --- a/libsuspend/include/suspend/autosuspend.h +++ b/libsuspend/include/suspend/autosuspend.h @@ -43,6 +43,13 @@ int autosuspend_enable(void); */ int autosuspend_disable(void); +/* + * set_wakeup_callback + * + * Set a function to be called each time the device wakes up from suspend. + */ +void set_wakeup_callback(void (*func)(void)); + __END_DECLS #endif diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c index cd8000a..488dd0e 100644 --- a/libusbhost/usbhost.c +++ b/libusbhost/usbhost.c @@ -454,6 +454,8 @@ char* usb_device_get_string(struct usb_device *device, int id) int i, result; int languageCount = 0; + if (id == 0) return NULL; + string[0] = 0; memset(languages, 0, sizeof(languages)); @@ -487,31 +489,19 @@ char* usb_device_get_string(struct usb_device *device, int id) char* usb_device_get_manufacturer_name(struct usb_device *device) { struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc; - - if (desc->iManufacturer) - return usb_device_get_string(device, desc->iManufacturer); - else - return NULL; + return usb_device_get_string(device, desc->iManufacturer); } char* usb_device_get_product_name(struct usb_device *device) { struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc; - - if (desc->iProduct) - return usb_device_get_string(device, desc->iProduct); - else - return NULL; + return usb_device_get_string(device, desc->iProduct); } char* usb_device_get_serial(struct usb_device *device) { struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc; - - if (desc->iSerialNumber) - return usb_device_get_string(device, desc->iSerialNumber); - else - return NULL; + return usb_device_get_string(device, desc->iSerialNumber); } int usb_device_is_writeable(struct usb_device *device) @@ -557,6 +547,21 @@ int usb_device_connect_kernel_driver(struct usb_device *device, return ioctl(device->fd, USBDEVFS_IOCTL, &ctl); } +int usb_device_set_configuration(struct usb_device *device, int configuration) +{ + return ioctl(device->fd, USBDEVFS_SETCONFIGURATION, &configuration); +} + +int usb_device_set_interface(struct usb_device *device, unsigned int interface, + unsigned int alt_setting) +{ + struct usbdevfs_setinterface ctl; + + ctl.interface = interface; + ctl.altsetting = alt_setting; + return ioctl(device->fd, USBDEVFS_SETINTERFACE, &ctl); +} + int usb_device_control_transfer(struct usb_device *device, int requestType, int request, diff --git a/libutils/Android.mk b/libutils/Android.mk index 1710d36..8e9dfd3 100644 --- a/libutils/Android.mk +++ b/libutils/Android.mk @@ -26,6 +26,7 @@ commonSources:= \ LinearAllocator.cpp \ LinearTransform.cpp \ Log.cpp \ + NativeHandle.cpp \ Printer.cpp \ ProcessCallStack.cpp \ PropertyMap.cpp \ diff --git a/libutils/NativeHandle.cpp b/libutils/NativeHandle.cpp new file mode 100644 index 0000000..e4daca7 --- /dev/null +++ b/libutils/NativeHandle.cpp @@ -0,0 +1,38 @@ +/* + * Copyright 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 <utils/NativeHandle.h> +#include <cutils/native_handle.h> + +namespace android { + +sp<NativeHandle> NativeHandle::create( + native_handle_t* handle, bool ownsHandle) { + return handle ? new NativeHandle(handle, ownsHandle) : NULL; +} + +NativeHandle::NativeHandle(native_handle_t* handle, bool ownsHandle) +: mHandle(handle), mOwnsHandle(ownsHandle) +{} + +NativeHandle::~NativeHandle() { + if (mOwnsHandle) { + native_handle_close(mHandle); + native_handle_delete(mHandle); + } +} + +} // namespace android diff --git a/lmkd/Android.mk b/lmkd/Android.mk index 5d6d1d2..2dd8af2 100644 --- a/lmkd/Android.mk +++ b/lmkd/Android.mk @@ -2,8 +2,8 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES := lmkd.c -LOCAL_STATIC_LIBRARIES := libcutils liblog libm libc -LOCAL_FORCE_STATIC_EXECUTABLE := true +LOCAL_SHARED_LIBRARIES := libcutils liblog libm libc +LOCAL_CFLAGS := -Werror LOCAL_MODULE := lmkd diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c index 376410b..5caf77d 100644 --- a/lmkd/lmkd.c +++ b/lmkd/lmkd.c @@ -16,20 +16,26 @@ #define LOG_TAG "lowmemorykiller" +#include <arpa/inet.h> #include <errno.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> -#include <unistd.h> -#include <arpa/inet.h> +#include <sys/cdefs.h> #include <sys/epoll.h> #include <sys/eventfd.h> #include <sys/socket.h> #include <sys/types.h> -#include <cutils/log.h> +#include <unistd.h> + #include <cutils/sockets.h> +#include <log/log.h> + +#ifndef __unused +#define __unused __attribute__((__unused__)) +#endif #define MEMCG_SYSFS_PATH "/dev/memcg/" #define MEMPRESSURE_WATCH_LEVEL "medium" @@ -75,6 +81,10 @@ static int maxevents; #define OOM_ADJUST_MIN (-16) #define OOM_ADJUST_MAX 15 +/* kernel OOM score values */ +#define OOM_SCORE_ADJ_MIN (-1000) +#define OOM_SCORE_ADJ_MAX 1000 + static int lowmem_adj[MAX_TARGETS]; static int lowmem_minfree[MAX_TARGETS]; static int lowmem_targets_size; @@ -116,6 +126,14 @@ static time_t kill_lasttime; /* PAGE_SIZE / 1024 */ static long page_k; +static int lowmem_oom_adj_to_oom_score_adj(int oom_adj) +{ + if (oom_adj == OOM_ADJUST_MAX) + return OOM_SCORE_ADJ_MAX; + else + return (oom_adj * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE; +} + static struct proc *pid_lookup(int pid) { struct proc *procp; @@ -219,8 +237,8 @@ static void cmd_procprio(int pid, int oomadj) { return; } - snprintf(path, sizeof(path), "/proc/%d/oom_adj", pid); - snprintf(val, sizeof(val), "%d", oomadj); + snprintf(path, sizeof(path), "/proc/%d/oom_score_adj", pid); + snprintf(val, sizeof(val), "%d", lowmem_oom_adj_to_oom_score_adj(oomadj)); writefilestring(path, val); if (use_inkernel_interface) @@ -245,8 +263,6 @@ static void cmd_procprio(int pid, int oomadj) { } static void cmd_procremove(int pid) { - struct proc *procp; - if (use_inkernel_interface) return; @@ -370,7 +386,7 @@ static void ctrl_data_handler(uint32_t events) { } } -static void ctrl_connect_handler(uint32_t events) { +static void ctrl_connect_handler(uint32_t events __unused) { struct sockaddr addr; socklen_t alen; struct epoll_event epev; @@ -412,7 +428,7 @@ static int zoneinfo_parse_protection(char *cp) { return 0; if (zoneval > max) max = zoneval; - } while (cp = strtok(NULL, " ")); + } while ((cp = strtok(NULL, " "))); return max; } @@ -443,7 +459,6 @@ static void zoneinfo_parse_line(char *line, struct sysmeminfo *mip) { static int zoneinfo_parse(struct sysmeminfo *mip) { FILE *f; - char *cp; char line[LINE_MAX]; memset(mip, 0, sizeof(struct sysmeminfo)); @@ -507,7 +522,7 @@ static struct proc *proc_adj_lru(int oomadj) { return (struct proc *)adjslot_tail(&procadjslot_list[ADJTOSLOT(oomadj)]); } -static void mp_event(uint32_t events) { +static void mp_event(uint32_t events __unused) { int i; int ret; unsigned long long evcount; @@ -726,7 +741,7 @@ static void mainloop(void) { } } -int main(int argc, char **argv) { +int main(int argc __unused, char **argv __unused) { if (!init()) mainloop(); diff --git a/rootdir/init.rc b/rootdir/init.rc index b5abfb0..b0cd45a 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -12,7 +12,7 @@ import /init.trace.rc on early-init # Set init and its forked children's oom_adj. - write /proc/1/oom_adj -16 + write /proc/1/oom_score_adj -1000 # Apply strict SELinux checking of PROT_EXEC on mmap/mprotect calls. write /sys/fs/selinux/checkreqprot 0 @@ -303,9 +303,9 @@ on boot write /proc/sys/vm/overcommit_memory 1 write /proc/sys/vm/min_free_order_shift 4 chown root system /sys/module/lowmemorykiller/parameters/adj - chmod 0664 /sys/module/lowmemorykiller/parameters/adj + chmod 0220 /sys/module/lowmemorykiller/parameters/adj chown root system /sys/module/lowmemorykiller/parameters/minfree - chmod 0664 /sys/module/lowmemorykiller/parameters/minfree + chmod 0220 /sys/module/lowmemorykiller/parameters/minfree # Tweak background writeout write /proc/sys/vm/dirty_expire_centisecs 200 @@ -394,11 +394,19 @@ on boot setprop net.tcp.default_init_rwnd 60 class_start core - class_start main on nonencrypted + class_start main class_start late_start +on property:vold.decrypt=trigger_default_encryption + start defaultcrypto + +on property:vold.decrypt=trigger_encryption + start surfaceflinger + start encrypt + class_start main + on charger class_start charger @@ -454,11 +462,6 @@ service healthd /sbin/healthd critical seclabel u:r:healthd:s0 -service healthd-charger /sbin/healthd -n - class charger - critical - seclabel u:r:healthd:s0 - service console /system/bin/sh class core console @@ -495,6 +498,7 @@ service servicemanager /system/bin/servicemanager onrestart restart zygote onrestart restart media onrestart restart surfaceflinger + onrestart restart inputflinger onrestart restart drm service vold /system/bin/vold @@ -527,6 +531,12 @@ service surfaceflinger /system/bin/surfaceflinger group graphics drmrpc onrestart restart zygote +service inputflinger /system/bin/inputflinger + class main + user system + group input + onrestart restart zygote + service drm /system/bin/drmserver class main user drm @@ -538,6 +548,20 @@ service media /system/bin/mediaserver group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm ioprio rt 4 +# One shot invocation to deal with encrypted volume. +service defaultcrypto /system/bin/vdc --wait cryptfs mountdefaultencrypted + disabled + oneshot + # vold will set vold.decrypt to trigger_restart_framework (default + # encryption) or trigger_restart_min_framework (other encryption) + +# One shot invocation to encrypt unencrypted volumes +service encrypt /system/bin/vdc --wait cryptfs enablecrypto inplace default + disabled + oneshot + # vold will set vold.decrypt to trigger_restart_framework (default + # encryption) + service bootanim /system/bin/bootanimation class main user graphics @@ -549,7 +573,7 @@ service installd /system/bin/installd class main socket installd stream 600 system system -service flash_recovery /system/etc/install-recovery.sh +service flash_recovery /system/bin/install-recovery.sh class main oneshot @@ -591,3 +615,8 @@ service mdnsd /system/bin/mdnsd socket mdnsd stream 0660 mdnsr inet disabled oneshot + +service pre-recovery /system/bin/uncrypt + class main + disabled + oneshot diff --git a/toolbox/Android.mk b/toolbox/Android.mk index 5383b83..26bb17b 100644 --- a/toolbox/Android.mk +++ b/toolbox/Android.mk @@ -68,7 +68,9 @@ TOOLS := \ swapon \ swapoff \ mkswap \ - readlink + readlink \ + mknod \ + nohup ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT))) TOOLS += r diff --git a/toolbox/getevent.c b/toolbox/getevent.c index ed381f5..c979c99 100644 --- a/toolbox/getevent.c +++ b/toolbox/getevent.c @@ -295,6 +295,7 @@ static int open_device(const char *device, int print_flags) { int version; int fd; + int clkid = CLOCK_MONOTONIC; struct pollfd *new_ufds; char **new_device_names; char name[80]; @@ -335,6 +336,11 @@ static int open_device(const char *device, int print_flags) idstr[0] = '\0'; } + if (ioctl(fd, EVIOCSCLOCKID, &clkid) != 0) { + fprintf(stderr, "Can't enable monotonic clock reporting: %s\n", strerror(errno)); + // a non-fatal error + } + new_ufds = realloc(ufds, sizeof(ufds[0]) * (nfds + 1)); if(new_ufds == NULL) { fprintf(stderr, "out of memory\n"); @@ -470,9 +476,9 @@ static int scan_dir(const char *dirname, int print_flags) return 0; } -static void usage(int argc, char *argv[]) +static void usage(char *name) { - fprintf(stderr, "Usage: %s [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-d] [-p] [-i] [-l] [-q] [-c count] [-r] [device]\n", argv[0]); + fprintf(stderr, "Usage: %s [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-d] [-p] [-i] [-l] [-q] [-c count] [-r] [device]\n", name); fprintf(stderr, " -t: show time stamps\n"); fprintf(stderr, " -n: don't print newlines\n"); fprintf(stderr, " -s: print switch states for given bits\n"); @@ -570,7 +576,7 @@ int getevent_main(int argc, char *argv[]) fprintf(stderr, "%s: invalid option -%c\n", argv[0], optopt); case 'h': - usage(argc, argv); + usage(argv[0]); exit(1); } } while (1); @@ -582,7 +588,7 @@ int getevent_main(int argc, char *argv[]) optind++; } if (optind != argc) { - usage(argc, argv); + usage(argv[0]); exit(1); } nfds = 1; diff --git a/toolbox/ioctl.c b/toolbox/ioctl.c index fb555d2..fd24885 100644 --- a/toolbox/ioctl.c +++ b/toolbox/ioctl.c @@ -63,10 +63,14 @@ int ioctl_main(int argc, char *argv[]) exit(1); } - fd = open(argv[optind], O_RDWR | O_SYNC); - if (fd < 0) { - fprintf(stderr, "cannot open %s\n", argv[optind]); - return 1; + if (!strcmp(argv[optind], "-")) { + fd = STDIN_FILENO; + } else { + fd = open(argv[optind], read_only ? O_RDONLY : (O_RDWR | O_SYNC)); + if (fd < 0) { + fprintf(stderr, "cannot open %s\n", argv[optind]); + return 1; + } } optind++; diff --git a/toolbox/mknod.c b/toolbox/mknod.c new file mode 100644 index 0000000..0fedece --- /dev/null +++ b/toolbox/mknod.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2014, The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google, Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/stat.h> + +static int print_usage() { + fprintf(stderr, "mknod <path> [b|c|u|p] <major> <minor>\n"); + return EXIT_FAILURE; +} + +int mknod_main(int argc, char **argv) { + char *path = NULL; + int major = 0; + int minor = 0; + int args = 0; + mode_t mode = 0660; + + /* Check correct argument count is 3 or 5 */ + if (argc != 3 && argc != 5) { + fprintf(stderr, "Incorrect argument count\n"); + return print_usage(); + } + + path = argv[1]; + + const char node_type = *argv[2]; + switch (node_type) { + case 'b': + mode |= S_IFBLK; + args = 5; + break; + case 'c': + case 'u': + mode |= S_IFCHR; + args = 5; + break; + case 'p': + mode |= S_IFIFO; + args = 3; + break; + default: + fprintf(stderr, "Invalid node type '%c'\n", node_type); + return print_usage(); + } + + if (argc != args) { + if (args == 5) { + fprintf(stderr, "Node type '%c' requires <major> and <minor>\n", node_type); + } else { + fprintf(stderr, "Node type '%c' does not require <major> and <minor>\n", node_type); + } + return print_usage(); + } + + if (args == 5) { + major = atoi(argv[3]); + minor = atoi(argv[4]); + } + + if (mknod(path, mode, makedev(major, minor))) { + perror("Unable to create node"); + return EXIT_FAILURE; + } + return 0; +} diff --git a/toolbox/nohup.c b/toolbox/nohup.c new file mode 100644 index 0000000..363999d --- /dev/null +++ b/toolbox/nohup.c @@ -0,0 +1,26 @@ +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +int nohup_main(int argc, char *argv[]) +{ + if (argc < 2) { + fprintf(stderr, "Usage: %s [-n] program args...\n", argv[0]); + return EXIT_FAILURE; + } + signal(SIGHUP, SIG_IGN); + argv++; + if (strcmp(argv[0], "-n") == 0) { + argv++; + signal(SIGINT, SIG_IGN); + signal(SIGSTOP, SIG_IGN); + signal(SIGTTIN, SIG_IGN); + signal(SIGTTOU, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGTERM, SIG_IGN); + } + execvp(argv[0], argv); + perror(argv[0]); + return EXIT_FAILURE; +} diff --git a/toolbox/ps.c b/toolbox/ps.c index 7c35ccb..de141fc 100644 --- a/toolbox/ps.c +++ b/toolbox/ps.c @@ -28,6 +28,7 @@ static char *nexttok(char **strp) #define SHOW_POLICY 4 #define SHOW_CPU 8 #define SHOW_MACLABEL 16 +#define SHOW_NUMERIC_UID 32 static int display_flags = 0; @@ -45,7 +46,7 @@ static int ps_line(int pid, int tid, char *namefilter) unsigned utime, stime; int prio, nice, rtprio, sched, psr; struct passwd *pw; - + sprintf(statline, "/proc/%d", pid); stat(statline, &stats); @@ -67,7 +68,7 @@ static int ps_line(int pid, int tid, char *namefilter) } cmdline[r] = 0; } - + fd = open(statline, O_RDONLY); if(fd == 0) return -1; r = read(fd, statline, 1023); @@ -89,7 +90,7 @@ static int ps_line(int pid, int tid, char *namefilter) nexttok(&ptr); // pgrp nexttok(&ptr); // sid tty = atoi(nexttok(&ptr)); - + nexttok(&ptr); // tpgid nexttok(&ptr); // flags nexttok(&ptr); // minflt @@ -129,21 +130,21 @@ static int ps_line(int pid, int tid, char *namefilter) psr = atoi(nexttok(&ptr)); // processor rtprio = atoi(nexttok(&ptr)); // rt_priority sched = atoi(nexttok(&ptr)); // scheduling policy - + tty = atoi(nexttok(&ptr)); - + if(tid != 0) { ppid = pid; pid = tid; } pw = getpwuid(stats.st_uid); - if(pw == 0) { + if(pw == 0 || (display_flags & SHOW_NUMERIC_UID)) { sprintf(user,"%d",(int)stats.st_uid); } else { strcpy(user,pw->pw_name); } - + if(!namefilter || !strncmp(name, namefilter, strlen(namefilter))) { if (display_flags & SHOW_MACLABEL) { fd = open(macline, O_RDONLY); @@ -189,7 +190,7 @@ void ps_threads(int pid, char *namefilter) sprintf(tmp,"/proc/%d/task",pid); d = opendir(tmp); if(d == 0) return; - + while((de = readdir(d)) != 0){ if(isdigit(de->d_name[0])){ int tid = atoi(de->d_name); @@ -197,7 +198,7 @@ void ps_threads(int pid, char *namefilter) ps_line(pid, tid, namefilter); } } - closedir(d); + closedir(d); } int ps_main(int argc, char **argv) @@ -207,13 +208,15 @@ int ps_main(int argc, char **argv) char *namefilter = 0; int pidfilter = 0; int threads = 0; - + d = opendir("/proc"); if(d == 0) return -1; while(argc > 1){ if(!strcmp(argv[1],"-t")) { threads = 1; + } else if(!strcmp(argv[1],"-n")) { + display_flags |= SHOW_NUMERIC_UID; } else if(!strcmp(argv[1],"-x")) { display_flags |= SHOW_TIME; } else if(!strcmp(argv[1], "-Z")) { |