am fe0d5d42: am 5434bf66: Merge "LP64: Enable debuggerd/libbacktrace/libunwind."
* commit 'fe0d5d42e4ca8b77d6a0657be1b8b6343c21d689':
LP64: Enable debuggerd/libbacktrace/libunwind.
diff --git a/adb/file_sync_service.c b/adb/file_sync_service.c
index 577fb8f..c3eb905 100644
--- a/adb/file_sync_service.c
+++ b/adb/file_sync_service.c
@@ -339,11 +339,14 @@
if(!tmp || errno) {
mode = 0644;
is_link = 0;
+ } else {
+ struct stat st;
+ /* Don't delete files before copying if they are not "regular" */
+ if(lstat(path, &st) || S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
+ adb_unlink(path);
+ }
}
- adb_unlink(path);
-
-
#ifdef HAVE_SYMLINKS
if(is_link)
ret = handle_send_link(s, path, buffer);
diff --git a/charger/Android.mk b/charger/Android.mk
deleted file mode 100644
index b9d3473..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 libpixelflinger_static 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/charger/charger.c b/charger/charger.c
deleted file mode 100644
index 66ddeaf..0000000
--- a/charger/charger.c
+++ /dev/null
@@ -1,1015 +0,0 @@
-/*
- * Copyright (C) 2011 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 DEBUG_UEVENTS
-#define CHARGER_KLOG_LEVEL 6
-
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/input.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/poll.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <sys/socket.h>
-#include <linux/netlink.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>
-#endif
-
-#include "minui/minui.h"
-
-#ifndef max
-#define max(a,b) ((a) > (b) ? (a) : (b))
-#endif
-
-#ifndef min
-#define min(a,b) ((a) < (b) ? (a) : (b))
-#endif
-
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
-
-#define MSEC_PER_SEC (1000LL)
-#define NSEC_PER_MSEC (1000000LL)
-
-#define BATTERY_UNKNOWN_TIME (2 * MSEC_PER_SEC)
-#define POWER_ON_KEY_TIME (2 * MSEC_PER_SEC)
-#define UNPLUGGED_SHUTDOWN_TIME (10 * MSEC_PER_SEC)
-
-#define BATTERY_FULL_THRESH 95
-
-#define LAST_KMSG_PATH "/proc/last_kmsg"
-#define LAST_KMSG_MAX_SZ (32 * 1024)
-
-#define LOGE(x...) do { KLOG_ERROR("charger", x); } while (0)
-#define LOGI(x...) do { KLOG_INFO("charger", x); } while (0)
-#define LOGV(x...) do { KLOG_DEBUG("charger", x); } while (0)
-
-struct key_state {
- bool pending;
- bool down;
- 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 {
- const char *name;
- int disp_time;
- int min_capacity;
- bool level_only;
-
- gr_surface surface;
-};
-
-struct animation {
- bool run;
-
- struct frame *frames;
- int cur_frame;
- int num_frames;
-
- int cur_cycle;
- int num_cycles;
-
- /* current capacity being animated */
- int capacity;
-};
-
-struct charger {
- 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[] = {
- {
- .name = "charger/battery_0",
- .disp_time = 750,
- .min_capacity = 0,
- },
- {
- .name = "charger/battery_1",
- .disp_time = 750,
- .min_capacity = 20,
- },
- {
- .name = "charger/battery_2",
- .disp_time = 750,
- .min_capacity = 40,
- },
- {
- .name = "charger/battery_3",
- .disp_time = 750,
- .min_capacity = 60,
- },
- {
- .name = "charger/battery_4",
- .disp_time = 750,
- .min_capacity = 80,
- .level_only = true,
- },
- {
- .name = "charger/battery_5",
- .disp_time = 750,
- .min_capacity = BATTERY_FULL_THRESH,
- },
-};
-
-static struct animation battery_animation = {
- .frames = batt_anim_frames,
- .num_frames = ARRAY_SIZE(batt_anim_frames),
- .num_cycles = 3,
-};
-
-static struct charger charger_state = {
- .batt_anim = &battery_animation,
-};
-
-static int char_width;
-static int char_height;
-
-/* current time in milliseconds */
-static int64_t curr_time_ms(void)
-{
- struct timespec tm;
- clock_gettime(CLOCK_MONOTONIC, &tm);
- return tm.tv_sec * MSEC_PER_SEC + (tm.tv_nsec / NSEC_PER_MSEC);
-}
-
-static void clear_screen(void)
-{
- gr_color(0, 0, 0, 255);
- gr_fill(0, 0, gr_fb_width(), gr_fb_height());
-};
-
-#define MAX_KLOG_WRITE_BUF_SZ 256
-
-static void dump_last_kmsg(void)
-{
- char *buf;
- char *ptr;
- unsigned sz = 0;
- int len;
-
- LOGI("\n");
- LOGI("*************** LAST KMSG ***************\n");
- LOGI("\n");
- buf = 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);
- ptr = buf + (sz - len);
-
- while (len > 0) {
- int cnt = min(len, MAX_KLOG_WRITE_BUF_SZ);
- char yoink;
- char *nl;
-
- nl = memrchr(ptr, '\n', cnt - 1);
- if (nl)
- cnt = nl - ptr + 1;
-
- yoink = ptr[cnt];
- ptr[cnt] = '\0';
- klog_write(6, "<6>%s", ptr);
- ptr[cnt] = yoink;
-
- len -= cnt;
- ptr += cnt;
- }
-
- free(buf);
-
-out:
- LOGI("\n");
- LOGI("************* END LAST KMSG *************\n");
- 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)
-{
- 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);
-}
-
-#ifdef CHARGER_ENABLE_SUSPEND
-static int request_suspend(bool enable)
-{
- if (enable)
- return autosuspend_enable();
- else
- return autosuspend_disable();
-}
-#else
-static int request_suspend(bool enable)
-{
- return 0;
-}
-#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);
-
- if (x < 0)
- x = (gr_fb_width() - str_len_px) / 2;
- if (y < 0)
- y = (gr_fb_height() - char_height) / 2;
- gr_text(x, y, str, 0);
-
- return y + char_height;
-}
-
-static void android_green(void)
-{
- gr_color(0xa4, 0xc6, 0x39, 255);
-}
-
-/* returns the last y-offset of where the surface ends */
-static int draw_surface_centered(struct charger *charger, gr_surface surface)
-{
- int w;
- int h;
- int x;
- int y;
-
- w = gr_get_width(surface);
- h = gr_get_height(surface);
- x = (gr_fb_width() - w) / 2 ;
- y = (gr_fb_height() - h) / 2 ;
-
- LOGV("drawing surface %dx%d+%d+%d\n", w, h, x, y);
- gr_blit(surface, 0, 0, w, h, x, y);
- return y + h;
-}
-
-static void draw_unknown(struct charger *charger)
-{
- int y;
- if (charger->surf_unknown) {
- draw_surface_centered(charger, charger->surf_unknown);
- } else {
- android_green();
- y = draw_text("Charging!", -1, -1);
- draw_text("?\?/100", -1, y + 25);
- }
-}
-
-static void draw_battery(struct charger *charger)
-{
- struct animation *batt_anim = charger->batt_anim;
- struct frame *frame = &batt_anim->frames[batt_anim->cur_frame];
-
- if (batt_anim->num_frames != 0) {
- draw_surface_centered(charger, frame->surface);
- LOGV("drawing frame #%d name=%s min_cap=%d time=%d\n",
- batt_anim->cur_frame, frame->name, frame->min_capacity,
- frame->disp_time);
- }
-}
-
-static void redraw_screen(struct charger *charger)
-{
- struct animation *batt_anim = charger->batt_anim;
-
- clear_screen();
-
- /* try to display *something* */
- if (batt_anim->capacity < 0 || batt_anim->num_frames == 0)
- draw_unknown(charger);
- else
- draw_battery(charger);
- gr_flip();
-}
-
-static void kick_animation(struct animation *anim)
-{
- anim->run = true;
-}
-
-static void reset_animation(struct animation *anim)
-{
- anim->cur_cycle = 0;
- anim->cur_frame = 0;
- anim->run = false;
-}
-
-static void update_screen_state(struct charger *charger, int64_t now)
-{
- struct animation *batt_anim = charger->batt_anim;
- int cur_frame;
- int disp_time;
-
- if (!batt_anim->run || now < charger->next_screen_transition)
- return;
-
- /* animation is over, blank screen and leave */
- if (batt_anim->cur_cycle == batt_anim->num_cycles) {
- reset_animation(batt_anim);
- charger->next_screen_transition = -1;
- gr_fb_blank(true);
- LOGV("[%lld] animation done\n", now);
- if (charger->num_supplies_online > 0)
- request_suspend(true);
- return;
- }
-
- disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time;
-
- /* animation starting, set up the animation */
- if (batt_anim->cur_frame == 0) {
- int batt_cap;
- int ret;
-
- LOGV("[%lld] animation starting\n", now);
- batt_cap = get_battery_capacity(charger);
- if (batt_cap >= 0 && batt_anim->num_frames != 0) {
- int i;
-
- /* find first frame given current capacity */
- for (i = 1; i < batt_anim->num_frames; i++) {
- if (batt_cap < batt_anim->frames[i].min_capacity)
- break;
- }
- batt_anim->cur_frame = i - 1;
-
- /* show the first frame for twice as long */
- disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time * 2;
- }
-
- batt_anim->capacity = batt_cap;
- }
-
- /* unblank the screen on first cycle */
- if (batt_anim->cur_cycle == 0)
- gr_fb_blank(false);
-
- /* draw the new frame (@ cur_frame) */
- redraw_screen(charger);
-
- /* if we don't have anim frames, we only have one image, so just bump
- * the cycle counter and exit
- */
- if (batt_anim->num_frames == 0 || batt_anim->capacity < 0) {
- LOGV("[%lld] animation missing or unknown battery status\n", now);
- charger->next_screen_transition = now + BATTERY_UNKNOWN_TIME;
- batt_anim->cur_cycle++;
- return;
- }
-
- /* schedule next screen transition */
- charger->next_screen_transition = now + disp_time;
-
- /* advance frame cntr to the next valid frame
- * if necessary, advance cycle cntr, and reset frame cntr
- */
- batt_anim->cur_frame++;
-
- /* if the frame is used for level-only, that is only show it when it's
- * the current level, skip it during the animation.
- */
- while (batt_anim->cur_frame < batt_anim->num_frames &&
- batt_anim->frames[batt_anim->cur_frame].level_only)
- batt_anim->cur_frame++;
- if (batt_anim->cur_frame >= batt_anim->num_frames) {
- batt_anim->cur_cycle++;
- batt_anim->cur_frame = 0;
-
- /* don't reset the cycle counter, since we use that as a signal
- * in a test above to check if animation is over
- */
- }
-}
-
-static int set_key_callback(int code, int value, void *data)
-{
- struct charger *charger = data;
- int64_t now = curr_time_ms();
- int down = !!value;
-
- if (code > KEY_MAX)
- return -1;
-
- /* ignore events that don't modify our state */
- if (charger->keys[code].down == down)
- return 0;
-
- /* only record the down even timestamp, as the amount
- * of time the key spent not being pressed is not useful */
- if (down)
- charger->keys[code].timestamp = now;
- charger->keys[code].down = down;
- charger->keys[code].pending = true;
- if (down) {
- LOGV("[%lld] key[%d] down\n", now, code);
- } else {
- int64_t duration = now - charger->keys[code].timestamp;
- int64_t secs = duration / 1000;
- int64_t msecs = duration - secs * 1000;
- LOGV("[%lld] key[%d] up (was down for %lld.%lldsec)\n", now,
- code, secs, msecs);
- }
-
- return 0;
-}
-
-static void update_input_state(struct charger *charger,
- struct input_event *ev)
-{
- if (ev->type != EV_KEY)
- return;
- set_key_callback(ev->code, ev->value, charger);
-}
-
-static void set_next_key_check(struct charger *charger,
- struct key_state *key,
- int64_t timeout)
-{
- int64_t then = key->timestamp + timeout;
-
- if (charger->next_key_check == -1 || then < charger->next_key_check)
- charger->next_key_check = then;
-}
-
-static void process_key(struct charger *charger, int code, int64_t now)
-{
- struct key_state *key = &charger->keys[code];
- int64_t next_key_check;
-
- if (code == KEY_POWER) {
- if (key->down) {
- int64_t reboot_timeout = key->timestamp + POWER_ON_KEY_TIME;
- if (now >= reboot_timeout) {
- LOGI("[%lld] rebooting\n", now);
- android_reboot(ANDROID_RB_RESTART, 0, 0);
- } else {
- /* if the key is pressed but timeout hasn't expired,
- * make sure we wake up at the right-ish time to check
- */
- set_next_key_check(charger, key, POWER_ON_KEY_TIME);
- }
- } else {
- /* if the power key got released, force screen state cycle */
- if (key->pending) {
- request_suspend(false);
- kick_animation(charger->batt_anim);
- }
- }
- }
-
- key->pending = false;
-}
-
-static void handle_input_state(struct charger *charger, int64_t now)
-{
- process_key(charger, KEY_POWER, now);
-
- if (charger->next_key_check != -1 && now > charger->next_key_check)
- charger->next_key_check = -1;
-}
-
-static void handle_power_supply_state(struct charger *charger, int64_t now)
-{
- if (charger->num_supplies_online == 0) {
- request_suspend(false);
- if (charger->next_pwr_check == -1) {
- charger->next_pwr_check = now + UNPLUGGED_SHUTDOWN_TIME;
- LOGI("[%lld] device unplugged: shutting down in %lld (@ %lld)\n",
- now, UNPLUGGED_SHUTDOWN_TIME, charger->next_pwr_check);
- } else if (now >= charger->next_pwr_check) {
- LOGI("[%lld] shutting down\n", now);
- android_reboot(ANDROID_RB_POWEROFF, 0, 0);
- } else {
- /* otherwise we already have a shutdown timer scheduled */
- }
- } else {
- /* online supply present, reset shutdown timer if set */
- if (charger->next_pwr_check != -1) {
- LOGI("[%lld] device plugged in: shutdown cancelled\n", now);
- kick_animation(charger->batt_anim);
- }
- charger->next_pwr_check = -1;
- }
-}
-
-static void wait_next_event(struct charger *charger, int64_t now)
-{
- int64_t next_event = INT64_MAX;
- int64_t timeout;
- struct input_event ev;
- int ret;
-
- LOGV("[%lld] next screen: %lld next key: %lld next pwr: %lld\n", now,
- charger->next_screen_transition, charger->next_key_check,
- charger->next_pwr_check);
-
- if (charger->next_screen_transition != -1)
- next_event = charger->next_screen_transition;
- if (charger->next_key_check != -1 && charger->next_key_check < next_event)
- next_event = charger->next_key_check;
- if (charger->next_pwr_check != -1 && charger->next_pwr_check < next_event)
- next_event = charger->next_pwr_check;
-
- if (next_event != -1 && next_event != INT64_MAX)
- 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();
-}
-
-static int input_callback(int fd, short revents, void *data)
-{
- struct charger *charger = data;
- struct input_event ev;
- int ret;
-
- ret = ev_get_input(fd, revents, &ev);
- if (ret)
- return -1;
- update_input_state(charger, &ev);
- return 0;
-}
-
-static void event_loop(struct charger *charger)
-{
- 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);
- }
-}
-
-int main(int argc, char **argv)
-{
- 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);
-
- dump_last_kmsg();
-
- LOGI("--------------- STARTING CHARGER MODE ---------------\n");
-
- 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);
- }
- charger->uevent_fd = fd;
- coldboot(charger, "/sys/class/power_supply", "add");
-
- ret = res_create_surface("charger/battery_fail", &charger->surf_unknown);
- if (ret < 0) {
- LOGE("Cannot load image\n");
- charger->surf_unknown = NULL;
- }
-
- for (i = 0; i < charger->batt_anim->num_frames; i++) {
- struct frame *frame = &charger->batt_anim->frames[i];
-
- ret = res_create_surface(frame->name, &frame->surface);
- if (ret < 0) {
- LOGE("Cannot load image %s\n", frame->name);
- /* TODO: free the already allocated surfaces... */
- charger->batt_anim->num_frames = 0;
- charger->batt_anim->num_cycles = 1;
- break;
- }
- }
-
- ev_sync_key_state(set_key_callback, charger);
-
-#ifndef CHARGER_DISABLE_INIT_BLANK
- gr_fb_blank(true);
-#endif
-
- charger->next_screen_transition = now - 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/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index b66890e..cf780d1 100755
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -453,14 +453,14 @@
// 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));
@@ -471,6 +471,7 @@
while (true) {
ssize_t actual = android_logger_list_read(logger_list, &log_entry);
+ struct logger_entry* entry;
if (actual < 0) {
if (actual == -EINTR) {
@@ -480,8 +481,7 @@
// 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) {
@@ -494,16 +494,11 @@
// 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;
}
@@ -516,7 +511,7 @@
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;
@@ -524,7 +519,7 @@
// 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] : '?');
@@ -548,7 +543,6 @@
_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));
}
@@ -557,7 +551,7 @@
// 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/fastboot/fastboot.c b/fastboot/fastboot.c
index 73a6e56..7d26c6f 100644
--- a/fastboot/fastboot.c
+++ b/fastboot/fastboot.c
@@ -889,6 +889,7 @@
{"kernel_offset", required_argument, 0, 'k'},
{"page_size", required_argument, 0, 'n'},
{"ramdisk_offset", required_argument, 0, 'r'},
+ {"tags_offset", required_argument, 0, 't'},
{"help", 0, 0, 'h'},
{0, 0, 0, 0}
};
@@ -897,7 +898,7 @@
while (1) {
int option_index = 0;
- c = getopt_long(argc, argv, "wub:k:n:r:s:S:lp:c:i:m:h", longopts, NULL);
+ c = getopt_long(argc, argv, "wub:k:n:r:t:s:S:lp:c:i:m:h", longopts, NULL);
if (c < 0) {
break;
}
@@ -938,6 +939,9 @@
case 'r':
ramdisk_offset = strtoul(optarg, 0, 16);
break;
+ case 't':
+ tags_offset = strtoul(optarg, 0, 16);
+ break;
case 's':
serial = optarg;
break;
diff --git a/healthd/Android.mk b/healthd/Android.mk
index 473d375..5cd5ce1 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -13,6 +13,8 @@
LOCAL_SRC_FILES := \
healthd.cpp \
+ healthd_mode_android.cpp \
+ healthd_mode_charger.cpp \
BatteryMonitor.cpp \
BatteryPropertiesRegistrar.cpp
@@ -22,9 +24,57 @@
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 libpixelflinger_static 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..3e6a4b1 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 @@
}
bool BatteryMonitor::update(void) {
- struct BatteryProperties props;
bool logthis;
props.chargerAcOnline = false;
@@ -178,23 +177,15 @@
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 @@
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 @@
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,91 @@
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;
+
+ 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 +378,8 @@
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 +435,14 @@
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 +485,25 @@
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 @@
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..58da4ee 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>
+#include "healthd.h"
+
namespace android {
-BatteryPropertiesRegistrar::BatteryPropertiesRegistrar(BatteryMonitor* monitor) {
- mBatteryMonitor = monitor;
-}
-
void BatteryPropertiesRegistrar::publish() {
- defaultServiceManager()->addService(String16("batterypropreg"), this);
+ defaultServiceManager()->addService(String16("batteryproperties"), this);
}
void BatteryPropertiesRegistrar::notifyListeners(struct BatteryProperties props) {
@@ -53,7 +54,7 @@
mListeners.add(listener);
listener->asBinder()->linkToDeath(this);
}
- mBatteryMonitor->update();
+ healthd_battery_update();
}
void BatteryPropertiesRegistrar::unregisterListener(const sp<IBatteryPropertiesListener>& listener) {
@@ -67,6 +68,23 @@
}
}
+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 @@
.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 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 @@
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 @@
-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 @@
while (*cp) {
if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {
- battery_update();
+ healthd_battery_update();
break;
}
@@ -154,6 +232,31 @@
}
}
+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;
+ }
+
+ 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(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");
+ return;
+ }
+
+ periodic_chores();
+}
+
static void wakealarm_init(void) {
wakealarm_fd = timerfd_create(CLOCK_BOOTTIME_ALARM, TFD_NONBLOCK);
if (wakealarm_fd == -1) {
@@ -161,82 +264,24 @@
return;
}
+ if (healthd_register_event(wakealarm_fd, wakealarm_event))
+ KLOG_ERROR(LOG_TAG,
+ "Registration of wakealarm event failed\n");
+
wakealarm_set_interval(healthd_config.periodic_chores_interval_fast);
}
-static void wakealarm_event(void) {
- unsigned long long wakeups;
-
- if (read(wakealarm_fd, &wakeups, sizeof(wakeups)) == -1) {
- 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);
- 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 (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++;
- }
-
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 @@
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;
}
-int main(int argc, char **argv) {
- int ch;
-
- 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);
- }
+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();
- binder_init();
gBatteryMonitor = new BatteryMonitor();
- gBatteryMonitor->init(&healthd_config, nosvcmgr);
+ gBatteryMonitor->init(&healthd_config);
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ int ch;
+ int ret;
+
+ klog_set_level(KLOG_LEVEL);
+ 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);
+ }
+ }
+ }
+
+ 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 @@
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/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
new file mode 100644
index 0000000..025d530
--- /dev/null
+++ b/healthd/healthd_mode_charger.cpp
@@ -0,0 +1,684 @@
+/*
+ * 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.
+ * 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 <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <linux/input.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/epoll.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <linux/netlink.h>
+
+#include <batteryservice/BatteryService.h>
+#include <cutils/android_reboot.h>
+#include <cutils/klog.h>
+#include <cutils/misc.h>
+
+#ifdef CHARGER_ENABLE_SUSPEND
+#include <suspend/autosuspend.h>
+#endif
+
+#include "minui/minui.h"
+
+#include "healthd.h"
+
+#ifndef max
+#define max(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+#ifndef min
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+
+#define MSEC_PER_SEC (1000LL)
+#define NSEC_PER_MSEC (1000000LL)
+
+#define BATTERY_UNKNOWN_TIME (2 * MSEC_PER_SEC)
+#define POWER_ON_KEY_TIME (2 * MSEC_PER_SEC)
+#define UNPLUGGED_SHUTDOWN_TIME (10 * MSEC_PER_SEC)
+
+#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)
+#define LOGI(x...) do { KLOG_INFO("charger", x); } while (0)
+#define LOGV(x...) do { KLOG_DEBUG("charger", x); } while (0)
+
+struct key_state {
+ bool pending;
+ bool down;
+ int64_t timestamp;
+};
+
+struct frame {
+ const char *name;
+ int disp_time;
+ int min_capacity;
+ bool level_only;
+
+ gr_surface surface;
+};
+
+struct animation {
+ bool run;
+
+ struct frame *frames;
+ int cur_frame;
+ int num_frames;
+
+ int cur_cycle;
+ int num_cycles;
+
+ /* current capacity being animated */
+ int capacity;
+};
+
+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];
+
+ struct animation *batt_anim;
+ gr_surface surf_unknown;
+};
+
+static struct frame batt_anim_frames[] = {
+ {
+ .name = "charger/battery_0",
+ .disp_time = 750,
+ .min_capacity = 0,
+ .level_only = false,
+ .surface = NULL,
+ },
+ {
+ .name = "charger/battery_1",
+ .disp_time = 750,
+ .min_capacity = 20,
+ .level_only = false,
+ .surface = NULL,
+ },
+ {
+ .name = "charger/battery_2",
+ .disp_time = 750,
+ .min_capacity = 40,
+ .level_only = false,
+ .surface = NULL,
+ },
+ {
+ .name = "charger/battery_3",
+ .disp_time = 750,
+ .min_capacity = 60,
+ .level_only = false,
+ .surface = NULL,
+ },
+ {
+ .name = "charger/battery_4",
+ .disp_time = 750,
+ .min_capacity = 80,
+ .level_only = true,
+ .surface = NULL,
+ },
+ {
+ .name = "charger/battery_5",
+ .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;
+
+static int char_width;
+static int char_height;
+
+/* current time in milliseconds */
+static int64_t curr_time_ms(void)
+{
+ struct timespec tm;
+ clock_gettime(CLOCK_MONOTONIC, &tm);
+ return tm.tv_sec * MSEC_PER_SEC + (tm.tv_nsec / NSEC_PER_MSEC);
+}
+
+static void clear_screen(void)
+{
+ gr_color(0, 0, 0, 255);
+ gr_fill(0, 0, gr_fb_width(), gr_fb_height());
+};
+
+#define MAX_KLOG_WRITE_BUF_SZ 256
+
+static void dump_last_kmsg(void)
+{
+ char *buf;
+ char *ptr;
+ unsigned sz = 0;
+ int len;
+
+ LOGI("\n");
+ LOGI("*************** LAST KMSG ***************\n");
+ LOGI("\n");
+ buf = (char *)load_file(LAST_KMSG_PSTORE_PATH, &sz);
+
+ if (!buf || !sz) {
+ 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);
+ ptr = buf + (sz - len);
+
+ while (len > 0) {
+ int cnt = min(len, MAX_KLOG_WRITE_BUF_SZ);
+ char yoink;
+ char *nl;
+
+ nl = (char *)memrchr(ptr, '\n', cnt - 1);
+ if (nl)
+ cnt = nl - ptr + 1;
+
+ yoink = ptr[cnt];
+ ptr[cnt] = '\0';
+ klog_write(6, "<6>%s", ptr);
+ ptr[cnt] = yoink;
+
+ len -= cnt;
+ ptr += cnt;
+ }
+
+ free(buf);
+
+out:
+ LOGI("\n");
+ LOGI("************* END LAST KMSG *************\n");
+ LOGI("\n");
+}
+
+static int get_battery_capacity()
+{
+ return charger_state.capacity;
+}
+
+#ifdef CHARGER_ENABLE_SUSPEND
+static int request_suspend(bool enable)
+{
+ if (enable)
+ return autosuspend_enable();
+ else
+ return autosuspend_disable();
+}
+#else
+static int request_suspend(bool enable)
+{
+ return 0;
+}
+#endif
+
+static int draw_text(const char *str, int x, int y)
+{
+ int str_len_px = gr_measure(str);
+
+ if (x < 0)
+ x = (gr_fb_width() - str_len_px) / 2;
+ if (y < 0)
+ y = (gr_fb_height() - char_height) / 2;
+ gr_text(x, y, str, 0);
+
+ return y + char_height;
+}
+
+static void android_green(void)
+{
+ gr_color(0xa4, 0xc6, 0x39, 255);
+}
+
+/* returns the last y-offset of where the surface ends */
+static int draw_surface_centered(struct charger *charger, gr_surface surface)
+{
+ int w;
+ int h;
+ int x;
+ int y;
+
+ w = gr_get_width(surface);
+ h = gr_get_height(surface);
+ x = (gr_fb_width() - w) / 2 ;
+ y = (gr_fb_height() - h) / 2 ;
+
+ LOGV("drawing surface %dx%d+%d+%d\n", w, h, x, y);
+ gr_blit(surface, 0, 0, w, h, x, y);
+ return y + h;
+}
+
+static void draw_unknown(struct charger *charger)
+{
+ int y;
+ if (charger->surf_unknown) {
+ draw_surface_centered(charger, charger->surf_unknown);
+ } else {
+ android_green();
+ y = draw_text("Charging!", -1, -1);
+ draw_text("?\?/100", -1, y + 25);
+ }
+}
+
+static void draw_battery(struct charger *charger)
+{
+ struct animation *batt_anim = charger->batt_anim;
+ struct frame *frame = &batt_anim->frames[batt_anim->cur_frame];
+
+ if (batt_anim->num_frames != 0) {
+ draw_surface_centered(charger, frame->surface);
+ LOGV("drawing frame #%d name=%s min_cap=%d time=%d\n",
+ batt_anim->cur_frame, frame->name, frame->min_capacity,
+ frame->disp_time);
+ }
+}
+
+static void redraw_screen(struct charger *charger)
+{
+ struct animation *batt_anim = charger->batt_anim;
+
+ clear_screen();
+
+ /* try to display *something* */
+ if (batt_anim->capacity < 0 || batt_anim->num_frames == 0)
+ draw_unknown(charger);
+ else
+ draw_battery(charger);
+ gr_flip();
+}
+
+static void kick_animation(struct animation *anim)
+{
+ anim->run = true;
+}
+
+static void reset_animation(struct animation *anim)
+{
+ anim->cur_cycle = 0;
+ anim->cur_frame = 0;
+ anim->run = false;
+}
+
+static void update_screen_state(struct charger *charger, int64_t now)
+{
+ struct animation *batt_anim = charger->batt_anim;
+ int cur_frame;
+ int disp_time;
+
+ if (!batt_anim->run || now < charger->next_screen_transition)
+ return;
+
+ /* animation is over, blank screen and leave */
+ if (batt_anim->cur_cycle == batt_anim->num_cycles) {
+ reset_animation(batt_anim);
+ charger->next_screen_transition = -1;
+ gr_fb_blank(true);
+ LOGV("[%lld] animation done\n", now);
+ if (!charger->charger_connected)
+ request_suspend(true);
+ return;
+ }
+
+ disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time;
+
+ /* animation starting, set up the animation */
+ if (batt_anim->cur_frame == 0) {
+ int batt_cap;
+ int ret;
+
+ LOGV("[%lld] animation starting\n", now);
+ batt_cap = get_battery_capacity();
+ if (batt_cap >= 0 && batt_anim->num_frames != 0) {
+ int i;
+
+ /* find first frame given current capacity */
+ for (i = 1; i < batt_anim->num_frames; i++) {
+ if (batt_cap < batt_anim->frames[i].min_capacity)
+ break;
+ }
+ batt_anim->cur_frame = i - 1;
+
+ /* show the first frame for twice as long */
+ disp_time = batt_anim->frames[batt_anim->cur_frame].disp_time * 2;
+ }
+
+ batt_anim->capacity = batt_cap;
+ }
+
+ /* unblank the screen on first cycle */
+ if (batt_anim->cur_cycle == 0)
+ gr_fb_blank(false);
+
+ /* draw the new frame (@ cur_frame) */
+ redraw_screen(charger);
+
+ /* if we don't have anim frames, we only have one image, so just bump
+ * the cycle counter and exit
+ */
+ if (batt_anim->num_frames == 0 || batt_anim->capacity < 0) {
+ LOGV("[%lld] animation missing or unknown battery status\n", now);
+ charger->next_screen_transition = now + BATTERY_UNKNOWN_TIME;
+ batt_anim->cur_cycle++;
+ return;
+ }
+
+ /* schedule next screen transition */
+ charger->next_screen_transition = now + disp_time;
+
+ /* advance frame cntr to the next valid frame
+ * if necessary, advance cycle cntr, and reset frame cntr
+ */
+ batt_anim->cur_frame++;
+
+ /* if the frame is used for level-only, that is only show it when it's
+ * the current level, skip it during the animation.
+ */
+ while (batt_anim->cur_frame < batt_anim->num_frames &&
+ batt_anim->frames[batt_anim->cur_frame].level_only)
+ batt_anim->cur_frame++;
+ if (batt_anim->cur_frame >= batt_anim->num_frames) {
+ batt_anim->cur_cycle++;
+ batt_anim->cur_frame = 0;
+
+ /* don't reset the cycle counter, since we use that as a signal
+ * in a test above to check if animation is over
+ */
+ }
+}
+
+static int set_key_callback(int code, int value, void *data)
+{
+ struct charger *charger = (struct charger *)data;
+ int64_t now = curr_time_ms();
+ int down = !!value;
+
+ if (code > KEY_MAX)
+ return -1;
+
+ /* ignore events that don't modify our state */
+ if (charger->keys[code].down == down)
+ return 0;
+
+ /* only record the down even timestamp, as the amount
+ * of time the key spent not being pressed is not useful */
+ if (down)
+ charger->keys[code].timestamp = now;
+ charger->keys[code].down = down;
+ charger->keys[code].pending = true;
+ if (down) {
+ LOGV("[%lld] key[%d] down\n", now, code);
+ } else {
+ int64_t duration = now - charger->keys[code].timestamp;
+ int64_t secs = duration / 1000;
+ int64_t msecs = duration - secs * 1000;
+ LOGV("[%lld] key[%d] up (was down for %lld.%lldsec)\n", now,
+ code, secs, msecs);
+ }
+
+ return 0;
+}
+
+static void update_input_state(struct charger *charger,
+ struct input_event *ev)
+{
+ if (ev->type != EV_KEY)
+ return;
+ set_key_callback(ev->code, ev->value, charger);
+}
+
+static void set_next_key_check(struct charger *charger,
+ struct key_state *key,
+ int64_t timeout)
+{
+ int64_t then = key->timestamp + timeout;
+
+ if (charger->next_key_check == -1 || then < charger->next_key_check)
+ charger->next_key_check = then;
+}
+
+static void process_key(struct charger *charger, int code, int64_t now)
+{
+ struct key_state *key = &charger->keys[code];
+ int64_t next_key_check;
+
+ if (code == KEY_POWER) {
+ if (key->down) {
+ int64_t reboot_timeout = key->timestamp + POWER_ON_KEY_TIME;
+ if (now >= reboot_timeout) {
+ LOGI("[%lld] rebooting\n", now);
+ android_reboot(ANDROID_RB_RESTART, 0, 0);
+ } else {
+ /* if the key is pressed but timeout hasn't expired,
+ * make sure we wake up at the right-ish time to check
+ */
+ set_next_key_check(charger, key, POWER_ON_KEY_TIME);
+ }
+ } else {
+ /* if the power key got released, force screen state cycle */
+ if (key->pending) {
+ request_suspend(false);
+ kick_animation(charger->batt_anim);
+ }
+ }
+ }
+
+ key->pending = false;
+}
+
+static void handle_input_state(struct charger *charger, int64_t now)
+{
+ process_key(charger, KEY_POWER, now);
+
+ if (charger->next_key_check != -1 && now > charger->next_key_check)
+ charger->next_key_check = -1;
+}
+
+static void handle_power_supply_state(struct charger *charger, int64_t now)
+{
+ 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;
+ LOGI("[%lld] device unplugged: shutting down in %lld (@ %lld)\n",
+ now, UNPLUGGED_SHUTDOWN_TIME, charger->next_pwr_check);
+ } else if (now >= charger->next_pwr_check) {
+ LOGI("[%lld] shutting down\n", now);
+ android_reboot(ANDROID_RB_POWEROFF, 0, 0);
+ } else {
+ /* otherwise we already have a shutdown timer scheduled */
+ }
+ } else {
+ /* online supply present, reset shutdown timer if set */
+ if (charger->next_pwr_check != -1) {
+ LOGI("[%lld] device plugged in: shutdown cancelled\n", now);
+ kick_animation(charger->batt_anim);
+ }
+ charger->next_pwr_check = -1;
+ }
+}
+
+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;
+ int ret;
+
+ LOGV("[%lld] next screen: %lld next key: %lld next pwr: %lld\n", now,
+ charger->next_screen_transition, charger->next_key_check,
+ charger->next_pwr_check);
+
+ if (charger->next_screen_transition != -1)
+ next_event = charger->next_screen_transition;
+ if (charger->next_key_check != -1 && charger->next_key_check < next_event)
+ next_event = charger->next_key_check;
+ if (charger->next_pwr_check != -1 && charger->next_pwr_check < next_event)
+ next_event = charger->next_pwr_check;
+
+ if (next_event != -1 && next_event != INT64_MAX)
+ timeout = max(0, next_event - now);
+ else
+ timeout = -1;
+
+ return (int)timeout;
+}
+
+static int input_callback(int fd, unsigned int epevents, void *data)
+{
+ struct charger *charger = (struct charger *)data;
+ struct input_event ev;
+ int ret;
+
+ ret = ev_get_input(fd, epevents, &ev);
+ if (ret)
+ return -1;
+ update_input_state(charger, &ev);
+ return 0;
+}
+
+static void charger_event_handler(uint32_t epevents)
+{
+ int ret;
+
+ ret = ev_wait(-1);
+ if (!ret)
+ ev_dispatch();
+}
+
+void healthd_mode_charger_init(struct healthd_config *config)
+{
+ int ret;
+ struct charger *charger = &charger_state;
+ int i;
+ int epollfd;
+
+ dump_last_kmsg();
+
+ LOGI("--------------- STARTING CHARGER MODE ---------------\n");
+
+ gr_init();
+ gr_font_size(&char_width, &char_height);
+
+ ret = ev_init(input_callback, charger);
+ if (!ret) {
+ epollfd = ev_get_epollfd();
+ healthd_register_event(epollfd, charger_event_handler);
+ }
+
+ ret = res_create_surface("charger/battery_fail", &charger->surf_unknown);
+ if (ret < 0) {
+ LOGE("Cannot load image\n");
+ charger->surf_unknown = NULL;
+ }
+
+ charger->batt_anim = &battery_animation;
+
+ for (i = 0; i < charger->batt_anim->num_frames; i++) {
+ struct frame *frame = &charger->batt_anim->frames[i];
+
+ ret = res_create_surface(frame->name, &frame->surface);
+ if (ret < 0) {
+ LOGE("Cannot load image %s\n", frame->name);
+ /* TODO: free the already allocated surfaces... */
+ charger->batt_anim->num_frames = 0;
+ charger->batt_anim->num_cycles = 1;
+ break;
+ }
+ }
+
+ ev_sync_key_state(set_key_callback, charger);
+
+#ifndef CHARGER_DISABLE_INIT_BLANK
+ gr_fb_blank(true);
+#endif
+
+ charger->next_screen_transition = -1;
+ charger->next_key_check = -1;
+ charger->next_pwr_check = -1;
+}
diff --git a/charger/images/battery_0.png b/healthd/images/battery_0.png
similarity index 100%
rename from charger/images/battery_0.png
rename to healthd/images/battery_0.png
Binary files differ
diff --git a/charger/images/battery_1.png b/healthd/images/battery_1.png
similarity index 100%
rename from charger/images/battery_1.png
rename to healthd/images/battery_1.png
Binary files differ
diff --git a/charger/images/battery_2.png b/healthd/images/battery_2.png
similarity index 100%
rename from charger/images/battery_2.png
rename to healthd/images/battery_2.png
Binary files differ
diff --git a/charger/images/battery_3.png b/healthd/images/battery_3.png
similarity index 100%
rename from charger/images/battery_3.png
rename to healthd/images/battery_3.png
Binary files differ
diff --git a/charger/images/battery_4.png b/healthd/images/battery_4.png
similarity index 100%
rename from charger/images/battery_4.png
rename to healthd/images/battery_4.png
Binary files differ
diff --git a/charger/images/battery_5.png b/healthd/images/battery_5.png
similarity index 100%
rename from charger/images/battery_5.png
rename to healthd/images/battery_5.png
Binary files differ
diff --git a/charger/images/battery_charge.png b/healthd/images/battery_charge.png
similarity index 100%
rename from charger/images/battery_charge.png
rename to healthd/images/battery_charge.png
Binary files differ
diff --git a/charger/images/battery_fail.png b/healthd/images/battery_fail.png
similarity index 100%
rename from charger/images/battery_fail.png
rename to healthd/images/battery_fail.png
Binary files differ
diff --git a/include/cutils/klog.h b/include/cutils/klog.h
index ba728ac..3953904 100644
--- a/include/cutils/klog.h
+++ b/include/cutils/klog.h
@@ -23,7 +23,7 @@
void klog_init(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)));
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 0ed0d78..e3568ae 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -247,6 +247,7 @@
/* 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" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin/*" },
{ 00755, AID_ROOT, AID_ROOT, 0, "system/lib/valgrind/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/xbin/*" },
@@ -255,7 +256,6 @@
{ 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 aa7ac02..2424baf 100644
--- a/include/system/audio.h
+++ b/include/system/audio.h
@@ -34,11 +34,17 @@
/* 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 @@
} 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,6 +101,13 @@
* (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). */
@@ -103,8 +118,11 @@
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_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 +147,7 @@
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
@@ -153,14 +171,18 @@
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_t;
enum {
@@ -266,6 +288,15 @@
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].
+ */
+enum {
+ AUDIO_INTERLEAVE_LEFT = 0,
+ AUDIO_INTERLEAVE_RIGHT = 1,
+};
+
typedef enum {
AUDIO_MODE_INVALID = -2,
AUDIO_MODE_CURRENT = -1,
@@ -278,7 +309,9 @@
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 +337,12 @@
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,
@@ -522,7 +558,7 @@
*/
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:
@@ -562,7 +598,7 @@
switch (format & AUDIO_FORMAT_MAIN_MASK) {
case AUDIO_FORMAT_PCM:
if (format != AUDIO_FORMAT_PCM_16_BIT &&
- format != AUDIO_FORMAT_PCM_8_BIT) {
+ format != AUDIO_FORMAT_PCM_8_BIT && format != AUDIO_FORMAT_PCM_FLOAT) {
return false;
}
case AUDIO_FORMAT_MP3:
@@ -598,6 +634,9 @@
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/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_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/LruCache.h b/include/utils/LruCache.h
index 053bfaf..fa8f03f 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 {
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/property_service.c b/init/property_service.c
index ac63377e..6cb2c7b 100644
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -110,6 +110,7 @@
} control_perms[] = {
{ "dumpstate",AID_SHELL, AID_LOG },
{ "ril-daemon",AID_RADIO, AID_RADIO },
+ { "pre-recovery", AID_SYSTEM, AID_SYSTEM },
{NULL, 0, 0 }
};
@@ -281,7 +282,6 @@
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;
@@ -291,11 +291,10 @@
/* 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;
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/libnetutils/packet.c b/libnetutils/packet.c
index be4e0db..3cdefb0 100644
--- a/libnetutils/packet.c
+++ b/libnetutils/packet.c
@@ -230,6 +230,8 @@
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/libnl_2/socket.c b/libnl_2/socket.c
index e94eb9e..f51cf56 100644
--- a/libnl_2/socket.c
+++ b/libnl_2/socket.c
@@ -18,6 +18,7 @@
#include <errno.h>
#include <unistd.h>
+#include <fcntl.h>
#include <malloc.h>
#include <sys/time.h>
#include <sys/socket.h>
@@ -139,3 +140,14 @@
{
return nl_cb_get(sk->s_cb);
}
+
+int nl_socket_set_nonblocking(struct nl_sock *sk)
+{
+ if (sk->s_fd == -1)
+ return -NLE_BAD_SOCK;
+
+ if (fcntl(sk->s_fd, F_SETFL, O_NONBLOCK) < 0)
+ return -errno;
+
+ return 0;
+}
diff --git a/libsparse/Android.mk b/libsparse/Android.mk
index 9025cc0..a21e090 100644
--- a/libsparse/Android.mk
+++ b/libsparse/Android.mk
@@ -82,8 +82,8 @@
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
diff --git a/libsparse/append2simg.c b/libsparse/append2simg.c
new file mode 100644
index 0000000..180584f
--- /dev/null
+++ b/libsparse/append2simg.c
@@ -0,0 +1,112 @@
+/*
+ * 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
+
+#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;
+
+ if (argc == 3) {
+ output_path = argv[1];
+ input_path = argv[2];
+ } else {
+ usage();
+ 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;
+
+ lseek64(output, 0, SEEK_SET);
+ if (sparse_file_write(sparse_output, output, false, true, false) < 0) {
+ fprintf(stderr, "Failed to write sparse file\n");
+ exit(-1);
+ }
+
+ sparse_file_destroy(sparse_output);
+ close(output);
+ close(input);
+ exit(0);
+}
diff --git a/libsysutils/src/SocketClient.cpp b/libsysutils/src/SocketClient.cpp
index 3625d93..d3ce8f5 100644
--- a/libsysutils/src/SocketClient.cpp
+++ b/libsysutils/src/SocketClient.cpp
@@ -1,10 +1,11 @@
#include <alloca.h>
#include <errno.h>
-#include <sys/socket.h>
-#include <sys/types.h>
#include <pthread.h>
+#include <signal.h>
#include <string.h>
#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <sys/types.h>
#define LOG_TAG "SocketClient"
#include <cutils/log.h>
@@ -43,8 +44,7 @@
}
}
-SocketClient::~SocketClient()
-{
+SocketClient::~SocketClient() {
if (mSocketOwned) {
close(mSocket);
}
@@ -180,10 +180,19 @@
return 0;
}
+ int ret = 0;
+ int e = 0; // SLOGW and sigaction are not inert regarding errno
int current = 0;
+ struct sigaction new_action, old_action;
+ memset(&new_action, 0, sizeof(new_action));
+ new_action.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &new_action, &old_action);
+
for (;;) {
- ssize_t rc = writev(mSocket, iov + current, iovcnt - current);
+ ssize_t rc = TEMP_FAILURE_RETRY(
+ writev(mSocket, iov + current, iovcnt - current));
+
if (rc > 0) {
size_t written = rc;
while ((current < iovcnt) && (written >= iov[current].iov_len)) {
@@ -198,18 +207,21 @@
continue;
}
- if (rc < 0 && errno == EINTR)
- continue;
-
if (rc == 0) {
+ e = EIO;
SLOGW("0 length write :(");
- errno = EIO;
} else {
- SLOGW("write error (%s)", strerror(errno));
+ e = errno;
+ SLOGW("write error (%s)", strerror(e));
}
- return -1;
+ ret = -1;
+ break;
}
- return 0;
+
+ sigaction(SIGPIPE, &old_action, &new_action);
+
+ errno = e;
+ return ret;
}
void SocketClient::incRef() {
diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c
index 8be393e..ab1b856 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -453,6 +453,8 @@
int i, result;
int languageCount = 0;
+ if (id == 0) return NULL;
+
string[0] = 0;
memset(languages, 0, sizeof(languages));
@@ -486,31 +488,19 @@
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)
@@ -556,6 +546,21 @@
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/lmkd/lmkd.c b/lmkd/lmkd.c
index 376410b..e489e81 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -75,6 +75,10 @@
#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 +120,14 @@
/* 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 +231,8 @@
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)
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 1aafaa3..dc260e6 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -11,7 +11,7 @@
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
@@ -434,11 +434,6 @@
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
@@ -475,6 +470,7 @@
onrestart restart zygote
onrestart restart media
onrestart restart surfaceflinger
+ onrestart restart inputflinger
onrestart restart drm
service vold /system/bin/vold
@@ -504,6 +500,12 @@
group graphics drmrpc
onrestart restart zygote
+service inputflinger /system/bin/inputflinger
+ class main
+ user system
+ group input
+ onrestart restart zygote
+
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
socket zygote stream 660 root system
@@ -576,3 +578,8 @@
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 4fff9f5..cdde20d 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -68,7 +68,9 @@
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 @@
{
int version;
int fd;
+ int clkid = CLOCK_MONOTONIC;
struct pollfd *new_ufds;
char **new_device_names;
char name[80];
@@ -335,6 +336,11 @@
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 @@
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 @@
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 @@
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 @@
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 @@
#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 @@
unsigned utime, stime;
int prio, nice, rtprio, sched, psr;
struct passwd *pw;
-
+
sprintf(statline, "/proc/%d", pid);
stat(statline, &stats);
@@ -67,7 +68,7 @@
}
cmdline[r] = 0;
}
-
+
fd = open(statline, O_RDONLY);
if(fd == 0) return -1;
r = read(fd, statline, 1023);
@@ -89,7 +90,7 @@
nexttok(&ptr); // pgrp
nexttok(&ptr); // sid
tty = atoi(nexttok(&ptr));
-
+
nexttok(&ptr); // tpgid
nexttok(&ptr); // flags
nexttok(&ptr); // minflt
@@ -129,21 +130,21 @@
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 @@
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 @@
ps_line(pid, tid, namefilter);
}
}
- closedir(d);
+ closedir(d);
}
int ps_main(int argc, char **argv)
@@ -207,13 +208,15 @@
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")) {