Merge "adb server: don't close stale fd when TCP transport is closed"
diff --git a/adb/Android.mk b/adb/Android.mk
index f030041..7977009 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -238,12 +238,11 @@
-D_GNU_SOURCE \
-Wno-deprecated-declarations \
-ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
-LOCAL_CFLAGS += -DALLOW_ADBD_ROOT=1
-endif
+LOCAL_CFLAGS += -DALLOW_ADBD_NO_AUTH=$(if $(filter userdebug eng,$(TARGET_BUILD_VARIANT)),1,0)
ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
LOCAL_CFLAGS += -DALLOW_ADBD_DISABLE_VERITY=1
+LOCAL_CFLAGS += -DALLOW_ADBD_ROOT=1
endif
LOCAL_MODULE := adbd
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 9af1586..2e59634 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -431,9 +431,9 @@
parse_banner(reinterpret_cast<const char*>(p->data), t);
- if (HOST || !auth_enabled) {
+ if (HOST || !auth_required) {
handle_online(t);
- if(!HOST) send_connect(t);
+ if (!HOST) send_connect(t);
} else {
send_auth_request(t);
}
@@ -835,6 +835,14 @@
return 0;
}
+#if ADB_HOST
+static int SendOkay(int fd, const std::string& s) {
+ SendOkay(fd);
+ SendProtocolString(fd, s);
+ return 0;
+}
+#endif
+
int handle_host_request(const char* service, TransportType type,
const char* serial, int reply_fd, asocket* s) {
if (strcmp(service, "kill") == 0) {
@@ -845,7 +853,6 @@
}
#if ADB_HOST
- atransport *transport = NULL;
// "transport:" is used for switching transport with a specified serial number
// "transport-usb:" is used for switching transport to the only USB transport
// "transport-local:" is used for switching transport to the only local transport
@@ -864,11 +871,10 @@
serial = service;
}
- std::string error_msg = "unknown failure";
- transport = acquire_one_transport(kCsAny, type, serial, &error_msg);
-
- if (transport) {
- s->transport = transport;
+ std::string error_msg;
+ atransport* t = acquire_one_transport(kCsAny, type, serial, &error_msg);
+ if (t != nullptr) {
+ s->transport = t;
SendOkay(reply_fd);
} else {
SendFail(reply_fd, error_msg);
@@ -883,9 +889,7 @@
D("Getting device list...\n");
std::string device_list = list_transports(long_listing);
D("Sending device list...\n");
- SendOkay(reply_fd);
- SendProtocolString(reply_fd, device_list);
- return 0;
+ return SendOkay(reply_fd, device_list);
}
return 1;
}
@@ -905,8 +909,7 @@
snprintf(hostbuf, sizeof(hostbuf) - 1, "%s:5555", serial);
serial = hostbuf;
}
- atransport *t = find_transport(serial);
-
+ atransport* t = find_transport(serial);
if (t) {
unregister_transport(t);
} else {
@@ -914,52 +917,38 @@
}
}
- SendOkay(reply_fd);
- SendProtocolString(reply_fd, buffer);
- return 0;
+ return SendOkay(reply_fd, buffer);
}
// returns our value for ADB_SERVER_VERSION
if (!strcmp(service, "version")) {
- SendOkay(reply_fd);
- SendProtocolString(reply_fd, android::base::StringPrintf("%04x", ADB_SERVER_VERSION));
- return 0;
+ return SendOkay(reply_fd, android::base::StringPrintf("%04x", ADB_SERVER_VERSION));
}
- if(!strncmp(service,"get-serialno",strlen("get-serialno"))) {
- const char *out = "unknown";
- transport = acquire_one_transport(kCsAny, type, serial, NULL);
- if (transport && transport->serial) {
- out = transport->serial;
- }
- SendOkay(reply_fd);
- SendProtocolString(reply_fd, out);
- return 0;
+ // These always report "unknown" rather than the actual error, for scripts.
+ if (!strcmp(service, "get-serialno")) {
+ std::string ignored;
+ atransport* t = acquire_one_transport(kCsAny, type, serial, &ignored);
+ return SendOkay(reply_fd, (t && t->serial) ? t->serial : "unknown");
}
- if(!strncmp(service,"get-devpath",strlen("get-devpath"))) {
- const char *out = "unknown";
- transport = acquire_one_transport(kCsAny, type, serial, NULL);
- if (transport && transport->devpath) {
- out = transport->devpath;
- }
- SendOkay(reply_fd);
- SendProtocolString(reply_fd, out);
- return 0;
+ if (!strcmp(service, "get-devpath")) {
+ std::string ignored;
+ atransport* t = acquire_one_transport(kCsAny, type, serial, &ignored);
+ return SendOkay(reply_fd, (t && t->devpath) ? t->devpath : "unknown");
}
+ if (!strcmp(service, "get-state")) {
+ std::string ignored;
+ atransport* t = acquire_one_transport(kCsAny, type, serial, &ignored);
+ return SendOkay(reply_fd, t ? t->connection_state_name() : "unknown");
+ }
+
// indicates a new emulator instance has started
- if (!strncmp(service,"emulator:",9)) {
+ if (!strncmp(service, "emulator:", 9)) {
int port = atoi(service+9);
local_connect(port);
/* we don't even need to send a reply */
return 0;
}
-
- if(!strncmp(service,"get-state",strlen("get-state"))) {
- transport = acquire_one_transport(kCsAny, type, serial, NULL);
- SendOkay(reply_fd);
- SendProtocolString(reply_fd, transport->connection_state_name());
- return 0;
- }
#endif // ADB_HOST
int ret = handle_forward_request(service, type, serial, reply_fd);
diff --git a/adb/adb_auth.cpp b/adb/adb_auth.cpp
index dc01825..cff26d6 100644
--- a/adb/adb_auth.cpp
+++ b/adb/adb_auth.cpp
@@ -28,7 +28,7 @@
#include "adb.h"
#include "transport.h"
-int auth_enabled = 0;
+bool auth_required = true;
void send_auth_request(atransport *t)
{
diff --git a/adb/adb_auth.h b/adb/adb_auth.h
index 1e1978d..a13604a 100644
--- a/adb/adb_auth.h
+++ b/adb/adb_auth.h
@@ -19,7 +19,7 @@
#include "adb.h"
-extern int auth_enabled;
+extern bool auth_required;
int adb_auth_keygen(const char* filename);
void adb_auth_verified(atransport *t);
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 7fbca31..4adac37 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -110,7 +110,6 @@
" ('-a' means copy timestamp and mode)\n"
" adb sync [ <directory> ] - copy host->device only if changed\n"
" (-l means list but don't copy)\n"
- " (see 'adb help all')\n"
" adb shell - run remote shell interactively\n"
" adb shell <command> - run remote shell command\n"
" adb emu <command> - run emulator console command\n"
@@ -202,11 +201,12 @@
" adb reboot sideload - reboots the device into the sideload mode in recovery program (adb root required).\n"
" adb reboot sideload-auto-reboot\n"
" - reboots into the sideload mode, then reboots automatically after the sideload regardless of the result.\n"
- " adb reboot-bootloader - reboots the device into the bootloader\n"
+ " adb sideload <file> - sideloads the given package\n"
" adb root - restarts the adbd daemon with root permissions\n"
" adb unroot - restarts the adbd daemon without root permissions\n"
" adb usb - restarts the adbd daemon listening on USB\n"
" adb tcpip <port> - restarts the adbd daemon listening on TCP on the specified port\n"
+ "\n"
"networking:\n"
" adb ppp <tty> [parameters] - Run PPP over USB.\n"
" Note: you should not automatically start a PPP connection.\n"
@@ -221,7 +221,7 @@
" - If it is \"system\", \"vendor\", \"oem\" or \"data\", only the corresponding partition\n"
" is updated.\n"
"\n"
- "environmental variables:\n"
+ "environment variables:\n"
" ADB_TRACE - Print debug information. A comma separated list of the following values\n"
" 1 or all, adb, sockets, packets, rwx, usb, sync, sysdeps, transport, jdwp\n"
" ANDROID_SERIAL - The serial number to connect to. -s takes priority over this if given.\n"
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index 78ab3f6..157c97b 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -125,11 +125,12 @@
// descriptor will always be open.
adbd_cloexec_auth_socket();
- auth_enabled = property_get_bool("ro.adb.secure", 0) != 0;
- if (auth_enabled) {
- adbd_auth_init();
+ if (ALLOW_ADBD_NO_AUTH && property_get_bool("ro.adb.secure", 0) == 0) {
+ auth_required = false;
}
+ adbd_auth_init();
+
// Our external storage path may be different than apps, since
// we aren't able to bind mount after dropping root.
const char* adb_external_storage = getenv("ADB_EXTERNAL_STORAGE");
@@ -171,7 +172,7 @@
D("Local port disabled\n");
} else {
- if ((root_seclabel != nullptr) && (is_selinux_enabled() > 0)) {
+ if (root_seclabel != nullptr) {
if (setcon(root_seclabel) < 0) {
LOG(FATAL) << "Could not set selinux context";
}
diff --git a/adb/services.cpp b/adb/services.cpp
index 2fd75ab..227f22a 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -528,7 +528,7 @@
std::string error_msg = "unknown error";
atransport* t = acquire_one_transport(sinfo->state, sinfo->transport_type, sinfo->serial,
&error_msg);
- if (t != 0) {
+ if (t != nullptr) {
SendOkay(fd);
} else {
SendFail(fd, error_msg);
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 379c702..274449b 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -731,12 +731,12 @@
int ambiguous = 0;
retry:
- if (error_out) *error_out = android::base::StringPrintf("device '%s' not found", serial);
+ *error_out = serial ? android::base::StringPrintf("device '%s' not found", serial) : "no devices found";
adb_mutex_lock(&transport_lock);
for (auto t : transport_list) {
if (t->connection_state == kCsNoPerm) {
- if (error_out) *error_out = "insufficient permissions for device";
+ *error_out = "insufficient permissions for device";
continue;
}
@@ -748,7 +748,7 @@
qual_match(serial, "model:", t->model, true) ||
qual_match(serial, "device:", t->device, false)) {
if (result) {
- if (error_out) *error_out = "more than one device";
+ *error_out = "more than one device";
ambiguous = 1;
result = NULL;
break;
@@ -758,7 +758,7 @@
} else {
if (type == kTransportUsb && t->type == kTransportUsb) {
if (result) {
- if (error_out) *error_out = "more than one device";
+ *error_out = "more than one device";
ambiguous = 1;
result = NULL;
break;
@@ -766,7 +766,7 @@
result = t;
} else if (type == kTransportLocal && t->type == kTransportLocal) {
if (result) {
- if (error_out) *error_out = "more than one emulator";
+ *error_out = "more than one emulator";
ambiguous = 1;
result = NULL;
break;
@@ -774,7 +774,7 @@
result = t;
} else if (type == kTransportAny) {
if (result) {
- if (error_out) *error_out = "more than one device/emulator";
+ *error_out = "more than one device/emulator";
ambiguous = 1;
result = NULL;
break;
@@ -787,33 +787,31 @@
if (result) {
if (result->connection_state == kCsUnauthorized) {
- if (error_out) {
- *error_out = "device unauthorized.\n";
- char* ADB_VENDOR_KEYS = getenv("ADB_VENDOR_KEYS");
- *error_out += "This adbd's $ADB_VENDOR_KEYS is ";
- *error_out += ADB_VENDOR_KEYS ? ADB_VENDOR_KEYS : "not set";
- *error_out += "; try 'adb kill-server' if that seems wrong.\n";
- *error_out += "Otherwise check for a confirmation dialog on your device.";
- }
+ *error_out = "device unauthorized.\n";
+ char* ADB_VENDOR_KEYS = getenv("ADB_VENDOR_KEYS");
+ *error_out += "This adbd's $ADB_VENDOR_KEYS is ";
+ *error_out += ADB_VENDOR_KEYS ? ADB_VENDOR_KEYS : "not set";
+ *error_out += "; try 'adb kill-server' if that seems wrong.\n";
+ *error_out += "Otherwise check for a confirmation dialog on your device.";
result = NULL;
}
/* offline devices are ignored -- they are either being born or dying */
if (result && result->connection_state == kCsOffline) {
- if (error_out) *error_out = "device offline";
+ *error_out = "device offline";
result = NULL;
}
/* check for required connection state */
if (result && state != kCsAny && result->connection_state != state) {
- if (error_out) *error_out = "invalid device state";
+ *error_out = "invalid device state";
result = NULL;
}
}
if (result) {
/* found one that we can take */
- if (error_out) *error_out = "success";
+ *error_out = "success";
} else if (state != kCsAny && (serial || !ambiguous)) {
adb_sleep_ms(1000);
goto retry;
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index b84a4e5..26d6389 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -134,8 +134,6 @@
return fields == 7 ? 0 : -1;
}
-static int selinux_enabled;
-
/*
* Corresponds with debugger_action_t enum type in
* include/cutils/debugger.h.
@@ -153,9 +151,6 @@
const char *perm;
bool allowed = false;
- if (selinux_enabled <= 0)
- return true;
-
if (action <= 0 || action >= (sizeof(debuggerd_perms)/sizeof(debuggerd_perms[0]))) {
ALOGE("SELinux: No permission defined for debugger action %d", action);
return false;
@@ -589,7 +584,6 @@
int main(int argc, char** argv) {
union selinux_callback cb;
if (argc == 1) {
- selinux_enabled = is_selinux_enabled();
cb.func_log = selinux_log_callback;
selinux_set_callback(SELINUX_CB_LOG, cb);
return do_server();
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 66a470a..ce8e15f 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -21,7 +21,7 @@
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../mkbootimg \
$(LOCAL_PATH)/../../extras/ext4_utils \
$(LOCAL_PATH)/../../extras/f2fs_utils
-LOCAL_SRC_FILES := protocol.c engine.c bootimg_utils.cpp fastboot.cpp util.c fs.c
+LOCAL_SRC_FILES := protocol.cpp engine.cpp bootimg_utils.cpp fastboot.cpp util.cpp fs.cpp
LOCAL_MODULE := fastboot
LOCAL_MODULE_TAGS := debug
LOCAL_CONLYFLAGS += -std=gnu99
@@ -30,17 +30,17 @@
LOCAL_CFLAGS += -DFASTBOOT_REVISION='"$(fastboot_version)"'
ifeq ($(HOST_OS),linux)
- LOCAL_SRC_FILES += usb_linux.c util_linux.c
+ LOCAL_SRC_FILES += usb_linux.cpp util_linux.cpp
endif
ifeq ($(HOST_OS),darwin)
- LOCAL_SRC_FILES += usb_osx.c util_osx.c
+ LOCAL_SRC_FILES += usb_osx.cpp util_osx.cpp
LOCAL_LDLIBS += -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
LOCAL_CFLAGS += -Wno-unused-parameter
endif
ifeq ($(HOST_OS),windows)
- LOCAL_SRC_FILES += usb_windows.c util_windows.c
+ LOCAL_SRC_FILES += usb_windows.cpp util_windows.cpp
EXTRA_STATIC_LIBS := AdbWinApi
ifneq ($(strip $(USE_CYGWIN)),)
# Pure cygwin case
@@ -97,10 +97,9 @@
$(call dist-for-goals,dist_files sdk,$(my_dist_files))
my_dist_files :=
-
ifeq ($(HOST_OS),linux)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES := usbtest.c usb_linux.c util.c
+LOCAL_SRC_FILES := usbtest.cpp usb_linux.cpp util.cpp
LOCAL_MODULE := usbtest
LOCAL_CFLAGS := -Werror
include $(BUILD_HOST_EXECUTABLE)
diff --git a/fastboot/engine.c b/fastboot/engine.cpp
similarity index 89%
rename from fastboot/engine.c
rename to fastboot/engine.cpp
index 2f90e41..66b8140 100644
--- a/fastboot/engine.c
+++ b/fastboot/engine.cpp
@@ -45,10 +45,6 @@
#include <sys/mman.h>
#endif
-#ifndef __unused
-#define __unused __attribute__((__unused__))
-#endif
-
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
#define OP_DOWNLOAD 1
@@ -73,7 +69,7 @@
unsigned size;
const char *msg;
- int (*func)(Action *a, int status, char *resp);
+ int (*func)(Action* a, int status, const char* resp);
double start;
};
@@ -121,8 +117,7 @@
return !!fs_get_generator(fs_type);
}
-static int cb_default(Action *a, int status, char *resp)
-{
+static int cb_default(Action* a, int status, const char* resp) {
if (status) {
fprintf(stderr,"FAILED (%s)\n", resp);
} else {
@@ -135,12 +130,11 @@
static Action *queue_action(unsigned op, const char *fmt, ...)
{
- Action *a;
va_list ap;
size_t cmdsize;
- a = calloc(1, sizeof(Action));
- if (a == 0) die("out of memory");
+ Action* a = reinterpret_cast<Action*>(calloc(1, sizeof(Action)));
+ if (a == nullptr) die("out of memory");
va_start(ap, fmt);
cmdsize = vsnprintf(a->cmd, sizeof(a->cmd), fmt, ap);
@@ -198,8 +192,7 @@
a->msg = mkmsg("writing '%s'", ptn);
}
-static int match(char *str, const char **value, unsigned count)
-{
+static int match(const char* str, const char** value, unsigned count) {
unsigned n;
for (n = 0; n < count; n++) {
@@ -222,9 +215,9 @@
-static int cb_check(Action *a, int status, char *resp, int invert)
+static int cb_check(Action* a, int status, const char* resp, int invert)
{
- const char **value = a->data;
+ const char** value = reinterpret_cast<const char**>(a->data);
unsigned count = a->size;
unsigned n;
int yes;
@@ -265,18 +258,16 @@
return -1;
}
-static int cb_require(Action *a, int status, char *resp)
-{
+static int cb_require(Action*a, int status, const char* resp) {
return cb_check(a, status, resp, 0);
}
-static int cb_reject(Action *a, int status, char *resp)
-{
+static int cb_reject(Action* a, int status, const char* resp) {
return cb_check(a, status, resp, 1);
}
void fb_queue_require(const char *prod, const char *var,
- int invert, unsigned nvalues, const char **value)
+ int invert, unsigned nvalues, const char **value)
{
Action *a;
a = queue_action(OP_QUERY, "getvar:%s", var);
@@ -285,11 +276,10 @@
a->size = nvalues;
a->msg = mkmsg("checking %s", var);
a->func = invert ? cb_reject : cb_require;
- if (a->data == 0) die("out of memory");
+ if (a->data == nullptr) die("out of memory");
}
-static int cb_display(Action *a, int status, char *resp)
-{
+static int cb_display(Action* a, int status, const char* resp) {
if (status) {
fprintf(stderr, "%s FAILED (%s)\n", a->cmd, resp);
return status;
@@ -303,17 +293,16 @@
Action *a;
a = queue_action(OP_QUERY, "getvar:%s", var);
a->data = strdup(prettyname);
- if (a->data == 0) die("out of memory");
+ if (a->data == nullptr) die("out of memory");
a->func = cb_display;
}
-static int cb_save(Action *a, int status, char *resp)
-{
+static int cb_save(Action* a, int status, const char* resp) {
if (status) {
fprintf(stderr, "%s FAILED (%s)\n", a->cmd, resp);
return status;
}
- strncpy(a->data, resp, a->size);
+ strncpy(reinterpret_cast<char*>(a->data), resp, a->size);
return 0;
}
@@ -326,8 +315,7 @@
a->func = cb_save;
}
-static int cb_do_nothing(Action *a __unused, int status __unused, char *resp __unused)
-{
+static int cb_do_nothing(Action*, int , const char*) {
fprintf(stderr,"\n");
return 0;
}
@@ -398,7 +386,7 @@
} else if (a->op == OP_NOTICE) {
fprintf(stderr,"%s\n",(char*)a->data);
} else if (a->op == OP_DOWNLOAD_SPARSE) {
- status = fb_download_data_sparse(usb, a->data);
+ status = fb_download_data_sparse(usb, reinterpret_cast<sparse_file*>(a->data));
status = a->func(a, status, status ? fb_get_error() : "");
if (status) break;
} else if (a->op == OP_WAIT_FOR_DISCONNECT) {
@@ -414,5 +402,5 @@
int fb_queue_is_empty(void)
{
- return (action_list == NULL);
+ return (action_list == nullptr);
}
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 0de1def..b964a36 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -275,52 +275,52 @@
"usage: fastboot [ <option> ] <command>\n"
"\n"
"commands:\n"
- " update <filename> reflash device from update.zip\n"
- " flashall flash boot, system, vendor and if found,\n"
- " recovery\n"
- " flash <partition> [ <filename> ] write a file to a flash partition\n"
- " flashing lock locks the device. Prevents flashing"
- " partitions\n"
- " flashing unlock unlocks the device. Allows user to"
- " flash any partition except the ones"
- " that are related to bootloader\n"
- " flashing lock_critical Prevents flashing bootloader related"
- " partitions\n"
- " flashing unlock_critical Enables flashing bootloader related"
- " partitions\n"
- " flashing get_unlock_ability Queries bootloader to see if the"
- " device is unlocked\n"
- " erase <partition> erase a flash partition\n"
- " format[:[<fs type>][:[<size>]] <partition> format a flash partition.\n"
- " Can override the fs type and/or\n"
- " size the bootloader reports.\n"
- " getvar <variable> display a bootloader variable\n"
- " boot <kernel> [ <ramdisk> [ <second> ] ] download and boot kernel\n"
- " flash:raw boot <kernel> [ <ramdisk> [ <second> ] ] create bootimage and \n"
- " flash it\n"
- " devices list all connected devices\n"
- " continue continue with autoboot\n"
- " reboot [bootloader] reboot device, optionally into bootloader\n"
- " reboot-bootloader reboot device into bootloader\n"
- " help show this help message\n"
+ " update <filename> Reflash device from update.zip.\n"
+ " flashall Flash boot, system, vendor, and --\n"
+ " if found -- recovery.\n"
+ " flash <partition> [ <filename> ] Write a file to a flash partition.\n"
+ " flashing lock Locks the device. Prevents flashing.\n"
+ " flashing unlock Unlocks the device. Allows flashing\n"
+ " any partition except\n"
+ " bootloader-related partitions.\n"
+ " flashing lock_critical Prevents flashing bootloader-related\n"
+ " partitions.\n"
+ " flashing unlock_critical Enables flashing bootloader-related\n"
+ " partitions.\n"
+ " flashing get_unlock_ability Queries bootloader to see if the\n"
+ " device is unlocked.\n"
+ " erase <partition> Erase a flash partition.\n"
+ " format[:[<fs type>][:[<size>]] <partition>\n"
+ " Format a flash partition. Can\n"
+ " override the fs type and/or size\n"
+ " the bootloader reports.\n"
+ " getvar <variable> Display a bootloader variable.\n"
+ " boot <kernel> [ <ramdisk> [ <second> ] ] Download and boot kernel.\n"
+ " flash:raw boot <kernel> [ <ramdisk> [ <second> ] ]\n"
+ " Create bootimage and flash it.\n"
+ " devices [-l] List all connected devices [with\n"
+ " device paths].\n"
+ " continue Continue with autoboot.\n"
+ " reboot [bootloader] Reboot device [into bootloader].\n"
+ " reboot-bootloader Reboot device into bootloader.\n"
+ " help Show this help message.\n"
"\n"
"options:\n"
- " -w erase userdata and cache (and format\n"
- " if supported by partition type)\n"
- " -u do not first erase partition before\n"
- " formatting\n"
- " -s <specific device> specify device serial number\n"
- " or path to device port\n"
- " -l with \"devices\", lists device paths\n"
- " -p <product> specify product name\n"
- " -c <cmdline> override kernel commandline\n"
- " -i <vendor id> specify a custom USB vendor id\n"
- " -b <base_addr> specify a custom kernel base address.\n"
- " default: 0x10000000\n"
- " -n <page size> specify the nand page size.\n"
- " default: 2048\n"
- " -S <size>[K|M|G] automatically sparse files greater\n"
- " than size. 0 to disable\n"
+ " -w Erase userdata and cache (and format\n"
+ " if supported by partition type).\n"
+ " -u Do not erase partition before\n"
+ " formatting.\n"
+ " -s <specific device> Specify device serial number\n"
+ " or path to device port.\n"
+ " -p <product> Specify product name.\n"
+ " -c <cmdline> Override kernel commandline.\n"
+ " -i <vendor id> Specify a custom USB vendor id.\n"
+ " -b <base_addr> Specify a custom kernel base\n"
+ " address (default: 0x10000000).\n"
+ " -n <page size> Specify the nand page size\n"
+ " (default: 2048).\n"
+ " -S <size>[K|M|G] Automatically sparse files greater\n"
+ " than 'size'. 0 to disable.\n"
);
}
@@ -391,7 +391,7 @@
static void* unzip_file(ZipArchiveHandle zip, const char* entry_name, unsigned* sz)
{
- ZipEntryName zip_entry_name(entry_name);
+ ZipString zip_entry_name(entry_name);
ZipEntry zip_entry;
if (FindEntry(zip, zip_entry_name, &zip_entry) != 0) {
fprintf(stderr, "archive does not contain '%s'\n", entry_name);
@@ -453,7 +453,7 @@
return -1;
}
- ZipEntryName zip_entry_name(entry_name);
+ ZipString zip_entry_name(entry_name);
ZipEntry zip_entry;
if (FindEntry(zip, zip_entry_name, &zip_entry) != 0) {
fprintf(stderr, "archive does not contain '%s'\n", entry_name);
diff --git a/fastboot/fs.c b/fastboot/fs.cpp
similarity index 93%
rename from fastboot/fs.c
rename to fastboot/fs.cpp
index 8a15e6f..d8f9e16 100644
--- a/fastboot/fs.c
+++ b/fastboot/fs.cpp
@@ -38,7 +38,7 @@
static const struct fs_generator {
- char *fs_type; //must match what fastboot reports for partition type
+ const char* fs_type; //must match what fastboot reports for partition type
int (*generate)(int fd, long long partSize); //returns 0 or error value
} generators[] = {
diff --git a/fastboot/protocol.c b/fastboot/protocol.cpp
similarity index 97%
rename from fastboot/protocol.c
rename to fastboot/protocol.cpp
index 5b97600..00c8a03 100644
--- a/fastboot/protocol.c
+++ b/fastboot/protocol.cpp
@@ -223,9 +223,9 @@
static int fb_download_data_sparse_write(void *priv, const void *data, int len)
{
int r;
- usb_handle *usb = priv;
+ usb_handle* usb = reinterpret_cast<usb_handle*>(priv);
int to_write;
- const char *ptr = data;
+ const char* ptr = reinterpret_cast<const char*>(data);
if (usb_buf_len) {
to_write = min(USB_BUF_SIZE - usb_buf_len, len);
diff --git a/fastboot/usb_linux.c b/fastboot/usb_linux.cpp
similarity index 98%
rename from fastboot/usb_linux.c
rename to fastboot/usb_linux.cpp
index 022f364..9078c8f 100644
--- a/fastboot/usb_linux.c
+++ b/fastboot/usb_linux.cpp
@@ -340,7 +340,7 @@
if(filter_usb_device(de->d_name, desc, n, writable, callback,
&in, &out, &ifc) == 0) {
- usb = calloc(1, sizeof(usb_handle));
+ usb = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle)));
strcpy(usb->fname, devname);
usb->ep_in = in;
usb->ep_out = out;
diff --git a/fastboot/usb_osx.c b/fastboot/usb_osx.cpp
similarity index 98%
rename from fastboot/usb_osx.c
rename to fastboot/usb_osx.cpp
index 0b6c515..a959566 100644
--- a/fastboot/usb_osx.c
+++ b/fastboot/usb_osx.cpp
@@ -26,6 +26,7 @@
* SUCH DAMAGE.
*/
+#include <inttypes.h>
#include <stdio.h>
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
@@ -121,7 +122,7 @@
result = (*plugInInterface)->QueryInterface(
plugInInterface,
CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID),
- (LPVOID) &interface);
+ (LPVOID*) &interface);
// No longer need the intermediate plugin
(*plugInInterface)->Release(plugInInterface);
@@ -279,7 +280,7 @@
// Now create the device interface.
result = (*plugin)->QueryInterface(plugin,
- CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID) &dev);
+ CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID*) &dev);
if ((result != 0) || (dev == NULL)) {
ERR("Couldn't create a device interface (%08x)\n", (int) result);
goto error;
@@ -432,7 +433,7 @@
}
if (h.success) {
- *handle = calloc(1, sizeof(usb_handle));
+ *handle = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle)));
memcpy(*handle, &h, sizeof(usb_handle));
ret = 0;
break;
diff --git a/fastboot/usb_windows.c b/fastboot/usb_windows.cpp
similarity index 100%
rename from fastboot/usb_windows.c
rename to fastboot/usb_windows.cpp
diff --git a/fastboot/usbtest.c b/fastboot/usbtest.cpp
similarity index 100%
rename from fastboot/usbtest.c
rename to fastboot/usbtest.cpp
diff --git a/fastboot/util.c b/fastboot/util.cpp
similarity index 100%
rename from fastboot/util.c
rename to fastboot/util.cpp
diff --git a/fastboot/util_linux.c b/fastboot/util_linux.cpp
similarity index 98%
rename from fastboot/util_linux.c
rename to fastboot/util_linux.cpp
index 91c3776..b788199 100644
--- a/fastboot/util_linux.c
+++ b/fastboot/util_linux.cpp
@@ -26,6 +26,8 @@
* SUCH DAMAGE.
*/
+#include "fastboot.h"
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/fastboot/util_osx.c b/fastboot/util_osx.cpp
similarity index 98%
rename from fastboot/util_osx.c
rename to fastboot/util_osx.cpp
index e718562..ae0b024 100644
--- a/fastboot/util_osx.c
+++ b/fastboot/util_osx.cpp
@@ -26,6 +26,8 @@
* SUCH DAMAGE.
*/
+#include "fastboot.h"
+
#import <Carbon/Carbon.h>
#include <unistd.h>
diff --git a/fastboot/util_windows.c b/fastboot/util_windows.cpp
similarity index 98%
rename from fastboot/util_windows.c
rename to fastboot/util_windows.cpp
index 74a5c27..ec52f39 100644
--- a/fastboot/util_windows.c
+++ b/fastboot/util_windows.cpp
@@ -26,6 +26,8 @@
* SUCH DAMAGE.
*/
+#include "fastboot.h"
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index bb2bed2..42f25c7 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -95,7 +95,7 @@
int status;
int ret;
long tmpmnt_flags = MS_NOATIME | MS_NOEXEC | MS_NOSUID;
- char *tmpmnt_opts = "nomblk_io_submit,errors=remount-ro";
+ char tmpmnt_opts[64] = "errors=remount-ro";
char *e2fsck_argv[] = {
E2FSCK_BIN,
"-y",
@@ -118,6 +118,10 @@
* fix the filesystem.
*/
errno = 0;
+ if (!strcmp(fs_type, "ext4")) {
+ // This option is only valid with ext4
+ strlcat(tmpmnt_opts, ",nomblk_io_submit", sizeof(tmpmnt_opts));
+ }
ret = mount(blk_device, target, fs_type, tmpmnt_flags, tmpmnt_opts);
INFO("%s(): mount(%s,%s,%s)=%d: %s\n",
__func__, blk_device, target, fs_type, ret, strerror(errno));
diff --git a/fs_mgr/fs_mgr_verity.c b/fs_mgr/fs_mgr_verity.c
index 81c7c9a..0a945a3 100644
--- a/fs_mgr/fs_mgr_verity.c
+++ b/fs_mgr/fs_mgr_verity.c
@@ -767,8 +767,24 @@
static int load_verity_state(struct fstab_rec *fstab, int *mode)
{
- off64_t offset = 0;
+ char propbuf[PROPERTY_VALUE_MAX];
int match = 0;
+ off64_t offset = 0;
+
+ /* use the kernel parameter if set */
+ property_get("ro.boot.veritymode", propbuf, "");
+
+ if (*propbuf != '\0') {
+ if (!strcmp(propbuf, "enforcing")) {
+ *mode = VERITY_MODE_DEFAULT;
+ return 0;
+ } else if (!strcmp(propbuf, "logging")) {
+ *mode = VERITY_MODE_LOGGING;
+ return 0;
+ } else {
+ INFO("Unknown value %s for veritymode; ignoring", propbuf);
+ }
+ }
if (get_verity_state_offset(fstab, &offset) < 0) {
/* fall back to stateless behavior */
@@ -855,6 +871,13 @@
struct dm_ioctl *io = (struct dm_ioctl *) buffer;
struct fstab *fstab = NULL;
+ /* check if we need to store the state */
+ property_get("ro.boot.veritymode", propbuf, "");
+
+ if (*propbuf != '\0') {
+ return 0; /* state is kept by the bootloader */
+ }
+
fd = TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC));
if (fd == -1) {
diff --git a/include/utils/TypeHelpers.h b/include/utils/TypeHelpers.h
index 13c9081..61d618e 100644
--- a/include/utils/TypeHelpers.h
+++ b/include/utils/TypeHelpers.h
@@ -131,7 +131,8 @@
template<typename TYPE> inline
void construct_type(TYPE* p, size_t n) {
if (!traits<TYPE>::has_trivial_ctor) {
- while (n--) {
+ while (n > 0) {
+ n--;
new(p++) TYPE;
}
}
@@ -140,7 +141,8 @@
template<typename TYPE> inline
void destroy_type(TYPE* p, size_t n) {
if (!traits<TYPE>::has_trivial_dtor) {
- while (n--) {
+ while (n > 0) {
+ n--;
p->~TYPE();
p++;
}
@@ -150,7 +152,8 @@
template<typename TYPE> inline
void copy_type(TYPE* d, const TYPE* s, size_t n) {
if (!traits<TYPE>::has_trivial_copy) {
- while (n--) {
+ while (n > 0) {
+ n--;
new(d) TYPE(*s);
d++, s++;
}
@@ -162,12 +165,14 @@
template<typename TYPE> inline
void splat_type(TYPE* where, const TYPE* what, size_t n) {
if (!traits<TYPE>::has_trivial_copy) {
- while (n--) {
+ while (n > 0) {
+ n--;
new(where) TYPE(*what);
where++;
}
} else {
- while (n--) {
+ while (n > 0) {
+ n--;
*where++ = *what;
}
}
@@ -182,7 +187,8 @@
} else {
d += n;
s += n;
- while (n--) {
+ while (n > 0) {
+ n--;
--d, --s;
if (!traits<TYPE>::has_trivial_copy) {
new(d) TYPE(*s);
@@ -203,7 +209,8 @@
{
memmove(d,s,n*sizeof(TYPE));
} else {
- while (n--) {
+ while (n > 0) {
+ n--;
if (!traits<TYPE>::has_trivial_copy) {
new(d) TYPE(*s);
} else {
diff --git a/include/ziparchive/zip_archive.h b/include/ziparchive/zip_archive.h
index 386a390..5ef2ab0 100644
--- a/include/ziparchive/zip_archive.h
+++ b/include/ziparchive/zip_archive.h
@@ -33,17 +33,33 @@
kCompressDeflated = 8, // standard deflate
};
-struct ZipEntryName {
+struct ZipString {
const uint8_t* name;
uint16_t name_length;
- ZipEntryName() {}
+ ZipString() {}
/*
* entry_name has to be an c-style string with only ASCII characters.
*/
- explicit ZipEntryName(const char* entry_name)
+ explicit ZipString(const char* entry_name)
: name(reinterpret_cast<const uint8_t*>(entry_name)), name_length(strlen(entry_name)) {}
+
+ bool operator==(const ZipString& rhs) const {
+ return name && (name_length == rhs.name_length) &&
+ (memcmp(name, rhs.name, name_length) == 0);
+ }
+
+ bool StartsWith(const ZipString& prefix) const {
+ return name && (name_length >= prefix.name_length) &&
+ (memcmp(name, prefix.name, prefix.name_length) == 0);
+ }
+
+ bool EndsWith(const ZipString& suffix) const {
+ return name && (name_length >= suffix.name_length) &&
+ (memcmp(name + name_length - suffix.name_length, suffix.name,
+ suffix.name_length) == 0);
+ }
};
/*
@@ -136,7 +152,7 @@
* and length, a call to VerifyCrcAndLengths must be made after entry data
* has been processed.
*/
-int32_t FindEntry(const ZipArchiveHandle handle, const ZipEntryName& entryName,
+int32_t FindEntry(const ZipArchiveHandle handle, const ZipString& entryName,
ZipEntry* data);
/*
@@ -147,13 +163,14 @@
* calls to Next. All calls to StartIteration must be matched by a call to
* EndIteration to free any allocated memory.
*
- * This method also accepts an optional prefix to restrict iteration to
- * entry names that start with |optional_prefix|.
+ * This method also accepts optional prefix and suffix to restrict iteration to
+ * entry names that start with |optional_prefix| or end with |optional_suffix|.
*
* Returns 0 on success and negative values on failure.
*/
int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr,
- const ZipEntryName* optional_prefix);
+ const ZipString* optional_prefix,
+ const ZipString* optional_suffix);
/*
* Advance to the next element in the zipfile in iteration order.
@@ -161,7 +178,7 @@
* Returns 0 on success, -1 if there are no more elements in this
* archive and lower negative values on failure.
*/
-int32_t Next(void* cookie, ZipEntry* data, ZipEntryName *name);
+int32_t Next(void* cookie, ZipEntry* data, ZipString* name);
/*
* End iteration over all entries of a zip file and frees the memory allocated
diff --git a/init/Android.mk b/init/Android.mk
index b14f9b5..45b002d 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -18,8 +18,6 @@
-Wno-unused-parameter \
-Werror \
-init_clang := true
-
# --
include $(CLEAR_VARS)
@@ -32,7 +30,7 @@
LOCAL_STATIC_LIBRARIES := libbase
LOCAL_MODULE := libinit
-LOCAL_CLANG := $(init_clang)
+LOCAL_CLANG := true
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
@@ -79,7 +77,7 @@
ln -sf ../init $(TARGET_ROOT_OUT)/sbin/ueventd; \
ln -sf ../init $(TARGET_ROOT_OUT)/sbin/watchdogd
-LOCAL_CLANG := $(init_clang)
+LOCAL_CLANG := true
include $(BUILD_EXECUTABLE)
@@ -96,5 +94,5 @@
libbase \
LOCAL_STATIC_LIBRARIES := libinit
-LOCAL_CLANG := $(init_clang)
+LOCAL_CLANG := true
include $(BUILD_NATIVE_TEST)
diff --git a/init/compare-bootcharts.py b/init/compare-bootcharts.py
new file mode 100755
index 0000000..2057b55
--- /dev/null
+++ b/init/compare-bootcharts.py
@@ -0,0 +1,146 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Compare two bootcharts and list start/end timestamps on key processes.
+
+This script extracts two bootchart.tgz files and compares the timestamps
+in proc_ps.log for selected processes. The proc_ps.log file consists of
+repetitive blocks of the following format:
+
+timestamp1 (jiffies)
+dumps of /proc/<pid>/stat
+
+timestamp2
+dumps of /proc/<pid>/stat
+
+The timestamps are 200ms apart, and the creation time of selected processes
+are listed. The termination time of the boot animation process is also listed
+as a coarse indication about when the boot process is complete as perceived by
+the user.
+"""
+
+import sys
+import tarfile
+
+# The bootchart timestamps are 200ms apart, but the USER_HZ value is not
+# reported in the bootchart, so we use the first two timestamps to calculate
+# the wall clock time of a jiffy.
+jiffy_to_wallclock = {
+ '1st_timestamp': -1,
+ '2nd_timestamp': -1,
+ 'jiffy_to_wallclock': -1
+}
+
+def analyze_process_maps(process_map1, process_map2, jiffy_record):
+ # List interesting processes here
+ processes_of_interest = [
+ '/init',
+ '/system/bin/surfaceflinger',
+ '/system/bin/bootanimation',
+ 'zygote64',
+ 'zygote',
+ 'system_server'
+ ]
+
+ jw = jiffy_record['jiffy_to_wallclock']
+ print "process: baseline experiment (delta)"
+ print " - Unit is ms (a jiffy is %d ms on the system)" % jw
+ print "------------------------------------"
+ for p in processes_of_interest:
+ # e.g., 32-bit system doesn't have zygote64
+ if p in process_map1 and p in process_map2:
+ print "%s: %d %d (%+d)" % (
+ p, process_map1[p]['start_time'] * jw,
+ process_map2[p]['start_time'] * jw,
+ (process_map2[p]['start_time'] -
+ process_map1[p]['start_time']) * jw)
+
+ # Print the last tick for the bootanimation process
+ print "bootanimation ends at: %d %d (%+d)" % (
+ process_map1['/system/bin/bootanimation']['last_tick'] * jw,
+ process_map2['/system/bin/bootanimation']['last_tick'] * jw,
+ (process_map2['/system/bin/bootanimation']['last_tick'] -
+ process_map1['/system/bin/bootanimation']['last_tick']) * jw)
+
+def parse_proc_file(pathname, process_map, jiffy_record=None):
+ # Uncompress bootchart.tgz
+ with tarfile.open(pathname + '/bootchart.tgz', 'r:*') as tf:
+ try:
+ # Read proc_ps.log
+ f = tf.extractfile('proc_ps.log')
+
+ # Break proc_ps into chunks based on timestamps
+ blocks = f.read().split('\n\n')
+ for b in blocks:
+ lines = b.split('\n')
+ if not lines[0]:
+ break
+
+ # 200ms apart in jiffies
+ timestamp = int(lines[0]);
+
+ # Figure out the wall clock time of a jiffy
+ if jiffy_record is not None:
+ if jiffy_record['1st_timestamp'] == -1:
+ jiffy_record['1st_timestamp'] = timestamp
+ elif jiffy_record['jiffy_to_wallclock'] == -1:
+ # Not really needed but for debugging purposes
+ jiffy_record['2nd_timestamp'] = timestamp
+ value = 200 / (timestamp -
+ jiffy_record['1st_timestamp'])
+ # Fix the rounding error
+ # e.g., 201 jiffies in 200ms when USER_HZ is 1000
+ if value == 0:
+ value = 1
+ # e.g., 21 jiffies in 200ms when USER_HZ is 100
+ elif value == 9:
+ value = 10
+ jiffy_record['jiffy_to_wallclock'] = value
+
+ # Populate the process_map table
+ for line in lines[1:]:
+ segs = line.split(' ')
+
+ # 0: pid
+ # 1: process name
+ # 17: priority
+ # 18: nice
+ # 21: creation time
+
+ proc_name = segs[1].strip('()')
+ if proc_name in process_map:
+ process = process_map[proc_name]
+ else:
+ process = {'start_time': int(segs[21])}
+ process_map[proc_name] = process
+
+ process['last_tick'] = timestamp
+ finally:
+ f.close()
+
+def main():
+ if len(sys.argv) != 3:
+ print "Usage: %s base_bootchart_dir exp_bootchart_dir" % sys.argv[0]
+ sys.exit(1)
+
+ process_map1 = {}
+ process_map2 = {}
+ parse_proc_file(sys.argv[1], process_map1, jiffy_to_wallclock)
+ parse_proc_file(sys.argv[2], process_map2)
+ analyze_process_maps(process_map1, process_map2, jiffy_to_wallclock)
+
+if __name__ == "__main__":
+ main()
diff --git a/init/devices.cpp b/init/devices.cpp
index 2c7f5a9..3652c57 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -241,10 +241,8 @@
mode = get_device_perm(path, links, &uid, &gid) | (block ? S_IFBLK : S_IFCHR);
- if (sehandle) {
- selabel_lookup_best_match(sehandle, &secontext, path, links, mode);
- setfscreatecon(secontext);
- }
+ selabel_lookup_best_match(sehandle, &secontext, path, links, mode);
+ setfscreatecon(secontext);
dev = makedev(major, minor);
/* Temporarily change egid to avoid race condition setting the gid of the
@@ -907,7 +905,7 @@
struct uevent uevent;
parse_event(msg, &uevent);
- if (sehandle && selinux_status_updated() > 0) {
+ if (selinux_status_updated() > 0) {
struct selabel_handle *sehandle2;
sehandle2 = selinux_android_file_context_handle();
if (sehandle2) {
@@ -974,11 +972,8 @@
}
void device_init() {
- sehandle = NULL;
- if (is_selinux_enabled() > 0) {
- sehandle = selinux_android_file_context_handle();
- selinux_status_open(true);
- }
+ sehandle = selinux_android_file_context_handle();
+ selinux_status_open(true);
/* is 256K enough? udev uses 16MB! */
device_fd = uevent_open_socket(256*1024, true);
diff --git a/init/init.cpp b/init/init.cpp
index 2500985..f48016f 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -220,40 +220,38 @@
}
char* scon = NULL;
- if (is_selinux_enabled() > 0) {
- if (svc->seclabel) {
- scon = strdup(svc->seclabel);
- if (!scon) {
- ERROR("Out of memory while starting '%s'\n", svc->name);
- return;
- }
- } else {
- char *mycon = NULL, *fcon = NULL;
+ if (svc->seclabel) {
+ scon = strdup(svc->seclabel);
+ if (!scon) {
+ ERROR("Out of memory while starting '%s'\n", svc->name);
+ return;
+ }
+ } else {
+ char *mycon = NULL, *fcon = NULL;
- INFO("computing context for service '%s'\n", svc->args[0]);
- int rc = getcon(&mycon);
- if (rc < 0) {
- ERROR("could not get context while starting '%s'\n", svc->name);
- return;
- }
+ INFO("computing context for service '%s'\n", svc->args[0]);
+ int rc = getcon(&mycon);
+ if (rc < 0) {
+ ERROR("could not get context while starting '%s'\n", svc->name);
+ return;
+ }
- rc = getfilecon(svc->args[0], &fcon);
- if (rc < 0) {
- ERROR("could not get context while starting '%s'\n", svc->name);
- freecon(mycon);
- return;
- }
-
- rc = security_compute_create(mycon, fcon, string_to_security_class("process"), &scon);
- if (rc == 0 && !strcmp(scon, mycon)) {
- ERROR("Warning! Service %s needs a SELinux domain defined; please fix!\n", svc->name);
- }
+ rc = getfilecon(svc->args[0], &fcon);
+ if (rc < 0) {
+ ERROR("could not get context while starting '%s'\n", svc->name);
freecon(mycon);
- freecon(fcon);
- if (rc < 0) {
- ERROR("could not get context while starting '%s'\n", svc->name);
- return;
- }
+ return;
+ }
+
+ rc = security_compute_create(mycon, fcon, string_to_security_class("process"), &scon);
+ if (rc == 0 && !strcmp(scon, mycon)) {
+ ERROR("Warning! Service %s needs a SELinux domain defined; please fix!\n", svc->name);
+ }
+ freecon(mycon);
+ freecon(fcon);
+ if (rc < 0) {
+ ERROR("could not get context while starting '%s'\n", svc->name);
+ return;
}
}
@@ -290,6 +288,16 @@
freecon(scon);
scon = NULL;
+ if (svc->writepid_files_) {
+ std::string pid_str = android::base::StringPrintf("%d", pid);
+ for (auto& file : *svc->writepid_files_) {
+ if (!android::base::WriteStringToFile(pid_str, file)) {
+ ERROR("couldn't write %s to %s: %s\n",
+ pid_str.c_str(), file.c_str(), strerror(errno));
+ }
+ }
+ }
+
if (svc->ioprio_class != IoSchedClass_NONE) {
if (android_set_ioprio(getpid(), svc->ioprio_class, svc->ioprio_pri)) {
ERROR("Failed to set pid %d ioprio = %d,%d: %s\n",
@@ -335,7 +343,7 @@
}
}
if (svc->seclabel) {
- if (is_selinux_enabled() > 0 && setexeccon(svc->seclabel) < 0) {
+ if (setexeccon(svc->seclabel) < 0) {
ERROR("cannot setexeccon('%s'): %s\n", svc->seclabel, strerror(errno));
_exit(127);
}
diff --git a/init/init.h b/init/init.h
index 1cabb14..c166969 100644
--- a/init/init.h
+++ b/init/init.h
@@ -19,6 +19,9 @@
#include <sys/types.h>
+#include <string>
+#include <vector>
+
#include <cutils/list.h>
#include <cutils/iosched_policy.h>
@@ -116,6 +119,8 @@
struct action onrestart; /* Actions to execute on restart. */
+ std::vector<std::string>* writepid_files_;
+
/* keycodes for triggering this service via /dev/keychord */
int *keycodes;
int nkeycodes;
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index f975b6c..956ed25 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -206,6 +206,7 @@
break;
case 'w':
if (!strcmp(s, "rite")) return K_write;
+ if (!strcmp(s, "ritepid")) return K_writepid;
if (!strcmp(s, "ait")) return K_wait;
break;
}
@@ -924,6 +925,16 @@
svc->seclabel = args[1];
}
break;
+ case K_writepid:
+ if (nargs < 2) {
+ parse_error(state, "writepid option requires at least one filename\n");
+ break;
+ }
+ svc->writepid_files_ = new std::vector<std::string>;
+ for (int i = 1; i < nargs; ++i) {
+ svc->writepid_files_->push_back(args[i]);
+ }
+ break;
default:
parse_error(state, "invalid option '%s'\n", args[0]);
diff --git a/init/keywords.h b/init/keywords.h
index 37f01b8..e637d7d 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -43,11 +43,15 @@
enum {
K_UNKNOWN,
#endif
+ KEYWORD(bootchart_init, COMMAND, 0, do_bootchart_init)
+ KEYWORD(chmod, COMMAND, 2, do_chmod)
+ KEYWORD(chown, COMMAND, 2, do_chown)
KEYWORD(class, OPTION, 0, 0)
+ KEYWORD(class_reset, COMMAND, 1, do_class_reset)
KEYWORD(class_start, COMMAND, 1, do_class_start)
KEYWORD(class_stop, COMMAND, 1, do_class_stop)
- KEYWORD(class_reset, COMMAND, 1, do_class_reset)
KEYWORD(console, OPTION, 0, 0)
+ KEYWORD(copy, COMMAND, 2, do_copy)
KEYWORD(critical, OPTION, 0, 0)
KEYWORD(disabled, OPTION, 0, 0)
KEYWORD(domainname, COMMAND, 1, do_domainname)
@@ -57,16 +61,20 @@
KEYWORD(group, OPTION, 0, 0)
KEYWORD(hostname, COMMAND, 1, do_hostname)
KEYWORD(ifup, COMMAND, 1, do_ifup)
+ KEYWORD(import, SECTION, 1, 0)
KEYWORD(insmod, COMMAND, 1, do_insmod)
KEYWORD(installkey, COMMAND, 1, do_installkey)
- KEYWORD(import, SECTION, 1, 0)
+ KEYWORD(ioprio, OPTION, 0, 0)
KEYWORD(keycodes, OPTION, 0, 0)
+ KEYWORD(load_all_props, COMMAND, 0, do_load_all_props)
+ KEYWORD(load_persist_props, COMMAND, 0, do_load_persist_props)
+ KEYWORD(loglevel, COMMAND, 1, do_loglevel)
KEYWORD(mkdir, COMMAND, 1, do_mkdir)
KEYWORD(mount_all, COMMAND, 1, do_mount_all)
KEYWORD(mount, COMMAND, 3, do_mount)
- KEYWORD(on, SECTION, 0, 0)
KEYWORD(oneshot, OPTION, 0, 0)
KEYWORD(onrestart, OPTION, 0, 0)
+ KEYWORD(on, SECTION, 0, 0)
KEYWORD(powerctl, COMMAND, 1, do_powerctl)
KEYWORD(restart, COMMAND, 1, do_restart)
KEYWORD(restorecon, COMMAND, 1, do_restorecon)
@@ -82,22 +90,15 @@
KEYWORD(start, COMMAND, 1, do_start)
KEYWORD(stop, COMMAND, 1, do_stop)
KEYWORD(swapon_all, COMMAND, 1, do_swapon_all)
- KEYWORD(trigger, COMMAND, 1, do_trigger)
KEYWORD(symlink, COMMAND, 1, do_symlink)
KEYWORD(sysclktz, COMMAND, 1, do_sysclktz)
+ KEYWORD(trigger, COMMAND, 1, do_trigger)
KEYWORD(user, OPTION, 0, 0)
KEYWORD(verity_load_state, COMMAND, 0, do_verity_load_state)
KEYWORD(verity_update_state, COMMAND, 0, do_verity_update_state)
KEYWORD(wait, COMMAND, 1, do_wait)
KEYWORD(write, COMMAND, 2, do_write)
- KEYWORD(copy, COMMAND, 2, do_copy)
- KEYWORD(chown, COMMAND, 2, do_chown)
- KEYWORD(chmod, COMMAND, 2, do_chmod)
- KEYWORD(loglevel, COMMAND, 1, do_loglevel)
- KEYWORD(load_persist_props, COMMAND, 0, do_load_persist_props)
- KEYWORD(load_all_props, COMMAND, 0, do_load_all_props)
- KEYWORD(ioprio, OPTION, 0, 0)
- KEYWORD(bootchart_init, COMMAND, 0, do_bootchart_init)
+ KEYWORD(writepid, OPTION, 0, 0)
#ifdef __MAKE_KEYWORD_ENUM__
KEYWORD_COUNT,
};
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 0ee0351..5b7a1cb 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -92,9 +92,6 @@
static int check_mac_perms(const char *name, char *sctx)
{
- if (is_selinux_enabled() <= 0)
- return 1;
-
char *tctx = NULL;
int result = 0;
diff --git a/init/readme.txt b/init/readme.txt
index c213041..4dda340 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -60,36 +60,36 @@
runs the service.
critical
- This is a device-critical service. If it exits more than four times in
- four minutes, the device will reboot into recovery mode.
+ This is a device-critical service. If it exits more than four times in
+ four minutes, the device will reboot into recovery mode.
disabled
- This service will not automatically start with its class.
- It must be explicitly started by name.
+ This service will not automatically start with its class.
+ It must be explicitly started by name.
setenv <name> <value>
- Set the environment variable <name> to <value> in the launched process.
+ Set the environment variable <name> to <value> in the launched process.
socket <name> <type> <perm> [ <user> [ <group> [ <seclabel> ] ] ]
- Create a unix domain socket named /dev/socket/<name> and pass
- its fd to the launched process. <type> must be "dgram", "stream" or "seqpacket".
- User and group default to 0.
- 'seclabel' is the SELinux security context for the socket.
- It defaults to the service security context, as specified by seclabel or
- computed based on the service executable file security context.
+ Create a unix domain socket named /dev/socket/<name> and pass
+ its fd to the launched process. <type> must be "dgram", "stream" or "seqpacket".
+ User and group default to 0.
+ 'seclabel' is the SELinux security context for the socket.
+ It defaults to the service security context, as specified by seclabel or
+ computed based on the service executable file security context.
user <username>
- Change to username before exec'ing this service.
- Currently defaults to root. (??? probably should default to nobody)
- Currently, if your process requires linux capabilities then you cannot use
- this command. You must instead request the capabilities in-process while
- still root, and then drop to your desired uid.
+ Change to username before exec'ing this service.
+ Currently defaults to root. (??? probably should default to nobody)
+ Currently, if your process requires linux capabilities then you cannot use
+ this command. You must instead request the capabilities in-process while
+ still root, and then drop to your desired uid.
group <groupname> [ <groupname> ]*
- Change to groupname before exec'ing this service. Additional
- groupnames beyond the (required) first one are used to set the
- supplemental groups of the process (via setgroups()).
- Currently defaults to root. (??? probably should default to nobody)
+ Change to groupname before exec'ing this service. Additional
+ groupnames beyond the (required) first one are used to set the
+ supplemental groups of the process (via setgroups()).
+ Currently defaults to root. (??? probably should default to nobody)
seclabel <seclabel>
Change to 'seclabel' before exec'ing this service.
@@ -99,22 +99,26 @@
If not specified and no transition is defined in policy, defaults to the init context.
oneshot
- Do not restart the service when it exits.
+ Do not restart the service when it exits.
class <name>
- Specify a class name for the service. All services in a
- named class may be started or stopped together. A service
- is in the class "default" if one is not specified via the
- class option.
+ Specify a class name for the service. All services in a
+ named class may be started or stopped together. A service
+ is in the class "default" if one is not specified via the
+ class option.
onrestart
- Execute a Command (see below) when service restarts.
+ Execute a Command (see below) when service restarts.
+
+writepid <file...>
+ Write the child's pid to the given files when it forks. Meant for
+ cgroup/cpuset usage.
Triggers
--------
- Triggers are strings which can be used to match certain kinds
- of events and used to cause an action to occur.
+Triggers are strings which can be used to match certain kinds
+of events and used to cause an action to occur.
boot
This is the first trigger that will occur when init starts
@@ -347,6 +351,29 @@
actually started init.
+Comparing two bootcharts
+------------------------
+A handy script named compare-bootcharts.py can be used to compare the
+start/end time of selected processes. The aforementioned grab-bootchart.sh
+will leave a bootchart tarball named bootchart.tgz at /tmp/android-bootchart.
+If two such barballs are preserved on the host machine under different
+directories, the script can list the timestamps differences. For example:
+
+Usage: system/core/init/compare-bootcharts.py base_bootchart_dir
+ exp_bootchart_dir
+
+process: baseline experiment (delta)
+ - Unit is ms (a jiffy is 10 ms on the system)
+------------------------------------
+/init: 50 40 (-10)
+/system/bin/surfaceflinger: 4320 4470 (+150)
+/system/bin/bootanimation: 6980 6990 (+10)
+zygote64: 10410 10640 (+230)
+zygote: 10410 10640 (+230)
+system_server: 15350 15150 (-200)
+bootanimation ends at: 33790 31230 (-2560)
+
+
Debugging init
--------------
By default, programs executed by init will drop stdout and stderr into
diff --git a/init/util.cpp b/init/util.cpp
index 8216892..7f29e94 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -47,7 +47,7 @@
/*
* android_name_to_id - returns the integer uid/gid associated with the given
- * name, or -1U on error.
+ * name, or UINT_MAX on error.
*/
static unsigned int android_name_to_id(const char *name)
{
@@ -59,27 +59,35 @@
return info[n].aid;
}
- return -1U;
+ return UINT_MAX;
}
-/*
- * decode_uid - decodes and returns the given string, which can be either the
- * numeric or name representation, into the integer uid or gid. Returns -1U on
- * error.
- */
-unsigned int decode_uid(const char *s)
+static unsigned int do_decode_uid(const char *s)
{
unsigned int v;
if (!s || *s == '\0')
- return -1U;
+ return UINT_MAX;
if (isalpha(s[0]))
return android_name_to_id(s);
errno = 0;
v = (unsigned int) strtoul(s, 0, 0);
if (errno)
- return -1U;
+ return UINT_MAX;
+ return v;
+}
+
+/*
+ * decode_uid - decodes and returns the given string, which can be either the
+ * numeric or name representation, into the integer uid or gid. Returns
+ * UINT_MAX on error.
+ */
+unsigned int decode_uid(const char *s) {
+ unsigned int v = do_decode_uid(s);
+ if (v == UINT_MAX) {
+ ERROR("decode_uid: Unable to find UID for '%s'. Returning UINT_MAX\n", s);
+ }
return v;
}
diff --git a/init/util_test.cpp b/init/util_test.cpp
index 5b3ab50..228954b 100644
--- a/init/util_test.cpp
+++ b/init/util_test.cpp
@@ -38,6 +38,6 @@
TEST(util, decode_uid) {
EXPECT_EQ(0U, decode_uid("root"));
- EXPECT_EQ(-1U, decode_uid("toot"));
+ EXPECT_EQ(UINT_MAX, decode_uid("toot"));
EXPECT_EQ(123U, decode_uid("123"));
}
diff --git a/libbacktrace/BacktracePtrace.cpp b/libbacktrace/BacktracePtrace.cpp
index e10cce1..fd8b713 100644
--- a/libbacktrace/BacktracePtrace.cpp
+++ b/libbacktrace/BacktracePtrace.cpp
@@ -37,8 +37,6 @@
errno = 0;
*out_value = ptrace(PTRACE_PEEKTEXT, tid, reinterpret_cast<void*>(addr), nullptr);
if (*out_value == static_cast<word_t>(-1) && errno) {
- BACK_LOGW("invalid pointer %p reading from tid %d, ptrace() strerror(errno)=%s",
- reinterpret_cast<void*>(addr), tid, strerror(errno));
return false;
}
return true;
diff --git a/liblog/Android.mk b/liblog/Android.mk
index d7766f5..ce282bd 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -68,6 +68,7 @@
LOCAL_LDLIBS := -lrt
endif
LOCAL_MULTILIB := both
+LOCAL_CXX_STL := none
include $(BUILD_HOST_SHARED_LIBRARY)
@@ -77,6 +78,8 @@
LOCAL_MODULE := liblog
LOCAL_SRC_FILES := $(liblog_target_sources)
LOCAL_CFLAGS := -Werror $(liblog_cflags)
+# AddressSanitizer runtime library depends on liblog.
+LOCAL_SANITIZE := never
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
@@ -87,6 +90,9 @@
# TODO: This is to work around b/19059885. Remove after root cause is fixed
LOCAL_LDFLAGS_arm := -Wl,--hash-style=both
+LOCAL_SANITIZE := never
+LOCAL_CXX_STL := none
+
include $(BUILD_SHARED_LIBRARY)
include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/liblog/log_is_loggable.c b/liblog/log_is_loggable.c
index 2e09192..7a8e33f 100644
--- a/liblog/log_is_loggable.c
+++ b/liblog/log_is_loggable.c
@@ -15,41 +15,158 @@
*/
#include <ctype.h>
+#include <pthread.h>
+#include <stdlib.h>
#include <string.h>
-#include <sys/system_properties.h>
+#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
+#include <sys/_system_properties.h>
#include <android/log.h>
-static int __android_log_level(const char *tag, int def)
+struct cache {
+ const prop_info *pinfo;
+ uint32_t serial;
+ char c;
+};
+
+static void refresh_cache(struct cache *cache, const char *key)
{
+ uint32_t serial;
char buf[PROP_VALUE_MAX];
- if (!tag || !*tag) {
- return def;
+ if (!cache->pinfo) {
+ cache->pinfo = __system_property_find(key);
+ if (!cache->pinfo) {
+ return;
+ }
}
- {
- static const char log_namespace[] = "persist.log.tag.";
- char key[sizeof(log_namespace) + strlen(tag)];
+ serial = __system_property_serial(cache->pinfo);
+ if (serial == cache->serial) {
+ return;
+ }
+ cache->serial = serial;
+ __system_property_read(cache->pinfo, 0, buf);
+ cache->c = buf[0];
+}
- strcpy(key, log_namespace);
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+
+static int __android_log_level(const char *tag, int def)
+{
+ /* sizeof() is used on this array below */
+ static const char log_namespace[] = "persist.log.tag.";
+ static const size_t base_offset = 8; /* skip "persist." */
+ /* calculate the size of our key temporary buffer */
+ const size_t taglen = (tag && *tag) ? strlen(tag) : 0;
+ /* sizeof(log_namespace) = strlen(log_namespace) + 1 */
+ char key[sizeof(log_namespace) + taglen];
+ char *kp;
+ size_t i;
+ char c = 0;
+ /*
+ * Single layer cache of four properties. Priorities are:
+ * log.tag.<tag>
+ * persist.log.tag.<tag>
+ * log.tag
+ * persist.log.tag
+ * Where the missing tag matches all tags and becomes the
+ * system global default. We do not support ro.log.tag* .
+ */
+ static char *last_tag;
+ static uint32_t global_serial;
+ uint32_t current_global_serial;
+ static struct cache tag_cache[2] = {
+ { NULL, -1, 0 },
+ { NULL, -1, 0 }
+ };
+ static struct cache global_cache[2] = {
+ { NULL, -1, 0 },
+ { NULL, -1, 0 }
+ };
+
+ strcpy(key, log_namespace);
+
+ pthread_mutex_lock(&lock);
+
+ current_global_serial = __system_property_area_serial();
+
+ if (taglen) {
+ uint32_t current_local_serial = current_global_serial;
+
+ if (!last_tag || strcmp(last_tag, tag)) {
+ /* invalidate log.tag.<tag> cache */
+ for(i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
+ tag_cache[i].pinfo = NULL;
+ tag_cache[i].serial = -1;
+ tag_cache[i].c = '\0';
+ }
+ free(last_tag);
+ last_tag = NULL;
+ current_global_serial = -1;
+ }
+ if (!last_tag) {
+ last_tag = strdup(tag);
+ }
strcpy(key + sizeof(log_namespace) - 1, tag);
- if (__system_property_get(key + 8, buf) <= 0) {
- buf[0] = '\0';
- }
- if (!buf[0] && __system_property_get(key, buf) <= 0) {
- buf[0] = '\0';
+ kp = key;
+ for(i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
+ if (current_local_serial != global_serial) {
+ refresh_cache(&tag_cache[i], kp);
+ }
+
+ if (tag_cache[i].c) {
+ c = tag_cache[i].c;
+ break;
+ }
+
+ kp = key + base_offset;
}
}
- switch (toupper(buf[0])) {
- case 'V': return ANDROID_LOG_VERBOSE;
- case 'D': return ANDROID_LOG_DEBUG;
- case 'I': return ANDROID_LOG_INFO;
- case 'W': return ANDROID_LOG_WARN;
- case 'E': return ANDROID_LOG_ERROR;
- case 'F': /* FALLTHRU */ /* Not officially supported */
- case 'A': return ANDROID_LOG_FATAL;
- case 'S': return -1; /* ANDROID_LOG_SUPPRESS */
+
+ switch (toupper(c)) { /* if invalid, resort to global */
+ case 'V':
+ case 'D':
+ case 'I':
+ case 'W':
+ case 'E':
+ case 'F': /* Not officially supported */
+ case 'A':
+ case 'S':
+ break;
+ default:
+ /* clear '.' after log.tag */
+ key[sizeof(log_namespace) - 2] = '\0';
+
+ kp = key;
+ for(i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) {
+ if (current_global_serial != global_serial) {
+ refresh_cache(&global_cache[i], kp);
+ }
+
+ if (global_cache[i].c) {
+ c = global_cache[i].c;
+ break;
+ }
+
+ kp = key + base_offset;
+ }
+ break;
+ }
+
+ global_serial = current_global_serial;
+
+ pthread_mutex_unlock(&lock);
+
+ switch (toupper(c)) {
+ case 'V': return ANDROID_LOG_VERBOSE;
+ case 'D': return ANDROID_LOG_DEBUG;
+ case 'I': return ANDROID_LOG_INFO;
+ case 'W': return ANDROID_LOG_WARN;
+ case 'E': return ANDROID_LOG_ERROR;
+ case 'F': /* FALLTHRU */ /* Not officially supported */
+ case 'A': return ANDROID_LOG_FATAL;
+ case 'S': return -1; /* ANDROID_LOG_SUPPRESS */
}
return def;
}
diff --git a/liblog/tests/Android.mk b/liblog/tests/Android.mk
index d75bbc9..a407c50 100644
--- a/liblog/tests/Android.mk
+++ b/liblog/tests/Android.mk
@@ -77,6 +77,6 @@
LOCAL_MODULE := $(test_module_prefix)unit-tests
LOCAL_MODULE_TAGS := $(test_tags)
LOCAL_CFLAGS += $(test_c_flags)
-LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_SHARED_LIBRARIES := liblog libcutils
LOCAL_SRC_FILES := $(test_src_files)
include $(BUILD_NATIVE_TEST)
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 33f6481..abe0239 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -17,6 +17,8 @@
#include <fcntl.h>
#include <inttypes.h>
#include <signal.h>
+
+#include <cutils/properties.h>
#include <gtest/gtest.h>
#include <log/log.h>
#include <log/logger.h>
@@ -439,6 +441,7 @@
LOG_FAILURE_RETRY(__android_log_buf_write(LOG_ID_SYSTEM, ANDROID_LOG_INFO,
tag, max_payload_buf));
+ sleep(2);
struct logger_list *logger_list;
@@ -603,10 +606,14 @@
if (id != android_name_to_log_id(name)) {
continue;
}
+ fprintf(stderr, "log buffer %s\r", name);
struct logger * logger;
EXPECT_TRUE(NULL != (logger = android_logger_open(logger_list, id)));
EXPECT_EQ(id, android_logger_get_id(logger));
- EXPECT_LT(0, android_logger_get_log_size(logger));
+ /* crash buffer is allowed to be empty, that is actually healthy! */
+ if (android_logger_get_log_size(logger) || strcmp("crash", name)) {
+ EXPECT_LT(0, android_logger_get_log_size(logger));
+ }
EXPECT_LT(0, android_logger_get_log_readable_size(logger));
EXPECT_LT(0, android_logger_get_log_version(logger));
}
@@ -682,3 +689,190 @@
android_log_format_free(p_format);
}
+
+TEST(liblog, is_loggable) {
+ static const char tag[] = "is_loggable";
+ static const char log_namespace[] = "persist.log.tag.";
+ static const size_t base_offset = 8; /* skip "persist." */
+ // sizeof("string") = strlen("string") + 1
+ char key[sizeof(log_namespace) + sizeof(tag) - 1];
+ char hold[4][PROP_VALUE_MAX];
+ static const struct {
+ int level;
+ char type;
+ } levels[] = {
+ { ANDROID_LOG_VERBOSE, 'v' },
+ { ANDROID_LOG_DEBUG , 'd' },
+ { ANDROID_LOG_INFO , 'i' },
+ { ANDROID_LOG_WARN , 'w' },
+ { ANDROID_LOG_ERROR , 'e' },
+ { ANDROID_LOG_FATAL , 'a' },
+ { -1 , 's' },
+ { -2 , 'g' }, // Illegal value, resort to default
+ };
+
+ // Set up initial test condition
+ memset(hold, 0, sizeof(hold));
+ snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
+ property_get(key, hold[0], "");
+ property_set(key, "");
+ property_get(key + base_offset, hold[1], "");
+ property_set(key + base_offset, "");
+ strcpy(key, log_namespace);
+ key[sizeof(log_namespace) - 2] = '\0';
+ property_get(key, hold[2], "");
+ property_set(key, "");
+ property_get(key, hold[3], "");
+ property_set(key + base_offset, "");
+
+ // All combinations of level and defaults
+ for(size_t i = 0; i < (sizeof(levels) / sizeof(levels[0])); ++i) {
+ if (levels[i].level == -2) {
+ continue;
+ }
+ for(size_t j = 0; j < (sizeof(levels) / sizeof(levels[0])); ++j) {
+ if (levels[j].level == -2) {
+ continue;
+ }
+ fprintf(stderr, "i=%zu j=%zu\r", i, j);
+ if ((levels[i].level < levels[j].level)
+ || (levels[j].level == -1)) {
+ EXPECT_FALSE(__android_log_is_loggable(levels[i].level, tag,
+ levels[j].level));
+ } else {
+ EXPECT_TRUE(__android_log_is_loggable(levels[i].level, tag,
+ levels[j].level));
+ }
+ }
+ }
+
+ // All combinations of level and tag and global properties
+ for(size_t i = 0; i < (sizeof(levels) / sizeof(levels[0])); ++i) {
+ if (levels[i].level == -2) {
+ continue;
+ }
+ for(size_t j = 0; j < (sizeof(levels) / sizeof(levels[0])); ++j) {
+ char buf[2];
+ buf[0] = levels[j].type;
+ buf[1] = '\0';
+
+ snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
+ fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
+ i, j, key, buf);
+ property_set(key, buf);
+ if ((levels[i].level < levels[j].level)
+ || (levels[j].level == -1)
+ || ((levels[i].level < ANDROID_LOG_DEBUG)
+ && (levels[j].level == -2))) {
+ EXPECT_FALSE(__android_log_is_loggable(levels[i].level, tag,
+ ANDROID_LOG_DEBUG));
+ } else {
+ EXPECT_TRUE(__android_log_is_loggable(levels[i].level, tag,
+ ANDROID_LOG_DEBUG));
+ }
+ property_set(key, "");
+
+ fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
+ i, j, key + base_offset, buf);
+ property_set(key + base_offset, buf);
+ if ((levels[i].level < levels[j].level)
+ || (levels[j].level == -1)
+ || ((levels[i].level < ANDROID_LOG_DEBUG)
+ && (levels[j].level == -2))) {
+ EXPECT_FALSE(__android_log_is_loggable(levels[i].level, tag,
+ ANDROID_LOG_DEBUG));
+ } else {
+ EXPECT_TRUE(__android_log_is_loggable(levels[i].level, tag,
+ ANDROID_LOG_DEBUG));
+ }
+ property_set(key + base_offset, "");
+
+ strcpy(key, log_namespace);
+ key[sizeof(log_namespace) - 2] = '\0';
+ fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
+ i, j, key, buf);
+ property_set(key, buf);
+ if ((levels[i].level < levels[j].level)
+ || (levels[j].level == -1)
+ || ((levels[i].level < ANDROID_LOG_DEBUG)
+ && (levels[j].level == -2))) {
+ EXPECT_FALSE(__android_log_is_loggable(levels[i].level, tag,
+ ANDROID_LOG_DEBUG));
+ } else {
+ EXPECT_TRUE(__android_log_is_loggable(levels[i].level, tag,
+ ANDROID_LOG_DEBUG));
+ }
+ property_set(key, "");
+
+ fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
+ i, j, key + base_offset, buf);
+ property_set(key + base_offset, buf);
+ if ((levels[i].level < levels[j].level)
+ || (levels[j].level == -1)
+ || ((levels[i].level < ANDROID_LOG_DEBUG)
+ && (levels[j].level == -2))) {
+ EXPECT_FALSE(__android_log_is_loggable(levels[i].level, tag,
+ ANDROID_LOG_DEBUG));
+ } else {
+ EXPECT_TRUE(__android_log_is_loggable(levels[i].level, tag,
+ ANDROID_LOG_DEBUG));
+ }
+ property_set(key + base_offset, "");
+ }
+ }
+
+ // All combinations of level and tag properties, but with global set to INFO
+ strcpy(key, log_namespace);
+ key[sizeof(log_namespace) - 2] = '\0';
+ property_set(key, "I");
+ snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
+ for(size_t i = 0; i < (sizeof(levels) / sizeof(levels[0])); ++i) {
+ if (levels[i].level == -2) {
+ continue;
+ }
+ for(size_t j = 0; j < (sizeof(levels) / sizeof(levels[0])); ++j) {
+ char buf[2];
+ buf[0] = levels[j].type;
+ buf[1] = '\0';
+
+ fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
+ i, j, key, buf);
+ property_set(key, buf);
+ if ((levels[i].level < levels[j].level)
+ || (levels[j].level == -1)
+ || ((levels[i].level < ANDROID_LOG_INFO) // Yes INFO
+ && (levels[j].level == -2))) {
+ EXPECT_FALSE(__android_log_is_loggable(levels[i].level, tag,
+ ANDROID_LOG_DEBUG));
+ } else {
+ EXPECT_TRUE(__android_log_is_loggable(levels[i].level, tag,
+ ANDROID_LOG_DEBUG));
+ }
+ property_set(key, "");
+
+ fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r",
+ i, j, key + base_offset, buf);
+ property_set(key + base_offset, buf);
+ if ((levels[i].level < levels[j].level)
+ || (levels[j].level == -1)
+ || ((levels[i].level < ANDROID_LOG_INFO) // Yes INFO
+ && (levels[j].level == -2))) {
+ EXPECT_FALSE(__android_log_is_loggable(levels[i].level, tag,
+ ANDROID_LOG_DEBUG));
+ } else {
+ EXPECT_TRUE(__android_log_is_loggable(levels[i].level, tag,
+ ANDROID_LOG_DEBUG));
+ }
+ property_set(key + base_offset, "");
+ }
+ }
+
+ // reset parms
+ snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
+ property_set(key, hold[0]);
+ property_set(key + base_offset, hold[1]);
+ strcpy(key, log_namespace);
+ key[sizeof(log_namespace) - 2] = '\0';
+ property_set(key, hold[2]);
+ property_set(key + base_offset, hold[3]);
+}
diff --git a/libutils/Android.mk b/libutils/Android.mk
index e9c5f89..8f829f3 100644
--- a/libutils/Android.mk
+++ b/libutils/Android.mk
@@ -91,7 +91,7 @@
liblog \
libdl
-LOCAL_MODULE:= libutils
+LOCAL_MODULE := libutils
include $(BUILD_STATIC_LIBRARY)
# For the device, shared
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index d7af34e..3716343 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -307,7 +307,7 @@
* ((4 * UINT16_MAX) / 3 + 1) which can safely fit into a uint32_t.
*/
uint32_t hash_table_size;
- ZipEntryName* hash_table;
+ ZipString* hash_table;
ZipArchive(const int fd, bool assume_ownership) :
fd(fd),
@@ -343,7 +343,7 @@
return val;
}
-static uint32_t ComputeHash(const ZipEntryName& name) {
+static uint32_t ComputeHash(const ZipString& name) {
uint32_t hash = 0;
uint16_t len = name.name_length;
const uint8_t* str = name.name;
@@ -359,16 +359,15 @@
* Convert a ZipEntry to a hash table index, verifying that it's in a
* valid range.
*/
-static int64_t EntryToIndex(const ZipEntryName* hash_table,
+static int64_t EntryToIndex(const ZipString* hash_table,
const uint32_t hash_table_size,
- const ZipEntryName& name) {
+ const ZipString& name) {
const uint32_t hash = ComputeHash(name);
// NOTE: (hash_table_size - 1) is guaranteed to be non-negative.
uint32_t ent = hash & (hash_table_size - 1);
while (hash_table[ent].name != NULL) {
- if (hash_table[ent].name_length == name.name_length &&
- memcmp(hash_table[ent].name, name.name, name.name_length) == 0) {
+ if (hash_table[ent] == name) {
return ent;
}
@@ -382,8 +381,8 @@
/*
* Add a new entry to the hash table.
*/
-static int32_t AddToHash(ZipEntryName *hash_table, const uint64_t hash_table_size,
- const ZipEntryName& name) {
+static int32_t AddToHash(ZipString *hash_table, const uint64_t hash_table_size,
+ const ZipString& name) {
const uint64_t hash = ComputeHash(name);
uint32_t ent = hash & (hash_table_size - 1);
@@ -392,8 +391,7 @@
* Further, we guarantee that the hashtable size is not 0.
*/
while (hash_table[ent].name != NULL) {
- if (hash_table[ent].name_length == name.name_length &&
- memcmp(hash_table[ent].name, name.name, name.name_length) == 0) {
+ if (hash_table[ent] == name) {
// We've found a duplicate entry. We don't accept it
ALOGW("Zip: Found duplicate entry %.*s", name.name_length, name.name);
return kDuplicateEntry;
@@ -565,8 +563,8 @@
* least one unused entry to avoid an infinite loop during creation.
*/
archive->hash_table_size = RoundUpPower2(1 + (num_entries * 4) / 3);
- archive->hash_table = reinterpret_cast<ZipEntryName*>(calloc(archive->hash_table_size,
- sizeof(ZipEntryName)));
+ archive->hash_table = reinterpret_cast<ZipString*>(calloc(archive->hash_table_size,
+ sizeof(ZipString)));
/*
* Walk through the central directory, adding entries to the hash
@@ -605,7 +603,7 @@
}
/* add the CDE filename to the hash table */
- ZipEntryName entry_name;
+ ZipString entry_name;
entry_name.name = file_name;
entry_name.name_length = file_name_length;
const int add_result = AddToHash(archive->hash_table,
@@ -851,26 +849,41 @@
uint32_t position;
// We're not using vector here because this code is used in the Windows SDK
// where the STL is not available.
- const uint8_t* prefix;
- uint16_t prefix_len;
+ ZipString prefix;
+ ZipString suffix;
ZipArchive* archive;
- IterationHandle() : prefix(NULL), prefix_len(0) {}
-
- IterationHandle(const ZipEntryName& prefix_name)
- : prefix_len(prefix_name.name_length) {
- uint8_t* prefix_copy = new uint8_t[prefix_len];
- memcpy(prefix_copy, prefix_name.name, prefix_len);
- prefix = prefix_copy;
+ IterationHandle(const ZipString* in_prefix,
+ const ZipString* in_suffix) {
+ if (in_prefix) {
+ uint8_t* name_copy = new uint8_t[in_prefix->name_length];
+ memcpy(name_copy, in_prefix->name, in_prefix->name_length);
+ prefix.name = name_copy;
+ prefix.name_length = in_prefix->name_length;
+ } else {
+ prefix.name = NULL;
+ prefix.name_length = 0;
+ }
+ if (in_suffix) {
+ uint8_t* name_copy = new uint8_t[in_suffix->name_length];
+ memcpy(name_copy, in_suffix->name, in_suffix->name_length);
+ suffix.name = name_copy;
+ suffix.name_length = in_suffix->name_length;
+ } else {
+ suffix.name = NULL;
+ suffix.name_length = 0;
+ }
}
~IterationHandle() {
- delete[] prefix;
+ delete[] prefix.name;
+ delete[] suffix.name;
}
};
int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr,
- const ZipEntryName* optional_prefix) {
+ const ZipString* optional_prefix,
+ const ZipString* optional_suffix) {
ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
if (archive == NULL || archive->hash_table == NULL) {
@@ -878,8 +891,7 @@
return kInvalidHandle;
}
- IterationHandle* cookie =
- optional_prefix != NULL ? new IterationHandle(*optional_prefix) : new IterationHandle();
+ IterationHandle* cookie = new IterationHandle(optional_prefix, optional_suffix);
cookie->position = 0;
cookie->archive = archive;
@@ -891,7 +903,7 @@
delete reinterpret_cast<IterationHandle*>(cookie);
}
-int32_t FindEntry(const ZipArchiveHandle handle, const ZipEntryName& entryName,
+int32_t FindEntry(const ZipArchiveHandle handle, const ZipString& entryName,
ZipEntry* data) {
const ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
if (entryName.name_length == 0) {
@@ -910,7 +922,7 @@
return FindEntry(archive, ent, data);
}
-int32_t Next(void* cookie, ZipEntry* data, ZipEntryName* name) {
+int32_t Next(void* cookie, ZipEntry* data, ZipString* name) {
IterationHandle* handle = reinterpret_cast<IterationHandle*>(cookie);
if (handle == NULL) {
return kInvalidHandle;
@@ -924,12 +936,14 @@
const uint32_t currentOffset = handle->position;
const uint32_t hash_table_length = archive->hash_table_size;
- const ZipEntryName *hash_table = archive->hash_table;
+ const ZipString* hash_table = archive->hash_table;
for (uint32_t i = currentOffset; i < hash_table_length; ++i) {
if (hash_table[i].name != NULL &&
- (handle->prefix_len == 0 ||
- (memcmp(handle->prefix, hash_table[i].name, handle->prefix_len) == 0))) {
+ (handle->prefix.name_length == 0 ||
+ hash_table[i].StartsWith(handle->prefix)) &&
+ (handle->suffix.name_length == 0 ||
+ hash_table[i].EndsWith(handle->suffix))) {
handle->position = (i + 1);
const int error = FindEntry(archive, i, data);
if (!error) {
@@ -1265,4 +1279,3 @@
int GetFileDescriptor(const ZipArchiveHandle handle) {
return reinterpret_cast<ZipArchive*>(handle)->fd;
}
-
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index f8952ce..9a3cdb4 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -70,7 +70,7 @@
}
static void AssertNameEquals(const std::string& name_str,
- const ZipEntryName& name) {
+ const ZipString& name) {
ASSERT_EQ(name_str.size(), name.name_length);
ASSERT_EQ(0, memcmp(name_str.c_str(), name.name, name.name_length));
}
@@ -115,10 +115,10 @@
ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
void* iteration_cookie;
- ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, NULL));
+ ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, NULL, NULL));
ZipEntry data;
- ZipEntryName name;
+ ZipString name;
// b/c.txt
ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
@@ -146,12 +146,122 @@
CloseArchive(handle);
}
+TEST(ziparchive, IterationWithPrefix) {
+ ZipArchiveHandle handle;
+ ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
+
+ void* iteration_cookie;
+ ZipString prefix("b/");
+ ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, NULL));
+
+ ZipEntry data;
+ ZipString name;
+
+ // b/c.txt
+ ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
+ AssertNameEquals("b/c.txt", name);
+
+ // b/d.txt
+ ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
+ AssertNameEquals("b/d.txt", name);
+
+ // b/
+ ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
+ AssertNameEquals("b/", name);
+
+ // End of iteration.
+ ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
+
+ CloseArchive(handle);
+}
+
+TEST(ziparchive, IterationWithSuffix) {
+ ZipArchiveHandle handle;
+ ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
+
+ void* iteration_cookie;
+ ZipString suffix(".txt");
+ ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, NULL, &suffix));
+
+ ZipEntry data;
+ ZipString name;
+
+ // b/c.txt
+ ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
+ AssertNameEquals("b/c.txt", name);
+
+ // b/d.txt
+ ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
+ AssertNameEquals("b/d.txt", name);
+
+ // a.txt
+ ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
+ AssertNameEquals("a.txt", name);
+
+ // b.txt
+ ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
+ AssertNameEquals("b.txt", name);
+
+ // End of iteration.
+ ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
+
+ CloseArchive(handle);
+}
+
+TEST(ziparchive, IterationWithPrefixAndSuffix) {
+ ZipArchiveHandle handle;
+ ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
+
+ void* iteration_cookie;
+ ZipString prefix("b");
+ ZipString suffix(".txt");
+ ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, &suffix));
+
+ ZipEntry data;
+ ZipString name;
+
+ // b/c.txt
+ ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
+ AssertNameEquals("b/c.txt", name);
+
+ // b/d.txt
+ ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
+ AssertNameEquals("b/d.txt", name);
+
+ // b.txt
+ ASSERT_EQ(0, Next(iteration_cookie, &data, &name));
+ AssertNameEquals("b.txt", name);
+
+ // End of iteration.
+ ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
+
+ CloseArchive(handle);
+}
+
+TEST(ziparchive, IterationWithBadPrefixAndSuffix) {
+ ZipArchiveHandle handle;
+ ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
+
+ void* iteration_cookie;
+ ZipString prefix("x");
+ ZipString suffix("y");
+ ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, &prefix, &suffix));
+
+ ZipEntry data;
+ ZipString name;
+
+ // End of iteration.
+ ASSERT_EQ(-1, Next(iteration_cookie, &data, &name));
+
+ CloseArchive(handle);
+}
+
TEST(ziparchive, FindEntry) {
ZipArchiveHandle handle;
ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
ZipEntry data;
- ZipEntryName name;
+ ZipString name;
name.name = kATxtName;
name.name_length = kATxtNameLength;
ASSERT_EQ(0, FindEntry(handle, name, &data));
@@ -164,7 +274,7 @@
ASSERT_EQ(0x950821c5, data.crc32);
// An entry that doesn't exist. Should be a negative return code.
- ZipEntryName absent_name;
+ ZipString absent_name;
absent_name.name = kNonexistentTxtName;
absent_name.name_length = kNonexistentTxtNameLength;
ASSERT_LT(FindEntry(handle, absent_name, &data), 0);
@@ -177,9 +287,9 @@
ASSERT_EQ(0, OpenArchiveWrapper("declaredlength.zip", &handle));
void* iteration_cookie;
- ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, NULL));
+ ASSERT_EQ(0, StartIteration(handle, &iteration_cookie, NULL, NULL));
- ZipEntryName name;
+ ZipString name;
ZipEntry data;
ASSERT_EQ(Next(iteration_cookie, &data, &name), 0);
@@ -194,7 +304,7 @@
// An entry that's deflated.
ZipEntry data;
- ZipEntryName a_name;
+ ZipString a_name;
a_name.name = kATxtName;
a_name.name_length = kATxtNameLength;
ASSERT_EQ(0, FindEntry(handle, a_name, &data));
@@ -206,7 +316,7 @@
delete[] buffer;
// An entry that's stored.
- ZipEntryName b_name;
+ ZipString b_name;
b_name.name = kBTxtName;
b_name.name_length = kBTxtNameLength;
ASSERT_EQ(0, FindEntry(handle, b_name, &data));
@@ -293,7 +403,7 @@
ASSERT_EQ(0, OpenArchiveFd(fd, "EmptyEntriesTest", &handle));
ZipEntry entry;
- ZipEntryName empty_name;
+ ZipString empty_name;
empty_name.name = kEmptyTxtName;
empty_name.name_length = kEmptyTxtNameLength;
ASSERT_EQ(0, FindEntry(handle, empty_name, &entry));
@@ -324,7 +434,7 @@
ASSERT_EQ(0, OpenArchiveFd(fd, "EntryLargerThan32KTest", &handle));
ZipEntry entry;
- ZipEntryName ab_name;
+ ZipString ab_name;
ab_name.name = kAbTxtName;
ab_name.name_length = kAbTxtNameLength;
ASSERT_EQ(0, FindEntry(handle, ab_name, &entry));
@@ -392,7 +502,7 @@
ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
ZipEntry entry;
- ZipEntryName name;
+ ZipString name;
name.name = kATxtName;
name.name_length = kATxtNameLength;
ASSERT_EQ(0, FindEntry(handle, name, &entry));
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 736e02e..e598bb8 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -14,6 +14,7 @@
#include <stdlib.h>
#include <string.h>
#include <sys/cdefs.h>
+#include <sys/resource.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -33,6 +34,7 @@
#include <log/logd.h>
#include <log/logger.h>
#include <log/logprint.h>
+#include <utils/threads.h>
#define DEFAULT_MAX_ROTATED_LOGS 4
@@ -221,6 +223,10 @@
fprintf(stderr, "failed to set to batch scheduler\n");
}
+ if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
+ fprintf(stderr, "failed set to priority\n");
+ }
+
g_outFD = openLogFile (g_outputFileName);
if (g_outFD < 0) {
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 4ec2e59..4b3547c 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -145,7 +145,9 @@
++cp;
}
tid = pid;
+ logbuf->lock();
uid = logbuf->pidToUid(pid);
+ logbuf->unlock();
memmove(pidptr, cp, strlen(cp) + 1);
}
@@ -180,14 +182,20 @@
static const char comm_str[] = " comm=\"";
const char *comm = strstr(str, comm_str);
const char *estr = str + strlen(str);
+ char *commfree = NULL;
if (comm) {
estr = comm;
comm += sizeof(comm_str) - 1;
} else if (pid == getpid()) {
pid = tid;
comm = "auditd";
- } else if (!(comm = logbuf->pidToName(pid))) {
- comm = "unknown";
+ } else {
+ logbuf->lock();
+ comm = commfree = logbuf->pidToName(pid);
+ logbuf->unlock();
+ if (!comm) {
+ comm = "unknown";
+ }
}
const char *ecomm = strchr(comm, '"');
@@ -218,6 +226,7 @@
}
}
+ free(commfree);
free(str);
if (notify) {
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 4373e2a..0f5071b 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -140,8 +140,26 @@
if ((log_id >= LOG_ID_MAX) || (log_id < 0)) {
return -EINVAL;
}
+
LogBufferElement *elem = new LogBufferElement(log_id, realtime,
uid, pid, tid, msg, len);
+ int prio = ANDROID_LOG_INFO;
+ const char *tag = NULL;
+ if (log_id == LOG_ID_EVENTS) {
+ tag = android::tagToName(elem->getTag());
+ } else {
+ prio = *msg;
+ tag = msg + 1;
+ }
+ if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
+ // Log traffic received to total
+ pthread_mutex_lock(&mLogElementsLock);
+ stats.add(elem);
+ stats.subtract(elem);
+ pthread_mutex_unlock(&mLogElementsLock);
+ delete elem;
+ return -EACCES;
+ }
pthread_mutex_lock(&mLogElementsLock);
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index 00b19b6..a13fded 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -71,10 +71,12 @@
// *strp uses malloc, use free to release.
void formatPrune(char **strp) { mPrune.format(strp); }
- // helper
+ // helper must be protected directly or implicitly by lock()/unlock()
char *pidToName(pid_t pid) { return stats.pidToName(pid); }
uid_t pidToUid(pid_t pid) { return stats.pidToUid(pid); }
char *uidToName(uid_t uid) { return stats.uidToName(uid); }
+ void lock() { pthread_mutex_lock(&mLogElementsLock); }
+ void unlock() { pthread_mutex_unlock(&mLogElementsLock); }
private:
void maybePrune(log_id_t id);
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index 8238a52..9fb1439 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -30,7 +30,7 @@
#include "LogReader.h"
const uint64_t LogBufferElement::FLUSH_ERROR(0);
-atomic_int_fast64_t LogBufferElement::sequence;
+atomic_int_fast64_t LogBufferElement::sequence(1);
LogBufferElement::LogBufferElement(log_id_t log_id, log_time realtime,
uid_t uid, pid_t pid, pid_t tid,
@@ -105,15 +105,23 @@
size_t LogBufferElement::populateDroppedMessage(char *&buffer,
LogBuffer *parent) {
static const char tag[] = "chatty";
- static const char format_uid[] = "uid=%u%s%s expire %u line%s";
+ if (!__android_log_is_loggable(ANDROID_LOG_INFO, tag, ANDROID_LOG_VERBOSE)) {
+ return 0;
+ }
+
+ static const char format_uid[] = "uid=%u%s%s expire %u line%s";
+ parent->lock();
char *name = parent->uidToName(mUid);
+ parent->unlock();
char *commName = android::tidToName(mTid);
if (!commName && (mTid != mPid)) {
commName = android::tidToName(mPid);
}
if (!commName) {
+ parent->lock();
commName = parent->pidToName(mPid);
+ parent->unlock();
}
size_t len = name ? strlen(name) : 0;
if (len && commName && !strncmp(name, commName, len)) {
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
index 7d14648..d578c04 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -45,8 +45,8 @@
}
char c;
while ((c = *s++)) {
- if (!isdigit(c) && (c == '>')) {
- return s;
+ if (!isdigit(c)) {
+ return (c == '>') ? s : NULL;
}
}
return NULL;
@@ -65,17 +65,15 @@
while ((c = *s++)) {
if ((c == '.') && first_period) {
first_period = false;
- continue;
- }
- if (!isdigit(c) && (c == ']')) {
- return s;
+ } else if (!isdigit(c)) {
+ return ((c == ']') && !first_period && (*s == ' ')) ? s : NULL;
}
}
return NULL;
}
// Like strtok_r with "\r\n" except that we look for log signatures (regex)
-// \(\(<[0-9]+>\)\([[] *[0-9]+[]]\)\{0,1\}\|[[] *[0-9]+[]]\)
+// \(\(<[0-9]+>\)\([[] *[0-9]+[.][0-9]+[]] \)\{0,1\}\|[[] *[0-9]+[.][0-9]+[]] \)
// and split if we see a second one without a newline.
#define SIGNATURE_MASK 0xF0
@@ -547,10 +545,21 @@
}
}
size_t l = etag - tag;
+ // skip leading space
while (isspace(*buf)) {
++buf;
}
- size_t n = 1 + l + 1 + strlen(buf) + 1;
+ // truncate trailing space
+ size_t b = strlen(buf);
+ while (b && isspace(buf[b-1])) {
+ --b;
+ }
+ // trick ... allow tag with empty content to be logged. log() drops empty
+ if (!b && l) {
+ buf = " ";
+ b = 1;
+ }
+ size_t n = 1 + l + 1 + b + 1;
// Allocate a buffer to hold the interpreted log message
int rc = n;
@@ -572,7 +581,8 @@
++np;
// Copy main message to the remainder
- strcpy(np, buf);
+ strncpy(np, buf, b);
+ np[b] = '\0';
// Log message
rc = logbuf->log(LOG_ID_KERNEL, now, uid, pid, tid, newstr,
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index b9e9650..760d6b2 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -334,7 +334,7 @@
// *strp = malloc, balance with free
void format(char **strp, uid_t uid, unsigned int logMask);
- // helper
+ // helper (must be locked directly or implicitly by mLogElementsLock)
char *pidToName(pid_t pid);
uid_t pidToUid(pid_t pid);
char *uidToName(uid_t uid);
diff --git a/logd/main.cpp b/logd/main.cpp
index 805cbe6..9b88983 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -27,16 +27,20 @@
#include <sys/capability.h>
#include <sys/klog.h>
#include <sys/prctl.h>
+#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <syslog.h>
#include <unistd.h>
+#include <memory>
+
#include <cutils/properties.h>
#include <cutils/sched_policy.h>
#include <cutils/sockets.h>
#include <log/event_tag_map.h>
#include <private/android_filesystem_config.h>
+#include <utils/threads.h>
#include "CommandListener.h"
#include "LogBuffer.h"
@@ -91,6 +95,10 @@
return -1;
}
+ if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
+ return -1;
+ }
+
if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
return -1;
}
@@ -156,6 +164,7 @@
static void *reinit_thread_start(void * /*obj*/) {
prctl(PR_SET_NAME, "logd.daemon");
set_sched_policy(0, SP_BACKGROUND);
+ setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND);
setgid(AID_SYSTEM);
setuid(AID_SYSTEM);
@@ -268,6 +277,45 @@
&& !property_get_bool("ro.config.low_ram", false));
}
+static void readDmesg(LogAudit *al, LogKlog *kl) {
+ if (!al && !kl) {
+ return;
+ }
+
+ int len = klogctl(KLOG_SIZE_BUFFER, NULL, 0);
+ if (len <= 0) {
+ return;
+ }
+
+ len += 1024; // Margin for additional input race or trailing nul
+ std::unique_ptr<char []> buf(new char[len]);
+
+ int rc = klogctl(KLOG_READ_ALL, buf.get(), len);
+ if (rc <= 0) {
+ return;
+ }
+
+ if (rc < len) {
+ len = rc + 1;
+ }
+ buf[len - 1] = '\0';
+
+ if (kl) {
+ kl->synchronize(buf.get());
+ }
+
+ for (char *ptr = NULL, *tok = buf.get();
+ (rc >= 0) && ((tok = log_strtok_r(tok, &ptr)));
+ tok = NULL) {
+ if (al) {
+ rc = al->log(tok);
+ }
+ if (kl) {
+ rc = kl->log(tok);
+ }
+ }
+}
+
// Foreground waits for exit of the main persistent threads
// that are started here. The threads are created to manage
// UNIX domain client sockets for writing, reading and
@@ -403,41 +451,16 @@
kl = new LogKlog(logBuf, reader, fdDmesg, fdPmesg, al != NULL);
}
- if (al || kl) {
- int len = klogctl(KLOG_SIZE_BUFFER, NULL, 0);
- if (len > 0) {
- len++;
- char buf[len];
+ readDmesg(al, kl);
- int rc = klogctl(KLOG_READ_ALL, buf, len);
+ // failure is an option ... messages are in dmesg (required by standard)
- buf[len - 1] = '\0';
+ if (kl && kl->startListener()) {
+ delete kl;
+ }
- if ((rc >= 0) && kl) {
- kl->synchronize(buf);
- }
-
- for (char *ptr = NULL, *tok = buf;
- (rc >= 0) && ((tok = log_strtok_r(tok, &ptr)));
- tok = NULL) {
- if (al) {
- rc = al->log(tok);
- }
- if (kl) {
- rc = kl->log(tok);
- }
- }
- }
-
- // failure is an option ... messages are in dmesg (required by standard)
-
- if (kl && kl->startListener()) {
- delete kl;
- }
-
- if (al && al->startListener()) {
- delete al;
- }
+ if (al && al->startListener()) {
+ delete al;
}
TEMP_FAILURE_RETRY(pause());
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 7ab76b8..05d8fe0 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -30,6 +30,11 @@
include $(BUILD_SYSTEM)/base_rules.mk
+EXPORT_GLOBAL_ASAN_OPTIONS :=
+ifeq (address,$(strip $(SANITIZE_TARGET)))
+ EXPORT_GLOBAL_ASAN_OPTIONS := export ASAN_OPTIONS allow_user_segv_handler=1:detect_odr_violation=0:alloc_dealloc_mismatch=0
+endif
+
# Regenerate init.environ.rc if PRODUCT_BOOTCLASSPATH has changed.
bcp_md5 := $(word 1, $(shell echo $(PRODUCT_BOOTCLASSPATH) $(PRODUCT_SYSTEM_SERVER_CLASSPATH) | $(MD5SUM)))
bcp_dep := $(intermediates)/$(bcp_md5).bcp.dep
@@ -41,6 +46,7 @@
@mkdir -p $(dir $@)
$(hide) sed -e 's?%BOOTCLASSPATH%?$(PRODUCT_BOOTCLASSPATH)?g' $< >$@
$(hide) sed -i -e 's?%SYSTEMSERVERCLASSPATH%?$(PRODUCT_SYSTEM_SERVER_CLASSPATH)?g' $@
+ $(hide) sed -i -e 's?%EXPORT_GLOBAL_ASAN_OPTIONS%?$(EXPORT_GLOBAL_ASAN_OPTIONS)?g' $@
bcp_md5 :=
bcp_dep :=
diff --git a/rootdir/init.environ.rc.in b/rootdir/init.environ.rc.in
index 0064790..e8b46eb 100644
--- a/rootdir/init.environ.rc.in
+++ b/rootdir/init.environ.rc.in
@@ -9,3 +9,4 @@
export LOOP_MOUNTPOINT /mnt/obb
export BOOTCLASSPATH %BOOTCLASSPATH%
export SYSTEMSERVERCLASSPATH %SYSTEMSERVERCLASSPATH%
+ %EXPORT_GLOBAL_ASAN_OPTIONS%
diff --git a/rootdir/init.rc b/rootdir/init.rc
index b5b74ea..72df0f5 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -194,9 +194,9 @@
# We restorecon /cache in case the cache partition has been reset.
restorecon_recursive /cache
- # This may have been created by the recovery system with odd permissions
- chown system cache /cache/recovery
- chmod 0770 /cache/recovery
+ # Create /cache/recovery in case it's not there. It'll also fix the odd
+ # permissions if created by the recovery system.
+ mkdir /cache/recovery 0770 system cache
#change permissions on vmallocinfo so we can grab it from bugreports
chown root log /proc/vmallocinfo
@@ -640,7 +640,12 @@
disabled
oneshot
-service pre-recovery /system/bin/uncrypt
+service uncrypt /system/bin/uncrypt
+ class main
+ disabled
+ oneshot
+
+service pre-recovery /system/bin/uncrypt --reboot
class main
disabled
oneshot