resolved conflicts for merge of ec9e5891 to master
Change-Id: I704e3159d529e436e060cb66c1739ef8e7b612d4
diff --git a/adb/Android.mk b/adb/Android.mk
index 155c6e5..62f012c 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -34,7 +34,7 @@
ifeq ($(HOST_OS),windows)
USB_SRCS := usb_windows.c
- EXTRA_SRCS := get_my_path_windows.c ../libcutils/list.c
+ EXTRA_SRCS := get_my_path_windows.c
EXTRA_STATIC_LIBS := AdbWinApi
ifneq ($(strip $(USE_CYGWIN)),)
# Pure cygwin case
@@ -114,8 +114,7 @@
jdwp_service.c \
framebuffer_service.c \
remount_service.c \
- usb_linux_client.c \
- log_service.c
+ usb_linux_client.c
LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter
LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE
diff --git a/adb/SERVICES.TXT b/adb/SERVICES.TXT
index 5966686..7f85dc3 100644
--- a/adb/SERVICES.TXT
+++ b/adb/SERVICES.TXT
@@ -198,11 +198,6 @@
Variants of local:<path> that are used to access other Android
socket namespaces.
-log:<name>
- Opens one of the system logs (/dev/log/<name>) and allows the client
- to read them directly. Used to implement 'adb logcat'. The stream
- will be read-only for the client.
-
framebuffer:
This service is used to send snapshots of the framebuffer to a client.
It requires sufficient privileges but works as follow:
diff --git a/adb/adb.h b/adb/adb.h
index c85b02a..6f5c93c 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -330,9 +330,7 @@
} BackupOperation;
int backup_service(BackupOperation operation, char* args);
void framebuffer_service(int fd, void *cookie);
-void log_service(int fd, void *cookie);
void remount_service(int fd, void *cookie);
-char * get_log_file_path(const char * log_name);
#endif
/* packet allocator */
diff --git a/adb/file_sync_service.c b/adb/file_sync_service.c
index c30f9fb..c2401b8 100644
--- a/adb/file_sync_service.c
+++ b/adb/file_sync_service.c
@@ -338,11 +338,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/adb/log_service.c b/adb/log_service.c
deleted file mode 100644
index af24356..0000000
--- a/adb/log_service.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2007 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 <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <sys/socket.h>
-#include <log/logger.h>
-#include "sysdeps.h"
-#include "adb.h"
-
-#define LOG_FILE_DIR "/dev/log/"
-
-void write_log_entry(int fd, struct logger_entry *buf);
-
-void log_service(int fd, void *cookie)
-{
- /* get the name of the log filepath to read */
- char * log_filepath = cookie;
-
- /* open the log file. */
- int logfd = unix_open(log_filepath, O_RDONLY);
- if (logfd < 0) {
- goto done;
- }
-
- // temp buffer to read the entries
- unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1] __attribute__((aligned(4)));
- struct logger_entry *entry = (struct logger_entry *) buf;
-
- while (1) {
- int ret;
-
- ret = unix_read(logfd, entry, LOGGER_ENTRY_MAX_LEN);
- if (ret < 0) {
- if (errno == EINTR || errno == EAGAIN)
- continue;
- // perror("logcat read");
- goto done;
- }
- else if (!ret) {
- // fprintf(stderr, "read: Unexpected EOF!\n");
- goto done;
- }
-
- /* NOTE: driver guarantees we read exactly one full entry */
-
- entry->msg[entry->len] = '\0';
-
- write_log_entry(fd, entry);
- }
-
-done:
- unix_close(fd);
- free(log_filepath);
-}
-
-/* returns the full path to the log file in a newly allocated string */
-char * get_log_file_path(const char * log_name) {
- char *log_device = malloc(strlen(LOG_FILE_DIR) + strlen(log_name) + 1);
-
- strcpy(log_device, LOG_FILE_DIR);
- strcat(log_device, log_name);
-
- return log_device;
-}
-
-
-/* prints one log entry into the file descriptor fd */
-void write_log_entry(int fd, struct logger_entry *buf)
-{
- size_t size = sizeof(struct logger_entry) + buf->len;
-
- writex(fd, buf, size);
-}
diff --git a/adb/services.c b/adb/services.c
index 17d40a0..dcaf276 100644
--- a/adb/services.c
+++ b/adb/services.c
@@ -355,8 +355,6 @@
ret = create_service_thread(framebuffer_service, 0);
} else if (!strncmp(name, "jdwp:", 5)) {
ret = create_jdwp_connection_fd(atoi(name+5));
- } else if (!strncmp(name, "log:", 4)) {
- ret = create_service_thread(log_service, get_log_file_path(name + 4));
} else if(!HOST && !strncmp(name, "shell:", 6)) {
if(name[6]) {
ret = create_subproc_thread(name + 6);
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 9c5d8c0..17fcc79 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2012-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.
@@ -29,6 +29,7 @@
#include <private/android_filesystem_config.h>
+#include <log/log.h>
#include <log/logger.h>
#include <cutils/properties.h>
@@ -452,39 +453,35 @@
// 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 "tailOnly" is set, we only print the last few lines.
-static void dump_log_file(log_t* log, pid_t pid, const char* filename, bool tailOnly) {
+// 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;
- // circular buffer, for "tailOnly" mode
- const int kShortLogMaxLines = 5;
- const int kShortLogLineLen = 256;
- char shortLog[kShortLogMaxLines][kShortLogLineLen];
- int shortLogCount = 0;
- int shortLogNext = 0;
+ logger_list = android_logger_list_open(
+ android_name_to_log_id(filename), O_RDONLY | O_NONBLOCK, tail, pid);
- int logfd = open(filename, O_RDONLY | O_NONBLOCK);
- if (logfd < 0) {
+ if (!logger_list) {
XLOG("Unable to open %s: %s\n", filename, strerror(errno));
return;
}
- union {
- unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
- struct logger_entry entry;
- } log_entry;
+ struct log_msg log_entry;
while (true) {
- ssize_t actual = read(logfd, log_entry.buf, LOGGER_ENTRY_MAX_LEN);
+ ssize_t actual = android_logger_list_read(logger_list, &log_entry);
+ struct logger_entry* entry;
+
if (actual < 0) {
- if (errno == EINTR) {
+ if (actual == -EINTR) {
// interrupted by signal, retry
continue;
- } else if (errno == EAGAIN) {
+ } else if (actual == -EAGAIN) {
// non-blocking EOF; we're done
break;
} else {
- _LOG(log, 0, "Error while reading log: %s\n", strerror(errno));
+ _LOG(log, 0, "Error while reading log: %s\n", strerror(-actual));
break;
}
} else if (actual == 0) {
@@ -496,15 +493,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;
- 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", tailOnly ? "tail end of " : "", filename);
+ _LOG(log, 0, "--------- %slog %s\n", tail ? "tail end of " : "", filename);
first = false;
}
@@ -516,9 +509,14 @@
// TODO: scan for line breaks ('\n') and display each text line
// on a separate line, prefixed with the header, like logcat does.
static const char* kPrioChars = "!.VDIWEFS";
- unsigned char prio = entry->msg[0];
- char* tag = entry->msg + 1;
- char* msg = tag + strlen(tag) + 1;
+ unsigned hdr_size = log_entry.entry.hdr_size;
+ if (!hdr_size) {
+ hdr_size = sizeof(log_entry.entry_v1);
+ }
+ char* msg = reinterpret_cast<char*>(log_entry.buf) + hdr_size;
+ unsigned char prio = msg[0];
+ char* tag = msg + 1;
+ msg = tag + strlen(tag) + 1;
// consume any trailing newlines
char* eatnl = msg + strlen(msg) - 1;
@@ -535,44 +533,18 @@
ptm = localtime_r(&sec, &tmBuf);
strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
- if (tailOnly) {
- snprintf(shortLog[shortLogNext], kShortLogLineLen,
- "%s.%03d %5d %5d %c %-8s: %s",
- timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
- prioChar, tag, msg);
- shortLogNext = (shortLogNext + 1) % kShortLogMaxLines;
- shortLogCount++;
- } else {
- _LOG(log, 0, "%s.%03d %5d %5d %c %-8s: %s\n",
- timeBuf, entry->nsec / 1000000, entry->pid, entry->tid, prioChar, tag, msg);
- }
+ _LOG(log, 0, "%s.%03d %5d %5d %c %-8s: %s\n",
+ timeBuf, entry->nsec / 1000000, entry->pid, entry->tid, prioChar, tag, msg);
}
- if (tailOnly) {
- int i;
-
- // If we filled the buffer, we want to start at "next", which has
- // the oldest entry. If we didn't, we want to start at zero.
- if (shortLogCount < kShortLogMaxLines) {
- shortLogNext = 0;
- } else {
- shortLogCount = kShortLogMaxLines; // cap at window size
- }
-
- for (i = 0; i < shortLogCount; i++) {
- _LOG(log, 0, "%s\n", shortLog[shortLogNext]);
- shortLogNext = (shortLogNext + 1) % kShortLogMaxLines;
- }
- }
-
- close(logfd);
+ android_logger_list_free(logger_list);
}
// 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, bool tailOnly) {
- dump_log_file(log, pid, "/dev/log/system", tailOnly);
- dump_log_file(log, pid, "/dev/log/main", tailOnly);
+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);
}
static void dump_abort_message(Backtrace* backtrace, log_t* log, uintptr_t address) {
@@ -647,7 +619,8 @@
}
if (want_logs) {
- dump_logs(log, pid, true);
+ // Dump the last five lines of the logs for the given pid.
+ dump_logs(log, pid, 5);
}
bool detach_failed = false;
@@ -659,7 +632,8 @@
backtrace_destroy_map_info_list(map_info);
if (want_logs) {
- dump_logs(log, pid, false);
+ // Dump the logs for the given pid.
+ dump_logs(log, pid, 0);
}
// send EOD to the Activity Manager, then wait for its ack to avoid racing ahead
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/cutils/list.h b/include/cutils/list.h
index 72395f4..945729a 100644
--- a/include/cutils/list.h
+++ b/include/cutils/list.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2008-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.
@@ -49,9 +49,25 @@
node != (list); \
node = next, next = node->next)
-void list_init(struct listnode *list);
-void list_add_tail(struct listnode *list, struct listnode *item);
-void list_remove(struct listnode *item);
+static inline void list_init(struct listnode *node)
+{
+ node->next = node;
+ node->prev = node;
+}
+
+static inline void list_add_tail(struct listnode *head, struct listnode *item)
+{
+ item->next = head;
+ item->prev = head->prev;
+ head->prev->next = item;
+ head->prev = item;
+}
+
+static inline void list_remove(struct listnode *item)
+{
+ item->next->prev = item->prev;
+ item->prev->next = item->next;
+}
#define list_empty(list) ((list) == (list)->next)
#define list_head(list) ((list)->next)
diff --git a/include/log/log.h b/include/log/log.h
index 7faddea..e3ecc69 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2005 The Android Open Source Project
+ * Copyright (C) 2005-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.
@@ -28,17 +28,16 @@
#ifndef _LIBS_LOG_LOG_H
#define _LIBS_LOG_LOG_H
-#include <stdio.h>
-#include <time.h>
#include <sys/types.h>
-#include <unistd.h>
#ifdef HAVE_PTHREADS
#include <pthread.h>
#endif
#include <stdarg.h>
-
-#include <log/uio.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
#include <log/logd.h>
+#include <log/uio.h>
#ifdef __cplusplus
extern "C" {
@@ -470,7 +469,8 @@
EVENT_TYPE_STRING = 2,
EVENT_TYPE_LIST = 3,
} AndroidEventLogType;
-
+#define sizeof_AndroidEventLogType sizeof(typeof_AndroidEventLogType)
+#define typeof_AndroidEventLogType unsigned char
#ifndef LOG_EVENT_INT
#define LOG_EVENT_INT(_tag, _value) { \
@@ -540,7 +540,9 @@
#define android_logToFile(tag, file) (0)
#define android_logToFd(tag, fd) (0)
-typedef enum {
+typedef enum log_id {
+ LOG_ID_MIN = 0,
+
LOG_ID_MAIN = 0,
LOG_ID_RADIO = 1,
LOG_ID_EVENTS = 2,
@@ -548,6 +550,8 @@
LOG_ID_MAX
} log_id_t;
+#define sizeof_log_id_t sizeof(typeof_log_id_t)
+#define typeof_log_id_t unsigned char
/*
* Send a simple string to the log.
@@ -555,7 +559,6 @@
int __android_log_buf_write(int bufID, int prio, const char *tag, const char *text);
int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...);
-
#ifdef __cplusplus
}
#endif
diff --git a/include/log/logger.h b/include/log/logger.h
index 04f3fb0..5d21794 100644
--- a/include/log/logger.h
+++ b/include/log/logger.h
@@ -1,6 +1,6 @@
-/* utils/logger.h
-**
-** Copyright 2007, The Android Open Source Project
+/*
+**
+** Copyright 2007-2014, The Android Open Source Project
**
** This file is dual licensed. It may be redistributed and/or modified
** under the terms of the Apache 2.0 License OR version 2 of the GNU
@@ -11,6 +11,11 @@
#define _UTILS_LOGGER_H
#include <stdint.h>
+#include <log/log.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
/*
* The userspace structure for version 1 of the logger_entry ABI.
@@ -43,11 +48,6 @@
char msg[0]; /* the entry's payload */
};
-#define LOGGER_LOG_MAIN "log/main"
-#define LOGGER_LOG_RADIO "log/radio"
-#define LOGGER_LOG_EVENTS "log/events"
-#define LOGGER_LOG_SYSTEM "log/system"
-
/*
* The maximum size of the log entry payload that can be
* written to the kernel logger driver. An attempt to write
@@ -63,6 +63,106 @@
*/
#define LOGGER_ENTRY_MAX_LEN (5*1024)
+#define NS_PER_SEC 1000000000ULL
+
+struct log_msg {
+ union {
+ unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
+ struct logger_entry_v2 entry;
+ struct logger_entry_v2 entry_v2;
+ struct logger_entry entry_v1;
+ struct {
+ unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
+ log_id_t id;
+ } extra;
+ } __attribute__((aligned(4)));
+#ifdef __cplusplus
+ /* Matching log_time_t operators */
+ bool operator== (log_msg &T)
+ {
+ return (entry.sec == T.entry.sec) && (entry.nsec == T.entry.nsec);
+ }
+ bool operator!= (log_msg &T)
+ {
+ return !(*this == T);
+ }
+ bool operator< (log_msg &T)
+ {
+ return (entry.sec < T.entry.sec)
+ || ((entry.sec == T.entry.sec)
+ && (entry.nsec < T.entry.nsec));
+ }
+ bool operator>= (log_msg &T)
+ {
+ return !(*this < T);
+ }
+ bool operator> (log_msg &T)
+ {
+ return (entry.sec > T.entry.sec)
+ || ((entry.sec == T.entry.sec)
+ && (entry.nsec > T.entry.nsec));
+ }
+ bool operator<= (log_msg &T)
+ {
+ return !(*this > T);
+ }
+ uint64_t nsec(void)
+ {
+ return static_cast<uint64_t>(entry.sec) * NS_PER_SEC + entry.nsec;
+ }
+
+ /* packet methods */
+ log_id_t id(void)
+ {
+ return extra.id;
+ }
+ char *msg(void)
+ {
+ return entry.hdr_size ? (char *) buf + entry.hdr_size : entry_v1.msg;
+ }
+ unsigned int len(void)
+ {
+ return (entry.hdr_size ? entry.hdr_size : sizeof(entry_v1)) + entry.len;
+ }
+#endif
+};
+
+struct logger;
+
+log_id_t android_logger_get_id(struct logger *logger);
+
+int android_logger_clear(struct logger *logger);
+int android_logger_get_log_size(struct logger *logger);
+int android_logger_get_log_readable_size(struct logger *logger);
+int android_logger_get_log_version(struct logger *logger);
+
+struct logger_list;
+
+struct logger_list *android_logger_list_alloc(int mode,
+ unsigned int tail,
+ pid_t pid);
+void android_logger_list_free(struct logger_list *logger_list);
+/* In the purest sense, the following two are orthogonal interfaces */
+int android_logger_list_read(struct logger_list *logger_list,
+ struct log_msg *log_msg);
+
+/* Multiple log_id_t opens */
+struct logger *android_logger_open(struct logger_list *logger_list,
+ log_id_t id);
+#define android_logger_close android_logger_free
+/* Single log_id_t open */
+struct logger_list *android_logger_list_open(log_id_t id,
+ int mode,
+ unsigned int tail,
+ pid_t pid);
+#define android_logger_list_close android_logger_list_free
+
+/*
+ * log_id_t helpers
+ */
+log_id_t android_name_to_log_id(const char *logName);
+const char *android_log_id_to_name(log_id_t log_id);
+
#ifdef HAVE_IOCTL
#include <sys/ioctl.h>
@@ -78,4 +178,8 @@
#endif // HAVE_IOCTL
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _UTILS_LOGGER_H */
diff --git a/include/log/uio.h b/include/log/uio.h
index 01a74d2..a71f515 100644
--- a/include/log/uio.h
+++ b/include/log/uio.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2007-2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,8 +31,8 @@
#include <stddef.h>
struct iovec {
- const void* iov_base;
- size_t iov_len;
+ void* iov_base;
+ size_t iov_len;
};
extern int readv( int fd, struct iovec* vecs, int count );
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 0ed0d78..53619ac 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -255,7 +255,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/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..a9bf9b4 100644
--- a/init/property_service.c
+++ b/init/property_service.c
@@ -281,7 +281,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 +290,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
index 9cc6e01..073b24a 100644
--- a/libbacktrace/map_info.c
+++ b/libbacktrace/map_info.c
@@ -21,7 +21,7 @@
#include <limits.h>
#include <pthread.h>
#include <unistd.h>
-#include <cutils/log.h>
+#include <log/log.h>
#include <sys/time.h>
#include <backtrace/backtrace.h>
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index f8dda36..002b730 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -37,7 +37,6 @@
config_utils.c \
cpu_info.c \
load_file.c \
- list.c \
open_memstream.c \
strdup16to8.c \
strdup8to16.c \
diff --git a/libcutils/android_reboot.c b/libcutils/android_reboot.c
index aef3054..b7895fa 100644
--- a/libcutils/android_reboot.c
+++ b/libcutils/android_reboot.c
@@ -25,6 +25,8 @@
#include <cutils/android_reboot.h>
+#define UNUSED __attribute__((unused))
+
/* Check to see if /proc/mounts contains any writeable filesystems
* backed by a block device.
* Return true if none found, else return false.
@@ -102,7 +104,7 @@
}
-int android_reboot(int cmd, int flags, char *arg)
+int android_reboot(int cmd, int flags UNUSED, char *arg)
{
int ret;
diff --git a/libcutils/list.c b/libcutils/list.c
deleted file mode 100644
index e13452d..0000000
--- a/libcutils/list.c
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <cutils/list.h>
-
-void list_init(struct listnode *node)
-{
- node->next = node;
- node->prev = node;
-}
-
-void list_add_tail(struct listnode *head, struct listnode *item)
-{
- item->next = head;
- item->prev = head->prev;
- head->prev->next = item;
- head->prev = item;
-}
-
-void list_remove(struct listnode *item)
-{
- item->next->prev = item->prev;
- item->prev->next = item->next;
-}
diff --git a/libcutils/socket_local_client.c b/libcutils/socket_local_client.c
index 036ce2e..5310516 100644
--- a/libcutils/socket_local_client.c
+++ b/libcutils/socket_local_client.c
@@ -39,6 +39,8 @@
#include "socket_local.h"
+#define UNUSED __attribute__((unused))
+
#define LISTEN_BACKLOG 4
/* Documented in header file. */
@@ -122,7 +124,7 @@
* Used by AndroidSocketImpl
*/
int socket_local_client_connect(int fd, const char *name, int namespaceId,
- int type)
+ int type UNUSED)
{
struct sockaddr_un addr;
socklen_t alen;
diff --git a/libcutils/str_parms.c b/libcutils/str_parms.c
index 9e1d2dc..7cfbcb3 100644
--- a/libcutils/str_parms.c
+++ b/libcutils/str_parms.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2011-2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,6 +30,8 @@
#include <cutils/str_parms.h>
+#define UNUSED __attribute__((unused))
+
struct str_parms {
Hashmap *map;
};
@@ -278,10 +280,11 @@
return -ENOENT;
out = strtof(value, &end);
- if (*value != '\0' && *end == '\0')
- return 0;
+ if (*value == '\0' || *end != '\0')
+ return -EINVAL;
- return -EINVAL;
+ *val = out;
+ return 0;
}
static bool combine_strings(void *key, void *value, void *context)
@@ -318,7 +321,7 @@
return str;
}
-static bool dump_entry(void *key, void *value, void *context)
+static bool dump_entry(void *key, void *value, void *context UNUSED)
{
ALOGI("key: '%s' value: '%s'\n", (char *)key, (char *)value);
return true;
diff --git a/liblog/Android.mk b/liblog/Android.mk
index 6bfb119..78ff1ed 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -42,7 +42,7 @@
endif
liblog_host_sources := $(liblog_sources) fake_log_device.c
-
+liblog_target_sources = $(liblog_sources) log_read.c
# Shared and static library for host
# ========================================================
@@ -72,7 +72,7 @@
# ========================================================
include $(CLEAR_VARS)
LOCAL_MODULE := liblog
-LOCAL_SRC_FILES := $(liblog_sources)
+LOCAL_SRC_FILES := $(liblog_target_sources)
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
diff --git a/liblog/README b/liblog/README
new file mode 100644
index 0000000..d7472e4
--- /dev/null
+++ b/liblog/README
@@ -0,0 +1,134 @@
+LIBLOG(3) Android NDK Programming Manual LIBLOG(3)
+
+
+
+NAME
+ liblog - Android NDK logger interfaces
+
+SYNOPSIS
+ #include <log/log.h>
+
+ ALOG(android_priority, tag, format, ...)
+ IF_ALOG(android_priority, tag)
+ LOG_PRI(priority, tag, format, ...)
+ LOG_PRI_VA(priority, tag, format, args)
+ #define LOG_TAG NULL
+ ALOGV(format, ...)
+ SLOGV(format, ...)
+ RLOGV(format, ...)
+ ALOGV_IF(cond, format, ...)
+ SLOGV_IF(cond, format, ...)
+ RLOGV_IF(cond, format, ...)
+ IF_ALOGC()
+ ALOGD(format, ...)
+ SLOGD(format, ...)
+ RLOGD(format, ...)
+ ALOGD_IF(cond, format, ...)
+ SLOGD_IF(cond, format, ...)
+ RLOGD_IF(cond, format, ...)
+ IF_ALOGD()
+ ALOGI(format, ...)
+ SLOGI(format, ...)
+ RLOGI(format, ...)
+ ALOGI_IF(cond, format, ...)
+ SLOGI_IF(cond, format, ...)
+ RLOGI_IF(cond, format, ...)
+ IF_ALOGI()
+ ALOGW(format, ...)
+ SLOGW(format, ...)
+ RLOGW(format, ...)
+ ALOGW_IF(cond, format, ...)
+ SLOGW_IF(cond, format, ...)
+ RLOGW_IF(cond, format, ...)
+ IF_ALOGW()
+ ALOGE(format, ...)
+ SLOGE(format, ...)
+ RLOGE(format, ...)
+ ALOGE_IF(cond, format, ...)
+ SLOGE_IF(cond, format, ...)
+ RLOGE_IF(cond, format, ...)
+ IF_ALOGE()
+ LOG_FATAL(format, ...)
+ LOG_ALWAYS_FATAL(format, ...)
+ LOG_FATAL_IF(cond, format, ...)
+ LOG_ALWAYS_FATAL_IF(cond, format, ...)
+ ALOG_ASSERT(cond, format, ...)
+ LOG_EVENT_INT(tag, value)
+ LOG_EVENT_LONG(tag, value)
+
+ Link with -llog
+
+ #include <log/logger.h>
+
+ log_id_t android_logger_get_id(struct logger *logger)
+ int android_logger_clear(struct logger *logger)
+ int android_logger_get_log_size(struct logger *logger)
+ int android_logger_get_log_readable_size(struct logger *logger)
+ int android_logger_get_log_version(struct logger *logger)
+
+ struct logger_list *android_logger_list_alloc(int mode, unsigned int
+ tail, pid_t pid)
+ struct logger *android_logger_open(struct logger_list *logger_list,
+ log_id_t id)
+ struct logger_list *android_logger_list_open(log_id_t id, int mode,
+ unsigned int tail, pid_t pid)
+
+ int android_logger_list_read(struct logger_list *logger_list, struct
+ log_msg *log_msg
+
+ void android_logger_list_free(struct logger_list *logger_list)
+
+ log_id_t android_name_to_log_id(const char *logName)
+ const char *android_log_id_to_name(log_id_t log_id)
+
+ Link with -llog
+
+DESCRIPTION
+ liblog represents an interface to the volatile Android Logging system
+ for NDK (Native) applications and libraries. Interfaces for either
+ writing or reading logs. The log buffers are divided up in Main, Sys‐
+ tem, Radio and Events sub-logs.
+
+ The logging interfaces are a series of macros, all of which can be
+ overridden individually in order to control the verbosity of the appli‐
+ cation or library. [ASR]LOG[VDIWE] calls are used to log to BAsic,
+ System or Radio sub-logs in either the Verbose, Debug, Info, Warning or
+ Error priorities. [ASR]LOG[VDIWE]_IF calls are used to perform thus
+ based on a condition being true. IF_ALOG[VDIWE] calls are true if the
+ current LOG_TAG is enabled at the specified priority. LOG_ALWAYS_FATAL
+ is used to ALOG a message, then kill the process. LOG_FATAL call is a
+ variant of LOG_ALWAYS_FATAL, only enabled in engineering, and not
+ release builds. ALOG_ASSERT is used to ALOG a message if the condition
+ is false; the condition is part of the logged message.
+ LOG_EVENT_(INT|LONG) is used to drop binary content into the Events
+ sub-log.
+
+ The log reading interfaces permit opening the logs either singly or
+ multiply, retrieving a log entry at a time in time sorted order,
+ optionally limited to a specific pid and tail of the log(s) and finally
+ a call closing the logs. A single log can be opened with android_log‐
+ ger_list_open; or multiple logs can be opened with android_log‐
+ ger_list_alloc, calling in turn the android_logger_open for each log
+ id. Each entry can be retrieved with android_logger_list_read. The
+ log(s) can be closed with android_logger_list_free. The logs should be
+ opened with an O_RDONLY mode. O_NDELAY mode will report when the log
+ reading is done with an EAGAIN error return code, otherwise the
+ android_logger_list_read call will block for new entries.
+
+ The value returned by android_logger_open can be used as a parameter to
+ the android_logger_clear function to empty the sub-log. It is recom‐
+ mended to only open log O_WRONLY.
+
+ The value returned by android_logger_open can be used as a parameter to
+ the android_logger_get_log_(size|readable_size|version) to retrieve the
+ sub-log maximum size, readable size and log buffer format protocol ver‐
+ sion respectively. android_logger_get_id returns the id that was used
+ when opening the sub-log. It is recommended to open the log O_RDONLY
+ in these cases.
+
+SEE ALSO
+ syslogd(8)
+
+
+
+ 17 Dec 2013 LIBLOG(3)
diff --git a/liblog/fake_log_device.c b/liblog/fake_log_device.c
index 5283619..da83a85 100644
--- a/liblog/fake_log_device.c
+++ b/liblog/fake_log_device.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2008-2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,6 +19,8 @@
* passed on to the underlying (fake) log device. When not in the
* simulator, messages are printed to stderr.
*/
+#include "fake_log_device.h"
+
#include <log/logd.h>
#include <stdlib.h>
@@ -320,11 +322,11 @@
* Make up something to replace it.
*/
static ssize_t fake_writev(int fd, const struct iovec *iov, int iovcnt) {
- int result = 0;
- struct iovec* end = iov + iovcnt;
+ ssize_t result = 0;
+ const struct iovec* end = iov + iovcnt;
for (; iov < end; iov++) {
- int w = write(fd, iov->iov_base, iov->iov_len);
- if (w != iov->iov_len) {
+ ssize_t w = write(fd, iov->iov_base, iov->iov_len);
+ if (w != (ssize_t) iov->iov_len) {
if (w < 0)
return w;
return result + w;
diff --git a/liblog/fake_log_device.h b/liblog/fake_log_device.h
new file mode 100644
index 0000000..9d168cd
--- /dev/null
+++ b/liblog/fake_log_device.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBLOG_FAKE_LOG_DEVICE_H
+#define _LIBLOG_FAKE_LOG_DEVICE_H
+
+#include <sys/types.h>
+
+struct iovec;
+
+int fakeLogOpen(const char *pathName, int flags);
+int fakeLogClose(int fd);
+ssize_t fakeLogWritev(int fd, const struct iovec* vector, int count);
+
+#endif // _LIBLOG_FAKE_LOG_DEVICE_H
diff --git a/liblog/log_read.c b/liblog/log_read.c
new file mode 100644
index 0000000..379105f
--- /dev/null
+++ b/liblog/log_read.c
@@ -0,0 +1,654 @@
+/*
+** Copyright 2013-2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define _GNU_SOURCE /* asprintf for x86 host */
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <cutils/list.h>
+#include <log/log.h>
+#include <log/logger.h>
+
+typedef char bool;
+#define false (const bool)0
+#define true (const bool)1
+
+#define LOG_FILE_DIR "/dev/log/"
+
+/* timeout in milliseconds */
+#define LOG_TIMEOUT_FLUSH 5
+#define LOG_TIMEOUT_NEVER -1
+
+#define logger_for_each(logger, logger_list) \
+ for (logger = node_to_item((logger_list)->node.next, struct logger, node); \
+ logger != node_to_item(&(logger_list)->node, struct logger, node); \
+ logger = node_to_item((logger)->node.next, struct logger, node))
+
+/* In the future, we would like to make this list extensible */
+static const char *LOG_NAME[LOG_ID_MAX] = {
+ [LOG_ID_MAIN] = "main",
+ [LOG_ID_RADIO] = "radio",
+ [LOG_ID_EVENTS] = "events",
+ [LOG_ID_SYSTEM] = "system"
+};
+
+const char *android_log_id_to_name(log_id_t log_id) {
+ if (log_id >= LOG_ID_MAX) {
+ log_id = LOG_ID_MAIN;
+ }
+ return LOG_NAME[log_id];
+}
+
+static int accessmode(int mode)
+{
+ if ((mode & O_ACCMODE) == O_WRONLY) {
+ return W_OK;
+ }
+ if ((mode & O_ACCMODE) == O_RDWR) {
+ return R_OK | W_OK;
+ }
+ return R_OK;
+}
+
+/* repeated fragment */
+static int check_allocate_accessible(char **n, const char *b, int mode)
+{
+ *n = NULL;
+
+ if (!b) {
+ return -EINVAL;
+ }
+
+ asprintf(n, LOG_FILE_DIR "%s", b);
+ if (!*n) {
+ return -1;
+ }
+
+ return access(*n, accessmode(mode));
+}
+
+log_id_t android_name_to_log_id(const char *logName) {
+ const char *b;
+ char *n;
+ int ret;
+
+ if (!logName) {
+ return -1; /* NB: log_id_t is unsigned */
+ }
+ b = strrchr(logName, '/');
+ if (!b) {
+ b = logName;
+ } else {
+ ++b;
+ }
+
+ ret = check_allocate_accessible(&n, b, O_RDONLY);
+ free(n);
+ if (ret) {
+ return ret;
+ }
+
+ for(ret = LOG_ID_MIN; ret < LOG_ID_MAX; ++ret) {
+ const char *l = LOG_NAME[ret];
+ if (l && !strcmp(b, l)) {
+ return ret;
+ }
+ }
+ return -1; /* should never happen */
+}
+
+struct logger_list {
+ struct listnode node;
+ int mode;
+ unsigned int tail;
+ pid_t pid;
+ unsigned int queued_lines;
+ int timeout_ms;
+ int error;
+ bool flush;
+ bool valid_entry; /* valiant(?) effort to deal with memory starvation */
+ struct log_msg entry;
+};
+
+struct log_list {
+ struct listnode node;
+ struct log_msg entry; /* Truncated to event->len() + 1 to save space */
+};
+
+struct logger {
+ struct listnode node;
+ struct logger_list *top;
+ int fd;
+ log_id_t id;
+ short *revents;
+ struct listnode log_list;
+};
+
+/* android_logger_alloc unimplemented, no use case */
+/* android_logger_free not exported */
+static void android_logger_free(struct logger *logger)
+{
+ if (!logger) {
+ return;
+ }
+
+ while (!list_empty(&logger->log_list)) {
+ struct log_list *entry = node_to_item(
+ list_head(&logger->log_list), struct log_list, node);
+ list_remove(&entry->node);
+ free(entry);
+ if (logger->top->queued_lines) {
+ logger->top->queued_lines--;
+ }
+ }
+
+ if (logger->fd >= 0) {
+ close(logger->fd);
+ }
+
+ list_remove(&logger->node);
+
+ free(logger);
+}
+
+log_id_t android_logger_get_id(struct logger *logger)
+{
+ return logger->id;
+}
+
+/* worker for sending the command to the logger */
+static int logger_ioctl(struct logger *logger, int cmd, int mode)
+{
+ char *n;
+ int f, ret;
+
+ if (!logger || !logger->top) {
+ return -EFAULT;
+ }
+
+ if (((mode & O_ACCMODE) == O_RDWR)
+ || (((mode ^ logger->top->mode) & O_ACCMODE) == 0)) {
+ return ioctl(logger->fd, cmd);
+ }
+
+ /* We go here if android_logger_list_open got mode wrong for this ioctl */
+ ret = check_allocate_accessible(&n, android_log_id_to_name(logger->id), mode);
+ if (ret) {
+ free(n);
+ return ret;
+ }
+
+ f = open(n, mode);
+ free(n);
+ if (f < 0) {
+ return f;
+ }
+
+ ret = ioctl(f, cmd);
+ close (f);
+
+ return ret;
+}
+
+int android_logger_clear(struct logger *logger)
+{
+ return logger_ioctl(logger, LOGGER_FLUSH_LOG, O_WRONLY);
+}
+
+/* returns the total size of the log's ring buffer */
+int android_logger_get_log_size(struct logger *logger)
+{
+ return logger_ioctl(logger, LOGGER_GET_LOG_BUF_SIZE, O_RDWR);
+}
+
+/*
+ * returns the readable size of the log's ring buffer (that is, amount of the
+ * log consumed)
+ */
+int android_logger_get_log_readable_size(struct logger *logger)
+{
+ return logger_ioctl(logger, LOGGER_GET_LOG_LEN, O_RDONLY);
+}
+
+/*
+ * returns the logger version
+ */
+int android_logger_get_log_version(struct logger *logger)
+{
+ int ret = logger_ioctl(logger, LOGGER_GET_VERSION, O_RDWR);
+ return (ret < 0) ? 1 : ret;
+}
+
+struct logger_list *android_logger_list_alloc(int mode,
+ unsigned int tail,
+ pid_t pid)
+{
+ struct logger_list *logger_list;
+
+ logger_list = calloc(1, sizeof(*logger_list));
+ if (!logger_list) {
+ return NULL;
+ }
+ list_init(&logger_list->node);
+ logger_list->mode = mode;
+ logger_list->tail = tail;
+ logger_list->pid = pid;
+ return logger_list;
+}
+
+/* android_logger_list_register unimplemented, no use case */
+/* android_logger_list_unregister unimplemented, no use case */
+
+/* Open the named log and add it to the logger list */
+struct logger *android_logger_open(struct logger_list *logger_list,
+ log_id_t id)
+{
+ struct listnode *node;
+ struct logger *logger;
+ char *n;
+
+ if (!logger_list || (id >= LOG_ID_MAX)) {
+ goto err;
+ }
+
+ logger_for_each(logger, logger_list) {
+ if (logger->id == id) {
+ goto ok;
+ }
+ }
+
+ logger = calloc(1, sizeof(*logger));
+ if (!logger) {
+ goto err;
+ }
+
+ if (check_allocate_accessible(&n, android_log_id_to_name(id),
+ logger_list->mode)) {
+ goto err_name;
+ }
+
+ logger->fd = open(n, logger_list->mode);
+ if (logger->fd < 0) {
+ goto err_name;
+ }
+
+ free(n);
+ logger->id = id;
+ list_init(&logger->log_list);
+ list_add_tail(&logger_list->node, &logger->node);
+ logger->top = logger_list;
+ logger_list->timeout_ms = LOG_TIMEOUT_FLUSH;
+ goto ok;
+
+err_name:
+ free(n);
+err_logger:
+ free(logger);
+err:
+ logger = NULL;
+ok:
+ return logger;
+}
+
+/* Open the single named log and make it part of a new logger list */
+struct logger_list *android_logger_list_open(log_id_t id,
+ int mode,
+ unsigned int tail,
+ pid_t pid)
+{
+ struct logger_list *logger_list = android_logger_list_alloc(mode, tail, pid);
+ if (!logger_list) {
+ return NULL;
+ }
+
+ if (!android_logger_open(logger_list, id)) {
+ android_logger_list_free(logger_list);
+ return NULL;
+ }
+
+ return logger_list;
+}
+
+/* prevent memory starvation when backfilling */
+static unsigned int queue_threshold(struct logger_list *logger_list)
+{
+ return (logger_list->tail < 64) ? 64 : logger_list->tail;
+}
+
+static bool low_queue(struct listnode *node)
+{
+ /* low is considered less than 2 */
+ return list_head(node) == list_tail(node);
+}
+
+/* Flush queues in sequential order, one at a time */
+static int android_logger_list_flush(struct logger_list *logger_list,
+ struct log_msg *log_msg)
+{
+ int ret = 0;
+ struct log_list *firstentry = NULL;
+
+ while ((ret == 0)
+ && (logger_list->flush
+ || (logger_list->queued_lines > logger_list->tail))) {
+ struct logger *logger;
+
+ /* Merge sort */
+ bool at_least_one_is_low = false;
+ struct logger *firstlogger = NULL;
+ firstentry = NULL;
+
+ logger_for_each(logger, logger_list) {
+ struct listnode *node;
+ struct log_list *oldest = NULL;
+
+ /* kernel logger channels not necessarily time-sort order */
+ list_for_each(node, &logger->log_list) {
+ struct log_list *entry = node_to_item(node,
+ struct log_list, node);
+ if (!oldest
+ || (entry->entry.entry.sec < oldest->entry.entry.sec)
+ || ((entry->entry.entry.sec == oldest->entry.entry.sec)
+ && (entry->entry.entry.nsec < oldest->entry.entry.nsec))) {
+ oldest = entry;
+ }
+ }
+
+ if (!oldest) {
+ at_least_one_is_low = true;
+ continue;
+ } else if (low_queue(&logger->log_list)) {
+ at_least_one_is_low = true;
+ }
+
+ if (!firstentry
+ || (oldest->entry.entry.sec < firstentry->entry.entry.sec)
+ || ((oldest->entry.entry.sec == firstentry->entry.entry.sec)
+ && (oldest->entry.entry.nsec < firstentry->entry.entry.nsec))) {
+ firstentry = oldest;
+ firstlogger = logger;
+ }
+ }
+
+ if (!firstentry) {
+ break;
+ }
+
+ /* when trimming list, tries to keep one entry behind in each bucket */
+ if (!logger_list->flush
+ && at_least_one_is_low
+ && (logger_list->queued_lines < queue_threshold(logger_list))) {
+ break;
+ }
+
+ /* within tail?, send! */
+ if ((logger_list->tail == 0)
+ || (logger_list->queued_lines <= logger_list->tail)) {
+ ret = firstentry->entry.entry.hdr_size;
+ if (!ret) {
+ ret = sizeof(firstentry->entry.entry_v1);
+ }
+ ret += firstentry->entry.entry.len;
+
+ memcpy(log_msg->buf, firstentry->entry.buf, ret + 1);
+ log_msg->extra.id = firstlogger->id;
+ }
+
+ /* next entry */
+ list_remove(&firstentry->node);
+ free(firstentry);
+ if (logger_list->queued_lines) {
+ logger_list->queued_lines--;
+ }
+ }
+
+ /* Flushed the list, no longer in tail mode for continuing content */
+ if (logger_list->flush && !firstentry) {
+ logger_list->tail = 0;
+ }
+ return ret;
+}
+
+/* Read from the selected logs */
+int android_logger_list_read(struct logger_list *logger_list,
+ struct log_msg *log_msg)
+{
+ struct logger *logger;
+ nfds_t nfds;
+ struct pollfd *p, *pollfds = NULL;
+ int error = 0, ret = 0;
+
+ memset(log_msg, 0, sizeof(struct log_msg));
+
+ if (!logger_list) {
+ return -ENODEV;
+ }
+
+ if (!(accessmode(logger_list->mode) & R_OK)) {
+ logger_list->error = EPERM;
+ goto done;
+ }
+
+ nfds = 0;
+ logger_for_each(logger, logger_list) {
+ ++nfds;
+ }
+ if (nfds <= 0) {
+ error = ENODEV;
+ goto done;
+ }
+
+ /* Do we have anything to offer from the buffer or state? */
+ if (logger_list->valid_entry) { /* implies we are also in a flush state */
+ goto flush;
+ }
+
+ ret = android_logger_list_flush(logger_list, log_msg);
+ if (ret) {
+ goto done;
+ }
+
+ if (logger_list->error) { /* implies we are also in a flush state */
+ goto done;
+ }
+
+ /* Lets start grinding on metal */
+ pollfds = calloc(nfds, sizeof(struct pollfd));
+ if (!pollfds) {
+ error = ENOMEM;
+ goto flush;
+ }
+
+ p = pollfds;
+ logger_for_each(logger, logger_list) {
+ p->fd = logger->fd;
+ p->events = POLLIN;
+ logger->revents = &p->revents;
+ ++p;
+ }
+
+ while (!ret && !error) {
+ int result;
+
+ /* If we oversleep it's ok, i.e. ignore EINTR. */
+ result = TEMP_FAILURE_RETRY(
+ poll(pollfds, nfds, logger_list->timeout_ms));
+
+ if (result <= 0) {
+ if (result) {
+ error = errno;
+ } else if (logger_list->mode & O_NDELAY) {
+ error = EAGAIN;
+ } else {
+ logger_list->timeout_ms = LOG_TIMEOUT_NEVER;
+ }
+
+ logger_list->flush = true;
+ goto try_flush;
+ }
+
+ logger_list->timeout_ms = LOG_TIMEOUT_FLUSH;
+
+ /* Anti starvation */
+ if (!logger_list->flush
+ && (logger_list->queued_lines > (queue_threshold(logger_list) / 2))) {
+ /* Any queues with input pending that is low? */
+ bool starving = false;
+ logger_for_each(logger, logger_list) {
+ if ((*(logger->revents) & POLLIN)
+ && low_queue(&logger->log_list)) {
+ starving = true;
+ break;
+ }
+ }
+
+ /* pushback on any queues that are not low */
+ if (starving) {
+ logger_for_each(logger, logger_list) {
+ if ((*(logger->revents) & POLLIN)
+ && !low_queue(&logger->log_list)) {
+ *(logger->revents) &= ~POLLIN;
+ }
+ }
+ }
+ }
+
+ logger_for_each(logger, logger_list) {
+ unsigned int hdr_size;
+ struct log_list *entry;
+
+ if (!(*(logger->revents) & POLLIN)) {
+ continue;
+ }
+
+ memset(logger_list->entry.buf, 0, sizeof(struct log_msg));
+ /* NOTE: driver guarantees we read exactly one full entry */
+ result = read(logger->fd, logger_list->entry.buf,
+ LOGGER_ENTRY_MAX_LEN);
+ if (result <= 0) {
+ if (!result) {
+ error = EIO;
+ } else if (errno != EINTR) {
+ error = errno;
+ }
+ continue;
+ }
+
+ if (logger_list->pid
+ && (logger_list->pid != logger_list->entry.entry.pid)) {
+ continue;
+ }
+
+ hdr_size = logger_list->entry.entry.hdr_size;
+ if (!hdr_size) {
+ hdr_size = sizeof(logger_list->entry.entry_v1);
+ }
+
+ if ((hdr_size > sizeof(struct log_msg))
+ || (logger_list->entry.entry.len
+ > sizeof(logger_list->entry.buf) - hdr_size)
+ || (logger_list->entry.entry.len != result - hdr_size)) {
+ error = EINVAL;
+ continue;
+ }
+
+ logger_list->entry.extra.id = logger->id;
+
+ /* speedup: If not tail, and only one list, send directly */
+ if (!logger_list->tail
+ && (list_head(&logger_list->node)
+ == list_tail(&logger_list->node))) {
+ ret = result;
+ memcpy(log_msg->buf, logger_list->entry.buf, result + 1);
+ log_msg->extra.id = logger->id;
+ break;
+ }
+
+ entry = malloc(sizeof(*entry) - sizeof(entry->entry) + result + 1);
+
+ if (!entry) {
+ logger_list->valid_entry = true;
+ error = ENOMEM;
+ break;
+ }
+
+ logger_list->queued_lines++;
+
+ memcpy(entry->entry.buf, logger_list->entry.buf, result);
+ entry->entry.buf[result] = '\0';
+ list_add_tail(&logger->log_list, &entry->node);
+ }
+
+ if (ret <= 0) {
+try_flush:
+ ret = android_logger_list_flush(logger_list, log_msg);
+ }
+ }
+
+ free(pollfds);
+
+flush:
+ if (error) {
+ logger_list->flush = true;
+ }
+
+ if (ret <= 0) {
+ ret = android_logger_list_flush(logger_list, log_msg);
+
+ if (!ret && logger_list->valid_entry) {
+ ret = logger_list->entry.entry.hdr_size;
+ if (!ret) {
+ ret = sizeof(logger_list->entry.entry_v1);
+ }
+ ret += logger_list->entry.entry.len;
+
+ memcpy(log_msg->buf, logger_list->entry.buf,
+ sizeof(struct log_msg));
+ logger_list->valid_entry = false;
+ }
+ }
+
+done:
+ if (logger_list->error) {
+ error = logger_list->error;
+ }
+ if (error) {
+ logger_list->error = error;
+ if (!ret) {
+ ret = -error;
+ }
+ }
+ return ret;
+}
+
+/* Close all the logs */
+void android_logger_list_free(struct logger_list *logger_list)
+{
+ if (logger_list == NULL) {
+ return;
+ }
+
+ while (!list_empty(&logger_list->node)) {
+ struct listnode *node = list_head(&logger_list->node);
+ struct logger *logger = node_to_item(node, struct logger, node);
+ android_logger_free(logger);
+ }
+
+ free(logger_list);
+}
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index fff7cc4..6b35a0f 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2007-2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -31,10 +31,16 @@
#include <log/logd.h>
#include <log/log.h>
-#define LOG_BUF_SIZE 1024
+#define LOGGER_LOG_MAIN "log/main"
+#define LOGGER_LOG_RADIO "log/radio"
+#define LOGGER_LOG_EVENTS "log/events"
+#define LOGGER_LOG_SYSTEM "log/system"
+
+#define LOG_BUF_SIZE 1024
#if FAKE_LOG_DEVICE
// This will be defined when building for the host.
+#include "fake_log_device.h"
#define log_open(pathname, flags) fakeLogOpen(pathname, flags)
#define log_writev(filedes, vector, count) fakeLogWritev(filedes, vector, count)
#define log_close(filedes) fakeLogClose(filedes)
@@ -50,6 +56,8 @@
static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
#endif
+#define UNUSED __attribute__((__unused__))
+
static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1 };
/*
@@ -72,7 +80,8 @@
return (g_log_status == kLogAvailable);
}
-static int __write_to_log_null(log_id_t log_fd, struct iovec *vec, size_t nr)
+static int __write_to_log_null(UNUSED log_id_t log_fd, UNUSED struct iovec *vec,
+ UNUSED size_t nr)
{
return -1;
}
@@ -236,7 +245,7 @@
}
void __android_log_assert(const char *cond, const char *tag,
- const char *fmt, ...)
+ const char *fmt, ...)
{
char buf[LOG_BUF_SIZE];
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 508c825..3927c22 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -1,4 +1,4 @@
-/* //device/libs/cutils/logprint.c
+/*
**
** Copyright 2006, The Android Open Source Project
**
diff --git a/liblog/uio.c b/liblog/uio.c
index cfa4cb1..24a6507 100644
--- a/liblog/uio.c
+++ b/liblog/uio.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2007-2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,8 +24,8 @@
int total = 0;
for ( ; count > 0; count--, vecs++ ) {
- const char* buf = vecs->iov_base;
- int len = vecs->iov_len;
+ char* buf = vecs->iov_base;
+ int len = vecs->iov_len;
while (len > 0) {
int ret = read( fd, buf, len );
@@ -51,8 +51,8 @@
int total = 0;
for ( ; count > 0; count--, vecs++ ) {
- const char* buf = (const char*)vecs->iov_base;
- int len = (int)vecs->iov_len;
+ const char* buf = vecs->iov_base;
+ int len = vecs->iov_len;
while (len > 0) {
int ret = write( fd, buf, len );
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/FrameworkCommand.cpp b/libsysutils/src/FrameworkCommand.cpp
index 038d87e..0b95a81 100644
--- a/libsysutils/src/FrameworkCommand.cpp
+++ b/libsysutils/src/FrameworkCommand.cpp
@@ -21,11 +21,14 @@
#include <sysutils/FrameworkCommand.h>
+#define UNUSED __attribute__((unused))
+
FrameworkCommand::FrameworkCommand(const char *cmd) {
mCommand = cmd;
}
-int FrameworkCommand::runCommand(SocketClient *c, int argc, char **argv) {
+int FrameworkCommand::runCommand(SocketClient *c UNUSED, int argc UNUSED,
+ char **argv UNUSED) {
SLOGW("Command %s has no run handler!", getCommand());
errno = ENOSYS;
return -1;
diff --git a/libsysutils/src/FrameworkListener.cpp b/libsysutils/src/FrameworkListener.cpp
index 02a401d..a5ffda2 100644
--- a/libsysutils/src/FrameworkListener.cpp
+++ b/libsysutils/src/FrameworkListener.cpp
@@ -27,6 +27,8 @@
static const int CMD_BUF_SIZE = 1024;
+#define UNUSED __attribute__((unused))
+
FrameworkListener::FrameworkListener(const char *socketName, bool withSeq) :
SocketListener(socketName, true, withSeq) {
init(socketName, withSeq);
@@ -37,7 +39,7 @@
init(socketName, false);
}
-void FrameworkListener::init(const char *socketName, bool withSeq) {
+void FrameworkListener::init(const char *socketName UNUSED, bool withSeq) {
mCommands = new FrameworkCommandCollection();
errorRate = 0;
mCommandCount = 0;
diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp
index 0361641..0296910 100644
--- a/libsysutils/src/SocketListener.cpp
+++ b/libsysutils/src/SocketListener.cpp
@@ -29,8 +29,6 @@
#include <sysutils/SocketListener.h>
#include <sysutils/SocketClient.h>
-#define LOG_NDEBUG 0
-
SocketListener::SocketListener(const char *socketName, bool listen) {
init(socketName, -1, listen, false);
}
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/logcat/logcat.cpp b/logcat/logcat.cpp
index 4c6139c..b6ca171 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -1,5 +1,6 @@
-// Copyright 2006 The Android Open Source Project
+// Copyright 2006-2013 The Android Open Source Project
+#include <log/log.h>
#include <log/logger.h>
#include <log/logd.h>
#include <log/logprint.h>
@@ -24,65 +25,27 @@
#define DEFAULT_MAX_ROTATED_LOGS 4
static AndroidLogFormat * g_logformat;
-static bool g_nonblock = false;
-static int g_tail_lines = 0;
/* logd prefixes records with a length field */
#define RECORD_LENGTH_FIELD_SIZE_BYTES sizeof(uint32_t)
-#define LOG_FILE_DIR "/dev/log/"
-
-struct queued_entry_t {
- union {
- unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1] __attribute__((aligned(4)));
- struct logger_entry entry __attribute__((aligned(4)));
- };
- queued_entry_t* next;
-
- queued_entry_t() {
- next = NULL;
- }
-};
-
-static int cmp(queued_entry_t* a, queued_entry_t* b) {
- int n = a->entry.sec - b->entry.sec;
- if (n != 0) {
- return n;
- }
- return a->entry.nsec - b->entry.nsec;
-}
-
struct log_device_t {
- char* device;
+ const char* device;
bool binary;
- int fd;
+ struct logger *logger;
+ struct logger_list *logger_list;
bool printed;
char label;
- queued_entry_t* queue;
log_device_t* next;
- log_device_t(char* d, bool b, char l) {
+ log_device_t(const char* d, bool b, char l) {
device = d;
binary = b;
label = l;
- queue = NULL;
next = NULL;
printed = false;
}
-
- void enqueue(queued_entry_t* entry) {
- if (this->queue == NULL) {
- this->queue = entry;
- } else {
- queued_entry_t** e = &this->queue;
- while (*e && cmp(entry, *e) >= 0) {
- e = &((*e)->next);
- }
- entry->next = *e;
- *e = entry;
- }
- }
};
namespace android {
@@ -147,17 +110,14 @@
}
-void printBinary(struct logger_entry *buf)
+void printBinary(struct log_msg *buf)
{
- size_t size = sizeof(logger_entry) + buf->len;
- int ret;
-
- do {
- ret = write(g_outFD, buf, size);
- } while (ret < 0 && errno == EINTR);
+ size_t size = buf->len();
+
+ TEMP_FAILURE_RETRY(write(g_outFD, buf, size));
}
-static void processBuffer(log_device_t* dev, struct logger_entry *buf)
+static void processBuffer(log_device_t* dev, struct log_msg *buf)
{
int bytesWritten = 0;
int err;
@@ -165,12 +125,14 @@
char binaryMsgBuf[1024];
if (dev->binary) {
- err = android_log_processBinaryLogBuffer(buf, &entry, g_eventTagMap,
- binaryMsgBuf, sizeof(binaryMsgBuf));
+ err = android_log_processBinaryLogBuffer(&buf->entry_v1, &entry,
+ g_eventTagMap,
+ binaryMsgBuf,
+ sizeof(binaryMsgBuf));
//printf(">>> pri=%d len=%d msg='%s'\n",
// entry.priority, entry.messageLen, entry.message);
} else {
- err = android_log_processLogBuffer(buf, &entry);
+ err = android_log_processLogBuffer(&buf->entry_v1, &entry);
}
if (err < 0) {
goto error;
@@ -197,7 +159,7 @@
g_outByteCount += bytesWritten;
- if (g_logRotateSizeKBytes > 0
+ if (g_logRotateSizeKBytes > 0
&& (g_outByteCount / 1024) >= g_logRotateSizeKBytes
) {
rotateLogs();
@@ -208,20 +170,13 @@
return;
}
-static void chooseFirst(log_device_t* dev, log_device_t** firstdev) {
- for (*firstdev = NULL; dev != NULL; dev = dev->next) {
- if (dev->queue != NULL && (*firstdev == NULL || cmp(dev->queue, (*firstdev)->queue) < 0)) {
- *firstdev = dev;
- }
- }
-}
-
static void maybePrintStart(log_device_t* dev) {
if (!dev->printed) {
dev->printed = true;
if (g_devCount > 1 && !g_printBinary) {
char buf[1024];
- snprintf(buf, sizeof(buf), "--------- beginning of %s\n", dev->device);
+ snprintf(buf, sizeof(buf), "--------- beginning of %s\n",
+ dev->device);
if (write(g_outFD, buf, strlen(buf)) < 0) {
perror("output error");
exit(-1);
@@ -230,145 +185,6 @@
}
}
-static void skipNextEntry(log_device_t* dev) {
- maybePrintStart(dev);
- queued_entry_t* entry = dev->queue;
- dev->queue = entry->next;
- delete entry;
-}
-
-static void printNextEntry(log_device_t* dev) {
- maybePrintStart(dev);
- if (g_printBinary) {
- printBinary(&dev->queue->entry);
- } else {
- processBuffer(dev, &dev->queue->entry);
- }
- skipNextEntry(dev);
-}
-
-static void readLogLines(log_device_t* devices)
-{
- log_device_t* dev;
- int max = 0;
- int ret;
- int queued_lines = 0;
- bool sleep = false;
-
- int result;
- fd_set readset;
-
- for (dev=devices; dev; dev = dev->next) {
- if (dev->fd > max) {
- max = dev->fd;
- }
- }
-
- while (1) {
- do {
- timeval timeout = { 0, 5000 /* 5ms */ }; // If we oversleep it's ok, i.e. ignore EINTR.
- FD_ZERO(&readset);
- for (dev=devices; dev; dev = dev->next) {
- FD_SET(dev->fd, &readset);
- }
- result = select(max + 1, &readset, NULL, NULL, sleep ? NULL : &timeout);
- } while (result == -1 && errno == EINTR);
-
- if (result >= 0) {
- for (dev=devices; dev; dev = dev->next) {
- if (FD_ISSET(dev->fd, &readset)) {
- queued_entry_t* entry = new queued_entry_t();
- /* NOTE: driver guarantees we read exactly one full entry */
- ret = read(dev->fd, entry->buf, LOGGER_ENTRY_MAX_LEN);
- if (ret < 0) {
- if (errno == EINTR) {
- delete entry;
- goto next;
- }
- if (errno == EAGAIN) {
- delete entry;
- break;
- }
- perror("logcat read");
- exit(EXIT_FAILURE);
- }
- else if (!ret) {
- fprintf(stderr, "read: Unexpected EOF!\n");
- exit(EXIT_FAILURE);
- }
- else if (entry->entry.len != ret - sizeof(struct logger_entry)) {
- fprintf(stderr, "read: unexpected length. Expected %d, got %d\n",
- entry->entry.len, ret - (int) sizeof(struct logger_entry));
- exit(EXIT_FAILURE);
- }
-
- entry->entry.msg[entry->entry.len] = '\0';
-
- dev->enqueue(entry);
- ++queued_lines;
- }
- }
-
- if (result == 0) {
- // we did our short timeout trick and there's nothing new
- // print everything we have and wait for more data
- sleep = true;
- while (true) {
- chooseFirst(devices, &dev);
- if (dev == NULL) {
- break;
- }
- if (g_tail_lines == 0 || queued_lines <= g_tail_lines) {
- printNextEntry(dev);
- } else {
- skipNextEntry(dev);
- }
- --queued_lines;
- }
-
- // the caller requested to just dump the log and exit
- if (g_nonblock) {
- return;
- }
- } else {
- // print all that aren't the last in their list
- sleep = false;
- while (g_tail_lines == 0 || queued_lines > g_tail_lines) {
- chooseFirst(devices, &dev);
- if (dev == NULL || dev->queue->next == NULL) {
- break;
- }
- if (g_tail_lines == 0) {
- printNextEntry(dev);
- } else {
- skipNextEntry(dev);
- }
- --queued_lines;
- }
- }
- }
-next:
- ;
- }
-}
-
-static int clearLog(int logfd)
-{
- return ioctl(logfd, LOGGER_FLUSH_LOG);
-}
-
-/* returns the total size of the log's ring buffer */
-static int getLogSize(int logfd)
-{
- return ioctl(logfd, LOGGER_GET_LOG_BUF_SIZE);
-}
-
-/* returns the readable size of the log's ring buffer (that is, amount of the log consumed) */
-static int getLogReadableSize(int logfd)
-{
- return ioctl(logfd, LOGGER_GET_LOG_LEN);
-}
-
static void setupOutput()
{
@@ -465,6 +281,8 @@
log_device_t* devices = NULL;
log_device_t* dev;
bool needBinary = false;
+ struct logger_list *logger_list;
+ int tail_lines = 0;
g_logformat = android_log_format_new();
@@ -488,7 +306,7 @@
}
switch(ret) {
- case 's':
+ case 's':
// default to all silent
android_log_addFilterRule(g_logformat, "*:s");
break;
@@ -499,12 +317,12 @@
break;
case 'd':
- g_nonblock = true;
+ mode = O_RDONLY | O_NDELAY;
break;
case 't':
- g_nonblock = true;
- g_tail_lines = atoi(optarg);
+ mode = O_RDONLY | O_NDELAY;
+ tail_lines = atoi(optarg);
break;
case 'g':
@@ -512,10 +330,6 @@
break;
case 'b': {
- char* buf = (char*) malloc(strlen(LOG_FILE_DIR) + strlen(optarg) + 1);
- strcpy(buf, LOG_FILE_DIR);
- strcat(buf, optarg);
-
bool binary = strcmp(optarg, "events") == 0;
if (binary) {
needBinary = true;
@@ -526,9 +340,9 @@
while (dev->next) {
dev = dev->next;
}
- dev->next = new log_device_t(buf, binary, optarg[0]);
+ dev->next = new log_device_t(optarg, binary, optarg[0]);
} else {
- devices = new log_device_t(buf, binary, optarg[0]);
+ devices = new log_device_t(optarg, binary, optarg[0]);
}
android::g_devCount++;
}
@@ -546,8 +360,8 @@
break;
case 'r':
- if (optarg == NULL) {
- android::g_logRotateSizeKBytes
+ if (optarg == NULL) {
+ android::g_logRotateSizeKBytes
= DEFAULT_LOG_ROTATE_SIZE_KBYTES;
} else {
long logRotateSize;
@@ -659,19 +473,15 @@
}
if (!devices) {
- devices = new log_device_t(strdup("/dev/"LOGGER_LOG_MAIN), false, 'm');
+ devices = new log_device_t("main", false, 'm');
android::g_devCount = 1;
- int accessmode =
- (mode & O_RDONLY) ? R_OK : 0
- | (mode & O_WRONLY) ? W_OK : 0;
- // only add this if it's available
- if (0 == access("/dev/"LOGGER_LOG_SYSTEM, accessmode)) {
- devices->next = new log_device_t(strdup("/dev/"LOGGER_LOG_SYSTEM), false, 's');
+ if (android_name_to_log_id("system") == LOG_ID_SYSTEM) {
+ devices->next = new log_device_t("system", false, 's');
android::g_devCount++;
}
}
- if (android::g_logRotateSizeKBytes != 0
+ if (android::g_logRotateSizeKBytes != 0
&& android::g_outputFileName == NULL
) {
fprintf(stderr,"-r requires -f as well\n");
@@ -688,7 +498,7 @@
err = setLogFormat(logFormat);
if (err < 0) {
- fprintf(stderr, "invalid format in ANDROID_PRINTF_LOG '%s'\n",
+ fprintf(stderr, "invalid format in ANDROID_PRINTF_LOG '%s'\n",
logFormat);
}
}
@@ -707,8 +517,8 @@
if (env_tags_orig != NULL) {
err = android_log_addFilterString(g_logformat, env_tags_orig);
- if (err < 0) {
- fprintf(stderr, "Invalid filter expression in"
+ if (err < 0) {
+ fprintf(stderr, "Invalid filter expression in"
" ANDROID_LOG_TAGS\n");
android::show_help(argv[0]);
exit(-1);
@@ -719,7 +529,7 @@
for (int i = optind ; i < argc ; i++) {
err = android_log_addFilterString(g_logformat, argv[i]);
- if (err < 0) {
+ if (err < 0) {
fprintf (stderr, "Invalid filter expression '%s'\n", argv[i]);
android::show_help(argv[0]);
exit(-1);
@@ -728,19 +538,21 @@
}
dev = devices;
+ logger_list = android_logger_list_alloc(mode, tail_lines, 0);
while (dev) {
- dev->fd = open(dev->device, mode);
- if (dev->fd < 0) {
- fprintf(stderr, "Unable to open log device '%s': %s\n",
- dev->device, strerror(errno));
+ dev->logger_list = logger_list;
+ dev->logger = android_logger_open(logger_list,
+ android_name_to_log_id(dev->device));
+ if (!dev->logger) {
+ fprintf(stderr, "Unable to open log device '%s'\n", dev->device);
exit(EXIT_FAILURE);
}
if (clearLog) {
int ret;
- ret = android::clearLog(dev->fd);
+ ret = android_logger_clear(dev->logger);
if (ret) {
- perror("ioctl");
+ perror("clearLog");
exit(EXIT_FAILURE);
}
}
@@ -748,15 +560,15 @@
if (getLogSize) {
int size, readable;
- size = android::getLogSize(dev->fd);
+ size = android_logger_get_log_size(dev->logger);
if (size < 0) {
- perror("ioctl");
+ perror("getLogSize");
exit(EXIT_FAILURE);
}
- readable = android::getLogReadableSize(dev->fd);
+ readable = android_logger_get_log_readable_size(dev->logger);
if (readable < 0) {
- perror("ioctl");
+ perror("getLogReadableSize");
exit(EXIT_FAILURE);
}
@@ -783,7 +595,51 @@
if (needBinary)
android::g_eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE);
- android::readLogLines(devices);
+ while (1) {
+ struct log_msg log_msg;
+ int ret = android_logger_list_read(logger_list, &log_msg);
+
+ if (ret == 0) {
+ fprintf(stderr, "read: Unexpected EOF!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (ret < 0) {
+ if (ret == -EAGAIN) {
+ break;
+ }
+
+ if (ret == -EIO) {
+ fprintf(stderr, "read: Unexpected EOF!\n");
+ exit(EXIT_FAILURE);
+ }
+ if (ret == -EINVAL) {
+ fprintf(stderr, "read: unexpected length.\n");
+ exit(EXIT_FAILURE);
+ }
+ perror("logcat read");
+ exit(EXIT_FAILURE);
+ }
+
+ for(dev = devices; dev; dev = dev->next) {
+ if (android_name_to_log_id(dev->device) == log_msg.id()) {
+ break;
+ }
+ }
+ if (!dev) {
+ fprintf(stderr, "read: Unexpected log ID!\n");
+ exit(EXIT_FAILURE);
+ }
+
+ android::maybePrintStart(dev);
+ if (android::g_printBinary) {
+ android::printBinary(&log_msg);
+ } else {
+ android::processBuffer(dev, &log_msg);
+ }
+ }
+
+ android_logger_list_free(logger_list);
return 0;
}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 199ee89..fc0fc3e 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
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 436f13d..138f455 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -69,7 +69,8 @@
swapon \
swapoff \
mkswap \
- readlink
+ readlink \
+ 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/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")) {