Merge commit 'b2042f7263c7bbacc5115de4a42c5a96b64a06f2' into HEAD

This commit is contained in:
Bill Yi 2014-10-22 08:49:05 -07:00
commit aad358fbc1
103 changed files with 6103 additions and 2546 deletions

View File

@ -53,3 +53,4 @@ $(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/init.rc)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/reboot)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/root/default.prop)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/recovery/root/default.prop)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/lmkd_intermediates/import_includes)

View File

@ -40,13 +40,11 @@ ifeq ($(HOST_OS),windows)
ifneq ($(strip $(USE_CYGWIN)),)
# Pure cygwin case
LOCAL_LDLIBS += -lpthread -lgdi32
LOCAL_C_INCLUDES += /usr/include/w32api/ddk
endif
ifneq ($(strip $(USE_MINGW)),)
# MinGW under Linux case
LOCAL_LDLIBS += -lws2_32 -lgdi32
USE_SYSDEPS_WIN32 := 1
LOCAL_C_INCLUDES += /usr/i586-mingw32msvc/include/ddk
endif
LOCAL_C_INCLUDES += development/host/windows/usb/api/
endif
@ -175,7 +173,7 @@ LOCAL_C_INCLUDES += external/openssl/include
LOCAL_MODULE := adb
LOCAL_STATIC_LIBRARIES := libzipfile libunz libcutils
LOCAL_STATIC_LIBRARIES := libzipfile libunz libcutils liblog
LOCAL_SHARED_LIBRARIES := libcrypto

View File

@ -19,6 +19,7 @@
#include <limits.h>
#include "adb_trace.h"
#include "transport.h" /* readx(), writex() */
#define MAX_PAYLOAD 4096
@ -337,85 +338,6 @@ void put_apacket(apacket *p);
int check_header(apacket *p);
int check_data(apacket *p);
/* define ADB_TRACE to 1 to enable tracing support, or 0 to disable it */
#define ADB_TRACE 1
/* IMPORTANT: if you change the following list, don't
* forget to update the corresponding 'tags' table in
* the adb_trace_init() function implemented in adb.c
*/
typedef enum {
TRACE_ADB = 0, /* 0x001 */
TRACE_SOCKETS,
TRACE_PACKETS,
TRACE_TRANSPORT,
TRACE_RWX, /* 0x010 */
TRACE_USB,
TRACE_SYNC,
TRACE_SYSDEPS,
TRACE_JDWP, /* 0x100 */
TRACE_SERVICES,
TRACE_AUTH,
} AdbTrace;
#if ADB_TRACE
#if !ADB_HOST
/*
* When running inside the emulator, guest's adbd can connect to 'adb-debug'
* qemud service that can display adb trace messages (on condition that emulator
* has been started with '-debug adb' option).
*/
/* Delivers a trace message to the emulator via QEMU pipe. */
void adb_qemu_trace(const char* fmt, ...);
/* Macro to use to send ADB trace messages to the emulator. */
#define DQ(...) adb_qemu_trace(__VA_ARGS__)
#else
#define DQ(...) ((void)0)
#endif /* !ADB_HOST */
extern int adb_trace_mask;
extern unsigned char adb_trace_output_count;
void adb_trace_init(void);
# define ADB_TRACING ((adb_trace_mask & (1 << TRACE_TAG)) != 0)
/* you must define TRACE_TAG before using this macro */
# define D(...) \
do { \
if (ADB_TRACING) { \
int save_errno = errno; \
adb_mutex_lock(&D_lock); \
fprintf(stderr, "%s::%s():", \
__FILE__, __FUNCTION__); \
errno = save_errno; \
fprintf(stderr, __VA_ARGS__ ); \
fflush(stderr); \
adb_mutex_unlock(&D_lock); \
errno = save_errno; \
} \
} while (0)
# define DR(...) \
do { \
if (ADB_TRACING) { \
int save_errno = errno; \
adb_mutex_lock(&D_lock); \
errno = save_errno; \
fprintf(stderr, __VA_ARGS__ ); \
fflush(stderr); \
adb_mutex_unlock(&D_lock); \
errno = save_errno; \
} \
} while (0)
#else
# define D(...) ((void)0)
# define DR(...) ((void)0)
# define ADB_TRACING 0
#endif /* ADB_TRACE */
#if !DEBUG_PACKETS
#define print_packet(tag,p) do {} while (0)
#endif

View File

@ -175,7 +175,7 @@ static void adb_auth_event(int fd, unsigned events, void *data)
if (events & FDE_READ) {
ret = unix_read(fd, response, sizeof(response));
if (ret < 0) {
if (ret <= 0) {
D("Framework disconnect\n");
if (usb_transport)
fdevent_remove(&usb_transport->auth_fde);

143
adb/adb_trace.h Normal file
View File

@ -0,0 +1,143 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __ADB_TRACE_H
#define __ADB_TRACE_H
#if !ADB_HOST
#include <android/log.h>
#endif
/* define ADB_TRACE to 1 to enable tracing support, or 0 to disable it */
#define ADB_TRACE 1
/* IMPORTANT: if you change the following list, don't
* forget to update the corresponding 'tags' table in
* the adb_trace_init() function implemented in adb.c
*/
typedef enum {
TRACE_ADB = 0, /* 0x001 */
TRACE_SOCKETS,
TRACE_PACKETS,
TRACE_TRANSPORT,
TRACE_RWX, /* 0x010 */
TRACE_USB,
TRACE_SYNC,
TRACE_SYSDEPS,
TRACE_JDWP, /* 0x100 */
TRACE_SERVICES,
TRACE_AUTH,
TRACE_FDEVENT,
} AdbTrace;
#if ADB_TRACE
#if !ADB_HOST
/*
* When running inside the emulator, guest's adbd can connect to 'adb-debug'
* qemud service that can display adb trace messages (on condition that emulator
* has been started with '-debug adb' option).
*/
/* Delivers a trace message to the emulator via QEMU pipe. */
void adb_qemu_trace(const char* fmt, ...);
/* Macro to use to send ADB trace messages to the emulator. */
#define DQ(...) adb_qemu_trace(__VA_ARGS__)
#else
#define DQ(...) ((void)0)
#endif /* !ADB_HOST */
extern int adb_trace_mask;
extern unsigned char adb_trace_output_count;
void adb_trace_init(void);
# define ADB_TRACING ((adb_trace_mask & (1 << TRACE_TAG)) != 0)
/* you must define TRACE_TAG before using this macro */
#if ADB_HOST
# define D(...) \
do { \
if (ADB_TRACING) { \
int save_errno = errno; \
adb_mutex_lock(&D_lock); \
fprintf(stderr, "%s::%s():", \
__FILE__, __FUNCTION__); \
errno = save_errno; \
fprintf(stderr, __VA_ARGS__ ); \
fflush(stderr); \
adb_mutex_unlock(&D_lock); \
errno = save_errno; \
} \
} while (0)
# define DR(...) \
do { \
if (ADB_TRACING) { \
int save_errno = errno; \
adb_mutex_lock(&D_lock); \
errno = save_errno; \
fprintf(stderr, __VA_ARGS__ ); \
fflush(stderr); \
adb_mutex_unlock(&D_lock); \
errno = save_errno; \
} \
} while (0)
# define DD(...) \
do { \
int save_errno = errno; \
adb_mutex_lock(&D_lock); \
fprintf(stderr, "%s::%s():", \
__FILE__, __FUNCTION__); \
errno = save_errno; \
fprintf(stderr, __VA_ARGS__ ); \
fflush(stderr); \
adb_mutex_unlock(&D_lock); \
errno = save_errno; \
} while (0)
#else
# define D(...) \
do { \
if (ADB_TRACING) { \
__android_log_print( \
ANDROID_LOG_INFO, \
__FUNCTION__, \
__VA_ARGS__ ); \
} \
} while (0)
# define DR(...) \
do { \
if (ADB_TRACING) { \
__android_log_print( \
ANDROID_LOG_INFO, \
__FUNCTION__, \
__VA_ARGS__ ); \
} \
} while (0)
# define DD(...) \
do { \
__android_log_print( \
ANDROID_LOG_INFO, \
__FUNCTION__, \
__VA_ARGS__ ); \
} while (0)
#endif /* ADB_HOST */
#else
# define D(...) ((void)0)
# define DR(...) ((void)0)
# define DD(...) ((void)0)
# define ADB_TRACING 0
#endif /* ADB_TRACE */
#endif /* __ADB_TRACE_H */

View File

@ -15,6 +15,7 @@
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
@ -41,8 +42,9 @@ static int do_cmd(transport_type ttype, char* serial, char *cmd, ...);
void get_my_path(char *s, size_t maxLen);
int find_sync_dirs(const char *srcarg,
char **android_srcdir_out, char **data_srcdir_out);
char **android_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out);
int install_app(transport_type transport, char* serial, int argc, char** argv);
int install_multiple_app(transport_type transport, char* serial, int argc, char** argv);
int uninstall_app(transport_type transport, char* serial, int argc, char** argv);
static const char *gProductOutPath = NULL;
@ -151,12 +153,15 @@ void help()
" - remove a specific reversed socket connection\n"
" adb reverse --remove-all - remove all reversed socket connections from device\n"
" adb jdwp - list PIDs of processes hosting a JDWP transport\n"
" adb install [-l] [-r] [-s] [--algo <algorithm name> --key <hex-encoded key> --iv <hex-encoded iv>] <file>\n"
" adb install [-lrtsd] <file>\n"
" adb install-multiple [-lrtsdp] <file...>\n"
" - push this package file to the device and install it\n"
" ('-l' means forward-lock the app)\n"
" ('-r' means reinstall the app, keeping its data)\n"
" ('-s' means install on SD card instead of internal storage)\n"
" ('--algo', '--key', and '--iv' mean the file is encrypted already)\n"
" (-l: forward lock application)\n"
" (-r: replace existing application)\n"
" (-t: allow test packages)\n"
" (-s: install application on sdcard)\n"
" (-d: allow version code downgrade)\n"
" (-p: partial application install)\n"
" adb uninstall [-k] <package> - remove this app package from the device\n"
" ('-k' means keep the data and cache directories)\n"
" adb bugreport - return all information from the device\n"
@ -195,7 +200,7 @@ void help()
" adb get-serialno - prints: <serial-number>\n"
" adb get-devpath - prints: <device-path>\n"
" adb status-window - continuously print device status for a specified device\n"
" adb remount - remounts the /system partition on the device read-write\n"
" adb remount - remounts the /system and /vendor (if present) partitions on the device read-write\n"
" adb reboot [bootloader|recovery] - reboots the device, optionally into the bootloader or recovery program\n"
" adb reboot-bootloader - reboots the device into the bootloader\n"
" adb root - restarts the adbd daemon with root permissions\n"
@ -211,9 +216,9 @@ void help()
"adb sync notes: adb sync [ <directory> ]\n"
" <localdir> can be interpreted in several ways:\n"
"\n"
" - If <directory> is not specified, both /system and /data partitions will be updated.\n"
" - If <directory> is not specified, /system, /vendor (if present), and /data partitions will be updated.\n"
"\n"
" - If it is \"system\" or \"data\", only the corresponding partition\n"
" - If it is \"system\", \"vendor\" or \"data\", only the corresponding partition\n"
" is updated.\n"
"\n"
"environmental variables:\n"
@ -279,6 +284,24 @@ static void read_and_dump(int fd)
}
}
static void read_status_line(int fd, char* buf, size_t count)
{
count--;
while (count > 0) {
int len = adb_read(fd, buf, count);
if (len == 0) {
break;
} else if (len < 0) {
if (errno == EINTR) continue;
break;
}
buf += len;
count -= len;
}
*buf = '\0';
}
static void copy_to_file(int inFd, int outFd) {
const size_t BUFSIZE = 32 * 1024;
char* buf = (char*) malloc(BUFSIZE);
@ -653,7 +676,12 @@ static void status_window(transport_type ttype, const char* serial)
}
}
/** Duplicate and escape given argument. */
static int should_escape(const char c)
{
return (c == ' ' || c == '\'' || c == '"' || c == '\\' || c == '(' || c == ')');
}
/* Duplicate and escape given argument. */
static char *escape_arg(const char *s)
{
const char *ts;
@ -664,7 +692,7 @@ static char *escape_arg(const char *s)
alloc_len = 0;
for (ts = s; *ts != '\0'; ts++) {
alloc_len++;
if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
if (should_escape(*ts)) {
alloc_len++;
}
}
@ -682,7 +710,7 @@ static char *escape_arg(const char *s)
dest = ret;
for (ts = s; *ts != '\0'; ts++) {
if (*ts == ' ' || *ts == '"' || *ts == '\\' || *ts == '(' || *ts == ')') {
if (should_escape(*ts)) {
*dest++ = '\\';
}
*dest++ = *ts;
@ -1575,7 +1603,7 @@ top:
parse_push_pull_args(&argv[1], argc - 1, &lpath, &rpath, &show_progress, &copy_attrs);
if ((lpath != NULL) && (rpath != NULL)) {
return do_sync_push(lpath, rpath, 0 /* no verify APK */, show_progress);
return do_sync_push(lpath, rpath, show_progress);
}
return usage();
@ -1595,18 +1623,23 @@ top:
return usage();
}
if(!strcmp(argv[0], "install")) {
if (!strcmp(argv[0], "install")) {
if (argc < 2) return usage();
return install_app(ttype, serial, argc, argv);
}
if(!strcmp(argv[0], "uninstall")) {
if (!strcmp(argv[0], "install-multiple")) {
if (argc < 2) return usage();
return install_multiple_app(ttype, serial, argc, argv);
}
if (!strcmp(argv[0], "uninstall")) {
if (argc < 2) return usage();
return uninstall_app(ttype, serial, argc, argv);
}
if(!strcmp(argv[0], "sync")) {
char *srcarg, *android_srcpath, *data_srcpath;
char *srcarg, *android_srcpath, *data_srcpath, *vendor_srcpath;
int listonly = 0;
int ret;
@ -1626,15 +1659,18 @@ top:
} else {
return usage();
}
ret = find_sync_dirs(srcarg, &android_srcpath, &data_srcpath);
ret = find_sync_dirs(srcarg, &android_srcpath, &data_srcpath, &vendor_srcpath);
if(ret != 0) return usage();
if(android_srcpath != NULL)
ret = do_sync_sync(android_srcpath, "/system", listonly);
if(ret == 0 && vendor_srcpath != NULL)
ret = do_sync_sync(vendor_srcpath, "/vendor", listonly);
if(ret == 0 && data_srcpath != NULL)
ret = do_sync_sync(data_srcpath, "/data", listonly);
free(android_srcpath);
free(vendor_srcpath);
free(data_srcpath);
return ret;
}
@ -1748,25 +1784,30 @@ static int do_cmd(transport_type ttype, char* serial, char *cmd, ...)
}
int find_sync_dirs(const char *srcarg,
char **android_srcdir_out, char **data_srcdir_out)
char **android_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out)
{
char *android_srcdir, *data_srcdir;
char *android_srcdir = NULL, *data_srcdir = NULL, *vendor_srcdir = NULL;
struct stat st;
if(srcarg == NULL) {
android_srcdir = product_file("system");
data_srcdir = product_file("data");
vendor_srcdir = product_file("vendor");
/* Check if vendor partition exists */
if (lstat(vendor_srcdir, &st) || !S_ISDIR(st.st_mode))
vendor_srcdir = NULL;
} else {
/* srcarg may be "data", "system" or NULL.
* if srcarg is NULL, then both data and system are synced
*/
if(strcmp(srcarg, "system") == 0) {
android_srcdir = product_file("system");
data_srcdir = NULL;
} else if(strcmp(srcarg, "data") == 0) {
android_srcdir = NULL;
data_srcdir = product_file("data");
} else if(strcmp(srcarg, "vendor") == 0) {
vendor_srcdir = product_file("vendor");
} else {
/* It's not "system" or "data".
/* It's not "system", "vendor", or "data".
*/
return 1;
}
@ -1777,11 +1818,15 @@ int find_sync_dirs(const char *srcarg,
else
free(android_srcdir);
if(data_srcdir_out != NULL)
*data_srcdir_out = data_srcdir;
if(vendor_srcdir_out != NULL)
*vendor_srcdir_out = vendor_srcdir;
else
free(data_srcdir);
free(vendor_srcdir);
if(data_srcdir_out != NULL)
*data_srcdir_out = data_srcdir;
else
free(data_srcdir);
return 0;
}
@ -1826,7 +1871,7 @@ static int delete_file(transport_type transport, char* serial, char* filename)
char buf[4096];
char* quoted;
snprintf(buf, sizeof(buf), "shell:rm ");
snprintf(buf, sizeof(buf), "shell:rm -f ");
quoted = escape_arg(filename);
strncat(buf, quoted, sizeof(buf)-1);
free(quoted);
@ -1846,117 +1891,186 @@ static const char* get_basename(const char* filename)
}
}
static int check_file(const char* filename)
{
struct stat st;
if (filename == NULL) {
return 0;
}
if (stat(filename, &st) != 0) {
fprintf(stderr, "can't find '%s' to install\n", filename);
return 1;
}
if (!S_ISREG(st.st_mode)) {
fprintf(stderr, "can't install '%s' because it's not a file\n", filename);
return 1;
}
return 0;
}
int install_app(transport_type transport, char* serial, int argc, char** argv)
{
static const char *const DATA_DEST = "/data/local/tmp/%s";
static const char *const SD_DEST = "/sdcard/tmp/%s";
const char* where = DATA_DEST;
char apk_dest[PATH_MAX];
char verification_dest[PATH_MAX];
char* apk_file;
char* verification_file = NULL;
int file_arg = -1;
int err;
int i;
int verify_apk = 1;
struct stat sb;
for (i = 1; i < argc; i++) {
if (*argv[i] != '-') {
file_arg = i;
break;
} else if (!strcmp(argv[i], "-i")) {
// Skip the installer package name.
i++;
} else if (!strcmp(argv[i], "-s")) {
if (!strcmp(argv[i], "-s")) {
where = SD_DEST;
} else if (!strcmp(argv[i], "--algo")) {
verify_apk = 0;
i++;
} else if (!strcmp(argv[i], "--iv")) {
verify_apk = 0;
i++;
} else if (!strcmp(argv[i], "--key")) {
verify_apk = 0;
i++;
} else if (!strcmp(argv[i], "--abi")) {
i++;
}
}
if (file_arg < 0) {
fprintf(stderr, "can't find filename in arguments\n");
return 1;
} else if (file_arg + 2 < argc) {
fprintf(stderr, "too many files specified; only takes APK file and verifier file\n");
return 1;
// Find last APK argument.
// All other arguments passed through verbatim.
int last_apk = -1;
for (i = argc - 1; i >= 0; i--) {
char* file = argv[i];
char* dot = strrchr(file, '.');
if (dot && !strcasecmp(dot, ".apk")) {
if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) {
fprintf(stderr, "Invalid APK file: %s\n", file);
return -1;
}
last_apk = i;
break;
}
}
apk_file = argv[file_arg];
if (file_arg != argc - 1) {
verification_file = argv[file_arg + 1];
}
if (check_file(apk_file) || check_file(verification_file)) {
return 1;
if (last_apk == -1) {
fprintf(stderr, "Missing APK file\n");
return -1;
}
char* apk_file = argv[last_apk];
char apk_dest[PATH_MAX];
snprintf(apk_dest, sizeof apk_dest, where, get_basename(apk_file));
if (verification_file != NULL) {
snprintf(verification_dest, sizeof(verification_dest), where, get_basename(verification_file));
if (!strcmp(apk_dest, verification_dest)) {
fprintf(stderr, "APK and verification file can't have the same name\n");
return 1;
}
}
err = do_sync_push(apk_file, apk_dest, verify_apk, 0 /* no show progress */);
int err = do_sync_push(apk_file, apk_dest, 0 /* no show progress */);
if (err) {
goto cleanup_apk;
} else {
argv[file_arg] = apk_dest; /* destination name, not source location */
}
if (verification_file != NULL) {
err = do_sync_push(verification_file, verification_dest, 0 /* no verify APK */,
0 /* no show progress */);
if (err) {
goto cleanup_apk;
} else {
argv[file_arg + 1] = verification_dest; /* destination name, not source location */
}
argv[last_apk] = apk_dest; /* destination name, not source location */
}
pm_command(transport, serial, argc, argv);
cleanup_apk:
if (verification_file != NULL) {
delete_file(transport, serial, verification_dest);
}
delete_file(transport, serial, apk_dest);
return err;
}
int install_multiple_app(transport_type transport, char* serial, int argc, char** argv)
{
char buf[1024];
int i;
struct stat sb;
unsigned long long total_size = 0;
// Find all APK arguments starting at end.
// All other arguments passed through verbatim.
int first_apk = -1;
for (i = argc - 1; i >= 0; i--) {
char* file = argv[i];
char* dot = strrchr(file, '.');
if (dot && !strcasecmp(dot, ".apk")) {
if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) {
fprintf(stderr, "Invalid APK file: %s\n", file);
return -1;
}
total_size += sb.st_size;
first_apk = i;
} else {
break;
}
}
if (first_apk == -1) {
fprintf(stderr, "Missing APK file\n");
return 1;
}
snprintf(buf, sizeof(buf), "exec:pm install-create -S %lld", total_size);
for (i = 1; i < first_apk; i++) {
char *quoted = escape_arg(argv[i]);
strncat(buf, " ", sizeof(buf) - 1);
strncat(buf, quoted, sizeof(buf) - 1);
free(quoted);
}
// Create install session
int fd = adb_connect(buf);
if (fd < 0) {
fprintf(stderr, "Connect error for create: %s\n", adb_error());
return -1;
}
read_status_line(fd, buf, sizeof(buf));
adb_close(fd);
int session_id = -1;
if (!strncmp("Success", buf, 7)) {
char* start = strrchr(buf, '[');
char* end = strrchr(buf, ']');
if (start && end) {
*end = '\0';
session_id = strtol(start + 1, NULL, 10);
}
}
if (session_id < 0) {
fprintf(stderr, "Failed to create session\n");
fputs(buf, stderr);
return -1;
}
// Valid session, now stream the APKs
int success = 1;
for (i = first_apk; i < argc; i++) {
char* file = argv[i];
if (stat(file, &sb) == -1) {
fprintf(stderr, "Failed to stat %s\n", file);
success = 0;
goto finalize_session;
}
snprintf(buf, sizeof(buf), "exec:pm install-write -S %lld %d %d_%s -",
(long long int) sb.st_size, session_id, i, get_basename(file));
int localFd = adb_open(file, O_RDONLY);
if (localFd < 0) {
fprintf(stderr, "Failed to open %s: %s\n", file, adb_error());
success = 0;
goto finalize_session;
}
int remoteFd = adb_connect(buf);
if (remoteFd < 0) {
fprintf(stderr, "Connect error for write: %s\n", adb_error());
adb_close(localFd);
success = 0;
goto finalize_session;
}
copy_to_file(localFd, remoteFd);
read_status_line(remoteFd, buf, sizeof(buf));
adb_close(localFd);
adb_close(remoteFd);
if (strncmp("Success", buf, 7)) {
fprintf(stderr, "Failed to write %s\n", file);
fputs(buf, stderr);
success = 0;
goto finalize_session;
}
}
finalize_session:
// Commit session if we streamed everything okay; otherwise abandon
if (success) {
snprintf(buf, sizeof(buf), "exec:pm install-commit %d", session_id);
} else {
snprintf(buf, sizeof(buf), "exec:pm install-abandon %d", session_id);
}
fd = adb_connect(buf);
if (fd < 0) {
fprintf(stderr, "Connect error for finalize: %s\n", adb_error());
return -1;
}
read_status_line(fd, buf, sizeof(buf));
adb_close(fd);
if (!strncmp("Success", buf, 7)) {
fputs(buf, stderr);
return 0;
} else {
fprintf(stderr, "Failed to finalize session\n");
fputs(buf, stderr);
return -1;
}
}

View File

@ -28,10 +28,12 @@
#include <stdarg.h>
#include <stddef.h>
#include "adb_trace.h"
#include "fdevent.h"
#include "transport.h"
#include "sysdeps.h"
#define TRACE_TAG TRACE_FDEVENT
/* !!! Do not enable DEBUG for the adb that will run as the server:
** both stdout and stderr are used to communicate between the client
@ -57,16 +59,6 @@ static void fatal(const char *fn, const char *fmt, ...)
#define FATAL(x...) fatal(__FUNCTION__, x)
#if DEBUG
#define D(...) \
do { \
adb_mutex_lock(&D_lock); \
int save_errno = errno; \
fprintf(stderr, "%s::%s():", __FILE__, __FUNCTION__); \
errno = save_errno; \
fprintf(stderr, __VA_ARGS__); \
adb_mutex_unlock(&D_lock); \
errno = save_errno; \
} while(0)
static void dump_fde(fdevent *fde, const char *info)
{
adb_mutex_lock(&D_lock);
@ -78,7 +70,6 @@ static void dump_fde(fdevent *fde, const char *info)
adb_mutex_unlock(&D_lock);
}
#else
#define D(...) ((void)0)
#define dump_fde(fde, info) do { } while(0)
#endif

View File

@ -335,7 +335,7 @@ static int write_data_link(int fd, const char *path, syncsendbuf *sbuf)
#endif
static int sync_send(int fd, const char *lpath, const char *rpath,
unsigned mtime, mode_t mode, int verifyApk, int show_progress)
unsigned mtime, mode_t mode, int show_progress)
{
syncmsg msg;
int len, r;
@ -350,63 +350,6 @@ static int sync_send(int fd, const char *lpath, const char *rpath,
snprintf(tmp, sizeof(tmp), ",%d", mode);
r = strlen(tmp);
if (verifyApk) {
int lfd;
zipfile_t zip;
zipentry_t entry;
int amt;
// if we are transferring an APK file, then sanity check to make sure
// we have a real zip file that contains an AndroidManifest.xml
// this requires that we read the entire file into memory.
lfd = adb_open(lpath, O_RDONLY);
if(lfd < 0) {
fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno));
return -1;
}
size = adb_lseek(lfd, 0, SEEK_END);
if (size == -1 || -1 == adb_lseek(lfd, 0, SEEK_SET)) {
fprintf(stderr, "error seeking in file '%s'\n", lpath);
adb_close(lfd);
return 1;
}
file_buffer = (char *)malloc(size);
if (file_buffer == NULL) {
fprintf(stderr, "could not allocate buffer for '%s'\n",
lpath);
adb_close(lfd);
return 1;
}
amt = adb_read(lfd, file_buffer, size);
if (amt != size) {
fprintf(stderr, "error reading from file: '%s'\n", lpath);
adb_close(lfd);
free(file_buffer);
return 1;
}
adb_close(lfd);
zip = init_zipfile(file_buffer, size);
if (zip == NULL) {
fprintf(stderr, "file '%s' is not a valid zip file\n",
lpath);
free(file_buffer);
return 1;
}
entry = lookup_zipentry(zip, "AndroidManifest.xml");
release_zipfile(zip);
if (entry == NULL) {
fprintf(stderr, "file '%s' does not contain AndroidManifest.xml\n",
lpath);
free(file_buffer);
return 1;
}
}
msg.req.id = ID_SEND;
msg.req.namelen = htoll(len + r);
@ -697,30 +640,33 @@ static int local_build_list(copyinfo **filelist,
continue;
strcpy(stat_path, lpath);
strcat(stat_path, de->d_name);
stat(stat_path, &st);
if (S_ISDIR(st.st_mode)) {
ci = mkcopyinfo(lpath, rpath, name, 1);
ci->next = dirlist;
dirlist = ci;
} else {
ci = mkcopyinfo(lpath, rpath, name, 0);
if(lstat(ci->src, &st)) {
fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
free(ci);
closedir(d);
return -1;
}
if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
fprintf(stderr, "skipping special file '%s'\n", ci->src);
free(ci);
if(!lstat(stat_path, &st)) {
if (S_ISDIR(st.st_mode)) {
ci = mkcopyinfo(lpath, rpath, name, 1);
ci->next = dirlist;
dirlist = ci;
} else {
ci->time = st.st_mtime;
ci->mode = st.st_mode;
ci->size = st.st_size;
ci->next = *filelist;
*filelist = ci;
ci = mkcopyinfo(lpath, rpath, name, 0);
if(lstat(ci->src, &st)) {
fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
free(ci);
closedir(d);
return -1;
}
if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
fprintf(stderr, "skipping special file '%s'\n", ci->src);
free(ci);
} else {
ci->time = st.st_mtime;
ci->mode = st.st_mode;
ci->size = st.st_size;
ci->next = *filelist;
*filelist = ci;
}
}
} else {
fprintf(stderr, "cannot lstat '%s': %s\n",stat_path , strerror(errno));
}
}
@ -786,7 +732,7 @@ static int copy_local_dir_remote(int fd, const char *lpath, const char *rpath, i
if(ci->flag == 0) {
fprintf(stderr,"%spush: %s -> %s\n", listonly ? "would " : "", ci->src, ci->dst);
if(!listonly &&
sync_send(fd, ci->src, ci->dst, ci->time, ci->mode, 0 /* no verify APK */,
sync_send(fd, ci->src, ci->dst, ci->time, ci->mode,
0 /* no show progress */)) {
return 1;
}
@ -805,7 +751,7 @@ static int copy_local_dir_remote(int fd, const char *lpath, const char *rpath, i
}
int do_sync_push(const char *lpath, const char *rpath, int verifyApk, int show_progress)
int do_sync_push(const char *lpath, const char *rpath, int show_progress)
{
struct stat st;
unsigned mode;
@ -852,7 +798,7 @@ int do_sync_push(const char *lpath, const char *rpath, int verifyApk, int show_p
rpath = tmp;
}
BEGIN();
if(sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, verifyApk, show_progress)) {
if(sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, show_progress)) {
return 1;
} else {
END();

View File

@ -39,6 +39,11 @@ static bool is_on_system(const char *name) {
return (strncmp(SYSTEM, name, strlen(SYSTEM)) == 0);
}
static bool is_on_vendor(const char *name) {
const char *VENDOR = "/vendor/";
return (strncmp(VENDOR, name, strlen(VENDOR)) == 0);
}
static int mkdirs(char *name)
{
int ret;
@ -54,7 +59,7 @@ static int mkdirs(char *name)
x = adb_dirstart(x);
if(x == 0) return 0;
*x = 0;
if (is_on_system(name)) {
if (is_on_system(name) || is_on_vendor(name)) {
fs_config(name, 1, &uid, &gid, &mode, &cap);
}
ret = adb_mkdir(name, mode);
@ -369,7 +374,7 @@ static int do_send(int s, char *path, char *buffer)
if(*tmp == '/') {
tmp++;
}
if (is_on_system(path)) {
if (is_on_system(path) || is_on_vendor(path)) {
fs_config(tmp, 0, &uid, &gid, &mode, &cap);
}
ret = handle_send_file(s, path, uid, gid, mode, buffer, do_unlink);

View File

@ -78,7 +78,7 @@ typedef union {
void file_sync_service(int fd, void *cookie);
int do_sync_ls(const char *path);
int do_sync_push(const char *lpath, const char *rpath, int verifyApk, int show_progress);
int do_sync_push(const char *lpath, const char *rpath, int show_progress);
int do_sync_sync(const char *lpath, const char *rpath, int listonly);
int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int pullTime);

View File

@ -29,6 +29,7 @@
static int system_ro = 1;
static int vendor_ro = 1;
/* Returns the device used to mount a directory in /proc/mounts */
static char *find_mount(const char *dir)
@ -67,18 +68,27 @@ static char *find_mount(const char *dir)
return NULL;
}
static int hasVendorPartition()
{
struct stat info;
if (!lstat("/vendor", &info))
if ((info.st_mode & S_IFMT) == S_IFDIR)
return true;
return false;
}
/* Init mounts /system as read only, remount to enable writes. */
static int remount_system()
static int remount(const char* dir, int* dir_ro)
{
char *dev;
int fd;
int OFF = 0;
if (system_ro == 0) {
if (dir_ro == 0) {
return 0;
}
dev = find_mount("/system");
dev = find_mount(dir);
if (!dev)
return -1;
@ -90,11 +100,11 @@ static int remount_system()
ioctl(fd, BLKROSET, &OFF);
adb_close(fd);
system_ro = mount(dev, "/system", "none", MS_REMOUNT, NULL);
*dir_ro = mount(dev, dir, "none", MS_REMOUNT, NULL);
free(dev);
return system_ro;
return *dir_ro;
}
static void write_string(int fd, const char* str)
@ -104,16 +114,25 @@ static void write_string(int fd, const char* str)
void remount_service(int fd, void *cookie)
{
int ret = remount_system();
if (!ret)
write_string(fd, "remount succeeded\n");
else {
char buffer[200];
snprintf(buffer, sizeof(buffer), "remount failed: %s\n", strerror(errno));
char buffer[200];
if (remount("/system", &system_ro)) {
snprintf(buffer, sizeof(buffer), "remount of system failed: %s\n",strerror(errno));
write_string(fd, buffer);
}
if (hasVendorPartition()) {
if (remount("/vendor", &vendor_ro)) {
snprintf(buffer, sizeof(buffer), "remount of vendor failed: %s\n",strerror(errno));
write_string(fd, buffer);
}
}
if (!system_ro && (!vendor_ro || !hasVendorPartition()))
write_string(fd, "remount succeeded\n");
else {
write_string(fd, "remount failed\n");
}
adb_close(fd);
}

View File

@ -281,9 +281,10 @@ static int create_subproc_raw(const char *cmd, const char *arg0, const char *arg
adb_close(sv[0]);
init_subproc_child();
// Only hook up stdin/stdout; drop stderr
dup2(sv[1], STDIN_FILENO);
dup2(sv[1], STDOUT_FILENO);
dup2(sv[1], STDERR_FILENO);
adb_close(sv[1]);
execl(cmd, cmd, arg0, arg1, NULL);

View File

@ -26,8 +26,8 @@
#ifdef _WIN32
#include <windows.h>
#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#include <process.h>
#include <fcntl.h>
@ -35,6 +35,7 @@
#include <sys/stat.h>
#include <errno.h>
#include <ctype.h>
#include <direct.h>
#define OS_PATH_SEPARATOR '\\'
#define OS_PATH_SEPARATOR_STR "\\"

View File

@ -1,6 +1,6 @@
#include "sysdeps.h"
#include <windows.h>
#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#include <errno.h>
#define TRACE_TAG TRACE_SYSDEPS
@ -1549,7 +1549,7 @@ _wait_for_all(HANDLE* handles, int handles_count)
* reset" event that will remain set once it was set. */
main_event = CreateEvent(NULL, TRUE, FALSE, NULL);
if (main_event == NULL) {
D("Unable to create main event. Error: %d", GetLastError());
D("Unable to create main event. Error: %d", (int)GetLastError());
free(threads);
return (int)WAIT_FAILED;
}

View File

@ -14,6 +14,7 @@
* limitations under the License.
*/
#include <winsock2.h>
#include <windows.h>
#include <winerror.h>
#include <errno.h>

View File

@ -1,61 +0,0 @@
# Copyright 2011 The Android Open Source Project
ifneq ($(BUILD_TINY_ANDROID),true)
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
charger.c
ifeq ($(strip $(BOARD_CHARGER_DISABLE_INIT_BLANK)),true)
LOCAL_CFLAGS := -DCHARGER_DISABLE_INIT_BLANK
endif
ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
LOCAL_CFLAGS += -DCHARGER_ENABLE_SUSPEND
endif
LOCAL_MODULE := charger
LOCAL_MODULE_TAGS := optional
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
LOCAL_C_INCLUDES := bootable/recovery
LOCAL_STATIC_LIBRARIES := libminui libpng
ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
LOCAL_STATIC_LIBRARIES += libsuspend
endif
LOCAL_STATIC_LIBRARIES += libz libstdc++ libcutils liblog libm libc
include $(BUILD_EXECUTABLE)
define _add-charger-image
include $$(CLEAR_VARS)
LOCAL_MODULE := system_core_charger_$(notdir $(1))
LOCAL_MODULE_STEM := $(notdir $(1))
_img_modules += $$(LOCAL_MODULE)
LOCAL_SRC_FILES := $1
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $$(TARGET_ROOT_OUT)/res/images/charger
include $$(BUILD_PREBUILT)
endef
_img_modules :=
_images :=
$(foreach _img, $(call find-subdir-subdir-files, "images", "*.png"), \
$(eval $(call _add-charger-image,$(_img))))
include $(CLEAR_VARS)
LOCAL_MODULE := charger_res_images
LOCAL_MODULE_TAGS := optional
LOCAL_REQUIRED_MODULES := $(_img_modules)
include $(BUILD_PHONY_PACKAGE)
_add-charger-image :=
_img_modules :=
endif

View File

@ -49,13 +49,13 @@ static void dump_process_header(log_t* log, pid_t pid) {
struct tm tm;
localtime_r(&t, &tm);
char timestr[64];
_LOG(log, logtype::BACKTRACE, "\n\nABI: '%s'\n", ABI_STRING);
strftime(timestr, sizeof(timestr), "%F %T", &tm);
_LOG(log, logtype::BACKTRACE, "\n----- pid %d at %s -----\n", pid, timestr);
_LOG(log, logtype::BACKTRACE, "\n\n----- pid %d at %s -----\n", pid, timestr);
if (procname) {
_LOG(log, logtype::BACKTRACE, "Cmd line: %s\n", procname);
}
_LOG(log, logtype::BACKTRACE, "ABI: '%s'\n", ABI_STRING);
}
static void dump_process_footer(log_t* log, pid_t pid) {

4
debuggerd/tombstone.cpp Executable file → Normal file
View File

@ -681,7 +681,7 @@ static char* find_and_open_tombstone(int* fd) {
if (errno != ENOENT)
continue;
*fd = open(path, O_CREAT | O_EXCL | O_WRONLY, 0600);
*fd = open(path, O_CREAT | O_EXCL | O_WRONLY | O_NOFOLLOW | O_CLOEXEC, 0600);
if (*fd < 0)
continue; // raced ?
@ -696,7 +696,7 @@ static char* find_and_open_tombstone(int* fd) {
// we didn't find an available file, so we clobber the oldest one
snprintf(path, sizeof(path), TOMBSTONE_TEMPLATE, oldest);
*fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
*fd = open(path, O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW | O_CLOEXEC, 0600);
if (*fd < 0) {
ALOGE("failed to open tombstone file '%s': %s\n", path, strerror(errno));
return NULL;

View File

@ -17,7 +17,8 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../mkbootimg \
$(LOCAL_PATH)/../../extras/ext4_utils
$(LOCAL_PATH)/../../extras/ext4_utils \
$(LOCAL_PATH)/../../extras/f2fs_utils
LOCAL_SRC_FILES := protocol.c engine.c bootimg.c fastboot.c util.c fs.c
LOCAL_MODULE := fastboot
LOCAL_MODULE_TAGS := debug
@ -40,13 +41,11 @@ ifeq ($(HOST_OS),windows)
ifneq ($(strip $(USE_CYGWIN)),)
# Pure cygwin case
LOCAL_LDLIBS += -lpthread
LOCAL_C_INCLUDES += /usr/include/w32api/ddk
endif
ifneq ($(strip $(USE_MINGW)),)
# MinGW under Linux case
LOCAL_LDLIBS += -lws2_32
USE_SYSDEPS_WIN32 := 1
LOCAL_C_INCLUDES += /usr/i586-mingw32msvc/include/ddk
endif
LOCAL_C_INCLUDES += development/host/windows/usb/api
endif
@ -63,10 +62,24 @@ ifneq ($(HOST_OS),windows)
LOCAL_STATIC_LIBRARIES += libselinux
endif # HOST_OS != windows
ifeq ($(HOST_OS),linux)
# libf2fs_dlutils_host will dlopen("libf2fs_fmt_host_dyn")
LOCAL_CFLAGS += -DUSE_F2FS
LOCAL_LDFLAGS += -ldl -rdynamic -Wl,-rpath,.
LOCAL_REQUIRED_MODULES := libf2fs_fmt_host_dyn
# The following libf2fs_* are from system/extras/f2fs_utils,
# and do not use code in external/f2fs-tools.
LOCAL_STATIC_LIBRARIES += libf2fs_utils_host libf2fs_ioutils_host libf2fs_dlutils_host
endif
include $(BUILD_HOST_EXECUTABLE)
$(call dist-for-goals,dist_files sdk,$(LOCAL_BUILT_MODULE))
my_dist_files := $(LOCAL_BUILT_MODULE)
ifeq ($(HOST_OS),linux)
my_dist_files += $(HOST_LIBRARY_PATH)/libf2fs_fmt_host_dyn$(HOST_SHLIB_SUFFIX)
endif
$(call dist-for-goals,dist_files sdk,$(my_dist_files))
my_dist_files :=
ifeq ($(HOST_OS),linux)

View File

@ -99,11 +99,11 @@ static struct {
char sig_name[13];
char part_name[9];
bool is_optional;
} images[4] = {
} images[] = {
{"boot.img", "boot.sig", "boot", false},
{"recovery.img", "recovery.sig", "recovery", true},
{"system.img", "system.sig", "system", false},
{"tos.img", "tos.sig", "tos", true},
{"vendor.img", "vendor.sig", "vendor", true},
};
void get_my_path(char *path);
@ -120,8 +120,8 @@ char *find_item(const char *item, const char *product)
fn = "recovery.img";
} else if(!strcmp(item,"system")) {
fn = "system.img";
} else if(!strcmp(item,"tos")) {
fn = "tos.img";
} else if(!strcmp(item,"vendor")) {
fn = "vendor.img";
} else if(!strcmp(item,"userdata")) {
fn = "userdata.img";
} else if(!strcmp(item,"cache")) {
@ -287,8 +287,8 @@ void usage(void)
"\n"
"commands:\n"
" update <filename> reflash device from update.zip\n"
" flashall flash boot, system, and if found,\n"
" recovery, tos\n"
" flashall flash boot, system, vendor and if found,\n"
" recovery\n"
" flash <partition> [ <filename> ] write a file to a flash partition\n"
" erase <partition> erase a flash partition\n"
" format[:[<fs type>][:[<size>]] <partition> format a flash partition.\n"

View File

@ -1,5 +1,6 @@
#include "fastboot.h"
#include "make_ext4fs.h"
#include "make_f2fs.h"
#include "fs.h"
#include <errno.h>
@ -28,15 +29,23 @@ static int generate_ext4_image(int fd, long long partSize)
return 0;
}
#ifdef USE_F2FS
static int generate_f2fs_image(int fd, long long partSize)
{
return make_f2fs_sparse_fd(fd, partSize, NULL, NULL);
}
#endif
static const struct fs_generator {
char *fs_type; //must match what fastboot reports for partition type
int (*generate)(int fd, long long partSize); //returns 0 or error value
} generators[] = {
{ "ext4", generate_ext4_image}
{ "ext4", generate_ext4_image},
#ifdef USE_F2FS
{ "f2fs", generate_f2fs_image},
#endif
};
const struct fs_generator* fs_get_generator(const char *fs_type)

View File

@ -31,6 +31,7 @@
#include <linux/loop.h>
#include <private/android_filesystem_config.h>
#include <cutils/android_reboot.h>
#include <cutils/partition_utils.h>
#include <cutils/properties.h>
#include <logwrap/logwrap.h>
@ -46,6 +47,7 @@
#define KEY_IN_FOOTER "footer"
#define E2FSCK_BIN "/system/bin/e2fsck"
#define F2FS_FSCK_BIN "/system/bin/fsck.f2fs"
#define MKSWAP_BIN "/system/bin/mkswap"
#define FSCK_LOG_FILE "/dev/fscklogs/log"
@ -112,6 +114,7 @@ static void check_fs(char *blk_device, char *fs_type, char *target)
* fix the filesystem.
*/
ret = mount(blk_device, target, fs_type, tmpmnt_flags, tmpmnt_opts);
INFO("%s(): mount(%s,%s,%s)=%d\n", __func__, blk_device, target, fs_type, ret);
if (!ret) {
umount(target);
}
@ -135,6 +138,20 @@ static void check_fs(char *blk_device, char *fs_type, char *target)
ERROR("Failed trying to run %s\n", E2FSCK_BIN);
}
}
} else if (!strcmp(fs_type, "f2fs")) {
char *f2fs_fsck_argv[] = {
F2FS_FSCK_BIN,
blk_device
};
INFO("Running %s on %s\n", F2FS_FSCK_BIN, blk_device);
ret = android_fork_execvp_ext(ARRAY_SIZE(f2fs_fsck_argv), f2fs_fsck_argv,
&status, true, LOG_KLOG | LOG_FILE,
true, FSCK_LOG_FILE);
if (ret < 0) {
/* No need to check for error in fork, we can't really handle it now */
ERROR("Failed trying to run %s\n", F2FS_FSCK_BIN);
}
}
return;
@ -175,16 +192,27 @@ static void fs_set_blk_ro(const char *blockdev)
* sets the underlying block device to read-only if the mount is read-only.
* See "man 2 mount" for return values.
*/
static int __mount(const char *source, const char *target,
const char *filesystemtype, unsigned long mountflags,
const void *data)
static int __mount(const char *source, const char *target, const struct fstab_rec *rec)
{
int ret = mount(source, target, filesystemtype, mountflags, data);
unsigned long mountflags = rec->flags;
int ret;
int save_errno;
/* We need this because sometimes we have legacy symlinks
* that are lingering around and need cleaning up.
*/
struct stat info;
if (!lstat(target, &info))
if ((info.st_mode & S_IFMT) == S_IFLNK)
unlink(target);
mkdir(target, 0755);
ret = mount(source, target, rec->fs_type, mountflags, rec->fs_options);
save_errno = errno;
INFO("%s(source=%s,target=%s,type=%s)=%d\n", __func__, source, target, rec->fs_type, ret);
if ((ret == 0) && (mountflags & MS_RDONLY) != 0) {
fs_set_blk_ro(source);
}
errno = save_errno;
return ret;
}
@ -208,16 +236,101 @@ static int fs_match(char *in1, char *in2)
return ret;
}
static int device_is_debuggable() {
int ret = -1;
char value[PROP_VALUE_MAX];
ret = __system_property_get("ro.debuggable", value);
if (ret < 0)
return ret;
return strcmp(value, "1") ? 0 : 1;
}
/*
* Tries to mount any of the consecutive fstab entries that match
* the mountpoint of the one given by fstab->recs[start_idx].
*
* end_idx: On return, will be the last rec that was looked at.
* attempted_idx: On return, will indicate which fstab rec
* succeeded. In case of failure, it will be the start_idx.
* Returns
* -1 on failure with errno set to match the 1st mount failure.
* 0 on success.
*/
static int mount_with_alternatives(struct fstab *fstab, int start_idx, int *end_idx, int *attempted_idx)
{
int i;
int mount_errno = 0;
int mounted = 0;
if (!end_idx || !attempted_idx || start_idx >= fstab->num_entries) {
errno = EINVAL;
if (end_idx) *end_idx = start_idx;
if (attempted_idx) *end_idx = start_idx;
return -1;
}
/* Hunt down an fstab entry for the same mount point that might succeed */
for (i = start_idx;
/* We required that fstab entries for the same mountpoint be consecutive */
i < fstab->num_entries && !strcmp(fstab->recs[start_idx].mount_point, fstab->recs[i].mount_point);
i++) {
/*
* Don't try to mount/encrypt the same mount point again.
* Deal with alternate entries for the same point which are required to be all following
* each other.
*/
if (mounted) {
ERROR("%s(): skipping fstab dup mountpoint=%s rec[%d].fs_type=%s already mounted as %s.\n", __func__,
fstab->recs[i].mount_point, i, fstab->recs[i].fs_type, fstab->recs[*attempted_idx].fs_type);
continue;
}
if (fstab->recs[i].fs_mgr_flags & MF_CHECK) {
check_fs(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
fstab->recs[i].mount_point);
}
if (!__mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point, &fstab->recs[i])) {
*attempted_idx = i;
mounted = 1;
if (i != start_idx) {
ERROR("%s(): Mounted %s on %s with fs_type=%s instead of %s\n", __func__,
fstab->recs[i].blk_device, fstab->recs[i].mount_point, fstab->recs[i].fs_type,
fstab->recs[start_idx].fs_type);
}
} else {
/* back up errno for crypto decisions */
mount_errno = errno;
}
}
/* Adjust i for the case where it was still withing the recs[] */
if (i < fstab->num_entries) --i;
*end_idx = i;
if (!mounted) {
*attempted_idx = start_idx;
errno = mount_errno;
return -1;
}
return 0;
}
/* When multiple fstab records share the same mount_point, it will
* try to mount each one in turn, and ignore any duplicates after a
* first successful mount.
* Returns -1 on error, and FS_MGR_MNTALL_* otherwise.
*/
int fs_mgr_mount_all(struct fstab *fstab)
{
int i = 0;
int encrypted = 0;
int ret = -1;
int mret;
int mount_errno;
int encryptable = FS_MGR_MNTALL_DEV_NOT_ENCRYPTED;
int error_count = 0;
int mret = -1;
int mount_errno = 0;
int attempted_idx = -1;
if (!fstab) {
return ret;
return -1;
}
for (i = 0; i < fstab->num_entries; i++) {
@ -237,70 +350,92 @@ int fs_mgr_mount_all(struct fstab *fstab)
wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT);
}
if (fstab->recs[i].fs_mgr_flags & MF_CHECK) {
check_fs(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
fstab->recs[i].mount_point);
}
if (fstab->recs[i].fs_mgr_flags & MF_VERIFY) {
if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) &&
!device_is_debuggable()) {
if (fs_mgr_setup_verity(&fstab->recs[i]) < 0) {
ERROR("Could not set up verified partition, skipping!");
ERROR("Could not set up verified partition, skipping!\n");
continue;
}
}
int last_idx_inspected;
mret = mount_with_alternatives(fstab, i, &last_idx_inspected, &attempted_idx);
i = last_idx_inspected;
mount_errno = errno;
mret = __mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point,
fstab->recs[i].fs_type, fstab->recs[i].flags,
fstab->recs[i].fs_options);
/* Deal with encryptability. */
if (!mret) {
/* If this is encryptable, need to trigger encryption */
if ((fstab->recs[attempted_idx].fs_mgr_flags & MF_FORCECRYPT)) {
if (umount(fstab->recs[attempted_idx].mount_point) == 0) {
if (encryptable == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
ERROR("Will try to encrypt %s %s\n", fstab->recs[attempted_idx].mount_point,
fstab->recs[attempted_idx].fs_type);
encryptable = FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION;
} else {
ERROR("Only one encryptable/encrypted partition supported\n");
encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED;
}
} else {
INFO("Could not umount %s - allow continue unencrypted\n",
fstab->recs[attempted_idx].mount_point);
continue;
}
}
/* Success! Go get the next one */
continue;
}
/* back up errno as partition_wipe clobbers the value */
mount_errno = errno;
/* mount(2) returned an error, check if it's encrypted and deal with it */
if ((fstab->recs[i].fs_mgr_flags & MF_CRYPT) &&
!partition_wiped(fstab->recs[i].blk_device)) {
/* Need to mount a tmpfs at this mountpoint for now, and set
* properties that vold will query later for decrypting
*/
if (mount("tmpfs", fstab->recs[i].mount_point, "tmpfs",
MS_NOATIME | MS_NOSUID | MS_NODEV, CRYPTO_TMPFS_OPTIONS) < 0) {
ERROR("Cannot mount tmpfs filesystem for encrypted fs at %s error: %s\n",
fstab->recs[i].mount_point, strerror(errno));
goto out;
/* mount(2) returned an error, check if it's encryptable and deal with it */
if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
fs_mgr_is_encryptable(&fstab->recs[attempted_idx])) {
if(partition_wiped(fstab->recs[attempted_idx].blk_device)) {
ERROR("%s(): %s is wiped and %s %s is encryptable. Suggest recovery...\n", __func__,
fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
fstab->recs[attempted_idx].fs_type);
encryptable = FS_MGR_MNTALL_DEV_NEEDS_RECOVERY;
continue;
} else {
/* Need to mount a tmpfs at this mountpoint for now, and set
* properties that vold will query later for decrypting
*/
ERROR("%s(): possibly an encryptable blkdev %s for mount %s type %s )\n", __func__,
fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
fstab->recs[attempted_idx].fs_type);
if (fs_mgr_do_tmpfs_mount(fstab->recs[attempted_idx].mount_point) < 0) {
++error_count;
continue;
}
}
encrypted = 1;
encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED;
} else {
ERROR("Failed to mount an un-encryptable or wiped partition on"
"%s at %s options: %s error: %s\n",
fstab->recs[i].blk_device, fstab->recs[i].mount_point,
fstab->recs[i].fs_options, strerror(mount_errno));
goto out;
"%s at %s options: %s error: %s\n",
fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point,
fstab->recs[attempted_idx].fs_options, strerror(mount_errno));
++error_count;
continue;
}
}
if (encrypted) {
ret = 1;
if (error_count) {
return -1;
} else {
ret = 0;
return encryptable;
}
out:
return ret;
}
/* If tmp_mount_point is non-null, mount the filesystem there. This is for the
* tmp mount we do to check the user password
* If multiple fstab entries are to be mounted on "n_name", it will try to mount each one
* in turn, and stop on 1st success, or no more match.
*/
int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
char *tmp_mount_point)
{
int i = 0;
int ret = -1;
int ret = FS_MGR_DOMNT_FAILED;
int mount_errors = 0;
int first_mount_errno = 0;
char *m;
if (!fstab) {
@ -332,9 +467,10 @@ int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
fstab->recs[i].mount_point);
}
if (fstab->recs[i].fs_mgr_flags & MF_VERIFY) {
if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) &&
!device_is_debuggable()) {
if (fs_mgr_setup_verity(&fstab->recs[i]) < 0) {
ERROR("Could not set up verified partition, skipping!");
ERROR("Could not set up verified partition, skipping!\n");
continue;
}
}
@ -345,19 +481,27 @@ int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
} else {
m = fstab->recs[i].mount_point;
}
if (__mount(n_blk_device, m, fstab->recs[i].fs_type,
fstab->recs[i].flags, fstab->recs[i].fs_options)) {
ERROR("Cannot mount filesystem on %s at %s options: %s error: %s\n",
n_blk_device, m, fstab->recs[i].fs_options, strerror(errno));
goto out;
if (__mount(n_blk_device, m, &fstab->recs[i])) {
if (!first_mount_errno) first_mount_errno = errno;
mount_errors++;
continue;
} else {
ret = 0;
goto out;
}
}
/* We didn't find a match, say so and return an error */
ERROR("Cannot find mount point %s in fstab\n", fstab->recs[i].mount_point);
if (mount_errors) {
ERROR("Cannot mount filesystem on %s at %s. error: %s\n",
n_blk_device, m, strerror(first_mount_errno));
if (first_mount_errno == EBUSY) {
ret = FS_MGR_DOMNT_BUSY;
} else {
ret = FS_MGR_DOMNT_FAILED;
}
} else {
/* We didn't find a match, say so and return an error */
ERROR("Cannot find mount point %s in fstab\n", fstab->recs[i].mount_point);
}
out:
return ret;
@ -437,7 +581,7 @@ int fs_mgr_swapon_all(struct fstab *fstab)
zram_fp = fopen(ZRAM_CONF_DEV, "r+");
if (zram_fp == NULL) {
ERROR("Unable to open zram conf device " ZRAM_CONF_DEV);
ERROR("Unable to open zram conf device %s\n", ZRAM_CONF_DEV);
ret = -1;
continue;
}
@ -504,7 +648,7 @@ int fs_mgr_get_crypt_info(struct fstab *fstab, char *key_loc, char *real_blk_dev
if (fstab->recs[i].fs_mgr_flags & MF_VOLDMANAGED) {
continue;
}
if (!(fstab->recs[i].fs_mgr_flags & MF_CRYPT)) {
if (!(fstab->recs[i].fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT))) {
continue;
}

View File

@ -59,6 +59,7 @@ static struct flag_list fs_mgr_flags[] = {
{ "wait", MF_WAIT },
{ "check", MF_CHECK },
{ "encryptable=",MF_CRYPT },
{ "forceencrypt=",MF_FORCECRYPT },
{ "nonremovable",MF_NONREMOVABLE },
{ "voldmanaged=",MF_VOLDMANAGED},
{ "length=", MF_LENGTH },
@ -106,6 +107,11 @@ static int parse_flags(char *flags, struct flag_list *fl,
* location of the keys. Get it and return it.
*/
flag_vals->key_loc = strdup(strchr(p, '=') + 1);
} else if ((fl[i].flag == MF_FORCECRYPT) && flag_vals) {
/* The forceencrypt flag is followed by an = and the
* location of the keys. Get it and return it.
*/
flag_vals->key_loc = strdup(strchr(p, '=') + 1);
} else if ((fl[i].flag == MF_LENGTH) && flag_vals) {
/* The length flag is followed by an = and the
* size of the partition. Get it and return it.
@ -361,25 +367,47 @@ int fs_mgr_add_entry(struct fstab *fstab,
return 0;
}
struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path)
/*
* Returns the 1st matching fstab_rec that follows the start_rec.
* start_rec is the result of a previous search or NULL.
*/
struct fstab_rec *fs_mgr_get_entry_for_mount_point_after(struct fstab_rec *start_rec, struct fstab *fstab, const char *path)
{
int i;
if (!fstab) {
return NULL;
}
for (i = 0; i < fstab->num_entries; i++) {
if (start_rec) {
for (i = 0; i < fstab->num_entries; i++) {
if (&fstab->recs[i] == start_rec) {
i++;
break;
}
}
} else {
i = 0;
}
for (; i < fstab->num_entries; i++) {
int len = strlen(fstab->recs[i].mount_point);
if (strncmp(path, fstab->recs[i].mount_point, len) == 0 &&
(path[len] == '\0' || path[len] == '/')) {
return &fstab->recs[i];
}
}
return NULL;
}
/*
* Returns the 1st matching mount point.
* There might be more. To look for others, use fs_mgr_get_entry_for_mount_point_after()
* and give the fstab_rec from the previous search.
*/
struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path)
{
return fs_mgr_get_entry_for_mount_point_after(NULL, fstab, path);
}
int fs_mgr_is_voldmanaged(struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & MF_VOLDMANAGED;
@ -392,7 +420,7 @@ int fs_mgr_is_nonremovable(struct fstab_rec *fstab)
int fs_mgr_is_encryptable(struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & MF_CRYPT;
return fstab->fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT);
}
int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab)

View File

@ -23,7 +23,7 @@
#define INFO(x...) KLOG_INFO("fs_mgr", x)
#define ERROR(x...) KLOG_ERROR("fs_mgr", x)
#define CRYPTO_TMPFS_OPTIONS "size=128m,mode=0771,uid=1000,gid=1000"
#define CRYPTO_TMPFS_OPTIONS "size=256m,mode=0771,uid=1000,gid=1000"
#define WAIT_TIMEOUT 20
@ -72,12 +72,9 @@
#define MF_SWAPPRIO 0x80
#define MF_ZRAMSIZE 0x100
#define MF_VERIFY 0x200
/*
* There is no emulated sdcard daemon running on /data/media on this device,
* so treat the physical SD card as the only external storage device,
* a la the Nexus One.
*/
#define MF_NOEMULATEDSD 0x400
#define MF_FORCECRYPT 0x400
#define MF_NOEMULATEDSD 0x800 /* no emulated sdcard daemon, sd card is the only
external storage */
#define DM_BUF_SIZE 4096

View File

@ -30,6 +30,7 @@
#include <time.h>
#include <private/android_filesystem_config.h>
#include <cutils/properties.h>
#include <logwrap/logwrap.h>
#include "mincrypt/rsa.h"
@ -336,6 +337,26 @@ static int test_access(char *device) {
return -1;
}
static int set_verified_property(char *name) {
int ret;
char *key;
ret = asprintf(&key, "partition.%s.verified", name);
if (ret < 0) {
ERROR("Error formatting verified property");
return ret;
}
ret = PROP_NAME_MAX - strlen(key);
if (ret < 0) {
ERROR("Verified property name is too long");
return -1;
}
ret = property_set(key, "1");
if (ret < 0)
ERROR("Error setting verified property %s: %d", key, ret);
free(key);
return ret;
}
int fs_mgr_setup_verity(struct fstab_rec *fstab) {
int retval = -1;
@ -352,6 +373,13 @@ int fs_mgr_setup_verity(struct fstab_rec *fstab) {
io->flags |= 1;
io->target_count = 1;
// check to ensure that the verity device is ext4
// TODO: support non-ext4 filesystems
if (strcmp(fstab->fs_type, "ext4")) {
ERROR("Cannot verify non-ext4 device (%s)", fstab->fs_type);
return retval;
}
// get the device mapper fd
int fd;
if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) {
@ -405,7 +433,8 @@ int fs_mgr_setup_verity(struct fstab_rec *fstab) {
goto out;
}
retval = 0;
// set the property indicating that the partition is verified
retval = set_verified_property(mount_point);
out:
close(fd);

View File

@ -24,6 +24,11 @@
extern "C" {
#endif
/*
* The entries must be kept in the same order as they were seen in the fstab.
* Unless explicitly requested, a lookup on mount point should always
* return the 1st one.
*/
struct fstab {
int num_entries;
struct fstab_rec *recs;
@ -48,7 +53,15 @@ struct fstab_rec {
struct fstab *fs_mgr_read_fstab(const char *fstab_path);
void fs_mgr_free_fstab(struct fstab *fstab);
#define FS_MGR_MNTALL_DEV_NEEDS_RECOVERY 3
#define FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION 2
#define FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED 1
#define FS_MGR_MNTALL_DEV_NOT_ENCRYPTED 0
int fs_mgr_mount_all(struct fstab *fstab);
#define FS_MGR_DOMNT_FAILED -1
#define FS_MGR_DOMNT_BUSY -2
int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device,
char *tmp_mount_point);
int fs_mgr_do_tmpfs_mount(char *n_name);

View File

@ -7,12 +7,15 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := healthd_board_default.cpp
LOCAL_MODULE := libhealthd.default
LOCAL_CFLAGS := -Werror
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
healthd.cpp \
healthd_mode_android.cpp \
healthd_mode_charger.cpp \
BatteryMonitor.cpp \
BatteryPropertiesRegistrar.cpp
@ -22,9 +25,57 @@ LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
LOCAL_STATIC_LIBRARIES := libbatteryservice libbinder libz libutils libstdc++ libcutils liblog libm libc
LOCAL_CFLAGS := -D__STDC_LIMIT_MACROS -Werror
ifeq ($(strip $(BOARD_CHARGER_DISABLE_INIT_BLANK)),true)
LOCAL_CFLAGS += -DCHARGER_DISABLE_INIT_BLANK
endif
ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
LOCAL_CFLAGS += -DCHARGER_ENABLE_SUSPEND
endif
LOCAL_C_INCLUDES := bootable/recovery
LOCAL_STATIC_LIBRARIES := libbatteryservice libbinder libminui libpng libz libutils libstdc++ libcutils liblog libm libc
ifeq ($(strip $(BOARD_CHARGER_ENABLE_SUSPEND)),true)
LOCAL_STATIC_LIBRARIES += libsuspend
endif
LOCAL_HAL_STATIC_LIBRARIES := libhealthd
# Symlink /charger to /sbin/healthd
LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT) \
&& ln -sf /sbin/healthd $(TARGET_ROOT_OUT)/charger
include $(BUILD_EXECUTABLE)
define _add-charger-image
include $$(CLEAR_VARS)
LOCAL_MODULE := system_core_charger_$(notdir $(1))
LOCAL_MODULE_STEM := $(notdir $(1))
_img_modules += $$(LOCAL_MODULE)
LOCAL_SRC_FILES := $1
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $$(TARGET_ROOT_OUT)/res/images/charger
include $$(BUILD_PREBUILT)
endef
_img_modules :=
_images :=
$(foreach _img, $(call find-subdir-subdir-files, "images", "*.png"), \
$(eval $(call _add-charger-image,$(_img))))
include $(CLEAR_VARS)
LOCAL_MODULE := charger_res_images
LOCAL_MODULE_TAGS := optional
LOCAL_REQUIRED_MODULES := $(_img_modules)
include $(BUILD_PHONY_PACKAGE)
_add-charger-image :=
_img_modules :=
endif

View File

@ -18,7 +18,6 @@
#include "healthd.h"
#include "BatteryMonitor.h"
#include "BatteryPropertiesRegistrar.h"
#include <dirent.h>
#include <errno.h>
@ -28,11 +27,16 @@
#include <unistd.h>
#include <batteryservice/BatteryService.h>
#include <cutils/klog.h>
#include <cutils/properties.h>
#include <sys/types.h>
#include <utils/Errors.h>
#include <utils/String8.h>
#include <utils/Vector.h>
#define POWER_SUPPLY_SUBSYSTEM "power_supply"
#define POWER_SUPPLY_SYSFS_PATH "/sys/class/" POWER_SUPPLY_SUBSYSTEM
#define FAKE_BATTERY_CAPACITY 42
#define FAKE_BATTERY_TEMPERATURE 424
namespace android {
@ -170,7 +174,6 @@ int BatteryMonitor::getIntField(const String8& path) {
}
bool BatteryMonitor::update(void) {
struct BatteryProperties props;
bool logthis;
props.chargerAcOnline = false;
@ -178,24 +181,20 @@ bool BatteryMonitor::update(void) {
props.chargerWirelessOnline = false;
props.batteryStatus = BATTERY_STATUS_UNKNOWN;
props.batteryHealth = BATTERY_HEALTH_UNKNOWN;
props.batteryCurrentNow = INT_MIN;
props.batteryChargeCounter = INT_MIN;
if (!mHealthdConfig->batteryPresentPath.isEmpty())
props.batteryPresent = getBooleanField(mHealthdConfig->batteryPresentPath);
else
props.batteryPresent = true;
props.batteryPresent = mBatteryDevicePresent;
props.batteryLevel = getIntField(mHealthdConfig->batteryCapacityPath);
props.batteryLevel = mBatteryFixedCapacity ?
mBatteryFixedCapacity :
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);
props.batteryTemperature = mBatteryFixedTemperature ?
mBatteryFixedTemperature :
getIntField(mHealthdConfig->batteryTemperaturePath);
const int SIZE = 128;
char buf[SIZE];
@ -244,7 +243,9 @@ bool BatteryMonitor::update(void) {
if (logthis) {
char dmesgline[256];
snprintf(dmesgline, sizeof(dmesgline),
if (props.batteryPresent) {
snprintf(dmesgline, sizeof(dmesgline),
"battery l=%d v=%d t=%s%d.%d h=%d st=%d",
props.batteryLevel, props.batteryVoltage,
props.batteryTemperature < 0 ? "-" : "",
@ -252,11 +253,16 @@ bool BatteryMonitor::update(void) {
abs(props.batteryTemperature % 10), props.batteryHealth,
props.batteryStatus);
if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
char b[20];
if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
int c = getIntField(mHealthdConfig->batteryCurrentNowPath);
char b[20];
snprintf(b, sizeof(b), " c=%d", props.batteryCurrentNow / 1000);
strlcat(dmesgline, b, sizeof(dmesgline));
snprintf(b, sizeof(b), " c=%d", c / 1000);
strlcat(dmesgline, b, sizeof(dmesgline));
}
} else {
snprintf(dmesgline, sizeof(dmesgline),
"battery none");
}
KLOG_INFO(LOG_TAG, "%s chg=%s%s%s\n", dmesgline,
@ -265,15 +271,110 @@ bool BatteryMonitor::update(void) {
props.chargerWirelessOnline ? "w" : "");
}
if (mBatteryPropertiesRegistrar != NULL)
mBatteryPropertiesRegistrar->notifyListeners(props);
healthd_mode_ops->battery_update(&props);
return props.chargerAcOnline | props.chargerUsbOnline |
props.chargerWirelessOnline;
}
void BatteryMonitor::init(struct healthd_config *hc, bool nosvcmgr) {
status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) {
status_t ret = BAD_VALUE;
val->valueInt64 = LONG_MIN;
switch(id) {
case BATTERY_PROP_CHARGE_COUNTER:
if (!mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
val->valueInt64 =
getIntField(mHealthdConfig->batteryChargeCounterPath);
ret = NO_ERROR;
} else {
ret = NAME_NOT_FOUND;
}
break;
case BATTERY_PROP_CURRENT_NOW:
if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
val->valueInt64 =
getIntField(mHealthdConfig->batteryCurrentNowPath);
ret = NO_ERROR;
} else {
ret = NAME_NOT_FOUND;
}
break;
case BATTERY_PROP_CURRENT_AVG:
if (!mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
val->valueInt64 =
getIntField(mHealthdConfig->batteryCurrentAvgPath);
ret = NO_ERROR;
} else {
ret = NAME_NOT_FOUND;
}
break;
case BATTERY_PROP_CAPACITY:
if (!mHealthdConfig->batteryCapacityPath.isEmpty()) {
val->valueInt64 =
getIntField(mHealthdConfig->batteryCapacityPath);
ret = NO_ERROR;
} else {
ret = NAME_NOT_FOUND;
}
break;
case BATTERY_PROP_ENERGY_COUNTER:
if (mHealthdConfig->energyCounter) {
ret = mHealthdConfig->energyCounter(&val->valueInt64);
} else {
ret = NAME_NOT_FOUND;
}
break;
default:
break;
}
return ret;
}
void BatteryMonitor::dumpState(int fd) {
int v;
char vs[128];
snprintf(vs, sizeof(vs), "ac: %d usb: %d wireless: %d\n",
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;
char pval[PROPERTY_VALUE_MAX];
mHealthdConfig = hc;
DIR* dir = opendir(POWER_SUPPLY_SYSFS_PATH);
@ -303,6 +404,8 @@ void BatteryMonitor::init(struct healthd_config *hc, bool nosvcmgr) {
break;
case ANDROID_POWER_SUPPLY_TYPE_BATTERY:
mBatteryDevicePresent = true;
if (mHealthdConfig->batteryStatusPath.isEmpty()) {
path.clear();
path.appendFormat("%s/%s/status", POWER_SUPPLY_SYSFS_PATH,
@ -358,6 +461,14 @@ void BatteryMonitor::init(struct healthd_config *hc, bool nosvcmgr) {
mHealthdConfig->batteryCurrentNowPath = path;
}
if (mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
path.clear();
path.appendFormat("%s/%s/current_avg",
POWER_SUPPLY_SYSFS_PATH, name);
if (access(path, R_OK) == 0)
mHealthdConfig->batteryCurrentAvgPath = path;
}
if (mHealthdConfig->batteryChargeCounterPath.isEmpty()) {
path.clear();
path.appendFormat("%s/%s/charge_counter",
@ -400,24 +511,31 @@ void BatteryMonitor::init(struct healthd_config *hc, bool nosvcmgr) {
if (!mChargerNames.size())
KLOG_ERROR(LOG_TAG, "No charger supplies found\n");
if (mHealthdConfig->batteryStatusPath.isEmpty())
KLOG_WARNING(LOG_TAG, "BatteryStatusPath not found\n");
if (mHealthdConfig->batteryHealthPath.isEmpty())
KLOG_WARNING(LOG_TAG, "BatteryHealthPath not found\n");
if (mHealthdConfig->batteryPresentPath.isEmpty())
KLOG_WARNING(LOG_TAG, "BatteryPresentPath not found\n");
if (mHealthdConfig->batteryCapacityPath.isEmpty())
KLOG_WARNING(LOG_TAG, "BatteryCapacityPath not found\n");
if (mHealthdConfig->batteryVoltagePath.isEmpty())
KLOG_WARNING(LOG_TAG, "BatteryVoltagePath not found\n");
if (mHealthdConfig->batteryTemperaturePath.isEmpty())
KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n");
if (mHealthdConfig->batteryTechnologyPath.isEmpty())
KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n");
if (!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");
}
if (nosvcmgr == false) {
mBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar(this);
mBatteryPropertiesRegistrar->publish();
if (property_get("ro.boot.fake_battery", pval, NULL) > 0
&& strtol(pval, NULL, 10) != 0) {
mBatteryFixedCapacity = FAKE_BATTERY_CAPACITY;
mBatteryFixedTemperature = FAKE_BATTERY_TEMPERATURE;
}
}

View File

@ -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,18 @@ class BatteryMonitor {
ANDROID_POWER_SUPPLY_TYPE_BATTERY
};
void init(struct healthd_config *hc, bool nosvcmgr);
void init(struct healthd_config *hc);
bool update(void);
status_t getProperty(int id, struct BatteryProperty *val);
void dumpState(int fd);
private:
struct healthd_config *mHealthdConfig;
Vector<String8> mChargerNames;
sp<BatteryPropertiesRegistrar> mBatteryPropertiesRegistrar;
bool mBatteryDevicePresent;
int mBatteryFixedCapacity;
int mBatteryFixedTemperature;
struct BatteryProperties props;
int getBatteryStatus(const char* status);
int getBatteryHealth(const char* status);

View File

@ -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) {
@ -42,6 +43,8 @@ void BatteryPropertiesRegistrar::notifyListeners(struct BatteryProperties props)
void BatteryPropertiesRegistrar::registerListener(const sp<IBatteryPropertiesListener>& listener) {
{
if (listener == NULL)
return;
Mutex::Autolock _l(mRegistrationLock);
// check whether this is a duplicate
for (size_t i = 0; i < mListeners.size(); i++) {
@ -53,10 +56,12 @@ void BatteryPropertiesRegistrar::registerListener(const sp<IBatteryPropertiesLis
mListeners.add(listener);
listener->asBinder()->linkToDeath(this);
}
mBatteryMonitor->update();
healthd_battery_update();
}
void BatteryPropertiesRegistrar::unregisterListener(const sp<IBatteryPropertiesListener>& listener) {
if (listener == NULL)
return;
Mutex::Autolock _l(mRegistrationLock);
for (size_t i = 0; i < mListeners.size(); i++) {
if (mListeners[i]->asBinder() == listener->asBinder()) {
@ -67,6 +72,23 @@ void BatteryPropertiesRegistrar::unregisterListener(const sp<IBatteryPropertiesL
}
}
status_t BatteryPropertiesRegistrar::getProperty(int id, struct BatteryProperty *val) {
return healthd_get_property(id, val);
}
status_t BatteryPropertiesRegistrar::dump(int fd, const Vector<String16>& /*args*/) {
IPCThreadState* self = IPCThreadState::self();
const int pid = self->getCallingPid();
const int uid = self->getCallingUid();
if ((uid != AID_SHELL) &&
!PermissionCache::checkPermission(
String16("android.permission.DUMP"), pid, uid))
return PERMISSION_DENIED;
healthd_dump_battery_state(fd);
return OK;
}
void BatteryPropertiesRegistrar::binderDied(const wp<IBinder>& who) {
Mutex::Autolock _l(mRegistrationLock);

View File

@ -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);
};

View File

@ -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,18 @@ static struct healthd_config healthd_config = {
.batteryTemperaturePath = String8(String8::kEmptyString),
.batteryTechnologyPath = String8(String8::kEmptyString),
.batteryCurrentNowPath = String8(String8::kEmptyString),
.batteryCurrentAvgPath = String8(String8::kEmptyString),
.batteryChargeCounterPath = String8(String8::kEmptyString),
.energyCounter = NULL,
};
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 +73,80 @@ static int wakealarm_wake_interval = DEFAULT_PERIODIC_CHORES_INTERVAL_FAST;
static BatteryMonitor* gBatteryMonitor;
static bool nosvcmgr;
struct healthd_mode_ops *healthd_mode_ops;
// Android mode
extern void healthd_mode_android_init(struct healthd_config *config);
extern int healthd_mode_android_preparetowait(void);
extern void healthd_mode_android_battery_update(
struct android::BatteryProperties *props);
// Charger mode
extern void healthd_mode_charger_init(struct healthd_config *config);
extern int healthd_mode_charger_preparetowait(void);
extern void healthd_mode_charger_heartbeat(void);
extern void healthd_mode_charger_battery_update(
struct android::BatteryProperties *props);
// NOPs for modes that need no special action
static void healthd_mode_nop_init(struct healthd_config *config);
static int healthd_mode_nop_preparetowait(void);
static void healthd_mode_nop_heartbeat(void);
static void healthd_mode_nop_battery_update(
struct android::BatteryProperties *props);
static struct healthd_mode_ops android_ops = {
.init = healthd_mode_android_init,
.preparetowait = healthd_mode_android_preparetowait,
.heartbeat = healthd_mode_nop_heartbeat,
.battery_update = healthd_mode_android_battery_update,
};
static struct healthd_mode_ops charger_ops = {
.init = healthd_mode_charger_init,
.preparetowait = healthd_mode_charger_preparetowait,
.heartbeat = healthd_mode_charger_heartbeat,
.battery_update = healthd_mode_charger_battery_update,
};
static struct healthd_mode_ops recovery_ops = {
.init = healthd_mode_nop_init,
.preparetowait = healthd_mode_nop_preparetowait,
.heartbeat = healthd_mode_nop_heartbeat,
.battery_update = healthd_mode_nop_battery_update,
};
static void healthd_mode_nop_init(struct healthd_config* /*config*/) {
}
static int healthd_mode_nop_preparetowait(void) {
return -1;
}
static void healthd_mode_nop_heartbeat(void) {
}
static void healthd_mode_nop_battery_update(
struct android::BatteryProperties* /*props*/) {
}
int healthd_register_event(int fd, void (*handler)(uint32_t)) {
struct epoll_event ev;
ev.events = EPOLLIN | EPOLLWAKEUP;
ev.data.ptr = (void *)handler;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
KLOG_ERROR(LOG_TAG,
"epoll_ctl failed; errno=%d\n", errno);
return -1;
}
eventct++;
return 0;
}
static void wakealarm_set_interval(int interval) {
struct itimerspec itval;
@ -89,7 +168,11 @@ static void wakealarm_set_interval(int interval) {
KLOG_ERROR(LOG_TAG, "wakealarm_set_interval: timerfd_settime failed\n");
}
static void battery_update(void) {
status_t healthd_get_property(int id, struct BatteryProperty *val) {
return gBatteryMonitor->getProperty(id, val);
}
void healthd_battery_update(void) {
// Fast wake interval when on charger (watch for overheat);
// slow wake interval when on battery (watch for drained battery).
@ -113,21 +196,17 @@ static void battery_update(void) {
-1 : healthd_config.periodic_chores_interval_fast * 1000;
}
static void periodic_chores() {
battery_update();
void healthd_dump_battery_state(int fd) {
gBatteryMonitor->dumpState(fd);
fsync(fd);
}
static void uevent_init(void) {
uevent_fd = uevent_open_socket(64*1024, true);
if (uevent_fd >= 0)
fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
else
KLOG_ERROR(LOG_TAG, "uevent_init: uevent_open_socket failed\n");
static void periodic_chores() {
healthd_battery_update();
}
#define UEVENT_MSG_LEN 2048
static void uevent_event(void) {
static void uevent_event(uint32_t /*epevents*/) {
char msg[UEVENT_MSG_LEN+2];
char *cp;
int n;
@ -144,7 +223,7 @@ static void uevent_event(void) {
while (*cp) {
if (!strcmp(cp, "SUBSYSTEM=" POWER_SUPPLY_SUBSYSTEM)) {
battery_update();
healthd_battery_update();
break;
}
@ -154,6 +233,31 @@ static void uevent_event(void) {
}
}
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 +265,24 @@ static void wakealarm_init(void) {
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 +293,70 @@ static void healthd_mainloop(void) {
for (int n = 0; n < nevents; ++n) {
if (events[n].data.ptr)
(*(void (*)())events[n].data.ptr)();
(*(void (*)(int))events[n].data.ptr)(events[n].events);
}
if (!nevents)
periodic_chores();
healthd_mode_ops->heartbeat();
}
return;
}
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);
healthd_mainloop();
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();
KLOG_ERROR("Main loop terminated, exiting\n");
return 3;
}

View File

@ -18,6 +18,8 @@
#define _HEALTHD_H_
#include <batteryservice/BatteryService.h>
#include <sys/types.h>
#include <utils/Errors.h>
#include <utils/String8.h>
// periodic_chores_interval_fast, periodic_chores_interval_slow: intervals at
@ -61,9 +63,37 @@ struct healthd_config {
android::String8 batteryTemperaturePath;
android::String8 batteryTechnologyPath;
android::String8 batteryCurrentNowPath;
android::String8 batteryCurrentAvgPath;
android::String8 batteryChargeCounterPath;
int (*energyCounter)(int64_t *);
};
// 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.
//

View File

@ -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();
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2011 The Android Open Source Project
* Copyright (C) 2011-2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -14,18 +14,16 @@
* limitations under the License.
*/
//#define DEBUG_UEVENTS
#define CHARGER_KLOG_LEVEL 6
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <linux/input.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/poll.h>
#include <sys/epoll.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/un.h>
@ -35,9 +33,9 @@
#include <sys/socket.h>
#include <linux/netlink.h>
#include <batteryservice/BatteryService.h>
#include <cutils/android_reboot.h>
#include <cutils/klog.h>
#include <cutils/list.h>
#include <cutils/misc.h>
#include <cutils/uevent.h>
#include <cutils/properties.h>
@ -48,6 +46,8 @@
#include "minui/minui.h"
#include "healthd.h"
char *locale;
#ifndef max
@ -68,8 +68,10 @@ char *locale;
#define UNPLUGGED_SHUTDOWN_TIME (10 * MSEC_PER_SEC)
#define BATTERY_FULL_THRESH 95
#define SCREEN_ON_BATTERY_THRESH 0
#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)
@ -82,15 +84,6 @@ struct key_state {
int64_t timestamp;
};
struct power_supply {
struct listnode list;
char name[256];
char type[32];
bool online;
bool valid;
char cap_path[PATH_MAX];
};
struct frame {
int disp_time;
int min_capacity;
@ -114,72 +107,73 @@ struct animation {
};
struct charger {
bool have_battery_state;
bool charger_connected;
int capacity;
int64_t next_screen_transition;
int64_t next_key_check;
int64_t next_pwr_check;
struct key_state keys[KEY_MAX + 1];
int uevent_fd;
struct listnode supplies;
int num_supplies;
int num_supplies_online;
struct animation *batt_anim;
gr_surface surf_unknown;
struct power_supply *battery;
};
struct uevent {
const char *action;
const char *path;
const char *subsystem;
const char *ps_name;
const char *ps_type;
const char *ps_online;
};
static struct frame batt_anim_frames[] = {
{
.disp_time = 750,
.min_capacity = 0,
.level_only = false,
.surface = NULL,
},
{
.disp_time = 750,
.min_capacity = 20,
.level_only = false,
.surface = NULL,
},
{
.disp_time = 750,
.min_capacity = 40,
.level_only = false,
.surface = NULL,
},
{
.disp_time = 750,
.min_capacity = 60,
.level_only = false,
.surface = NULL,
},
{
.disp_time = 750,
.min_capacity = 80,
.level_only = true,
.surface = NULL,
},
{
.disp_time = 750,
.min_capacity = BATTERY_FULL_THRESH,
.level_only = false,
.surface = NULL,
},
};
static struct animation battery_animation = {
.run = false,
.frames = batt_anim_frames,
.cur_frame = 0,
.num_frames = ARRAY_SIZE(batt_anim_frames),
.cur_cycle = 0,
.num_cycles = 3,
.capacity = 0,
};
static struct charger charger_state = {
.batt_anim = &battery_animation,
};
static struct charger charger_state;
static int char_width;
static int char_height;
static bool minui_inited;
/* current time in milliseconds */
static int64_t curr_time_ms(void)
@ -207,10 +201,14 @@ static void dump_last_kmsg(void)
LOGI("\n");
LOGI("*************** LAST KMSG ***************\n");
LOGI("\n");
buf = load_file(LAST_KMSG_PATH, &sz);
buf = (char *)load_file(LAST_KMSG_PSTORE_PATH, &sz);
if (!buf || !sz) {
LOGI("last_kmsg not found. Cold reset?\n");
goto out;
buf = (char *)load_file(LAST_KMSG_PATH, &sz);
if (!buf || !sz) {
LOGI("last_kmsg not found. Cold reset?\n");
goto out;
}
}
len = min(sz, LAST_KMSG_MAX_SZ);
@ -221,7 +219,7 @@ static void dump_last_kmsg(void)
char yoink;
char *nl;
nl = memrchr(ptr, '\n', cnt - 1);
nl = (char *)memrchr(ptr, '\n', cnt - 1);
if (nl)
cnt = nl - ptr + 1;
@ -242,114 +240,9 @@ out:
LOGI("\n");
}
static int read_file(const char *path, char *buf, size_t sz)
static int get_battery_capacity()
{
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);
return charger_state.capacity;
}
#ifdef CHARGER_ENABLE_SUSPEND
@ -361,243 +254,12 @@ static int request_suspend(bool enable)
return autosuspend_disable();
}
#else
static int request_suspend(bool enable)
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);
@ -617,7 +279,7 @@ static void android_green(void)
}
/* returns the last y-offset of where the surface ends */
static int draw_surface_centered(struct charger *charger, gr_surface surface)
static int draw_surface_centered(struct charger* /*charger*/, gr_surface surface)
{
int w;
int h;
@ -694,13 +356,34 @@ static void update_screen_state(struct charger *charger, int64_t now)
if (!batt_anim->run || now < charger->next_screen_transition)
return;
if (!minui_inited) {
int batt_cap = get_battery_capacity();
if (batt_cap < SCREEN_ON_BATTERY_THRESH) {
LOGV("[%" PRId64 "] level %d, leave screen off\n", now, batt_cap);
batt_anim->run = false;
charger->next_screen_transition = -1;
if (charger->charger_connected)
request_suspend(true);
return;
}
gr_init();
gr_font_size(&char_width, &char_height);
#ifndef CHARGER_DISABLE_INIT_BLANK
gr_fb_blank(true);
#endif
minui_inited = true;
}
/* 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)
LOGV("[%" PRId64 "] animation done\n", now);
if (charger->charger_connected)
request_suspend(true);
return;
}
@ -712,8 +395,8 @@ static void update_screen_state(struct charger *charger, int64_t now)
int batt_cap;
int ret;
LOGV("[%lld] animation starting\n", now);
batt_cap = get_battery_capacity(charger);
LOGV("[%" PRId64 "] animation starting\n", now);
batt_cap = get_battery_capacity();
if (batt_cap >= 0 && batt_anim->num_frames != 0) {
int i;
@ -742,7 +425,7 @@ static void update_screen_state(struct charger *charger, int64_t now)
* 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);
LOGV("[%" PRId64 "] animation missing or unknown battery status\n", now);
charger->next_screen_transition = now + BATTERY_UNKNOWN_TIME;
batt_anim->cur_cycle++;
return;
@ -751,30 +434,39 @@ static void update_screen_state(struct charger *charger, int64_t now)
/* schedule next screen transition */
charger->next_screen_transition = now + disp_time;
/* advance frame cntr to the next valid frame
/* advance frame cntr to the next valid frame only if we are charging
* 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)
if (charger->charger_connected) {
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
/* 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
*/
}
} else {
/* Stop animating if we're not charging.
* If we stop it immediately instead of going through this loop, then
* the animation would stop somewhere in the middle.
*/
batt_anim->cur_frame = 0;
batt_anim->cur_cycle++;
}
}
static int set_key_callback(int code, int value, void *data)
{
struct charger *charger = data;
struct charger *charger = (struct charger *)data;
int64_t now = curr_time_ms();
int down = !!value;
@ -792,13 +484,13 @@ static int set_key_callback(int code, int value, void *data)
charger->keys[code].down = down;
charger->keys[code].pending = true;
if (down) {
LOGV("[%lld] key[%d] down\n", now, code);
LOGV("[%" PRId64 "] 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);
LOGV("[%" PRId64 "] key[%d] up (was down for %" PRId64 ".%" PRId64 "sec)\n",
now, code, secs, msecs);
}
return 0;
@ -835,10 +527,10 @@ static void process_key(struct charger *charger, int code, int64_t now)
all devices. Check the property and continue booting or reboot
accordingly. */
if (property_get_bool("ro.enable_boot_charger_mode", false)) {
LOGI("[%lld] booting from charger mode\n", now);
LOGI("[%" PRId64 "] booting from charger mode\n", now);
property_set("sys.boot_from_charger_mode", "1");
} else {
LOGI("[%lld] rebooting\n", now);
LOGI("[%" PRId64 "] rebooting\n", now);
android_reboot(ANDROID_RB_RESTART, 0, 0);
}
} else {
@ -869,14 +561,17 @@ static void handle_input_state(struct charger *charger, int64_t now)
static void handle_power_supply_state(struct charger *charger, int64_t now)
{
if (charger->num_supplies_online == 0) {
if (!charger->have_battery_state)
return;
if (!charger->charger_connected) {
request_suspend(false);
if (charger->next_pwr_check == -1) {
charger->next_pwr_check = now + UNPLUGGED_SHUTDOWN_TIME;
LOGI("[%lld] device unplugged: shutting down in %lld (@ %lld)\n",
now, UNPLUGGED_SHUTDOWN_TIME, charger->next_pwr_check);
LOGI("[%" PRId64 "] device unplugged: shutting down in %" PRId64 " (@ %" PRId64 ")\n",
now, (int64_t)UNPLUGGED_SHUTDOWN_TIME, charger->next_pwr_check);
} else if (now >= charger->next_pwr_check) {
LOGI("[%lld] shutting down\n", now);
LOGI("[%" PRId64 "] shutting down\n", now);
android_reboot(ANDROID_RB_POWEROFF, 0, 0);
} else {
/* otherwise we already have a shutdown timer scheduled */
@ -884,21 +579,56 @@ static void handle_power_supply_state(struct charger *charger, int64_t now)
} else {
/* online supply present, reset shutdown timer if set */
if (charger->next_pwr_check != -1) {
LOGI("[%lld] device plugged in: shutdown cancelled\n", now);
LOGI("[%" PRId64 "] 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)
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,
LOGV("[%" PRId64 "] next screen: %" PRId64 " next key: %" PRId64 " next pwr: %" PRId64 "\n", now,
charger->next_screen_transition, charger->next_key_check,
charger->next_pwr_check);
@ -913,74 +643,48 @@ static void wait_next_event(struct charger *charger, int64_t now)
timeout = max(0, next_event - now);
else
timeout = -1;
LOGV("[%lld] blocking (%lld)\n", now, timeout);
ret = ev_wait((int)timeout);
if (!ret)
ev_dispatch();
return (int)timeout;
}
static int input_callback(int fd, short revents, void *data)
static int input_callback(int fd, unsigned int epevents, void *data)
{
struct charger *charger = data;
struct charger *charger = (struct charger *)data;
struct input_event ev;
int ret;
ret = ev_get_input(fd, revents, &ev);
ret = ev_get_input(fd, epevents, &ev);
if (ret)
return -1;
update_input_state(charger, &ev);
return 0;
}
static void event_loop(struct charger *charger)
static void charger_event_handler(uint32_t /*epevents*/)
{
int ret;
while (true) {
int64_t now = curr_time_ms();
LOGV("[%lld] event_loop()\n", now);
handle_input_state(charger, now);
handle_power_supply_state(charger, now);
/* do screen update last in case any of the above want to start
* screen transitions (animations, etc)
*/
update_screen_state(charger, now);
wait_next_event(charger, now);
}
ret = ev_wait(-1);
if (!ret)
ev_dispatch();
}
int main(int argc, char **argv)
void healthd_mode_charger_init(struct healthd_config* /*config*/)
{
int ret;
struct charger *charger = &charger_state;
int64_t now = curr_time_ms() - 1;
int fd;
int i;
list_init(&charger->supplies);
klog_init();
klog_set_level(CHARGER_KLOG_LEVEL);
int epollfd;
dump_last_kmsg();
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);
ret = ev_init(input_callback, charger);
if (!ret) {
epollfd = ev_get_epollfd();
healthd_register_event(epollfd, charger_event_handler);
}
charger->uevent_fd = fd;
coldboot(charger, "/sys/class/power_supply", "add");
ret = res_create_display_surface("charger/battery_fail", &charger->surf_unknown);
if (ret < 0) {
@ -1010,17 +714,7 @@ int main(int argc, char **argv)
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_screen_transition = -1;
charger->next_key_check = -1;
charger->next_pwr_check = -1;
reset_animation(charger->batt_anim);
kick_animation(charger->batt_anim);
event_loop(charger);
return 0;
}

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 463 B

After

Width:  |  Height:  |  Size: 463 B

View File

@ -25,7 +25,7 @@ __BEGIN_DECLS
void klog_init(void);
int klog_get_level(void);
void klog_set_level(int level);
void klog_close(void);
/* TODO: void klog_close(void); - and make klog_fd users thread safe. */
void klog_write(int level, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));
void klog_vwrite(int level, const char *fmt, va_list ap);

View File

@ -34,6 +34,12 @@ int str_parms_add_int(struct str_parms *str_parms, const char *key, int value);
int str_parms_add_float(struct str_parms *str_parms, const char *key,
float value);
// Returns non-zero if the str_parms contains the specified key.
int str_parms_has_key(struct str_parms *str_parms, const char *key);
// Gets value associated with the specified key (if present), placing it in the buffer
// pointed to by the out_val parameter. Returns the length of the returned string value.
// If 'key' isn't in the parms, then return -ENOENT (-2) and leave 'out_val' untouched.
int str_parms_get_str(struct str_parms *str_parms, const char *key,
char *out_val, int len);
int str_parms_get_int(struct str_parms *str_parms, const char *key,

View File

@ -70,7 +70,8 @@ __BEGIN_DECLS
#define ATRACE_TAG_DALVIK (1<<14)
#define ATRACE_TAG_RS (1<<15)
#define ATRACE_TAG_BIONIC (1<<16)
#define ATRACE_TAG_LAST ATRACE_TAG_BIONIC
#define ATRACE_TAG_POWER (1<<17)
#define ATRACE_TAG_LAST ATRACE_TAG_POWER
// Reserved for initialization.
#define ATRACE_TAG_NOT_READY (1LL<<63)

View File

@ -36,6 +36,7 @@ extern int ifc_disable(const char *ifname);
#define RESET_IPV4_ADDRESSES 0x01
#define RESET_IPV6_ADDRESSES 0x02
#define RESET_IGNORE_INTERFACE_ADDRESS 0x04
#define RESET_ALL_ADDRESSES (RESET_IPV4_ADDRESSES | RESET_IPV6_ADDRESSES)
extern int ifc_reset_connections(const char *ifname, const int reset_mask);
@ -49,19 +50,8 @@ extern int ifc_set_prefixLength(const char *name, int prefixLength);
extern int ifc_set_hwaddr(const char *name, const void *ptr);
extern int ifc_clear_addresses(const char *name);
/* This function is deprecated. Use ifc_add_route instead. */
extern int ifc_add_host_route(const char *name, in_addr_t addr);
extern int ifc_remove_host_routes(const char *name);
extern int ifc_get_default_route(const char *ifname);
/* This function is deprecated. Use ifc_add_route instead */
extern int ifc_set_default_route(const char *ifname, in_addr_t gateway);
/* This function is deprecated. Use ifc_add_route instead */
extern int ifc_create_default_route(const char *name, in_addr_t addr);
extern int ifc_remove_default_route(const char *ifname);
extern int ifc_add_route(const char *name, const char *addr, int prefix_length,
const char *gw);
extern int ifc_remove_route(const char *ifname, const char *dst,
int prefix_length, const char *gw);
extern int ifc_get_info(const char *name, in_addr_t *addr, int *prefixLength,
unsigned *flags);

View File

@ -254,6 +254,8 @@ static const struct fs_path_config android_files[] = {
/* the following files have enhanced capabilities and ARE included in user builds. */
{ 00750, AID_ROOT, AID_SHELL, (1 << CAP_SETUID) | (1 << CAP_SETGID), "system/bin/run-as" },
{ 00750, AID_ROOT, AID_ROOT, 0, "system/bin/uncrypt" },
{ 00750, AID_ROOT, AID_ROOT, 0, "system/bin/install-recovery.sh" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin/*" },
{ 00755, AID_ROOT, AID_ROOT, 0, "system/lib/valgrind/*" },
{ 00755, AID_ROOT, AID_ROOT, 0, "system/lib64/valgrind/*" },
@ -263,7 +265,6 @@ static const struct fs_path_config android_files[] = {
{ 00750, AID_ROOT, AID_SHELL, 0, "sbin/*" },
{ 00755, AID_ROOT, AID_ROOT, 0, "bin/*" },
{ 00750, AID_ROOT, AID_SHELL, 0, "init*" },
{ 00750, AID_ROOT, AID_SHELL, 0, "charger*" },
{ 00750, AID_ROOT, AID_SHELL, 0, "sbin/fs_mgr" },
{ 00640, AID_ROOT, AID_SHELL, 0, "fstab.*" },
{ 00644, AID_ROOT, AID_ROOT, 0, 0 },

File diff suppressed because it is too large Load Diff

View File

@ -44,6 +44,7 @@ typedef enum {
AUDIO_POLICY_FORCE_DIGITAL_DOCK,
AUDIO_POLICY_FORCE_NO_BT_A2DP, /* A2DP sink is not preferred to speaker or wired HS */
AUDIO_POLICY_FORCE_SYSTEM_ENFORCED,
AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED,
AUDIO_POLICY_FORCE_CFG_CNT,
AUDIO_POLICY_FORCE_CFG_MAX = AUDIO_POLICY_FORCE_CFG_CNT - 1,
@ -58,6 +59,7 @@ typedef enum {
AUDIO_POLICY_FORCE_FOR_RECORD,
AUDIO_POLICY_FORCE_FOR_DOCK,
AUDIO_POLICY_FORCE_FOR_SYSTEM,
AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO,
AUDIO_POLICY_FORCE_USE_CNT,
AUDIO_POLICY_FORCE_USE_MAX = AUDIO_POLICY_FORCE_USE_CNT - 1,

View File

@ -165,24 +165,104 @@ enum {
/*
* Android RAW sensor format:
*
* This format is exposed outside of the HAL to applications.
* This format is exposed outside of the camera HAL to applications.
*
* RAW_SENSOR is a single-channel 16-bit format, typically representing raw
* Bayer-pattern images from an image sensor, with minimal processing.
* RAW_SENSOR is a single-channel, 16-bit, little endian format, typically
* representing raw Bayer-pattern images from an image sensor, with minimal
* processing.
*
* The exact pixel layout of the data in the buffer is sensor-dependent, and
* needs to be queried from the camera device.
*
* Generally, not all 16 bits are used; more common values are 10 or 12
* bits. All parameters to interpret the raw data (black and white points,
* bits. If not all bits are used, the lower-order bits are filled first.
* All parameters to interpret the raw data (black and white points,
* color space, etc) must be queried from the camera device.
*
* This format assumes
* - an even width
* - an even height
* - a horizontal stride multiple of 16 pixels (32 bytes).
* - a horizontal stride multiple of 16 pixels
* - a vertical stride equal to the height
* - strides are specified in pixels, not in bytes
*
* size = stride * height * 2
*
* This format must be accepted by the gralloc module when used with the
* following usage flags:
* - GRALLOC_USAGE_HW_CAMERA_*
* - GRALLOC_USAGE_SW_*
* - GRALLOC_USAGE_RENDERSCRIPT
*/
HAL_PIXEL_FORMAT_RAW_SENSOR = 0x20,
HAL_PIXEL_FORMAT_RAW16 = 0x20,
HAL_PIXEL_FORMAT_RAW_SENSOR = 0x20, // TODO(rubenbrunk): Remove RAW_SENSOR.
/*
* Android RAW10 format:
*
* This format is exposed outside of the camera HAL to applications.
*
* RAW10 is a single-channel, 10-bit per pixel, densely packed in each row,
* unprocessed format, usually representing raw Bayer-pattern images coming from
* an image sensor.
*
* In an image buffer with this format, starting from the first pixel of each
* row, each 4 consecutive pixels are packed into 5 bytes (40 bits). Each one
* of the first 4 bytes contains the top 8 bits of each pixel, The fifth byte
* contains the 2 least significant bits of the 4 pixels, the exact layout data
* for each 4 consecutive pixels is illustrated below (Pi[j] stands for the jth
* bit of the ith pixel):
*
* bit 7 bit 0
* =====|=====|=====|=====|=====|=====|=====|=====|
* Byte 0: |P0[9]|P0[8]|P0[7]|P0[6]|P0[5]|P0[4]|P0[3]|P0[2]|
* |-----|-----|-----|-----|-----|-----|-----|-----|
* Byte 1: |P1[9]|P1[8]|P1[7]|P1[6]|P1[5]|P1[4]|P1[3]|P1[2]|
* |-----|-----|-----|-----|-----|-----|-----|-----|
* Byte 2: |P2[9]|P2[8]|P2[7]|P2[6]|P2[5]|P2[4]|P2[3]|P2[2]|
* |-----|-----|-----|-----|-----|-----|-----|-----|
* Byte 3: |P3[9]|P3[8]|P3[7]|P3[6]|P3[5]|P3[4]|P3[3]|P3[2]|
* |-----|-----|-----|-----|-----|-----|-----|-----|
* Byte 4: |P3[1]|P3[0]|P2[1]|P2[0]|P1[1]|P1[0]|P0[1]|P0[0]|
* ===============================================
*
* This format assumes
* - a width multiple of 4 pixels
* - an even height
* - a vertical stride equal to the height
* - strides are specified in bytes, not in pixels
*
* size = stride * height
*
* When stride is equal to width * (10 / 8), there will be no padding bytes at
* the end of each row, the entire image data is densely packed. When stride is
* larger than width * (10 / 8), padding bytes will be present at the end of each
* row (including the last row).
*
* This format must be accepted by the gralloc module when used with the
* following usage flags:
* - GRALLOC_USAGE_HW_CAMERA_*
* - GRALLOC_USAGE_SW_*
* - GRALLOC_USAGE_RENDERSCRIPT
*/
HAL_PIXEL_FORMAT_RAW10 = 0x25,
/*
* Android opaque RAW format:
*
* This format is exposed outside of the camera HAL to applications.
*
* RAW_OPAQUE is a format for unprocessed raw image buffers coming from an
* image sensor. The actual structure of buffers of this format is
* implementation-dependent.
*
* This format must be accepted by the gralloc module when used with the
* following usage flags:
* - GRALLOC_USAGE_HW_CAMERA_*
* - GRALLOC_USAGE_SW_*
* - GRALLOC_USAGE_RENDERSCRIPT
*/
HAL_PIXEL_FORMAT_RAW_OPAQUE = 0x24,
/*
* Android binary blob graphics buffer format:
@ -297,6 +377,136 @@ enum {
HAL_TRANSFORM_RESERVED = 0x08,
};
/**
* Colorspace Definitions
* ======================
*
* Colorspace is the definition of how pixel values should be interpreted.
* It includes primaries (including white point) and the transfer
* characteristic function, which describes both gamma curve and numeric
* range (within the bit depth).
*/
enum {
/*
* Arbitrary colorspace with manually defined characteristics.
* Colorspace definition must be communicated separately.
*
* This is used when specifying primaries, transfer characteristics,
* etc. separately.
*
* A typical use case is in video encoding parameters (e.g. for H.264),
* where a colorspace can have separately defined primaries, transfer
* characteristics, etc.
*/
HAL_COLORSPACE_ARBITRARY = 0x1,
/*
* YCbCr Colorspaces
* -----------------
*
* Primaries are given using (x,y) coordinates in the CIE 1931 definition
* of x and y specified by ISO 11664-1.
*
* Transfer characteristics are the opto-electronic transfer characteristic
* at the source as a function of linear optical intensity (luminance).
*/
/*
* JPEG File Interchange Format (JFIF)
*
* Same model as BT.601-625, but all values (Y, Cb, Cr) range from 0 to 255
*
* Transfer characteristic curve:
* E = 1.099 * L ^ 0.45 - 0.099, 1.00 >= L >= 0.018
* E = 4.500 L, 0.018 > L >= 0
* L - luminance of image 0 <= L <= 1 for conventional colorimetry
* E - corresponding electrical signal
*
* Primaries: x y
* green 0.290 0.600
* blue 0.150 0.060
* red 0.640 0.330
* white (D65) 0.3127 0.3290
*/
HAL_COLORSPACE_JFIF = 0x101,
/*
* ITU-R Recommendation 601 (BT.601) - 625-line
*
* Standard-definition television, 625 Lines (PAL)
*
* For 8-bit-depth formats:
* Luma (Y) samples should range from 16 to 235, inclusive
* Chroma (Cb, Cr) samples should range from 16 to 240, inclusive
*
* For 10-bit-depth formats:
* Luma (Y) samples should range from 64 to 940, inclusive
* Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
*
* Transfer characteristic curve:
* E = 1.099 * L ^ 0.45 - 0.099, 1.00 >= L >= 0.018
* E = 4.500 L, 0.018 > L >= 0
* L - luminance of image 0 <= L <= 1 for conventional colorimetry
* E - corresponding electrical signal
*
* Primaries: x y
* green 0.290 0.600
* blue 0.150 0.060
* red 0.640 0.330
* white (D65) 0.3127 0.3290
*/
HAL_COLORSPACE_BT601_625 = 0x102,
/*
* ITU-R Recommendation 601 (BT.601) - 525-line
*
* Standard-definition television, 525 Lines (NTSC)
*
* For 8-bit-depth formats:
* Luma (Y) samples should range from 16 to 235, inclusive
* Chroma (Cb, Cr) samples should range from 16 to 240, inclusive
*
* For 10-bit-depth formats:
* Luma (Y) samples should range from 64 to 940, inclusive
* Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
*
* Transfer characteristic curve:
* E = 1.099 * L ^ 0.45 - 0.099, 1.00 >= L >= 0.018
* E = 4.500 L, 0.018 > L >= 0
* L - luminance of image 0 <= L <= 1 for conventional colorimetry
* E - corresponding electrical signal
*
* Primaries: x y
* green 0.310 0.595
* blue 0.155 0.070
* red 0.630 0.340
* white (D65) 0.3127 0.3290
*/
HAL_COLORSPACE_BT601_525 = 0x103,
/*
* ITU-R Recommendation 709 (BT.709)
*
* High-definition television
*
* For 8-bit-depth formats:
* Luma (Y) samples should range from 16 to 235, inclusive
* Chroma (Cb, Cr) samples should range from 16 to 240, inclusive
*
* For 10-bit-depth formats:
* Luma (Y) samples should range from 64 to 940, inclusive
* Chroma (Cb, Cr) samples should range from 64 to 960, inclusive
*
* Primaries: x y
* green 0.300 0.600
* blue 0.150 0.060
* red 0.640 0.330
* white (D65) 0.3127 0.3290
*/
HAL_COLORSPACE_BT709 = 0x104,
};
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,223 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_SOUND_TRIGGER_H
#define ANDROID_SOUND_TRIGGER_H
#include <stdbool.h>
#include <system/audio.h>
#define SOUND_TRIGGER_MAX_STRING_LEN 64 /* max length of strings in properties or
descriptor structs */
#define SOUND_TRIGGER_MAX_LOCALE_LEN 6 /* max length of locale string. e.g en_US */
#define SOUND_TRIGGER_MAX_USERS 10 /* max number of concurrent users */
#define SOUND_TRIGGER_MAX_PHRASES 10 /* max number of concurrent phrases */
typedef enum {
SOUND_TRIGGER_STATE_NO_INIT = -1, /* The sound trigger service is not initialized */
SOUND_TRIGGER_STATE_ENABLED = 0, /* The sound trigger service is enabled */
SOUND_TRIGGER_STATE_DISABLED = 1 /* The sound trigger service is disabled */
} sound_trigger_service_state_t;
#define RECOGNITION_MODE_VOICE_TRIGGER 0x1 /* simple voice trigger */
#define RECOGNITION_MODE_USER_IDENTIFICATION 0x2 /* trigger only if one user in model identified */
#define RECOGNITION_MODE_USER_AUTHENTICATION 0x4 /* trigger only if one user in mode
authenticated */
#define RECOGNITION_STATUS_SUCCESS 0
#define RECOGNITION_STATUS_ABORT 1
#define RECOGNITION_STATUS_FAILURE 2
#define SOUND_MODEL_STATUS_UPDATED 0
typedef enum {
SOUND_MODEL_TYPE_UNKNOWN = -1, /* use for unspecified sound model type */
SOUND_MODEL_TYPE_KEYPHRASE = 0 /* use for key phrase sound models */
} sound_trigger_sound_model_type_t;
typedef struct sound_trigger_uuid_s {
unsigned int timeLow;
unsigned short timeMid;
unsigned short timeHiAndVersion;
unsigned short clockSeq;
unsigned char node[6];
} sound_trigger_uuid_t;
/*
* sound trigger implementation descriptor read by the framework via get_properties().
* Used by SoundTrigger service to report to applications and manage concurrency and policy.
*/
struct sound_trigger_properties {
char implementor[SOUND_TRIGGER_MAX_STRING_LEN]; /* implementor name */
char description[SOUND_TRIGGER_MAX_STRING_LEN]; /* implementation description */
unsigned int version; /* implementation version */
sound_trigger_uuid_t uuid; /* unique implementation ID.
Must change with version each version */
unsigned int max_sound_models; /* maximum number of concurrent sound models
loaded */
unsigned int max_key_phrases; /* maximum number of key phrases */
unsigned int max_users; /* maximum number of concurrent users detected */
unsigned int recognition_modes; /* all supported modes.
e.g RECOGNITION_MODE_VOICE_TRIGGER */
bool capture_transition; /* supports seamless transition from detection
to capture */
unsigned int max_buffer_ms; /* maximum buffering capacity in ms if
capture_transition is true*/
bool concurrent_capture; /* supports capture by other use cases while
detection is active */
bool trigger_in_event; /* returns the trigger capture in event */
unsigned int power_consumption_mw; /* Rated power consumption when detection is active
with TDB silence/sound/speech ratio */
};
typedef int sound_trigger_module_handle_t;
struct sound_trigger_module_descriptor {
sound_trigger_module_handle_t handle;
struct sound_trigger_properties properties;
};
typedef int sound_model_handle_t;
/*
* Generic sound model descriptor. This struct is the header of a larger block passed to
* load_sound_model() and containing the binary data of the sound model.
* Proprietary representation of users in binary data must match information indicated
* by users field
*/
struct sound_trigger_sound_model {
sound_trigger_sound_model_type_t type; /* model type. e.g. SOUND_MODEL_TYPE_KEYPHRASE */
sound_trigger_uuid_t uuid; /* unique sound model ID. */
sound_trigger_uuid_t vendor_uuid; /* unique vendor ID. Identifies the engine the
sound model was build for */
unsigned int data_size; /* size of opaque model data */
unsigned int data_offset; /* offset of opaque data start from head of struct
(e.g sizeof struct sound_trigger_sound_model) */
};
/* key phrase descriptor */
struct sound_trigger_phrase {
unsigned int id; /* keyphrase ID */
unsigned int recognition_mode; /* recognition modes supported by this key phrase */
unsigned int num_users; /* number of users in the key phrase */
unsigned int users[SOUND_TRIGGER_MAX_USERS]; /* users ids: (not uid_t but sound trigger
specific IDs */
char locale[SOUND_TRIGGER_MAX_LOCALE_LEN]; /* locale - JAVA Locale style (e.g. en_US) */
char text[SOUND_TRIGGER_MAX_STRING_LEN]; /* phrase text in UTF-8 format. */
};
/*
* Specialized sound model for key phrase detection.
* Proprietary representation of key phrases in binary data must match information indicated
* by phrases field
*/
struct sound_trigger_phrase_sound_model {
struct sound_trigger_sound_model common;
unsigned int num_phrases; /* number of key phrases in model */
struct sound_trigger_phrase phrases[SOUND_TRIGGER_MAX_PHRASES];
};
/*
* Generic recognition event sent via recognition callback
*/
struct sound_trigger_recognition_event {
int status; /* recognition status e.g.
RECOGNITION_STATUS_SUCCESS */
sound_trigger_sound_model_type_t type; /* event type, same as sound model type.
e.g. SOUND_MODEL_TYPE_KEYPHRASE */
sound_model_handle_t model; /* loaded sound model that triggered the
event */
bool capture_available; /* it is possible to capture audio from this
utterance buffered by the
implementation */
int capture_session; /* audio session ID. framework use */
int capture_delay_ms; /* delay in ms between end of model
detection and start of audio available
for capture. A negative value is possible
(e.g. if key phrase is also available for
capture */
int capture_preamble_ms; /* duration in ms of audio captured
before the start of the trigger.
0 if none. */
bool trigger_in_data; /* the opaque data is the capture of
the trigger sound */
audio_config_t audio_config; /* audio format of either the trigger in
event data or to use for capture of the
rest of the utterance */
unsigned int data_size; /* size of opaque event data */
unsigned int data_offset; /* offset of opaque data start from start of
this struct (e.g sizeof struct
sound_trigger_phrase_recognition_event) */
};
/*
* Confidence level for each user in struct sound_trigger_phrase_recognition_extra
*/
struct sound_trigger_confidence_level {
unsigned int user_id; /* user ID */
unsigned int level; /* confidence level in percent (0 - 100).
- min level for recognition configuration
- detected level for recognition event */
};
/*
* Specialized recognition event for key phrase detection
*/
struct sound_trigger_phrase_recognition_extra {
unsigned int id; /* keyphrase ID */
unsigned int recognition_modes; /* recognition modes used for this keyphrase */
unsigned int confidence_level; /* confidence level for mode RECOGNITION_MODE_VOICE_TRIGGER */
unsigned int num_levels; /* number of user confidence levels */
struct sound_trigger_confidence_level levels[SOUND_TRIGGER_MAX_USERS];
};
struct sound_trigger_phrase_recognition_event {
struct sound_trigger_recognition_event common;
unsigned int num_phrases;
struct sound_trigger_phrase_recognition_extra phrase_extras[SOUND_TRIGGER_MAX_PHRASES];
};
/*
* configuration for sound trigger capture session passed to start_recognition()
*/
struct sound_trigger_recognition_config {
audio_io_handle_t capture_handle; /* IO handle that will be used for capture.
N/A if capture_requested is false */
audio_devices_t capture_device; /* input device requested for detection capture */
bool capture_requested; /* capture and buffer audio for this recognition
instance */
unsigned int num_phrases; /* number of key phrases recognition extras */
struct sound_trigger_phrase_recognition_extra phrases[SOUND_TRIGGER_MAX_PHRASES];
/* configuration for each key phrase */
unsigned int data_size; /* size of opaque capture configuration data */
unsigned int data_offset; /* offset of opaque data start from start of this struct
(e.g sizeof struct sound_trigger_recognition_config) */
};
/*
* Event sent via load sound model callback
*/
struct sound_trigger_model_event {
int status; /* sound model status e.g. SOUND_MODEL_STATUS_UPDATED */
sound_model_handle_t model; /* loaded sound model that triggered the event */
unsigned int data_size; /* size of event data if any. Size of updated sound model if
status is SOUND_MODEL_STATUS_UPDATED */
unsigned int data_offset; /* offset of data start from start of this struct
(e.g sizeof struct sound_trigger_model_event) */
};
#endif // ANDROID_SOUND_TRIGGER_H

View File

@ -242,7 +242,26 @@ enum {
* The consumer gralloc usage bits currently set by the consumer.
* The values are defined in hardware/libhardware/include/gralloc.h.
*/
NATIVE_WINDOW_CONSUMER_USAGE_BITS = 10
NATIVE_WINDOW_CONSUMER_USAGE_BITS = 10,
/**
* Transformation that will by applied to buffers by the hwcomposer.
* This must not be set or checked by producer endpoints, and will
* disable the transform hint set in SurfaceFlinger (see
* NATIVE_WINDOW_TRANSFORM_HINT).
*
* INTENDED USE:
* Temporary - Please do not use this. This is intended only to be used
* by the camera's LEGACY mode.
*
* In situations where a SurfaceFlinger client wishes to set a transform
* that is not visible to the producer, and will always be applied in the
* hardware composer, the client can set this flag with
* native_window_set_buffers_sticky_transform. This can be used to rotate
* and flip buffers consumed by hardware composer without actually changing
* the aspect ratio of the buffers produced.
*/
NATIVE_WINDOW_STICKY_TRANSFORM = 11,
};
/* Valid operations for the (*perform)() hook.
@ -273,6 +292,8 @@ enum {
NATIVE_WINDOW_API_DISCONNECT = 14, /* private */
NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS = 15, /* private */
NATIVE_WINDOW_SET_POST_TRANSFORM_CROP = 16, /* private */
NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17,/* private */
NATIVE_WINDOW_SET_SIDEBAND_STREAM = 18,
};
/* parameter for NATIVE_WINDOW_[API_][DIS]CONNECT */
@ -790,6 +811,23 @@ static inline int native_window_set_buffers_transform(
transform);
}
/*
* native_window_set_buffers_sticky_transform(..., int transform)
* All buffers queued after this call will be displayed transformed according
* to the transform parameter specified applied on top of the regular buffer
* transform. Setting this transform will disable the transform hint.
*
* Temporary - This is only intended to be used by the LEGACY camera mode, do
* not use this for anything else.
*/
static inline int native_window_set_buffers_sticky_transform(
struct ANativeWindow* window,
int transform)
{
return window->perform(window, NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM,
transform);
}
/*
* native_window_set_buffers_timestamp(..., int64_t timestamp)
* All buffers queued after this call will be associated with the timestamp
@ -856,6 +894,17 @@ static inline int native_window_dequeue_buffer_and_wait(ANativeWindow *anw,
return anw->dequeueBuffer_DEPRECATED(anw, anb);
}
/*
* native_window_set_sideband_stream(..., native_handle_t*)
* Attach a sideband buffer stream to a native window.
*/
static inline int native_window_set_sideband_stream(
struct ANativeWindow* window,
native_handle_t* sidebandHandle)
{
return window->perform(window, NATIVE_WINDOW_SET_SIDEBAND_STREAM,
sidebandHandle);
}
__END_DECLS

View File

@ -37,6 +37,8 @@ public:
const static int NlActionAddressUpdated;
const static int NlActionAddressRemoved;
const static int NlActionRdnss;
const static int NlActionRouteUpdated;
const static int NlActionRouteRemoved;
NetlinkEvent();
virtual ~NetlinkEvent();
@ -52,8 +54,11 @@ public:
protected:
bool parseBinaryNetlinkMessage(char *buffer, int size);
bool parseAsciiNetlinkMessage(char *buffer, int size);
bool parseIfAddrMessage(int type, struct ifaddrmsg *ifaddr, int rtasize);
bool parseNdUserOptMessage(struct nduseroptmsg *msg, int optsize);
bool parseIfInfoMessage(const struct nlmsghdr *nh);
bool parseIfAddrMessage(const struct nlmsghdr *nh);
bool parseUlogPacketMessage(const struct nlmsghdr *nh);
bool parseRtMessage(const struct nlmsghdr *nh);
bool parseNdUserOptMessage(const struct nlmsghdr *nh);
};
#endif

View File

@ -189,6 +189,13 @@ int usb_device_release_interface(struct usb_device *device, unsigned int interfa
int usb_device_connect_kernel_driver(struct usb_device *device,
unsigned int interface, int connect);
/* Sets the current configuration for the device to the specified configuration */
int usb_device_set_configuration(struct usb_device *device, int configuration);
/* Sets the specified interface of a USB device */
int usb_device_set_interface(struct usb_device *device, unsigned int interface,
unsigned int alt_setting);
/* Sends a control message to the specified device on endpoint zero */
int usb_device_control_transfer(struct usb_device *device,
int requestType,

View File

@ -30,73 +30,103 @@ namespace android {
struct BitSet32 {
uint32_t value;
inline BitSet32() : value(0) { }
inline BitSet32() : value(0UL) { }
explicit inline BitSet32(uint32_t value) : value(value) { }
// Gets the value associated with a particular bit index.
static inline uint32_t valueForBit(uint32_t n) { return 0x80000000 >> n; }
static inline uint32_t valueForBit(uint32_t n) { return 0x80000000UL >> n; }
// Clears the bit set.
inline void clear() { value = 0; }
inline void clear() { clear(value); }
static inline void clear(uint32_t& value) { value = 0UL; }
// Returns the number of marked bits in the set.
inline uint32_t count() const { return __builtin_popcount(value); }
inline uint32_t count() const { return count(value); }
static inline uint32_t count(uint32_t value) { return __builtin_popcountl(value); }
// Returns true if the bit set does not contain any marked bits.
inline bool isEmpty() const { return ! value; }
inline bool isEmpty() const { return isEmpty(value); }
static inline bool isEmpty(uint32_t value) { return ! value; }
// Returns true if the bit set does not contain any unmarked bits.
inline bool isFull() const { return value == 0xffffffff; }
inline bool isFull() const { return isFull(value); }
static inline bool isFull(uint32_t value) { return value == 0xffffffffUL; }
// Returns true if the specified bit is marked.
inline bool hasBit(uint32_t n) const { return value & valueForBit(n); }
inline bool hasBit(uint32_t n) const { return hasBit(value, n); }
static inline bool hasBit(uint32_t value, uint32_t n) { return value & valueForBit(n); }
// Marks the specified bit.
inline void markBit(uint32_t n) { value |= valueForBit(n); }
inline void markBit(uint32_t n) { markBit(value, n); }
static inline void markBit (uint32_t& value, uint32_t n) { value |= valueForBit(n); }
// Clears the specified bit.
inline void clearBit(uint32_t n) { value &= ~ valueForBit(n); }
inline void clearBit(uint32_t n) { clearBit(value, n); }
static inline void clearBit(uint32_t& value, uint32_t n) { value &= ~ valueForBit(n); }
// Finds the first marked bit in the set.
// Result is undefined if all bits are unmarked.
inline uint32_t firstMarkedBit() const { return __builtin_clz(value); }
inline uint32_t firstMarkedBit() const { return firstMarkedBit(value); }
static uint32_t firstMarkedBit(uint32_t value) { return clz_checked(value); }
// Finds the first unmarked bit in the set.
// Result is undefined if all bits are marked.
inline uint32_t firstUnmarkedBit() const { return __builtin_clz(~ value); }
inline uint32_t firstUnmarkedBit() const { return firstUnmarkedBit(value); }
static inline uint32_t firstUnmarkedBit(uint32_t value) { return clz_checked(~ value); }
// Finds the last marked bit in the set.
// Result is undefined if all bits are unmarked.
inline uint32_t lastMarkedBit() const { return 31 - __builtin_ctz(value); }
inline uint32_t lastMarkedBit() const { return lastMarkedBit(value); }
static inline uint32_t lastMarkedBit(uint32_t value) { return 31 - ctz_checked(value); }
// Finds the first marked bit in the set and clears it. Returns the bit index.
// Result is undefined if all bits are unmarked.
inline uint32_t clearFirstMarkedBit() {
uint32_t n = firstMarkedBit();
clearBit(n);
inline uint32_t clearFirstMarkedBit() { return clearFirstMarkedBit(value); }
static inline uint32_t clearFirstMarkedBit(uint32_t& value) {
uint32_t n = firstMarkedBit(value);
clearBit(value, n);
return n;
}
// Finds the first unmarked bit in the set and marks it. Returns the bit index.
// Result is undefined if all bits are marked.
inline uint32_t markFirstUnmarkedBit() {
uint32_t n = firstUnmarkedBit();
markBit(n);
inline uint32_t markFirstUnmarkedBit() { return markFirstUnmarkedBit(value); }
static inline uint32_t markFirstUnmarkedBit(uint32_t& value) {
uint32_t n = firstUnmarkedBit(value);
markBit(value, n);
return n;
}
// Finds the last marked bit in the set and clears it. Returns the bit index.
// Result is undefined if all bits are unmarked.
inline uint32_t clearLastMarkedBit() {
uint32_t n = lastMarkedBit();
clearBit(n);
inline uint32_t clearLastMarkedBit() { return clearLastMarkedBit(value); }
static inline uint32_t clearLastMarkedBit(uint32_t& value) {
uint32_t n = lastMarkedBit(value);
clearBit(value, n);
return n;
}
// Gets the index of the specified bit in the set, which is the number of
// marked bits that appear before the specified bit.
inline uint32_t getIndexOfBit(uint32_t n) const {
return __builtin_popcount(value & ~(0xffffffffUL >> n));
return getIndexOfBit(value, n);
}
static inline uint32_t getIndexOfBit(uint32_t value, uint32_t n) {
return __builtin_popcountl(value & ~(0xffffffffUL >> n));
}
inline bool operator== (const BitSet32& other) const { return value == other.value; }
@ -115,10 +145,150 @@ struct BitSet32 {
value |= other.value;
return *this;
}
private:
// We use these helpers as the signature of __builtin_c{l,t}z has "unsigned int" for the
// input, which is only guaranteed to be 16b, not 32. The compiler should optimize this away.
static inline uint32_t clz_checked(uint32_t value) {
if (sizeof(unsigned int) == sizeof(uint32_t)) {
return __builtin_clz(value);
} else {
return __builtin_clzl(value);
}
}
static inline uint32_t ctz_checked(uint32_t value) {
if (sizeof(unsigned int) == sizeof(uint32_t)) {
return __builtin_ctz(value);
} else {
return __builtin_ctzl(value);
}
}
};
ANDROID_BASIC_TYPES_TRAITS(BitSet32)
// A simple set of 64 bits that can be individually marked or cleared.
struct BitSet64 {
uint64_t value;
inline BitSet64() : value(0ULL) { }
explicit inline BitSet64(uint64_t value) : value(value) { }
// Gets the value associated with a particular bit index.
static inline uint64_t valueForBit(uint32_t n) { return 0x8000000000000000ULL >> n; }
// Clears the bit set.
inline void clear() { clear(value); }
static inline void clear(uint64_t& value) { value = 0ULL; }
// Returns the number of marked bits in the set.
inline uint32_t count() const { return count(value); }
static inline uint32_t count(uint64_t value) { return __builtin_popcountll(value); }
// Returns true if the bit set does not contain any marked bits.
inline bool isEmpty() const { return isEmpty(value); }
static inline bool isEmpty(uint64_t value) { return ! value; }
// Returns true if the bit set does not contain any unmarked bits.
inline bool isFull() const { return isFull(value); }
static inline bool isFull(uint64_t value) { return value == 0xffffffffffffffffULL; }
// Returns true if the specified bit is marked.
inline bool hasBit(uint32_t n) const { return hasBit(value, n); }
static inline bool hasBit(uint64_t value, uint32_t n) { return value & valueForBit(n); }
// Marks the specified bit.
inline void markBit(uint32_t n) { markBit(value, n); }
static inline void markBit(uint64_t& value, uint32_t n) { value |= valueForBit(n); }
// Clears the specified bit.
inline void clearBit(uint32_t n) { clearBit(value, n); }
static inline void clearBit(uint64_t& value, uint32_t n) { value &= ~ valueForBit(n); }
// Finds the first marked bit in the set.
// Result is undefined if all bits are unmarked.
inline uint32_t firstMarkedBit() const { return firstMarkedBit(value); }
static inline uint32_t firstMarkedBit(uint64_t value) { return __builtin_clzll(value); }
// Finds the first unmarked bit in the set.
// Result is undefined if all bits are marked.
inline uint32_t firstUnmarkedBit() const { return firstUnmarkedBit(value); }
static inline uint32_t firstUnmarkedBit(uint64_t value) { return __builtin_clzll(~ value); }
// Finds the last marked bit in the set.
// Result is undefined if all bits are unmarked.
inline uint32_t lastMarkedBit() const { return lastMarkedBit(value); }
static inline uint32_t lastMarkedBit(uint64_t value) { return 63 - __builtin_ctzll(value); }
// Finds the first marked bit in the set and clears it. Returns the bit index.
// Result is undefined if all bits are unmarked.
inline uint32_t clearFirstMarkedBit() { return clearFirstMarkedBit(value); }
static inline uint32_t clearFirstMarkedBit(uint64_t& value) {
uint64_t n = firstMarkedBit(value);
clearBit(value, n);
return n;
}
// Finds the first unmarked bit in the set and marks it. Returns the bit index.
// Result is undefined if all bits are marked.
inline uint32_t markFirstUnmarkedBit() { return markFirstUnmarkedBit(value); }
static inline uint32_t markFirstUnmarkedBit(uint64_t& value) {
uint64_t n = firstUnmarkedBit(value);
markBit(value, n);
return n;
}
// Finds the last marked bit in the set and clears it. Returns the bit index.
// Result is undefined if all bits are unmarked.
inline uint32_t clearLastMarkedBit() { return clearLastMarkedBit(value); }
static inline uint32_t clearLastMarkedBit(uint64_t& value) {
uint64_t n = lastMarkedBit(value);
clearBit(value, n);
return n;
}
// Gets the index of the specified bit in the set, which is the number of
// marked bits that appear before the specified bit.
inline uint32_t getIndexOfBit(uint32_t n) const { return getIndexOfBit(value, n); }
static inline uint32_t getIndexOfBit(uint64_t value, uint32_t n) {
return __builtin_popcountll(value & ~(0xffffffffffffffffULL >> n));
}
inline bool operator== (const BitSet64& other) const { return value == other.value; }
inline bool operator!= (const BitSet64& other) const { return value != other.value; }
inline BitSet64 operator& (const BitSet64& other) const {
return BitSet64(value & other.value);
}
inline BitSet64& operator&= (const BitSet64& other) {
value &= other.value;
return *this;
}
inline BitSet64 operator| (const BitSet64& other) const {
return BitSet64(value | other.value);
}
inline BitSet64& operator|= (const BitSet64& other) {
value |= other.value;
return *this;
}
};
ANDROID_BASIC_TYPES_TRAITS(BitSet64)
} // namespace android
#endif // UTILS_BITSET_H

View File

@ -60,7 +60,7 @@ public:
status_t wait(Mutex& mutex);
// same with relative timeout
status_t waitRelative(Mutex& mutex, nsecs_t reltime);
// Signal the condition variable, allowing one thread to continue.
// Signal the condition variable, allowing exactly one thread to continue.
void signal();
// Signal the condition variable, allowing one or all threads to continue.
void signal(WakeUpType type) {
@ -132,6 +132,17 @@ inline status_t Condition::waitRelative(Mutex& mutex, nsecs_t reltime) {
#endif // HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
}
inline void Condition::signal() {
/*
* POSIX says pthread_cond_signal wakes up "one or more" waiting threads.
* However bionic follows the glibc guarantee which wakes up "exactly one"
* waiting thread.
*
* man 3 pthread_cond_signal
* pthread_cond_signal restarts one of the threads that are waiting on
* the condition variable cond. If no threads are waiting on cond,
* nothing happens. If several threads are waiting on cond, exactly one
* is restarted, but it is not specified which.
*/
pthread_cond_signal(&mCond);
}
inline void Condition::broadcast() {

View File

@ -17,8 +17,8 @@
#ifndef ANDROID_UTILS_LRU_CACHE_H
#define ANDROID_UTILS_LRU_CACHE_H
#include <UniquePtr.h>
#include <utils/BasicHashtable.h>
#include <utils/UniquePtr.h>
namespace android {
@ -48,6 +48,7 @@ public:
bool remove(const TKey& key);
bool removeOldest();
void clear();
const TValue& peekOldestValue();
class Iterator {
public:
@ -183,6 +184,14 @@ bool LruCache<TKey, TValue>::removeOldest() {
return false;
}
template <typename TKey, typename TValue>
const TValue& LruCache<TKey, TValue>::peekOldestValue() {
if (mOldest) {
return mOldest->value;
}
return mNullValue;
}
template <typename TKey, typename TValue>
void LruCache<TKey, TValue>::clear() {
if (mListener) {

View File

@ -0,0 +1,56 @@
/*
* Copyright 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_NATIVE_HANDLE_H
#define ANDROID_NATIVE_HANDLE_H
#include <utils/RefBase.h>
#include <utils/StrongPointer.h>
typedef struct native_handle native_handle_t;
namespace android {
class NativeHandle: public LightRefBase<NativeHandle> {
public:
// Create a refcounted wrapper around a native_handle_t, and declare
// whether the wrapper owns the handle (so that it should clean up the
// handle upon destruction) or not.
// If handle is NULL, no NativeHandle will be created.
static sp<NativeHandle> create(native_handle_t* handle, bool ownsHandle);
const native_handle_t* handle() const {
return mHandle;
}
private:
// for access to the destructor
friend class LightRefBase<NativeHandle>;
NativeHandle(native_handle_t* handle, bool ownsHandle);
virtual ~NativeHandle();
native_handle_t* mHandle;
bool mOwnsHandle;
// non-copyable
NativeHandle(const NativeHandle&);
NativeHandle& operator=(const NativeHandle&);
};
} // namespace android
#endif // ANDROID_NATIVE_HANDLE_H

View File

@ -203,6 +203,13 @@ private:
mutable volatile int32_t mCount;
};
// This is a wrapper around LightRefBase that simply enforces a virtual
// destructor to eliminate the template requirement of LightRefBase
class VirtualLightRefBase : public LightRefBase<VirtualLightRefBase> {
public:
virtual ~VirtualLightRefBase() {}
};
// ---------------------------------------------------------------------------
template <typename T>

View File

@ -130,11 +130,19 @@ public:
// start, or -1 if not found
ssize_t find(const char* other, size_t start = 0) const;
// return true if this string contains the specified substring
inline bool contains(const char* other) const;
// removes all occurrence of the specified substring
// returns true if any were found and removed
bool removeAll(const char* other);
void toLower();
void toLower(size_t start, size_t numChars);
void toUpper();
void toUpper(size_t start, size_t numChars);
/*
* These methods operate on the string as if it were a path name.
*/
@ -280,6 +288,11 @@ inline const SharedBuffer* String8::sharedBuffer() const
return SharedBuffer::bufferFromData(mString);
}
inline bool String8::contains(const char* other) const
{
return find(other) >= 0;
}
inline String8& String8::operator=(const String8& other)
{
setTo(other);

View File

@ -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

View File

@ -473,6 +473,27 @@ exit_success:
}
static int wipe_data_via_recovery()
{
mkdir("/cache/recovery", 0700);
int fd = open("/cache/recovery/command", O_RDWR|O_CREAT|O_TRUNC, 0600);
if (fd >= 0) {
write(fd, "--wipe_data\n", strlen("--wipe_data\n") + 1);
write(fd, "--reason=wipe_data_via_recovery\n", strlen("--reason=wipe_data_via_recovery\n") + 1);
close(fd);
} else {
ERROR("could not open /cache/recovery/command\n");
return -1;
}
android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
while (1) { pause(); } // never reached
}
/*
* This function might request a reboot, in which case it will
* not return.
*/
int do_mount_all(int nargs, char **args)
{
pid_t pid;
@ -495,7 +516,12 @@ int do_mount_all(int nargs, char **args)
pid = fork();
if (pid > 0) {
/* Parent. Wait for the child to return */
waitpid(pid, &status, 0);
int wp_ret = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
if (wp_ret < 0) {
/* Unexpected error code. We will continue anyway. */
NOTICE("waitpid failed rc=%d, errno=%d\n", wp_ret, errno);
}
if (WIFEXITED(status)) {
ret = WEXITSTATUS(status);
} else {
@ -510,23 +536,32 @@ int do_mount_all(int nargs, char **args)
if (child_ret == -1) {
ERROR("fs_mgr_mount_all returned an error\n");
}
exit(child_ret);
_exit(child_ret);
} else {
/* fork failed, return an error */
return -1;
}
/* ret is 1 if the device is encrypted, 0 if not, and -1 on error */
if (ret == 1) {
if (ret == FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION) {
property_set("vold.decrypt", "trigger_encryption");
} else if (ret == FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED) {
property_set("ro.crypto.state", "encrypted");
property_set("vold.decrypt", "1");
} else if (ret == 0) {
property_set("vold.decrypt", "trigger_default_encryption");
} else if (ret == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
property_set("ro.crypto.state", "unencrypted");
/* If fs_mgr determined this is an unencrypted device, then trigger
* that action.
*/
action_for_each_trigger("nonencrypted", action_add_queue_tail);
} else if (ret == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) {
/* Setup a wipe via recovery, and reboot into recovery */
ERROR("fs_mgr_mount_all suggested recovery, so wiping data via recovery.\n");
ret = wipe_data_via_recovery();
/* If reboot worked, there is no return. */
} else if (ret > 0) {
ERROR("fs_mgr_mount_all returned unexpected error %d\n", ret);
}
/* else ... < 0: error */
return ret;
}

View File

@ -944,7 +944,7 @@ static void handle_firmware_event(struct uevent *uevent)
}
}
#define UEVENT_MSG_LEN 1024
#define UEVENT_MSG_LEN 2048
void handle_device_fd()
{
char msg[UEVENT_MSG_LEN+2];

View File

@ -24,6 +24,7 @@
#include <dirent.h>
#include <limits.h>
#include <errno.h>
#include <sys/poll.h>
#include <cutils/misc.h>
#include <cutils/sockets.h>
@ -181,7 +182,6 @@ static void write_persistent_property(const char *name, const char *value)
static bool is_legal_property_name(const char* name, size_t namelen)
{
size_t i;
bool previous_was_dot = false;
if (namelen >= PROP_NAME_MAX) return false;
if (namelen < 1) return false;
if (name[0] == '.') return false;
@ -191,11 +191,10 @@ static bool is_legal_property_name(const char* name, size_t namelen)
/* Don't allow ".." to appear in a property name */
for (i = 0; i < namelen; i++) {
if (name[i] == '.') {
if (previous_was_dot == true) return false;
previous_was_dot = true;
// i=0 is guaranteed to never have a dot. See above.
if (name[i-1] == '.') return false;
continue;
}
previous_was_dot = false;
if (name[i] == '_' || name[i] == '-') continue;
if (name[i] >= 'a' && name[i] <= 'z') continue;
if (name[i] >= 'A' && name[i] <= 'Z') continue;
@ -268,6 +267,9 @@ void handle_property_set_fd()
socklen_t addr_size = sizeof(addr);
socklen_t cr_size = sizeof(cr);
char * source_ctx = NULL;
struct pollfd ufds[1];
const int timeout_ms = 2 * 1000; /* Default 2 sec timeout for caller to send property. */
int nr;
if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {
return;
@ -280,7 +282,21 @@ void handle_property_set_fd()
return;
}
r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), 0));
ufds[0].fd = s;
ufds[0].events = POLLIN;
ufds[0].revents = 0;
nr = TEMP_FAILURE_RETRY(poll(ufds, 1, timeout_ms));
if (nr == 0) {
ERROR("sys_prop: timeout waiting for uid=%d to send property message.\n", cr.uid);
close(s);
return;
} else if (nr < 0) {
ERROR("sys_prop: error waiting for uid=%d to send property message. err=%d %s\n", cr.uid, errno, strerror(errno));
close(s);
return;
}
r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), MSG_DONTWAIT));
if(r != sizeof(prop_msg)) {
ERROR("sys_prop: mis-match msg size received: %d expected: %zu errno: %d\n",
r, sizeof(prop_msg), errno);

173
libbacktrace/map_info.c Normal file
View File

@ -0,0 +1,173 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <pthread.h>
#include <unistd.h>
#include <log/log.h>
#include <sys/time.h>
#include <backtrace/backtrace.h>
#if defined(__APPLE__)
// Mac OS vmmap(1) output:
// __TEXT 0009f000-000a1000 [ 8K 8K] r-x/rwx SM=COW /Volumes/android/dalvik-dev/out/host/darwin-x86/bin/libcorkscrew_test\n
// 012345678901234567890123456789012345678901234567890123456789
// 0 1 2 3 4 5
static backtrace_map_info_t* parse_vmmap_line(const char* line) {
unsigned long int start;
unsigned long int end;
char permissions[4];
int name_pos;
if (sscanf(line, "%*21c %lx-%lx [%*13c] %3c/%*3c SM=%*3c %n",
&start, &end, permissions, &name_pos) != 3) {
return NULL;
}
const char* name = line + name_pos;
size_t name_len = strlen(name);
backtrace_map_info_t* mi = calloc(1, sizeof(backtrace_map_info_t) + name_len);
if (mi != NULL) {
mi->start = start;
mi->end = end;
mi->is_readable = permissions[0] == 'r';
mi->is_writable = permissions[1] == 'w';
mi->is_executable = permissions[2] == 'x';
memcpy(mi->name, name, name_len);
mi->name[name_len - 1] = '\0';
ALOGV("Parsed map: start=0x%08x, end=0x%08x, "
"is_readable=%d, is_writable=%d is_executable=%d, name=%s",
mi->start, mi->end,
mi->is_readable, mi->is_writable, mi->is_executable, mi->name);
}
return mi;
}
backtrace_map_info_t* backtrace_create_map_info_list(pid_t pid) {
char cmd[1024];
if (pid < 0) {
pid = getpid();
}
snprintf(cmd, sizeof(cmd), "vmmap -w -resident -submap -allSplitLibs -interleaved %d", pid);
FILE* fp = popen(cmd, "r");
if (fp == NULL) {
return NULL;
}
char line[1024];
backtrace_map_info_t* milist = NULL;
while (fgets(line, sizeof(line), fp) != NULL) {
backtrace_map_info_t* mi = parse_vmmap_line(line);
if (mi != NULL) {
mi->next = milist;
milist = mi;
}
}
pclose(fp);
return milist;
}
#else
// Linux /proc/<pid>/maps lines:
// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so\n
// 012345678901234567890123456789012345678901234567890123456789
// 0 1 2 3 4 5
static backtrace_map_info_t* parse_maps_line(const char* line)
{
unsigned long int start;
unsigned long int end;
char permissions[5];
int name_pos;
if (sscanf(line, "%lx-%lx %4s %*x %*x:%*x %*d%n", &start, &end,
permissions, &name_pos) != 3) {
return NULL;
}
while (isspace(line[name_pos])) {
name_pos += 1;
}
const char* name = line + name_pos;
size_t name_len = strlen(name);
if (name_len && name[name_len - 1] == '\n') {
name_len -= 1;
}
backtrace_map_info_t* mi = calloc(1, sizeof(backtrace_map_info_t) + name_len + 1);
if (mi) {
mi->start = start;
mi->end = end;
mi->is_readable = strlen(permissions) == 4 && permissions[0] == 'r';
mi->is_writable = strlen(permissions) == 4 && permissions[1] == 'w';
mi->is_executable = strlen(permissions) == 4 && permissions[2] == 'x';
memcpy(mi->name, name, name_len);
mi->name[name_len] = '\0';
ALOGV("Parsed map: start=0x%08x, end=0x%08x, "
"is_readable=%d, is_writable=%d, is_executable=%d, name=%s",
mi->start, mi->end,
mi->is_readable, mi->is_writable, mi->is_executable, mi->name);
}
return mi;
}
backtrace_map_info_t* backtrace_create_map_info_list(pid_t tid) {
char path[PATH_MAX];
char line[1024];
FILE* fp;
backtrace_map_info_t* milist = NULL;
if (tid < 0) {
tid = getpid();
}
snprintf(path, PATH_MAX, "/proc/%d/maps", tid);
fp = fopen(path, "r");
if (fp) {
while(fgets(line, sizeof(line), fp)) {
backtrace_map_info_t* mi = parse_maps_line(line);
if (mi) {
mi->next = milist;
milist = mi;
}
}
fclose(fp);
}
return milist;
}
#endif
void backtrace_destroy_map_info_list(backtrace_map_info_t* milist) {
while (milist) {
backtrace_map_info_t* next = milist->next;
free(milist);
milist = next;
}
}
const backtrace_map_info_t* backtrace_find_map_info(
const backtrace_map_info_t* milist, uintptr_t addr) {
const backtrace_map_info_t* mi = milist;
while (mi && !(addr >= mi->start && addr < mi->end)) {
mi = mi->next;
}
return mi;
}

View File

@ -212,7 +212,7 @@ int fs_mkdirs(const char* path, mode_t mode) {
/* Yay, segment is ready for us to step into */
int next_fd;
if ((next_fd = openat(fd, segment, 0)) == -1) {
if ((next_fd = openat(fd, segment, O_NOFOLLOW | O_CLOEXEC)) == -1) {
ALOGE("Failed to openat(%s): %s", buf, strerror(errno));
res = -errno;
goto done_close;

View File

@ -39,21 +39,20 @@ static inline SchedPolicy _policy(SchedPolicy p)
#if defined(HAVE_ANDROID_OS) && defined(HAVE_SCHED_H) && defined(HAVE_PTHREADS)
#include <sched.h>
#include <pthread.h>
#ifndef SCHED_NORMAL
#define SCHED_NORMAL 0
#endif
#ifndef SCHED_BATCH
#define SCHED_BATCH 3
#endif
#include <sched.h>
#include <sys/prctl.h>
#define POLICY_DEBUG 0
#define CAN_SET_SP_SYSTEM 0 // non-zero means to implement set_sched_policy(tid, SP_SYSTEM)
// This prctl is only available in Android kernels.
#define PR_SET_TIMERSLACK_PID 41
// timer slack value in nS enforced when the thread moves to background
#define TIMER_SLACK_BG 40000000
static pthread_once_t the_once = PTHREAD_ONCE_INIT;
static int __sys_supports_schedgroups = -1;
@ -321,6 +320,8 @@ int set_sched_policy(int tid, SchedPolicy policy)
&param);
}
prctl(PR_SET_TIMERSLACK_PID, policy == SP_BACKGROUND ? TIMER_SLACK_BG : 0, tid);
return 0;
}

View File

@ -262,6 +262,10 @@ int str_parms_add_float(struct str_parms *str_parms, const char *key,
return ret;
}
int str_parms_has_key(struct str_parms *str_parms, const char *key) {
return hashmapGet(str_parms->map, (void *)key) != NULL;
}
int str_parms_get_str(struct str_parms *str_parms, const char *key, char *val,
int len)
{

View File

@ -208,6 +208,26 @@ fail:
}
static struct write_list *
mk_mbr_sig()
{
struct write_list *item;
if (!(item = alloc_wl(sizeof(uint16_t)))) {
ALOGE("Unable to allocate memory for MBR signature.");
return NULL;
}
{
/* DO NOT DEREFERENCE */
struct pc_boot_record *mbr = (void *)PC_MBR_DISK_OFFSET;
/* grab the offset in mbr where to write mbr signature. */
item->offset = (loff_t)((uintptr_t)((uint8_t *)(&mbr->mbr_sig)));
}
*((uint16_t*)item->data) = PC_BIOS_BOOT_SIG;
return item;
}
struct write_list *
config_mbr(struct disk_info *dinfo)
{
@ -276,6 +296,13 @@ config_mbr(struct disk_info *dinfo)
wlist_add(&wr_list, temp_wr);
}
if ((temp_wr = mk_mbr_sig()))
wlist_add(&wr_list, temp_wr);
else {
ALOGE("Cannot set MBR signature");
goto fail;
}
return wr_list;
nospace:

View File

@ -58,7 +58,6 @@ static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER;
#endif
#if FAKE_LOG_DEVICE
#define WEAK __attribute__((weak))
static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1, -1 };
#else
static int logd_fd = -1;
@ -274,7 +273,7 @@ static const char *LOG_NAME[LOG_ID_MAX] = {
[LOG_ID_CRASH] = "crash"
};
const WEAK char *android_log_id_to_name(log_id_t log_id)
const char *android_log_id_to_name(log_id_t log_id)
{
if (log_id >= LOG_ID_MAX) {
log_id = LOG_ID_MAIN;

View File

@ -12,6 +12,7 @@ test_src_files := \
ValidNameNativeBridge_test.cpp
shared_libraries := \
liblog \
libnativebridge
$(foreach file,$(test_src_files), \
@ -32,4 +33,4 @@ $(foreach file,$(test_src_files), \
$(eval LOCAL_SRC_FILES := $(file)) \
$(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
$(eval include $(BUILD_HOST_NATIVE_TEST)) \
)
)

View File

@ -563,17 +563,7 @@ int ifc_create_default_route(const char *name, in_addr_t gw)
return ret;
}
/* deprecated v4-only */
int ifc_add_host_route(const char *name, in_addr_t dst)
{
struct in_addr in_dst, in_gw;
in_dst.s_addr = dst;
in_gw.s_addr = 0;
return ifc_act_on_ipv4_route(SIOCADDRT, name, in_dst, 32, in_gw);
}
// Needed by code in hidden partner repositories / branches, so don't delete.
int ifc_enable(const char *ifname)
{
int result;
@ -584,6 +574,7 @@ int ifc_enable(const char *ifname)
return result;
}
// Needed by code in hidden partner repositories / branches, so don't delete.
int ifc_disable(const char *ifname)
{
unsigned addr, count;
@ -608,14 +599,16 @@ int ifc_reset_connections(const char *ifname, const int reset_mask)
{
#ifdef HAVE_ANDROID_OS
int result, success;
in_addr_t myaddr;
in_addr_t myaddr = 0;
struct ifreq ifr;
struct in6_ifreq ifr6;
if (reset_mask & RESET_IPV4_ADDRESSES) {
/* IPv4. Clear connections on the IP address. */
ifc_init();
ifc_get_info(ifname, &myaddr, NULL, NULL);
if (!(reset_mask & RESET_IGNORE_INTERFACE_ADDRESS)) {
ifc_get_info(ifname, &myaddr, NULL, NULL);
}
ifc_init_ifr(ifname, &ifr);
init_sockaddr_in(&ifr.ifr_addr, myaddr);
result = ioctl(ifc_ctl_sock, SIOCKILLADDR, &ifr);
@ -647,118 +640,6 @@ int ifc_reset_connections(const char *ifname, const int reset_mask)
#endif
}
/*
* Remove the routes associated with the named interface.
*/
int ifc_remove_host_routes(const char *name)
{
char ifname[64];
in_addr_t dest, gway, mask;
int flags, refcnt, use, metric, mtu, win, irtt;
struct rtentry rt;
FILE *fp;
struct in_addr addr;
fp = fopen("/proc/net/route", "r");
if (fp == NULL)
return -1;
/* Skip the header line */
if (fscanf(fp, "%*[^\n]\n") < 0) {
fclose(fp);
return -1;
}
ifc_init();
for (;;) {
int nread = fscanf(fp, "%63s%X%X%X%d%d%d%X%d%d%d\n",
ifname, &dest, &gway, &flags, &refcnt, &use, &metric, &mask,
&mtu, &win, &irtt);
if (nread != 11) {
break;
}
if ((flags & (RTF_UP|RTF_HOST)) != (RTF_UP|RTF_HOST)
|| strcmp(ifname, name) != 0) {
continue;
}
memset(&rt, 0, sizeof(rt));
rt.rt_dev = (void *)name;
init_sockaddr_in(&rt.rt_dst, dest);
init_sockaddr_in(&rt.rt_gateway, gway);
init_sockaddr_in(&rt.rt_genmask, mask);
addr.s_addr = dest;
if (ioctl(ifc_ctl_sock, SIOCDELRT, &rt) < 0) {
ALOGD("failed to remove route for %s to %s: %s",
ifname, inet_ntoa(addr), strerror(errno));
}
}
fclose(fp);
ifc_close();
return 0;
}
/*
* Return the address of the default gateway
*
* TODO: factor out common code from this and remove_host_routes()
* so that we only scan /proc/net/route in one place.
*
* DEPRECATED
*/
int ifc_get_default_route(const char *ifname)
{
char name[64];
in_addr_t dest, gway, mask;
int flags, refcnt, use, metric, mtu, win, irtt;
int result;
FILE *fp;
fp = fopen("/proc/net/route", "r");
if (fp == NULL)
return 0;
/* Skip the header line */
if (fscanf(fp, "%*[^\n]\n") < 0) {
fclose(fp);
return 0;
}
ifc_init();
result = 0;
for (;;) {
int nread = fscanf(fp, "%63s%X%X%X%d%d%d%X%d%d%d\n",
name, &dest, &gway, &flags, &refcnt, &use, &metric, &mask,
&mtu, &win, &irtt);
if (nread != 11) {
break;
}
if ((flags & (RTF_UP|RTF_GATEWAY)) == (RTF_UP|RTF_GATEWAY)
&& dest == 0
&& strcmp(ifname, name) == 0) {
result = gway;
break;
}
}
fclose(fp);
ifc_close();
return result;
}
/*
* Sets the specified gateway as the default route for the named interface.
* DEPRECATED
*/
int ifc_set_default_route(const char *ifname, in_addr_t gateway)
{
struct in_addr addr;
int result;
ifc_init();
addr.s_addr = gateway;
if ((result = ifc_create_default_route(ifname, gateway)) < 0) {
ALOGD("failed to add %s as default route for %s: %s",
inet_ntoa(addr), ifname, strerror(errno));
}
ifc_close();
return result;
}
/*
* Removes the default route for the named interface.
*/
@ -821,151 +702,3 @@ ifc_configure(const char *ifname,
return 0;
}
int ifc_act_on_ipv6_route(int action, const char *ifname, struct in6_addr dst, int prefix_length,
struct in6_addr gw)
{
struct in6_rtmsg rtmsg;
int result;
int ifindex;
memset(&rtmsg, 0, sizeof(rtmsg));
ifindex = if_nametoindex(ifname);
if (ifindex == 0) {
printerr("if_nametoindex() failed: interface %s\n", ifname);
return -ENXIO;
}
rtmsg.rtmsg_ifindex = ifindex;
rtmsg.rtmsg_dst = dst;
rtmsg.rtmsg_dst_len = prefix_length;
rtmsg.rtmsg_flags = RTF_UP;
if (prefix_length == 128) {
rtmsg.rtmsg_flags |= RTF_HOST;
}
if (memcmp(&gw, &in6addr_any, sizeof(in6addr_any))) {
rtmsg.rtmsg_flags |= RTF_GATEWAY;
rtmsg.rtmsg_gateway = gw;
}
ifc_init6();
if (ifc_ctl_sock6 < 0) {
return -errno;
}
result = ioctl(ifc_ctl_sock6, action, &rtmsg);
if (result < 0) {
if (errno == EEXIST) {
result = 0;
} else {
result = -errno;
}
}
ifc_close6();
return result;
}
int ifc_act_on_route(int action, const char *ifname, const char *dst, int prefix_length,
const char *gw)
{
int ret = 0;
struct sockaddr_in ipv4_dst, ipv4_gw;
struct sockaddr_in6 ipv6_dst, ipv6_gw;
struct addrinfo hints, *addr_ai, *gw_ai;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
hints.ai_flags = AI_NUMERICHOST;
ret = getaddrinfo(dst, NULL, &hints, &addr_ai);
if (ret != 0) {
printerr("getaddrinfo failed: invalid address %s\n", dst);
return -EINVAL;
}
if (gw == NULL || (strlen(gw) == 0)) {
if (addr_ai->ai_family == AF_INET6) {
gw = "::";
} else if (addr_ai->ai_family == AF_INET) {
gw = "0.0.0.0";
}
}
if (((addr_ai->ai_family == AF_INET6) && (prefix_length < 0 || prefix_length > 128)) ||
((addr_ai->ai_family == AF_INET) && (prefix_length < 0 || prefix_length > 32))) {
printerr("ifc_add_route: invalid prefix length");
freeaddrinfo(addr_ai);
return -EINVAL;
}
ret = getaddrinfo(gw, NULL, &hints, &gw_ai);
if (ret != 0) {
printerr("getaddrinfo failed: invalid gateway %s\n", gw);
freeaddrinfo(addr_ai);
return -EINVAL;
}
if (addr_ai->ai_family != gw_ai->ai_family) {
printerr("ifc_add_route: different address families: %s and %s\n", dst, gw);
freeaddrinfo(addr_ai);
freeaddrinfo(gw_ai);
return -EINVAL;
}
if (addr_ai->ai_family == AF_INET6) {
memcpy(&ipv6_dst, addr_ai->ai_addr, sizeof(struct sockaddr_in6));
memcpy(&ipv6_gw, gw_ai->ai_addr, sizeof(struct sockaddr_in6));
ret = ifc_act_on_ipv6_route(action, ifname, ipv6_dst.sin6_addr,
prefix_length, ipv6_gw.sin6_addr);
} else if (addr_ai->ai_family == AF_INET) {
memcpy(&ipv4_dst, addr_ai->ai_addr, sizeof(struct sockaddr_in));
memcpy(&ipv4_gw, gw_ai->ai_addr, sizeof(struct sockaddr_in));
ret = ifc_act_on_ipv4_route(action, ifname, ipv4_dst.sin_addr,
prefix_length, ipv4_gw.sin_addr);
} else {
printerr("ifc_add_route: getaddrinfo returned un supported address family %d\n",
addr_ai->ai_family);
ret = -EAFNOSUPPORT;
}
freeaddrinfo(addr_ai);
freeaddrinfo(gw_ai);
return ret;
}
/*
* DEPRECATED
*/
int ifc_add_ipv4_route(const char *ifname, struct in_addr dst, int prefix_length,
struct in_addr gw)
{
int i =ifc_act_on_ipv4_route(SIOCADDRT, ifname, dst, prefix_length, gw);
if (DBG) printerr("ifc_add_ipv4_route(%s, xx, %d, xx) = %d", ifname, prefix_length, i);
return i;
}
/*
* DEPRECATED
*/
int ifc_add_ipv6_route(const char *ifname, struct in6_addr dst, int prefix_length,
struct in6_addr gw)
{
return ifc_act_on_ipv6_route(SIOCADDRT, ifname, dst, prefix_length, gw);
}
int ifc_add_route(const char *ifname, const char *dst, int prefix_length, const char *gw)
{
int i = ifc_act_on_route(SIOCADDRT, ifname, dst, prefix_length, gw);
if (DBG) printerr("ifc_add_route(%s, %s, %d, %s) = %d", ifname, dst, prefix_length, gw, i);
return i;
}
int ifc_remove_route(const char *ifname, const char*dst, int prefix_length, const char *gw)
{
return ifc_act_on_route(SIOCDELRT, ifname, dst, prefix_length, gw);
}

View File

@ -230,6 +230,8 @@ int receive_packet(int s, struct dhcp_msg *msg)
packet.udp.check = 0;
sum = finish_sum(checksum(&packet, nread, 0));
packet.udp.check = temp;
if (!sum)
sum = finish_sum(sum);
if (temp != sum) {
ALOGW("UDP header checksum failure (0x%x should be 0x%x)", sum, temp);
return -1;

View File

@ -0,0 +1,21 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := processgroup.cpp
LOCAL_MODULE := libprocessgroup
LOCAL_SHARED_LIBRARIES := liblog libutils
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_CFLAGS := -Wall -Werror
LOCAL_REQUIRED_MODULE := processgroup_cleanup
include external/libcxx/libcxx.mk
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := cleanup.cpp
LOCAL_MODULE := processgroup_cleanup
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_CFLAGS := -Wall -Werror
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_STATIC_LIBRARIES := libc libcutils
include $(BUILD_EXECUTABLE)

View File

@ -0,0 +1,31 @@
/*
* Copyright 2014 Google, Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include <unistd.h>
#include <sys/syslimits.h>
#include "processgroup_priv.h"
int main(int argc, char **argv)
{
char buf[PATH_MAX];
if (argc != 2)
return -1;
memcpy(buf, PROCESSGROUP_CGROUP_PATH, sizeof(PROCESSGROUP_CGROUP_PATH));
strlcat(buf, argv[1], sizeof(buf));
return rmdir(buf);
}

View File

@ -0,0 +1,33 @@
/*
* Copyright 2014 Google, Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _PROCESSGROUP_H_
#define _PROCESSGROUP_H_
#include <sys/cdefs.h>
#include <sys/types.h>
__BEGIN_DECLS
int killProcessGroup(uid_t uid, int initialPid, int signal);
int createProcessGroup(uid_t uid, int initialPid);
void removeAllProcessGroups(void);
__END_DECLS
#endif

View File

@ -0,0 +1,341 @@
/*
* Copyright 2014 Google, Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//#define LOG_NDEBUG 0
#define LOG_TAG "libprocessgroup"
#include <assert.h>
#include <dirent.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <log/log.h>
#include <private/android_filesystem_config.h>
#include <utils/SystemClock.h>
#include <processgroup/processgroup.h>
#include "processgroup_priv.h"
struct ctx {
bool initialized;
int fd;
char buf[128];
char *buf_ptr;
size_t buf_len;
};
static int convertUidToPath(char *path, size_t size, uid_t uid)
{
return snprintf(path, size, "%s/%s%d",
PROCESSGROUP_CGROUP_PATH,
PROCESSGROUP_UID_PREFIX,
uid);
}
static int convertUidPidToPath(char *path, size_t size, uid_t uid, int pid)
{
return snprintf(path, size, "%s/%s%d/%s%d",
PROCESSGROUP_CGROUP_PATH,
PROCESSGROUP_UID_PREFIX,
uid,
PROCESSGROUP_PID_PREFIX,
pid);
}
static int initCtx(uid_t uid, int pid, struct ctx *ctx)
{
int ret;
char path[PROCESSGROUP_MAX_PATH_LEN] = {0};
convertUidPidToPath(path, sizeof(path), uid, pid);
strlcat(path, PROCESSGROUP_CGROUP_PROCS_FILE, sizeof(path));
int fd = open(path, O_RDONLY);
if (fd < 0) {
ret = -errno;
SLOGW("failed to open %s: %s", path, strerror(errno));
return ret;
}
ctx->fd = fd;
ctx->buf_ptr = ctx->buf;
ctx->buf_len = 0;
ctx->initialized = true;
SLOGV("Initialized context for %s", path);
return 0;
}
static int refillBuffer(struct ctx *ctx)
{
memmove(ctx->buf, ctx->buf_ptr, ctx->buf_len);
ctx->buf_ptr = ctx->buf;
ssize_t ret = read(ctx->fd, ctx->buf_ptr + ctx->buf_len,
sizeof(ctx->buf) - ctx->buf_len - 1);
if (ret < 0) {
return -errno;
} else if (ret == 0) {
return 0;
}
ctx->buf_len += ret;
ctx->buf[ctx->buf_len] = 0;
SLOGV("Read %d to buffer: %s", ret, ctx->buf);
assert(ctx->buf_len <= sizeof(ctx->buf));
return ret;
}
static pid_t getOneAppProcess(uid_t uid, int appProcessPid, struct ctx *ctx)
{
if (!ctx->initialized) {
int ret = initCtx(uid, appProcessPid, ctx);
if (ret < 0) {
return ret;
}
}
char *eptr;
while ((eptr = (char *)memchr(ctx->buf_ptr, '\n', ctx->buf_len)) == NULL) {
int ret = refillBuffer(ctx);
if (ret == 0) {
return -ERANGE;
}
if (ret < 0) {
return ret;
}
}
*eptr = '\0';
char *pid_eptr = NULL;
errno = 0;
long pid = strtol(ctx->buf_ptr, &pid_eptr, 10);
if (errno != 0) {
return -errno;
}
if (pid_eptr != eptr) {
return -EINVAL;
}
ctx->buf_len -= (eptr - ctx->buf_ptr) + 1;
ctx->buf_ptr = eptr + 1;
return (pid_t)pid;
}
static int removeProcessGroup(uid_t uid, int pid)
{
int ret;
char path[PROCESSGROUP_MAX_PATH_LEN] = {0};
convertUidPidToPath(path, sizeof(path), uid, pid);
ret = rmdir(path);
convertUidToPath(path, sizeof(path), uid);
rmdir(path);
return ret;
}
static void removeUidProcessGroups(const char *uid_path)
{
DIR *uid = opendir(uid_path);
if (uid != NULL) {
struct dirent cur;
struct dirent *dir;
while ((readdir_r(uid, &cur, &dir) == 0) && dir) {
char path[PROCESSGROUP_MAX_PATH_LEN];
if (dir->d_type != DT_DIR) {
continue;
}
if (strncmp(dir->d_name, PROCESSGROUP_PID_PREFIX, strlen(PROCESSGROUP_PID_PREFIX))) {
continue;
}
snprintf(path, sizeof(path), "%s/%s", uid_path, dir->d_name);
SLOGV("removing %s\n", path);
rmdir(path);
}
closedir(uid);
}
}
void removeAllProcessGroups()
{
SLOGV("removeAllProcessGroups()");
DIR *root = opendir(PROCESSGROUP_CGROUP_PATH);
if (root == NULL) {
SLOGE("failed to open %s: %s", PROCESSGROUP_CGROUP_PATH, strerror(errno));
} else {
struct dirent cur;
struct dirent *dir;
while ((readdir_r(root, &cur, &dir) == 0) && dir) {
char path[PROCESSGROUP_MAX_PATH_LEN];
if (dir->d_type != DT_DIR) {
continue;
}
if (strncmp(dir->d_name, PROCESSGROUP_UID_PREFIX, strlen(PROCESSGROUP_UID_PREFIX))) {
continue;
}
snprintf(path, sizeof(path), "%s/%s", PROCESSGROUP_CGROUP_PATH, dir->d_name);
removeUidProcessGroups(path);
SLOGV("removing %s\n", path);
rmdir(path);
}
closedir(root);
}
}
static int killProcessGroupOnce(uid_t uid, int initialPid, int signal)
{
int processes = 0;
struct ctx ctx;
pid_t pid;
ctx.initialized = false;
while ((pid = getOneAppProcess(uid, initialPid, &ctx)) >= 0) {
processes++;
if (pid == 0) {
// Should never happen... but if it does, trying to kill this
// will boomerang right back and kill us! Let's not let that happen.
SLOGW("Yikes, we've been told to kill pid 0! How about we don't do that.");
continue;
}
if (pid != initialPid) {
// We want to be noisy about killing processes so we can understand
// what is going on in the log; however, don't be noisy about the base
// process, since that it something we always kill, and we have already
// logged elsewhere about killing it.
SLOGI("Killing pid %d in uid %d as part of process group %d", pid, uid, initialPid);
}
int ret = kill(pid, signal);
if (ret == -1) {
SLOGW("failed to kill pid %d: %s", pid, strerror(errno));
}
}
if (ctx.initialized) {
close(ctx.fd);
}
return processes;
}
int killProcessGroup(uid_t uid, int initialPid, int signal)
{
int processes;
int sleep_us = 100;
long startTime = android::uptimeMillis();
while ((processes = killProcessGroupOnce(uid, initialPid, signal)) > 0) {
SLOGV("killed %d processes for processgroup %d\n", processes, initialPid);
if (sleep_us < 128000) {
usleep(sleep_us);
sleep_us *= 2;
} else {
SLOGE("failed to kill %d processes for processgroup %d\n",
processes, initialPid);
break;
}
}
SLOGV("Killed process group uid %d pid %d in %ldms, %d procs remain", uid, initialPid,
android::uptimeMillis()-startTime, processes);
if (processes == 0) {
return removeProcessGroup(uid, initialPid);
} else {
return -1;
}
}
static int mkdirAndChown(const char *path, mode_t mode, uid_t uid, gid_t gid)
{
int ret;
ret = mkdir(path, 0750);
if (ret < 0 && errno != EEXIST) {
return -errno;
}
ret = chown(path, AID_SYSTEM, AID_SYSTEM);
if (ret < 0) {
ret = -errno;
rmdir(path);
return ret;
}
return 0;
}
int createProcessGroup(uid_t uid, int initialPid)
{
char path[PROCESSGROUP_MAX_PATH_LEN] = {0};
int ret;
convertUidToPath(path, sizeof(path), uid);
ret = mkdirAndChown(path, 0750, AID_SYSTEM, AID_SYSTEM);
if (ret < 0) {
SLOGE("failed to make and chown %s: %s", path, strerror(-ret));
return ret;
}
convertUidPidToPath(path, sizeof(path), uid, initialPid);
ret = mkdirAndChown(path, 0750, AID_SYSTEM, AID_SYSTEM);
if (ret < 0) {
SLOGE("failed to make and chown %s: %s", path, strerror(-ret));
return ret;
}
strlcat(path, PROCESSGROUP_CGROUP_PROCS_FILE, sizeof(path));
int fd = open(path, O_WRONLY);
if (fd < 0) {
ret = -errno;
SLOGE("failed to open %s: %s", path, strerror(errno));
return ret;
}
char pid[PROCESSGROUP_MAX_PID_LEN + 1] = {0};
int len = snprintf(pid, sizeof(pid), "%d", initialPid);
ret = write(fd, pid, len);
if (ret < 0) {
ret = -errno;
SLOGE("failed to write '%s' to %s: %s", pid, path, strerror(errno));
} else {
ret = 0;
}
close(fd);
return ret;
}

View File

@ -0,0 +1,35 @@
/*
* Copyright 2014 Google, Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _PROCESSGROUP_PRIV_H_
#define _PROCESSGROUP_PRIV_H_
#define PROCESSGROUP_CGROUP_PATH "/acct"
#define PROCESSGROUP_UID_PREFIX "uid_"
#define PROCESSGROUP_PID_PREFIX "pid_"
#define PROCESSGROUP_CGROUP_PROCS_FILE "/cgroup.procs"
#define PROCESSGROUP_MAX_UID_LEN 11
#define PROCESSGROUP_MAX_PID_LEN 11
#define PROCESSGROUP_MAX_PATH_LEN \
(sizeof(PROCESSGROUP_CGROUP_PATH) + \
sizeof(PROCESSGROUP_UID_PREFIX) + 1 + \
PROCESSGROUP_MAX_UID_LEN + \
sizeof(PROCESSGROUP_PID_PREFIX) + 1 + \
PROCESSGROUP_MAX_PID_LEN + \
sizeof(PROCESSGROUP_CGROUP_PROCS_FILE) + \
1)
#endif

View File

@ -88,15 +88,18 @@ LOCAL_CFLAGS := -Werror
include $(BUILD_EXECUTABLE)
ifneq ($(HOST_OS),windows)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := simg2simg.c
LOCAL_MODULE := simg2simg
LOCAL_SRC_FILES := append2simg.c
LOCAL_MODULE := append2simg
LOCAL_STATIC_LIBRARIES := \
libsparse_host \
libz
LOCAL_CFLAGS := -Werror
include $(BUILD_HOST_EXECUTABLE)
endif
include $(CLEAR_VARS)
LOCAL_MODULE := simg_dump.py

140
libsparse/append2simg.c Normal file
View File

@ -0,0 +1,140 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define _FILE_OFFSET_BITS 64
#define _LARGEFILE64_SOURCE 1
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sparse/sparse.h>
#include "sparse_file.h"
#include "backed_block.h"
#ifndef O_BINARY
#define O_BINARY 0
#endif
#if defined(__APPLE__) && defined(__MACH__)
#define lseek64 lseek
#endif
#if defined(__APPLE__) && defined(__MACH__)
#define lseek64 lseek
#define off64_t off_t
#endif
void usage()
{
fprintf(stderr, "Usage: append2simg <output> <input>\n");
}
int main(int argc, char *argv[])
{
int output;
int output_block;
char *output_path;
struct sparse_file *sparse_output;
int input;
char *input_path;
off64_t input_len;
int tmp_fd;
char *tmp_path;
int ret;
if (argc == 3) {
output_path = argv[1];
input_path = argv[2];
} else {
usage();
exit(-1);
}
ret = asprintf(&tmp_path, "%s.append2simg", output_path);
if (ret < 0) {
fprintf(stderr, "Couldn't allocate filename\n");
exit(-1);
}
output = open(output_path, O_RDWR | O_BINARY);
if (output < 0) {
fprintf(stderr, "Couldn't open output file (%s)\n", strerror(errno));
exit(-1);
}
sparse_output = sparse_file_import_auto(output, true);
if (!sparse_output) {
fprintf(stderr, "Couldn't import output file\n");
exit(-1);
}
input = open(input_path, O_RDONLY | O_BINARY);
if (input < 0) {
fprintf(stderr, "Couldn't open input file (%s)\n", strerror(errno));
exit(-1);
}
input_len = lseek64(input, 0, SEEK_END);
if (input_len < 0) {
fprintf(stderr, "Couldn't get input file length (%s)\n", strerror(errno));
exit(-1);
} else if (input_len % sparse_output->block_size) {
fprintf(stderr, "Input file is not a multiple of the output file's block size");
exit(-1);
}
lseek64(input, 0, SEEK_SET);
output_block = sparse_output->len / sparse_output->block_size;
if (sparse_file_add_fd(sparse_output, input, 0, input_len, output_block) < 0) {
fprintf(stderr, "Couldn't add input file\n");
exit(-1);
}
sparse_output->len += input_len;
tmp_fd = open(tmp_path, O_WRONLY | O_CREAT | O_BINARY, 0664);
if (tmp_fd < 0) {
fprintf(stderr, "Couldn't open temporary file (%s)\n", strerror(errno));
exit(-1);
}
lseek64(output, 0, SEEK_SET);
if (sparse_file_write(sparse_output, tmp_fd, false, true, false) < 0) {
fprintf(stderr, "Failed to write sparse file\n");
exit(-1);
}
sparse_file_destroy(sparse_output);
close(tmp_fd);
close(output);
close(input);
ret = rename(tmp_path, output_path);
if (ret < 0) {
fprintf(stderr, "Failed to rename temporary file (%s)\n", strerror(errno));
exit(-1);
}
free(tmp_path);
exit(0);
}

View File

@ -38,10 +38,13 @@ static int autosuspend_init(void)
goto out;
}
/* Remove autosleep so userspace can manager suspend/resume and keep stats */
#if 0
autosuspend_ops = autosuspend_autosleep_init();
if (autosuspend_ops) {
goto out;
}
#endif
autosuspend_ops = autosuspend_wakeup_count_init();
if (autosuspend_ops) {

View File

@ -25,6 +25,7 @@
#include <unistd.h>
#define LOG_TAG "libsuspend"
//#define LOG_NDEBUG 0
#include <cutils/log.h>
#include "autosuspend_ops.h"
@ -37,6 +38,7 @@ static int wakeup_count_fd;
static pthread_t suspend_thread;
static sem_t suspend_lockout;
static const char *sleep_state = "mem";
static void (*wakeup_func)(void) = NULL;
static void *suspend_thread_func(void *arg __attribute__((unused)))
{
@ -80,6 +82,11 @@ static void *suspend_thread_func(void *arg __attribute__((unused)))
if (ret < 0) {
strerror_r(errno, buf, sizeof(buf));
ALOGE("Error writing to %s: %s\n", SYS_POWER_STATE, buf);
} else {
void (*func)(void) = wakeup_func;
if (func != NULL) {
(*func)();
}
}
}
@ -131,6 +138,15 @@ static int autosuspend_wakeup_count_disable(void)
return ret;
}
void set_wakeup_callback(void (*func)(void))
{
if (wakeup_func != NULL) {
ALOGE("Duplicate wakeup callback applied, keeping original");
return;
}
wakeup_func = func;
}
struct autosuspend_ops autosuspend_wakeup_count_ops = {
.enable = autosuspend_wakeup_count_enable,
.disable = autosuspend_wakeup_count_disable,

View File

@ -43,6 +43,13 @@ int autosuspend_enable(void);
*/
int autosuspend_disable(void);
/*
* set_wakeup_callback
*
* Set a function to be called each time the device wakes up from suspend.
*/
void set_wakeup_callback(void (*func)(void));
__END_DECLS
#endif

View File

@ -29,6 +29,8 @@
#include <net/if.h>
#include <linux/if.h>
#include <linux/if_addr.h>
#include <linux/if_link.h>
#include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter_ipv4/ipt_ULOG.h>
/* From kernel's net/netfilter/xt_quota2.c */
@ -46,6 +48,8 @@ const int NetlinkEvent::NlActionLinkDown = 5;
const int NetlinkEvent::NlActionAddressUpdated = 6;
const int NetlinkEvent::NlActionAddressRemoved = 7;
const int NetlinkEvent::NlActionRdnss = 8;
const int NetlinkEvent::NlActionRouteUpdated = 9;
const int NetlinkEvent::NlActionRouteRemoved = 10;
NetlinkEvent::NetlinkEvent() {
mAction = NlActionUnknown;
@ -77,33 +81,110 @@ void NetlinkEvent::dump() {
}
}
/*
* Returns the message name for a message in the NETLINK_ROUTE family, or NULL
* if parsing that message is not supported.
*/
static const char *rtMessageName(int type) {
#define NL_EVENT_RTM_NAME(rtm) case rtm: return #rtm;
switch (type) {
NL_EVENT_RTM_NAME(RTM_NEWLINK);
NL_EVENT_RTM_NAME(RTM_DELLINK);
NL_EVENT_RTM_NAME(RTM_NEWADDR);
NL_EVENT_RTM_NAME(RTM_DELADDR);
NL_EVENT_RTM_NAME(RTM_NEWROUTE);
NL_EVENT_RTM_NAME(RTM_DELROUTE);
NL_EVENT_RTM_NAME(RTM_NEWNDUSEROPT);
NL_EVENT_RTM_NAME(QLOG_NL_EVENT);
default:
return NULL;
}
#undef NL_EVENT_RTM_NAME
}
/*
* Checks that a binary NETLINK_ROUTE message is long enough for a payload of
* size bytes.
*/
static bool checkRtNetlinkLength(const struct nlmsghdr *nh, size_t size) {
if (nh->nlmsg_len < NLMSG_LENGTH(size)) {
SLOGE("Got a short %s message\n", rtMessageName(nh->nlmsg_type));
return false;
}
return true;
}
/*
* Utility function to log errors.
*/
static bool maybeLogDuplicateAttribute(bool isDup,
const char *attributeName,
const char *messageName) {
if (isDup) {
SLOGE("Multiple %s attributes in %s, ignoring\n", attributeName, messageName);
return true;
}
return false;
}
/*
* Parse a RTM_NEWLINK message.
*/
bool NetlinkEvent::parseIfInfoMessage(const struct nlmsghdr *nh) {
struct ifinfomsg *ifi = (struct ifinfomsg *) NLMSG_DATA(nh);
if (!checkRtNetlinkLength(nh, sizeof(*ifi)))
return false;
if ((ifi->ifi_flags & IFF_LOOPBACK) != 0) {
return false;
}
int len = IFLA_PAYLOAD(nh);
struct rtattr *rta;
for (rta = IFLA_RTA(ifi); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
switch(rta->rta_type) {
case IFLA_IFNAME:
asprintf(&mParams[0], "INTERFACE=%s", (char *) RTA_DATA(rta));
mAction = (ifi->ifi_flags & IFF_LOWER_UP) ? NlActionLinkUp :
NlActionLinkDown;
mSubsystem = strdup("net");
return true;
}
}
return false;
}
/*
* Parse a RTM_NEWADDR or RTM_DELADDR message.
*/
bool NetlinkEvent::parseIfAddrMessage(int type, struct ifaddrmsg *ifaddr,
int rtasize) {
struct rtattr *rta;
bool NetlinkEvent::parseIfAddrMessage(const struct nlmsghdr *nh) {
struct ifaddrmsg *ifaddr = (struct ifaddrmsg *) NLMSG_DATA(nh);
struct ifa_cacheinfo *cacheinfo = NULL;
char addrstr[INET6_ADDRSTRLEN] = "";
char ifname[IFNAMSIZ];
if (!checkRtNetlinkLength(nh, sizeof(*ifaddr)))
return false;
// Sanity check.
int type = nh->nlmsg_type;
if (type != RTM_NEWADDR && type != RTM_DELADDR) {
SLOGE("parseIfAddrMessage on incorrect message type 0x%x\n", type);
return false;
}
// For log messages.
const char *msgtype = (type == RTM_NEWADDR) ? "RTM_NEWADDR" : "RTM_DELADDR";
const char *msgtype = rtMessageName(type);
for (rta = IFA_RTA(ifaddr); RTA_OK(rta, rtasize);
rta = RTA_NEXT(rta, rtasize)) {
struct rtattr *rta;
int len = IFA_PAYLOAD(nh);
for (rta = IFA_RTA(ifaddr); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
if (rta->rta_type == IFA_ADDRESS) {
// Only look at the first address, because we only support notifying
// one change at a time.
if (*addrstr != '\0') {
SLOGE("Multiple IFA_ADDRESSes in %s, ignoring\n", msgtype);
if (maybeLogDuplicateAttribute(*addrstr != '\0', "IFA_ADDRESS", msgtype))
continue;
}
// Convert the IP address to a string.
if (ifaddr->ifa_family == AF_INET) {
@ -128,28 +209,15 @@ bool NetlinkEvent::parseIfAddrMessage(int type, struct ifaddrmsg *ifaddr,
}
// Find the interface name.
char ifname[IFNAMSIZ + 1];
if (!if_indextoname(ifaddr->ifa_index, ifname)) {
SLOGE("Unknown ifindex %d in %s", ifaddr->ifa_index, msgtype);
return false;
}
// Fill in interface information.
mAction = (type == RTM_NEWADDR) ? NlActionAddressUpdated :
NlActionAddressRemoved;
mSubsystem = strdup("net");
asprintf(&mParams[0], "ADDRESS=%s/%d", addrstr,
ifaddr->ifa_prefixlen);
asprintf(&mParams[1], "INTERFACE=%s", ifname);
asprintf(&mParams[2], "FLAGS=%u", ifaddr->ifa_flags);
asprintf(&mParams[3], "SCOPE=%u", ifaddr->ifa_scope);
} else if (rta->rta_type == IFA_CACHEINFO) {
// Address lifetime information.
if (cacheinfo) {
// We only support one address.
SLOGE("Multiple IFA_CACHEINFOs in %s, ignoring\n", msgtype);
if (maybeLogDuplicateAttribute(cacheinfo, "IFA_CACHEINFO", msgtype))
continue;
}
if (RTA_PAYLOAD(rta) < sizeof(*cacheinfo)) {
SLOGE("Short IFA_CACHEINFO (%zu vs. %zu bytes) in %s",
@ -158,10 +226,6 @@ bool NetlinkEvent::parseIfAddrMessage(int type, struct ifaddrmsg *ifaddr,
}
cacheinfo = (struct ifa_cacheinfo *) RTA_DATA(rta);
asprintf(&mParams[4], "PREFERRED=%u", cacheinfo->ifa_prefered);
asprintf(&mParams[5], "VALID=%u", cacheinfo->ifa_valid);
asprintf(&mParams[6], "CSTAMP=%u", cacheinfo->cstamp);
asprintf(&mParams[7], "TSTAMP=%u", cacheinfo->tstamp);
}
}
@ -170,14 +234,145 @@ bool NetlinkEvent::parseIfAddrMessage(int type, struct ifaddrmsg *ifaddr,
return false;
}
// Fill in netlink event information.
mAction = (type == RTM_NEWADDR) ? NlActionAddressUpdated :
NlActionAddressRemoved;
mSubsystem = strdup("net");
asprintf(&mParams[0], "ADDRESS=%s/%d", addrstr,
ifaddr->ifa_prefixlen);
asprintf(&mParams[1], "INTERFACE=%s", ifname);
asprintf(&mParams[2], "FLAGS=%u", ifaddr->ifa_flags);
asprintf(&mParams[3], "SCOPE=%u", ifaddr->ifa_scope);
if (cacheinfo) {
asprintf(&mParams[4], "PREFERRED=%u", cacheinfo->ifa_prefered);
asprintf(&mParams[5], "VALID=%u", cacheinfo->ifa_valid);
asprintf(&mParams[6], "CSTAMP=%u", cacheinfo->cstamp);
asprintf(&mParams[7], "TSTAMP=%u", cacheinfo->tstamp);
}
return true;
}
/*
* Parse a QLOG_NL_EVENT message.
*/
bool NetlinkEvent::parseUlogPacketMessage(const struct nlmsghdr *nh) {
const char *devname;
ulog_packet_msg_t *pm = (ulog_packet_msg_t *) NLMSG_DATA(nh);
if (!checkRtNetlinkLength(nh, sizeof(*pm)))
return false;
devname = pm->indev_name[0] ? pm->indev_name : pm->outdev_name;
asprintf(&mParams[0], "ALERT_NAME=%s", pm->prefix);
asprintf(&mParams[1], "INTERFACE=%s", devname);
mSubsystem = strdup("qlog");
mAction = NlActionChange;
return true;
}
/*
* Parse a RTM_NEWROUTE or RTM_DELROUTE message.
*/
bool NetlinkEvent::parseRtMessage(const struct nlmsghdr *nh) {
uint8_t type = nh->nlmsg_type;
const char *msgname = rtMessageName(type);
// Sanity check.
if (type != RTM_NEWROUTE && type != RTM_DELROUTE) {
SLOGE("%s: incorrect message type %d (%s)\n", __func__, type, msgname);
return false;
}
struct rtmsg *rtm = (struct rtmsg *) NLMSG_DATA(nh);
if (!checkRtNetlinkLength(nh, sizeof(*rtm)))
return false;
if (// Ignore static routes we've set up ourselves.
(rtm->rtm_protocol != RTPROT_KERNEL &&
rtm->rtm_protocol != RTPROT_RA) ||
// We're only interested in global unicast routes.
(rtm->rtm_scope != RT_SCOPE_UNIVERSE) ||
(rtm->rtm_type != RTN_UNICAST) ||
// We don't support source routing.
(rtm->rtm_src_len != 0) ||
// Cloned routes aren't real routes.
(rtm->rtm_flags & RTM_F_CLONED)) {
return false;
}
int family = rtm->rtm_family;
int prefixLength = rtm->rtm_dst_len;
// Currently we only support: destination, (one) next hop, ifindex.
char dst[INET6_ADDRSTRLEN] = "";
char gw[INET6_ADDRSTRLEN] = "";
char dev[IFNAMSIZ] = "";
size_t len = RTM_PAYLOAD(nh);
struct rtattr *rta;
for (rta = RTM_RTA(rtm); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
switch (rta->rta_type) {
case RTA_DST:
if (maybeLogDuplicateAttribute(*dst, "RTA_DST", msgname))
continue;
if (!inet_ntop(family, RTA_DATA(rta), dst, sizeof(dst)))
return false;
continue;
case RTA_GATEWAY:
if (maybeLogDuplicateAttribute(*gw, "RTA_GATEWAY", msgname))
continue;
if (!inet_ntop(family, RTA_DATA(rta), gw, sizeof(gw)))
return false;
continue;
case RTA_OIF:
if (maybeLogDuplicateAttribute(*dev, "RTA_OIF", msgname))
continue;
if (!if_indextoname(* (int *) RTA_DATA(rta), dev))
return false;
default:
continue;
}
}
// If there's no RTA_DST attribute, then:
// - If the prefix length is zero, it's the default route.
// - If the prefix length is nonzero, there's something we don't understand.
// Ignore the event.
if (!*dst && !prefixLength) {
if (family == AF_INET) {
strncpy(dst, "0.0.0.0", sizeof(dst));
} else if (family == AF_INET6) {
strncpy(dst, "::", sizeof(dst));
}
}
// A useful route must have a destination and at least either a gateway or
// an interface.
if (!*dst || (!*gw && !*dev))
return false;
// Fill in netlink event information.
mAction = (type == RTM_NEWROUTE) ? NlActionRouteUpdated :
NlActionRouteRemoved;
mSubsystem = strdup("net");
asprintf(&mParams[0], "ROUTE=%s/%d", dst, prefixLength);
asprintf(&mParams[1], "GATEWAY=%s", (*gw) ? gw : "");
asprintf(&mParams[2], "INTERFACE=%s", (*dev) ? dev : "");
return true;
}
/*
* Parse a RTM_NEWNDUSEROPT message.
*/
bool NetlinkEvent::parseNdUserOptMessage(struct nduseroptmsg *msg, int len) {
bool NetlinkEvent::parseNdUserOptMessage(const struct nlmsghdr *nh) {
struct nduseroptmsg *msg = (struct nduseroptmsg *) NLMSG_DATA(nh);
if (!checkRtNetlinkLength(nh, sizeof(*msg)))
return false;
// Check the length is valid.
int len = NLMSG_PAYLOAD(nh, sizeof(*msg));
if (msg->nduseropt_opts_len > len) {
SLOGE("RTM_NEWNDUSEROPT invalid length %d > %d\n",
msg->nduseropt_opts_len, len);
@ -200,7 +395,7 @@ bool NetlinkEvent::parseNdUserOptMessage(struct nduseroptmsg *msg, int len) {
}
// Find the interface name.
char ifname[IFNAMSIZ + 1];
char ifname[IFNAMSIZ];
if (!if_indextoname(msg->nduseropt_ifindex, ifname)) {
SLOGE("RTM_NEWNDUSEROPT on unknown ifindex %d\n",
msg->nduseropt_ifindex);
@ -273,6 +468,14 @@ bool NetlinkEvent::parseNdUserOptMessage(struct nduseroptmsg *msg, int len) {
/*
* Parse a binary message from a NETLINK_ROUTE netlink socket.
*
* Note that this function can only parse one message, because the message's
* content has to be stored in the class's member variables (mAction,
* mSubsystem, etc.). Invalid or unrecognized messages are skipped, but if
* there are multiple valid messages in the buffer, only the first one will be
* returned.
*
* TODO: consider only ever looking at the first message.
*/
bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) {
const struct nlmsghdr *nh;
@ -281,93 +484,37 @@ bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) {
NLMSG_OK(nh, (unsigned) size) && (nh->nlmsg_type != NLMSG_DONE);
nh = NLMSG_NEXT(nh, size)) {
if (!rtMessageName(nh->nlmsg_type)) {
SLOGD("Unexpected netlink message type %d\n", nh->nlmsg_type);
continue;
}
if (nh->nlmsg_type == RTM_NEWLINK) {
int len = nh->nlmsg_len - sizeof(*nh);
struct ifinfomsg *ifi;
if (sizeof(*ifi) > (size_t) len) {
SLOGE("Got a short RTM_NEWLINK message\n");
continue;
}
ifi = (ifinfomsg *)NLMSG_DATA(nh);
if ((ifi->ifi_flags & IFF_LOOPBACK) != 0) {
continue;
}
struct rtattr *rta = (struct rtattr *)
((char *) ifi + NLMSG_ALIGN(sizeof(*ifi)));
len = NLMSG_PAYLOAD(nh, sizeof(*ifi));
while(RTA_OK(rta, len)) {
switch(rta->rta_type) {
case IFLA_IFNAME:
char buffer[16 + IFNAMSIZ];
snprintf(buffer, sizeof(buffer), "INTERFACE=%s",
(char *) RTA_DATA(rta));
mParams[0] = strdup(buffer);
mAction = (ifi->ifi_flags & IFF_LOWER_UP) ?
NlActionLinkUp : NlActionLinkDown;
mSubsystem = strdup("net");
break;
}
rta = RTA_NEXT(rta, len);
}
if (parseIfInfoMessage(nh))
return true;
} else if (nh->nlmsg_type == QLOG_NL_EVENT) {
char *devname;
ulog_packet_msg_t *pm;
size_t len = nh->nlmsg_len - sizeof(*nh);
if (sizeof(*pm) > len) {
SLOGE("Got a short QLOG message\n");
continue;
}
pm = (ulog_packet_msg_t *)NLMSG_DATA(nh);
devname = pm->indev_name[0] ? pm->indev_name : pm->outdev_name;
asprintf(&mParams[0], "ALERT_NAME=%s", pm->prefix);
asprintf(&mParams[1], "INTERFACE=%s", devname);
mSubsystem = strdup("qlog");
mAction = NlActionChange;
if (parseUlogPacketMessage(nh))
return true;
} else if (nh->nlmsg_type == RTM_NEWADDR ||
nh->nlmsg_type == RTM_DELADDR) {
int len = nh->nlmsg_len - sizeof(*nh);
struct ifaddrmsg *ifa;
if (parseIfAddrMessage(nh))
return true;
if (sizeof(*ifa) > (size_t) len) {
SLOGE("Got a short RTM_xxxADDR message\n");
continue;
}
ifa = (ifaddrmsg *)NLMSG_DATA(nh);
size_t rtasize = IFA_PAYLOAD(nh);
if (!parseIfAddrMessage(nh->nlmsg_type, ifa, rtasize)) {
continue;
}
} else if (nh->nlmsg_type == RTM_NEWROUTE ||
nh->nlmsg_type == RTM_DELROUTE) {
if (parseRtMessage(nh))
return true;
} else if (nh->nlmsg_type == RTM_NEWNDUSEROPT) {
int len = nh->nlmsg_len - sizeof(*nh);
struct nduseroptmsg *ndmsg = (struct nduseroptmsg *) NLMSG_DATA(nh);
if (parseNdUserOptMessage(nh))
return true;
if (sizeof(*ndmsg) > (size_t) len) {
SLOGE("Got a short RTM_NEWNDUSEROPT message\n");
continue;
}
size_t optsize = NLMSG_PAYLOAD(nh, sizeof(*ndmsg));
if (!parseNdUserOptMessage(ndmsg, optsize)) {
continue;
}
} else {
SLOGD("Unexpected netlink message. type=0x%x\n",
nh->nlmsg_type);
}
}
return true;
return false;
}
/* If the string between 'str' and 'end' begins with 'prefixlen' characters

View File

@ -57,10 +57,12 @@ bool NetlinkListener::onDataAvailable(SocketClient *cli)
}
NetlinkEvent *evt = new NetlinkEvent();
if (!evt->decode(mBuffer, count, mFormat)) {
SLOGE("Error decoding NetlinkEvent");
} else {
if (evt->decode(mBuffer, count, mFormat)) {
onEvent(evt);
} else if (mFormat != NETLINK_FORMAT_BINARY) {
// Don't complain if parseBinaryNetlinkMessage returns false. That can
// just mean that the buffer contained no messages we're interested in.
SLOGE("Error decoding NetlinkEvent");
}
delete evt;

View File

@ -454,6 +454,8 @@ char* usb_device_get_string(struct usb_device *device, int id)
int i, result;
int languageCount = 0;
if (id == 0) return NULL;
string[0] = 0;
memset(languages, 0, sizeof(languages));
@ -487,31 +489,19 @@ char* usb_device_get_string(struct usb_device *device, int id)
char* usb_device_get_manufacturer_name(struct usb_device *device)
{
struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
if (desc->iManufacturer)
return usb_device_get_string(device, desc->iManufacturer);
else
return NULL;
return usb_device_get_string(device, desc->iManufacturer);
}
char* usb_device_get_product_name(struct usb_device *device)
{
struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
if (desc->iProduct)
return usb_device_get_string(device, desc->iProduct);
else
return NULL;
return usb_device_get_string(device, desc->iProduct);
}
char* usb_device_get_serial(struct usb_device *device)
{
struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
if (desc->iSerialNumber)
return usb_device_get_string(device, desc->iSerialNumber);
else
return NULL;
return usb_device_get_string(device, desc->iSerialNumber);
}
int usb_device_is_writeable(struct usb_device *device)
@ -557,6 +547,21 @@ int usb_device_connect_kernel_driver(struct usb_device *device,
return ioctl(device->fd, USBDEVFS_IOCTL, &ctl);
}
int usb_device_set_configuration(struct usb_device *device, int configuration)
{
return ioctl(device->fd, USBDEVFS_SETCONFIGURATION, &configuration);
}
int usb_device_set_interface(struct usb_device *device, unsigned int interface,
unsigned int alt_setting)
{
struct usbdevfs_setinterface ctl;
ctl.interface = interface;
ctl.altsetting = alt_setting;
return ioctl(device->fd, USBDEVFS_SETINTERFACE, &ctl);
}
int usb_device_control_transfer(struct usb_device *device,
int requestType,
int request,

View File

@ -26,6 +26,7 @@ commonSources:= \
LinearAllocator.cpp \
LinearTransform.cpp \
Log.cpp \
NativeHandle.cpp \
Printer.cpp \
ProcessCallStack.cpp \
PropertyMap.cpp \

View File

@ -31,7 +31,7 @@ namespace android {
static const uint32_t blobCacheMagic = ('_' << 24) + ('B' << 16) + ('b' << 8) + '$';
// BlobCache::Header::mBlobCacheVersion value
static const uint32_t blobCacheVersion = 1;
static const uint32_t blobCacheVersion = 2;
// BlobCache::Header::mDeviceVersion value
static const uint32_t blobCacheDeviceVersion = 1;
@ -165,14 +165,13 @@ static inline size_t align4(size_t size) {
}
size_t BlobCache::getFlattenedSize() const {
size_t size = sizeof(Header);
size_t size = align4(sizeof(Header));
for (size_t i = 0; i < mCacheEntries.size(); i++) {
const CacheEntry& e(mCacheEntries[i]);
sp<Blob> keyBlob = e.getKey();
sp<Blob> valueBlob = e.getValue();
size = align4(size);
size += sizeof(EntryHeader) + keyBlob->getSize() +
valueBlob->getSize();
size += align4(sizeof(EntryHeader) + keyBlob->getSize() +
valueBlob->getSize());
}
return size;
}
@ -200,7 +199,8 @@ status_t BlobCache::flatten(void* buffer, size_t size) const {
size_t valueSize = valueBlob->getSize();
size_t entrySize = sizeof(EntryHeader) + keySize + valueSize;
if (byteOffset + entrySize > size) {
size_t totalSize = align4(entrySize);
if (byteOffset + totalSize > size) {
ALOGE("flatten: not enough room for cache entries");
return BAD_VALUE;
}
@ -213,7 +213,13 @@ status_t BlobCache::flatten(void* buffer, size_t size) const {
memcpy(eheader->mData, keyBlob->getData(), keySize);
memcpy(eheader->mData + keySize, valueBlob->getData(), valueSize);
byteOffset += align4(entrySize);
if (totalSize > entrySize) {
// We have padding bytes. Those will get written to storage, and contribute to the CRC,
// so make sure we zero-them to have reproducible results.
memset(eheader->mData + keySize + valueSize, 0, totalSize - entrySize);
}
byteOffset += totalSize;
}
return OK;
@ -256,7 +262,8 @@ status_t BlobCache::unflatten(void const* buffer, size_t size) {
size_t valueSize = eheader->mValueSize;
size_t entrySize = sizeof(EntryHeader) + keySize + valueSize;
if (byteOffset + entrySize > size) {
size_t totalSize = align4(entrySize);
if (byteOffset + totalSize > size) {
mCacheEntries.clear();
ALOGE("unflatten: not enough room for cache entry headers");
return BAD_VALUE;
@ -265,7 +272,7 @@ status_t BlobCache::unflatten(void const* buffer, size_t size) {
const uint8_t* data = eheader->mData;
set(data, keySize, data + keySize, valueSize);
byteOffset += align4(entrySize);
byteOffset += totalSize;
}
return OK;

View File

@ -77,7 +77,6 @@ FileMap::~FileMap(void)
if (mFileMapping != INVALID_HANDLE_VALUE) {
CloseHandle(mFileMapping);
}
CloseHandle(mFileHandle);
#endif
}

38
libutils/NativeHandle.cpp Normal file
View File

@ -0,0 +1,38 @@
/*
* Copyright 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <utils/NativeHandle.h>
#include <cutils/native_handle.h>
namespace android {
sp<NativeHandle> NativeHandle::create(
native_handle_t* handle, bool ownsHandle) {
return handle ? new NativeHandle(handle, ownsHandle) : NULL;
}
NativeHandle::NativeHandle(native_handle_t* handle, bool ownsHandle)
: mHandle(handle), mOwnsHandle(ownsHandle)
{}
NativeHandle::~NativeHandle() {
if (mOwnsHandle) {
native_handle_close(mHandle);
native_handle_delete(mHandle);
}
}
} // namespace android

View File

@ -90,6 +90,11 @@ static String8 getThreadName(pid_t tid) {
ALOGE("%s: Failed to open %s", __FUNCTION__, path);
}
if (procName == NULL) {
// Reading /proc/self/task/%d/comm failed due to a race
return String8::format("[err-unknown-tid-%d]", tid);
}
// Strip ending newline
strtok(procName, "\n");

View File

@ -408,6 +408,30 @@ ssize_t String8::find(const char* other, size_t start) const
return p ? p-mString : -1;
}
bool String8::removeAll(const char* other) {
ssize_t index = find(other);
if (index < 0) return false;
char* buf = lockBuffer(size());
if (!buf) return false; // out of memory
size_t skip = strlen(other);
size_t len = size();
size_t tail = index;
while (size_t(index) < len) {
ssize_t next = find(other, index + skip);
if (next < 0) {
next = len;
}
memcpy(buf + tail, buf + index + skip, next - index - skip);
tail += next - index - skip;
index = next;
}
unlockBuffer(tail);
return true;
}
void String8::toLower()
{
toLower(0, size());

View File

@ -342,7 +342,8 @@ void utf16_to_utf8(const char16_t* src, size_t src_len, char* dst)
while (cur_utf16 < end_utf16) {
char32_t utf32;
// surrogate pairs
if ((*cur_utf16 & 0xFC00) == 0xD800) {
if((*cur_utf16 & 0xFC00) == 0xD800 && (cur_utf16 + 1) < end_utf16
&& (*(cur_utf16 + 1) & 0xFC00) == 0xDC00) {
utf32 = (*cur_utf16++ - 0xD800) << 10;
utf32 |= *cur_utf16++ - 0xDC00;
utf32 += 0x10000;

View File

@ -23,7 +23,7 @@
namespace android {
class BitSetTest : public testing::Test {
class BitSet32Test : public testing::Test {
protected:
BitSet32 b1;
BitSet32 b2;
@ -34,7 +34,7 @@ protected:
};
TEST_F(BitSetTest, BitWiseOr) {
TEST_F(BitSet32Test, BitWiseOr) {
b1.markBit(2);
b2.markBit(4);
@ -49,7 +49,7 @@ TEST_F(BitSetTest, BitWiseOr) {
EXPECT_TRUE(b1.hasBit(2) && b1.hasBit(4));
EXPECT_TRUE(b2.hasBit(4) && b2.count() == 1u);
}
TEST_F(BitSetTest, BitWiseAnd_Disjoint) {
TEST_F(BitSet32Test, BitWiseAnd_Disjoint) {
b1.markBit(2);
b1.markBit(4);
b1.markBit(6);
@ -65,7 +65,7 @@ TEST_F(BitSetTest, BitWiseAnd_Disjoint) {
EXPECT_TRUE(b1.hasBit(2) && b1.hasBit(4) && b1.hasBit(6));
}
TEST_F(BitSetTest, BitWiseAnd_NonDisjoint) {
TEST_F(BitSet32Test, BitWiseAnd_NonDisjoint) {
b1.markBit(2);
b1.markBit(4);
b1.markBit(6);
@ -84,4 +84,187 @@ TEST_F(BitSetTest, BitWiseAnd_NonDisjoint) {
EXPECT_EQ(b2.count(), 3u);
EXPECT_TRUE(b2.hasBit(3) && b2.hasBit(6) && b2.hasBit(9));
}
TEST_F(BitSet32Test, MarkFirstUnmarkedBit) {
b1.markBit(1);
b1.markFirstUnmarkedBit();
EXPECT_EQ(b1.count(), 2u);
EXPECT_TRUE(b1.hasBit(0) && b1.hasBit(1));
b1.markFirstUnmarkedBit();
EXPECT_EQ(b1.count(), 3u);
EXPECT_TRUE(b1.hasBit(0) && b1.hasBit(1) && b1.hasBit(2));
}
TEST_F(BitSet32Test, ClearFirstMarkedBit) {
b1.markBit(0);
b1.markBit(10);
b1.clearFirstMarkedBit();
EXPECT_EQ(b1.count(), 1u);
EXPECT_TRUE(b1.hasBit(10));
b1.markBit(30);
b1.clearFirstMarkedBit();
EXPECT_EQ(b1.count(), 1u);
EXPECT_TRUE(b1.hasBit(30));
}
TEST_F(BitSet32Test, ClearLastMarkedBit) {
b1.markBit(10);
b1.markBit(31);
b1.clearLastMarkedBit();
EXPECT_EQ(b1.count(), 1u);
EXPECT_TRUE(b1.hasBit(10));
b1.markBit(5);
b1.clearLastMarkedBit();
EXPECT_EQ(b1.count(), 1u);
EXPECT_TRUE(b1.hasBit(5));
}
TEST_F(BitSet32Test, FillAndClear) {
EXPECT_TRUE(b1.isEmpty());
for (size_t i = 0; i < 32; i++) {
b1.markFirstUnmarkedBit();
}
EXPECT_TRUE(b1.isFull());
b1.clear();
EXPECT_TRUE(b1.isEmpty());
}
TEST_F(BitSet32Test, GetIndexOfBit) {
b1.markBit(1);
b1.markBit(4);
EXPECT_EQ(b1.getIndexOfBit(1), 0);
EXPECT_EQ(b1.getIndexOfBit(4), 1);
b1.markFirstUnmarkedBit();
EXPECT_EQ(b1.getIndexOfBit(1), 1);
EXPECT_EQ(b1.getIndexOfBit(4), 2);
}
class BitSet64Test : public testing::Test {
protected:
BitSet64 b1;
BitSet64 b2;
virtual void TearDown() {
b1.clear();
b2.clear();
}
};
TEST_F(BitSet64Test, BitWiseOr) {
b1.markBit(20);
b2.markBit(40);
BitSet64 tmp = b1 | b2;
EXPECT_EQ(tmp.count(), 2u);
EXPECT_TRUE(tmp.hasBit(20) && tmp.hasBit(40));
// Check that the operator is symmetric
EXPECT_TRUE((b2 | b1) == (b1 | b2));
b1 |= b2;
EXPECT_EQ(b1.count(), 2u);
EXPECT_TRUE(b1.hasBit(20) && b1.hasBit(40));
EXPECT_TRUE(b2.hasBit(40) && b2.count() == 1u);
}
TEST_F(BitSet64Test, BitWiseAnd_Disjoint) {
b1.markBit(20);
b1.markBit(40);
b1.markBit(60);
BitSet64 tmp = b1 & b2;
EXPECT_TRUE(tmp.isEmpty());
// Check that the operator is symmetric
EXPECT_TRUE((b2 & b1) == (b1 & b2));
b2 &= b1;
EXPECT_TRUE(b2.isEmpty());
EXPECT_EQ(b1.count(), 3u);
EXPECT_TRUE(b1.hasBit(20) && b1.hasBit(40) && b1.hasBit(60));
}
TEST_F(BitSet64Test, BitWiseAnd_NonDisjoint) {
b1.markBit(20);
b1.markBit(40);
b1.markBit(60);
b2.markBit(30);
b2.markBit(60);
b2.markBit(63);
BitSet64 tmp = b1 & b2;
EXPECT_EQ(tmp.count(), 1u);
EXPECT_TRUE(tmp.hasBit(60));
// Check that the operator is symmetric
EXPECT_TRUE((b2 & b1) == (b1 & b2));
b1 &= b2;
EXPECT_EQ(b1.count(), 1u);
EXPECT_EQ(b2.count(), 3u);
EXPECT_TRUE(b2.hasBit(30) && b2.hasBit(60) && b2.hasBit(63));
}
TEST_F(BitSet64Test, MarkFirstUnmarkedBit) {
b1.markBit(1);
b1.markFirstUnmarkedBit();
EXPECT_EQ(b1.count(), 2u);
EXPECT_TRUE(b1.hasBit(0) && b1.hasBit(1));
b1.markFirstUnmarkedBit();
EXPECT_EQ(b1.count(), 3u);
EXPECT_TRUE(b1.hasBit(0) && b1.hasBit(1) && b1.hasBit(2));
}
TEST_F(BitSet64Test, ClearFirstMarkedBit) {
b1.markBit(0);
b1.markBit(10);
b1.clearFirstMarkedBit();
EXPECT_EQ(b1.count(), 1u);
EXPECT_TRUE(b1.hasBit(10));
b1.markBit(50);
b1.clearFirstMarkedBit();
EXPECT_EQ(b1.count(), 1u);
EXPECT_TRUE(b1.hasBit(50));
}
TEST_F(BitSet64Test, ClearLastMarkedBit) {
b1.markBit(10);
b1.markBit(63);
b1.clearLastMarkedBit();
EXPECT_EQ(b1.count(), 1u);
EXPECT_TRUE(b1.hasBit(10));
b1.markBit(5);
b1.clearLastMarkedBit();
EXPECT_EQ(b1.count(), 1u);
EXPECT_TRUE(b1.hasBit(5));
}
TEST_F(BitSet64Test, FillAndClear) {
EXPECT_TRUE(b1.isEmpty());
for (size_t i = 0; i < 64; i++) {
b1.markFirstUnmarkedBit();
}
EXPECT_TRUE(b1.isFull());
b1.clear();
EXPECT_TRUE(b1.isEmpty());
}
TEST_F(BitSet64Test, GetIndexOfBit) {
b1.markBit(10);
b1.markBit(40);
EXPECT_EQ(b1.getIndexOfBit(10), 0);
EXPECT_EQ(b1.getIndexOfBit(40), 1);
b1.markFirstUnmarkedBit();
EXPECT_EQ(b1.getIndexOfBit(10), 1);
EXPECT_EQ(b1.getIndexOfBit(40), 2);
}
} // namespace android

View File

@ -42,6 +42,9 @@ LOCAL_C_INCLUDES += ${includes}
LOCAL_STATIC_LIBRARIES := libz libutils
LOCAL_MODULE:= libziparchive-host
LOCAL_CFLAGS := -Werror
ifneq ($(strip $(USE_MINGW)),)
LOCAL_CFLAGS += -mno-ms-bitfields
endif
LOCAL_MULTILIB := both
include $(BUILD_HOST_STATIC_LIBRARY)

10
lmkd/Android.mk Normal file
View File

@ -0,0 +1,10 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := lmkd.c
LOCAL_SHARED_LIBRARIES := liblog libm libc libprocessgroup
LOCAL_CFLAGS := -Werror
LOCAL_MODULE := lmkd
include $(BUILD_EXECUTABLE)

833
lmkd/lmkd.c Normal file
View File

@ -0,0 +1,833 @@
/*
* 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 "lowmemorykiller"
#include <arpa/inet.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/cdefs.h>
#include <sys/epoll.h>
#include <sys/eventfd.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <cutils/sockets.h>
#include <log/log.h>
#include <processgroup/processgroup.h>
#ifndef __unused
#define __unused __attribute__((__unused__))
#endif
#define MEMCG_SYSFS_PATH "/dev/memcg/"
#define MEMPRESSURE_WATCH_LEVEL "medium"
#define ZONEINFO_PATH "/proc/zoneinfo"
#define LINE_MAX 128
#define INKERNEL_MINFREE_PATH "/sys/module/lowmemorykiller/parameters/minfree"
#define INKERNEL_ADJ_PATH "/sys/module/lowmemorykiller/parameters/adj"
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
enum lmk_cmd {
LMK_TARGET,
LMK_PROCPRIO,
LMK_PROCREMOVE,
};
#define MAX_TARGETS 6
/*
* longest is LMK_TARGET followed by MAX_TARGETS each minfree and minkillprio
* values
*/
#define CTRL_PACKET_MAX (sizeof(int) * (MAX_TARGETS * 2 + 1))
/* default to old in-kernel interface if no memory pressure events */
static int use_inkernel_interface = 1;
/* memory pressure level medium event */
static int mpevfd;
/* control socket listen and data */
static int ctrl_lfd;
static int ctrl_dfd = -1;
static int ctrl_dfd_reopened; /* did we reopen ctrl conn on this loop? */
/* 1 memory pressure level, 1 ctrl listen socket, 1 ctrl data socket */
#define MAX_EPOLL_EVENTS 3
static int epollfd;
static int maxevents;
#define OOM_DISABLE (-17)
/* inclusive */
#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;
struct sysmeminfo {
int nr_free_pages;
int nr_file_pages;
int nr_shmem;
int totalreserve_pages;
};
struct adjslot_list {
struct adjslot_list *next;
struct adjslot_list *prev;
};
struct proc {
struct adjslot_list asl;
int pid;
uid_t uid;
int oomadj;
struct proc *pidhash_next;
};
#define PIDHASH_SZ 1024
static struct proc *pidhash[PIDHASH_SZ];
#define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
#define ADJTOSLOT(adj) (adj + -OOM_ADJUST_MIN)
static struct adjslot_list procadjslot_list[ADJTOSLOT(OOM_ADJUST_MAX) + 1];
/*
* Wait 1-2 seconds for the death report of a killed process prior to
* considering killing more processes.
*/
#define KILL_TIMEOUT 2
/* Time of last process kill we initiated, stop me before I kill again */
static time_t kill_lasttime;
/* PAGE_SIZE / 1024 */
static long page_k;
static ssize_t read_all(int fd, char *buf, size_t max_len)
{
ssize_t ret = 0;
while (max_len > 0) {
ssize_t r = read(fd, buf, max_len);
if (r == 0) {
break;
}
if (r == -1) {
return -1;
}
ret += r;
buf += r;
max_len -= r;
}
return ret;
}
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;
for (procp = pidhash[pid_hashfn(pid)]; procp && procp->pid != pid;
procp = procp->pidhash_next)
;
return procp;
}
static void adjslot_insert(struct adjslot_list *head, struct adjslot_list *new)
{
struct adjslot_list *next = head->next;
new->prev = head;
new->next = next;
next->prev = new;
head->next = new;
}
static void adjslot_remove(struct adjslot_list *old)
{
struct adjslot_list *prev = old->prev;
struct adjslot_list *next = old->next;
next->prev = prev;
prev->next = next;
}
static struct adjslot_list *adjslot_tail(struct adjslot_list *head) {
struct adjslot_list *asl = head->prev;
return asl == head ? NULL : asl;
}
static void proc_slot(struct proc *procp) {
int adjslot = ADJTOSLOT(procp->oomadj);
adjslot_insert(&procadjslot_list[adjslot], &procp->asl);
}
static void proc_unslot(struct proc *procp) {
adjslot_remove(&procp->asl);
}
static void proc_insert(struct proc *procp) {
int hval = pid_hashfn(procp->pid);
procp->pidhash_next = pidhash[hval];
pidhash[hval] = procp;
proc_slot(procp);
}
static int pid_remove(int pid) {
int hval = pid_hashfn(pid);
struct proc *procp;
struct proc *prevp;
for (procp = pidhash[hval], prevp = NULL; procp && procp->pid != pid;
procp = procp->pidhash_next)
prevp = procp;
if (!procp)
return -1;
if (!prevp)
pidhash[hval] = procp->pidhash_next;
else
prevp->pidhash_next = procp->pidhash_next;
proc_unslot(procp);
free(procp);
return 0;
}
static void writefilestring(char *path, char *s) {
int fd = open(path, O_WRONLY);
int len = strlen(s);
int ret;
if (fd < 0) {
ALOGE("Error opening %s; errno=%d", path, errno);
return;
}
ret = write(fd, s, len);
if (ret < 0) {
ALOGE("Error writing %s; errno=%d", path, errno);
} else if (ret < len) {
ALOGE("Short write on %s; length=%d", path, ret);
}
close(fd);
}
static void cmd_procprio(int pid, int uid, int oomadj) {
struct proc *procp;
char path[80];
char val[20];
if (oomadj < OOM_DISABLE || oomadj > OOM_ADJUST_MAX) {
ALOGE("Invalid PROCPRIO oomadj argument %d", oomadj);
return;
}
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)
return;
procp = pid_lookup(pid);
if (!procp) {
procp = malloc(sizeof(struct proc));
if (!procp) {
// Oh, the irony. May need to rebuild our state.
return;
}
procp->pid = pid;
procp->uid = uid;
procp->oomadj = oomadj;
proc_insert(procp);
} else {
proc_unslot(procp);
procp->oomadj = oomadj;
proc_slot(procp);
}
}
static void cmd_procremove(int pid) {
if (use_inkernel_interface)
return;
pid_remove(pid);
kill_lasttime = 0;
}
static void cmd_target(int ntargets, int *params) {
int i;
if (ntargets > (int)ARRAY_SIZE(lowmem_adj))
return;
for (i = 0; i < ntargets; i++) {
lowmem_minfree[i] = ntohl(*params++);
lowmem_adj[i] = ntohl(*params++);
}
lowmem_targets_size = ntargets;
if (use_inkernel_interface) {
char minfreestr[128];
char killpriostr[128];
minfreestr[0] = '\0';
killpriostr[0] = '\0';
for (i = 0; i < lowmem_targets_size; i++) {
char val[40];
if (i) {
strlcat(minfreestr, ",", sizeof(minfreestr));
strlcat(killpriostr, ",", sizeof(killpriostr));
}
snprintf(val, sizeof(val), "%d", lowmem_minfree[i]);
strlcat(minfreestr, val, sizeof(minfreestr));
snprintf(val, sizeof(val), "%d", lowmem_adj[i]);
strlcat(killpriostr, val, sizeof(killpriostr));
}
writefilestring(INKERNEL_MINFREE_PATH, minfreestr);
writefilestring(INKERNEL_ADJ_PATH, killpriostr);
}
}
static void ctrl_data_close(void) {
ALOGI("Closing Activity Manager data connection");
close(ctrl_dfd);
ctrl_dfd = -1;
maxevents--;
}
static int ctrl_data_read(char *buf, size_t bufsz) {
int ret = 0;
ret = read(ctrl_dfd, buf, bufsz);
if (ret == -1) {
ALOGE("control data socket read failed; errno=%d", errno);
} else if (ret == 0) {
ALOGE("Got EOF on control data socket");
ret = -1;
}
return ret;
}
static void ctrl_command_handler(void) {
int ibuf[CTRL_PACKET_MAX / sizeof(int)];
int len;
int cmd = -1;
int nargs;
int targets;
len = ctrl_data_read((char *)ibuf, CTRL_PACKET_MAX);
if (len <= 0)
return;
nargs = len / sizeof(int) - 1;
if (nargs < 0)
goto wronglen;
cmd = ntohl(ibuf[0]);
switch(cmd) {
case LMK_TARGET:
targets = nargs / 2;
if (nargs & 0x1 || targets > (int)ARRAY_SIZE(lowmem_adj))
goto wronglen;
cmd_target(targets, &ibuf[1]);
break;
case LMK_PROCPRIO:
if (nargs != 3)
goto wronglen;
cmd_procprio(ntohl(ibuf[1]), ntohl(ibuf[2]), ntohl(ibuf[3]));
break;
case LMK_PROCREMOVE:
if (nargs != 1)
goto wronglen;
cmd_procremove(ntohl(ibuf[1]));
break;
default:
ALOGE("Received unknown command code %d", cmd);
return;
}
return;
wronglen:
ALOGE("Wrong control socket read length cmd=%d len=%d", cmd, len);
}
static void ctrl_data_handler(uint32_t events) {
if (events & EPOLLHUP) {
ALOGI("ActivityManager disconnected");
if (!ctrl_dfd_reopened)
ctrl_data_close();
} else if (events & EPOLLIN) {
ctrl_command_handler();
}
}
static void ctrl_connect_handler(uint32_t events __unused) {
struct sockaddr addr;
socklen_t alen;
struct epoll_event epev;
if (ctrl_dfd >= 0) {
ctrl_data_close();
ctrl_dfd_reopened = 1;
}
alen = sizeof(addr);
ctrl_dfd = accept(ctrl_lfd, &addr, &alen);
if (ctrl_dfd < 0) {
ALOGE("lmkd control socket accept failed; errno=%d", errno);
return;
}
ALOGI("ActivityManager connected");
maxevents++;
epev.events = EPOLLIN;
epev.data.ptr = (void *)ctrl_data_handler;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, ctrl_dfd, &epev) == -1) {
ALOGE("epoll_ctl for data connection socket failed; errno=%d", errno);
ctrl_data_close();
return;
}
}
static int zoneinfo_parse_protection(char *cp) {
int max = 0;
int zoneval;
char *save_ptr;
for (cp = strtok_r(cp, "(), ", &save_ptr); cp; cp = strtok_r(NULL, "), ", &save_ptr)) {
zoneval = strtol(cp, &cp, 0);
if (zoneval > max)
max = zoneval;
}
return max;
}
static void zoneinfo_parse_line(char *line, struct sysmeminfo *mip) {
char *cp = line;
char *ap;
char *save_ptr;
cp = strtok_r(line, " ", &save_ptr);
if (!cp)
return;
ap = strtok_r(NULL, " ", &save_ptr);
if (!ap)
return;
if (!strcmp(cp, "nr_free_pages"))
mip->nr_free_pages += strtol(ap, NULL, 0);
else if (!strcmp(cp, "nr_file_pages"))
mip->nr_file_pages += strtol(ap, NULL, 0);
else if (!strcmp(cp, "nr_shmem"))
mip->nr_shmem += strtol(ap, NULL, 0);
else if (!strcmp(cp, "high"))
mip->totalreserve_pages += strtol(ap, NULL, 0);
else if (!strcmp(cp, "protection:"))
mip->totalreserve_pages += zoneinfo_parse_protection(ap);
}
static int zoneinfo_parse(struct sysmeminfo *mip) {
int fd;
ssize_t size;
char buf[PAGE_SIZE];
char *save_ptr;
char *line;
memset(mip, 0, sizeof(struct sysmeminfo));
fd = open(ZONEINFO_PATH, O_RDONLY);
if (fd == -1) {
ALOGE("%s open: errno=%d", ZONEINFO_PATH, errno);
return -1;
}
size = read_all(fd, buf, sizeof(buf) - 1);
if (size < 0) {
ALOGE("%s read: errno=%d", ZONEINFO_PATH, errno);
close(fd);
return -1;
}
ALOG_ASSERT((size_t)size < sizeof(buf) - 1, "/proc/zoneinfo too large");
buf[size] = 0;
for (line = strtok_r(buf, "\n", &save_ptr); line; line = strtok_r(NULL, "\n", &save_ptr))
zoneinfo_parse_line(line, mip);
close(fd);
return 0;
}
static int proc_get_size(int pid) {
char path[PATH_MAX];
char line[LINE_MAX];
int fd;
int rss = 0;
int total;
ssize_t ret;
snprintf(path, PATH_MAX, "/proc/%d/statm", pid);
fd = open(path, O_RDONLY);
if (fd == -1)
return -1;
ret = read_all(fd, line, sizeof(line) - 1);
if (ret < 0) {
close(fd);
return -1;
}
sscanf(line, "%d %d ", &total, &rss);
close(fd);
return rss;
}
static char *proc_get_name(int pid) {
char path[PATH_MAX];
static char line[LINE_MAX];
int fd;
char *cp;
ssize_t ret;
snprintf(path, PATH_MAX, "/proc/%d/cmdline", pid);
fd = open(path, O_RDONLY);
if (fd == -1)
return NULL;
ret = read_all(fd, line, sizeof(line) - 1);
close(fd);
if (ret < 0) {
return NULL;
}
cp = strchr(line, ' ');
if (cp)
*cp = '\0';
return line;
}
static struct proc *proc_adj_lru(int oomadj) {
return (struct proc *)adjslot_tail(&procadjslot_list[ADJTOSLOT(oomadj)]);
}
/* Kill one process specified by procp. Returns the size of the process killed */
static int kill_one_process(struct proc *procp, int other_free, int other_file,
int minfree, int min_score_adj, bool first)
{
int pid = procp->pid;
uid_t uid = procp->uid;
char *taskname;
int tasksize;
int r;
taskname = proc_get_name(pid);
if (!taskname) {
pid_remove(pid);
return -1;
}
tasksize = proc_get_size(pid);
if (tasksize <= 0) {
pid_remove(pid);
return -1;
}
ALOGI("Killing '%s' (%d), uid %d, adj %d\n"
" to free %ldkB because cache %s%ldkB is below limit %ldkB for oom_adj %d\n"
" Free memory is %s%ldkB %s reserved",
taskname, pid, uid, procp->oomadj, tasksize * page_k,
first ? "" : "~", other_file * page_k, minfree * page_k, min_score_adj,
first ? "" : "~", other_free * page_k, other_free >= 0 ? "above" : "below");
r = kill(pid, SIGKILL);
killProcessGroup(uid, pid, SIGKILL);
pid_remove(pid);
if (r) {
ALOGE("kill(%d): errno=%d", procp->pid, errno);
return -1;
} else {
return tasksize;
}
}
/*
* Find a process to kill based on the current (possibly estimated) free memory
* and cached memory sizes. Returns the size of the killed processes.
*/
static int find_and_kill_process(int other_free, int other_file, bool first)
{
int i;
int r;
int min_score_adj = OOM_ADJUST_MAX + 1;
int minfree = 0;
int killed_size = 0;
for (i = 0; i < lowmem_targets_size; i++) {
minfree = lowmem_minfree[i];
if (other_free < minfree && other_file < minfree) {
min_score_adj = lowmem_adj[i];
break;
}
}
if (min_score_adj == OOM_ADJUST_MAX + 1)
return 0;
for (i = OOM_ADJUST_MAX; i >= min_score_adj; i--) {
struct proc *procp;
retry:
procp = proc_adj_lru(i);
if (procp) {
killed_size = kill_one_process(procp, other_free, other_file, minfree, min_score_adj, first);
if (killed_size < 0) {
goto retry;
} else {
return killed_size;
}
}
}
return 0;
}
static void mp_event(uint32_t events __unused) {
int i;
int ret;
unsigned long long evcount;
struct sysmeminfo mi;
int other_free;
int other_file;
int killed_size;
bool first = true;
ret = read(mpevfd, &evcount, sizeof(evcount));
if (ret < 0)
ALOGE("Error reading memory pressure event fd; errno=%d",
errno);
if (time(NULL) - kill_lasttime < KILL_TIMEOUT)
return;
while (zoneinfo_parse(&mi) < 0) {
// Failed to read /proc/zoneinfo, assume ENOMEM and kill something
find_and_kill_process(0, 0, true);
}
other_free = mi.nr_free_pages - mi.totalreserve_pages;
other_file = mi.nr_file_pages - mi.nr_shmem;
do {
killed_size = find_and_kill_process(other_free, other_file, first);
if (killed_size > 0) {
first = false;
other_free += killed_size;
other_file += killed_size;
}
} while (killed_size > 0);
}
static int init_mp(char *levelstr, void *event_handler)
{
int mpfd;
int evfd;
int evctlfd;
char buf[256];
struct epoll_event epev;
int ret;
mpfd = open(MEMCG_SYSFS_PATH "memory.pressure_level", O_RDONLY);
if (mpfd < 0) {
ALOGI("No kernel memory.pressure_level support (errno=%d)", errno);
goto err_open_mpfd;
}
evctlfd = open(MEMCG_SYSFS_PATH "cgroup.event_control", O_WRONLY);
if (evctlfd < 0) {
ALOGI("No kernel memory cgroup event control (errno=%d)", errno);
goto err_open_evctlfd;
}
evfd = eventfd(0, EFD_NONBLOCK);
if (evfd < 0) {
ALOGE("eventfd failed for level %s; errno=%d", levelstr, errno);
goto err_eventfd;
}
ret = snprintf(buf, sizeof(buf), "%d %d %s", evfd, mpfd, levelstr);
if (ret >= (ssize_t)sizeof(buf)) {
ALOGE("cgroup.event_control line overflow for level %s", levelstr);
goto err;
}
ret = write(evctlfd, buf, strlen(buf) + 1);
if (ret == -1) {
ALOGE("cgroup.event_control write failed for level %s; errno=%d",
levelstr, errno);
goto err;
}
epev.events = EPOLLIN;
epev.data.ptr = event_handler;
ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, evfd, &epev);
if (ret == -1) {
ALOGE("epoll_ctl for level %s failed; errno=%d", levelstr, errno);
goto err;
}
maxevents++;
mpevfd = evfd;
return 0;
err:
close(evfd);
err_eventfd:
close(evctlfd);
err_open_evctlfd:
close(mpfd);
err_open_mpfd:
return -1;
}
static int init(void) {
struct epoll_event epev;
int i;
int ret;
page_k = sysconf(_SC_PAGESIZE);
if (page_k == -1)
page_k = PAGE_SIZE;
page_k /= 1024;
epollfd = epoll_create(MAX_EPOLL_EVENTS);
if (epollfd == -1) {
ALOGE("epoll_create failed (errno=%d)", errno);
return -1;
}
ctrl_lfd = android_get_control_socket("lmkd");
if (ctrl_lfd < 0) {
ALOGE("get lmkd control socket failed");
return -1;
}
ret = listen(ctrl_lfd, 1);
if (ret < 0) {
ALOGE("lmkd control socket listen failed (errno=%d)", errno);
return -1;
}
epev.events = EPOLLIN;
epev.data.ptr = (void *)ctrl_connect_handler;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, ctrl_lfd, &epev) == -1) {
ALOGE("epoll_ctl for lmkd control socket failed (errno=%d)", errno);
return -1;
}
maxevents++;
use_inkernel_interface = !access(INKERNEL_MINFREE_PATH, W_OK);
if (use_inkernel_interface) {
ALOGI("Using in-kernel low memory killer interface");
} else {
ret = init_mp(MEMPRESSURE_WATCH_LEVEL, (void *)&mp_event);
if (ret)
ALOGE("Kernel does not support memory pressure events or in-kernel low memory killer");
}
for (i = 0; i <= ADJTOSLOT(OOM_ADJUST_MAX); i++) {
procadjslot_list[i].next = &procadjslot_list[i];
procadjslot_list[i].prev = &procadjslot_list[i];
}
return 0;
}
static void mainloop(void) {
while (1) {
struct epoll_event events[maxevents];
int nevents;
int i;
ctrl_dfd_reopened = 0;
nevents = epoll_wait(epollfd, events, maxevents, -1);
if (nevents == -1) {
if (errno == EINTR)
continue;
ALOGE("epoll_wait failed (errno=%d)", errno);
continue;
}
for (i = 0; i < nevents; ++i) {
if (events[i].events & EPOLLERR)
ALOGD("EPOLLERR on event #%d", i);
if (events[i].data.ptr)
(*(void (*)(uint32_t))events[i].data.ptr)(events[i].events);
}
}
}
int main(int argc __unused, char **argv __unused) {
struct sched_param param = {
.sched_priority = 1,
};
mlockall(MCL_FUTURE);
sched_setscheduler(0, SCHED_FIFO, &param);
if (!init())
mainloop();
ALOGI("exiting");
return 0;
}

View File

@ -134,5 +134,7 @@
# libcore failure logging
90100 exp_det_cert_pin_failure (certs|4)
1397638484 snet_event_log (subtag|3) (uid|1) (message|3)
# NOTE - the range 1000000-2000000 is reserved for partners and others who
# want to define their own log tags without conflicting with the core platform.

View File

@ -102,7 +102,6 @@ struct
{ "dhcp", 1, do_dhcp },
{ "up", 1, ifc_up },
{ "down", 1, ifc_down },
{ "flhosts", 1, ifc_remove_host_routes },
{ "deldefault", 1, ifc_remove_default_route },
{ "hwaddr", 2, set_hwaddr },
{ 0, 0, 0 },

View File

@ -31,7 +31,7 @@ LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
include $(BUILD_SYSTEM)/base_rules.mk
# Regenerate init.environ.rc if PRODUCT_BOOTCLASSPATH has changed.
bcp_md5 := $(word 1, $(shell echo $(PRODUCT_BOOTCLASSPATH) | $(MD5SUM)))
bcp_md5 := $(word 1, $(shell echo $(PRODUCT_BOOTCLASSPATH) $(PRODUCT_SYSTEM_SERVER_CLASSPATH) | $(MD5SUM)))
bcp_dep := $(intermediates)/$(bcp_md5).bcp.dep
$(bcp_dep) :
$(hide) mkdir -p $(dir $@) && rm -rf $(dir $@)*.bcp.dep && touch $@
@ -40,6 +40,7 @@ $(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/init.environ.rc.in $(bcp_dep)
@echo "Generate: $< -> $@"
@mkdir -p $(dir $@)
$(hide) sed -e 's?%BOOTCLASSPATH%?$(PRODUCT_BOOTCLASSPATH)?g' $< >$@
$(hide) sed -i -e 's?%SYSTEMSERVERCLASSPATH%?$(PRODUCT_SYSTEM_SERVER_CLASSPATH)?g' $@
bcp_md5 :=
bcp_dep :=

View File

@ -9,3 +9,4 @@ on init
export ASEC_MOUNTPOINT /mnt/asec
export LOOP_MOUNTPOINT /mnt/obb
export BOOTCLASSPATH %BOOTCLASSPATH%
export SYSTEMSERVERCLASSPATH %SYSTEMSERVERCLASSPATH%

View File

@ -12,7 +12,7 @@ import /init.trace.rc
on early-init
# Set init and its forked children's oom_adj.
write /proc/1/oom_adj -16
write /proc/1/oom_score_adj -1000
# Apply strict SELinux checking of PROT_EXEC on mmap/mprotect calls.
write /sys/fs/selinux/checkreqprot 0
@ -88,6 +88,10 @@ on init
mkdir /mnt/obb 0700 root system
mount tmpfs tmpfs /mnt/obb mode=0755,gid=1000
# memory control cgroup
mkdir /dev/memcg 0700 root system
mount cgroup none /dev/memcg memory
write /proc/sys/kernel/panic_on_oops 1
write /proc/sys/kernel/hung_task_timeout_secs 0
write /proc/cpu/alignment 4
@ -267,6 +271,7 @@ on post-fs-data
mkdir /data/misc/wifi 0770 wifi wifi
mkdir /data/misc/wifi/sockets 0770 wifi wifi
mkdir /data/misc/wifi/wpa_supplicant 0770 wifi wifi
mkdir /data/misc/ethernet 0770 system system
mkdir /data/misc/dhcp 0770 dhcp dhcp
mkdir /data/misc/user 0771 root root
# give system access to wpa_supplicant.conf for backup and restore
@ -339,9 +344,9 @@ on boot
write /proc/sys/vm/overcommit_memory 1
write /proc/sys/vm/min_free_order_shift 4
chown root system /sys/module/lowmemorykiller/parameters/adj
chmod 0664 /sys/module/lowmemorykiller/parameters/adj
chmod 0220 /sys/module/lowmemorykiller/parameters/adj
chown root system /sys/module/lowmemorykiller/parameters/minfree
chmod 0664 /sys/module/lowmemorykiller/parameters/minfree
chmod 0220 /sys/module/lowmemorykiller/parameters/minfree
# Tweak background writeout
write /proc/sys/vm/dirty_expire_centisecs 200
@ -411,30 +416,22 @@ on boot
chown system system /sys/kernel/ipv4/tcp_rmem_max
chown root radio /proc/cmdline
# Define TCP buffer sizes for various networks
# ReadMin, ReadInitial, ReadMax, WriteMin, WriteInitial, WriteMax,
setprop net.tcp.buffersize.default 4096,87380,110208,4096,16384,110208
setprop net.tcp.buffersize.wifi 524288,1048576,2097152,262144,524288,1048576
setprop net.tcp.buffersize.ethernet 524288,1048576,3145728,524288,1048576,2097152
setprop net.tcp.buffersize.lte 524288,1048576,2097152,262144,524288,1048576
setprop net.tcp.buffersize.umts 58254,349525,1048576,58254,349525,1048576
setprop net.tcp.buffersize.hspa 40778,244668,734003,16777,100663,301990
setprop net.tcp.buffersize.hsupa 40778,244668,734003,16777,100663,301990
setprop net.tcp.buffersize.hsdpa 61167,367002,1101005,8738,52429,262114
setprop net.tcp.buffersize.hspap 122334,734003,2202010,32040,192239,576717
setprop net.tcp.buffersize.edge 4093,26280,70800,4096,16384,70800
setprop net.tcp.buffersize.gprs 4092,8760,48000,4096,8760,48000
setprop net.tcp.buffersize.evdo 4094,87380,262144,4096,16384,262144
# Define default initial receive window size in segments.
setprop net.tcp.default_init_rwnd 60
class_start core
class_start main
on nonencrypted
class_start main
class_start late_start
on property:vold.decrypt=trigger_default_encryption
start defaultcrypto
on property:vold.decrypt=trigger_encryption
start surfaceflinger
start encrypt
on property:sys.init_log_level=*
loglevel ${sys.init_log_level}
@ -494,11 +491,6 @@ service healthd /sbin/healthd
critical
seclabel u:r:healthd:s0
service healthd-charger /sbin/healthd -n
class charger
critical
seclabel u:r:healthd:s0
service console /system/bin/sh
class core
console
@ -521,6 +513,11 @@ service adbd /sbin/adbd --root_seclabel=u:r:su:s0
on property:ro.kernel.qemu=1
start adbd
service lmkd /system/bin/lmkd
class core
critical
socket lmkd seqpacket 0660 system system
service servicemanager /system/bin/servicemanager
class core
user system
@ -558,7 +555,7 @@ service ril-daemon /system/bin/rild
group radio cache inet misc audio log
service surfaceflinger /system/bin/surfaceflinger
class main
class core
user system
group graphics drmrpc
onrestart restart zygote
@ -574,10 +571,24 @@ service media /system/bin/mediaserver
group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm
ioprio rt 4
# One shot invocation to deal with encrypted volume.
service defaultcrypto /system/bin/vdc --wait cryptfs mountdefaultencrypted
disabled
oneshot
# vold will set vold.decrypt to trigger_restart_framework (default
# encryption) or trigger_restart_min_framework (other encryption)
# One shot invocation to encrypt unencrypted volumes
service encrypt /system/bin/vdc --wait cryptfs enablecrypto inplace default
disabled
oneshot
# vold will set vold.decrypt to trigger_restart_framework (default
# encryption)
service bootanim /system/bin/bootanimation
class main
class core
user graphics
group graphics
group graphics audio
disabled
oneshot
@ -585,8 +596,9 @@ service installd /system/bin/installd
class main
socket installd stream 600 system system
service flash_recovery /system/etc/install-recovery.sh
service flash_recovery /system/bin/install-recovery.sh
class main
seclabel u:r:install_recovery:s0
oneshot
service racoon /system/bin/racoon
@ -623,3 +635,8 @@ service mdnsd /system/bin/mdnsd
socket mdnsd stream 0660 mdnsr inet
disabled
oneshot
service pre-recovery /system/bin/uncrypt
class main
disabled
oneshot

View File

@ -1,6 +1,6 @@
## Permissions to allow system-wide tracing to the kernel trace buffer.
##
on boot
on early-boot
# Allow writing to the kernel trace log.
chmod 0222 /sys/kernel/debug/tracing/trace_marker

View File

@ -17,12 +17,12 @@ on property:sys.usb.config=none
setprop sys.usb.state ${sys.usb.config}
# adb only USB configuration
# This should only be used during device bringup
# and as a fallback if the USB manager fails to set a standard configuration
# This is the fallback configuration if the
# USB manager fails to set a standard configuration
on property:sys.usb.config=adb
write /sys/class/android_usb/android0/enable 0
write /sys/class/android_usb/android0/idVendor 18d1
write /sys/class/android_usb/android0/idProduct D002
write /sys/class/android_usb/android0/idProduct 4EE7
write /sys/class/android_usb/android0/functions ${sys.usb.config}
write /sys/class/android_usb/android0/enable 1
start adbd

View File

@ -144,6 +144,8 @@ typedef enum {
PERM_ANDROID_DATA,
/* This node is "/Android/obb" */
PERM_ANDROID_OBB,
/* This node is "/Android/media" */
PERM_ANDROID_MEDIA,
/* This node is "/Android/user" */
PERM_ANDROID_USER,
} perm_t;
@ -480,6 +482,10 @@ static void derive_permissions_locked(struct fuse* fuse, struct node *parent,
/* Single OBB directory is always shared */
node->graft_path = fuse->obbpath;
node->graft_pathlen = strlen(fuse->obbpath);
} else if (!strcasecmp(node->name, "media")) {
/* App-specific directories inside; let anyone traverse */
node->perm = PERM_ANDROID_MEDIA;
node->mode = 0771;
} else if (!strcasecmp(node->name, "user")) {
/* User directories must only be accessible to system, protected
* by sdcard_all. Zygote will bind mount the appropriate user-
@ -491,6 +497,7 @@ static void derive_permissions_locked(struct fuse* fuse, struct node *parent,
break;
case PERM_ANDROID_DATA:
case PERM_ANDROID_OBB:
case PERM_ANDROID_MEDIA:
appid = (appid_t) (uintptr_t) hashmapGet(fuse->package_to_appid, node->name);
if (appid != 0) {
node->uid = multiuser_get_uid(parent->userid, appid);

Some files were not shown because too many files have changed in this diff Show More