Merge "LibNativeBridge: Version 2"
diff --git a/adb/Android.mk b/adb/Android.mk
index 9b6e147..f3a4822 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -6,11 +6,18 @@
LOCAL_PATH:= $(call my-dir)
ifeq ($(HOST_OS),windows)
- adb_host_clang := false # libc++ for mingw not ready yet.
+ adb_host_clang := false # libc++ for mingw not ready yet.
else
- adb_host_clang := true
+ adb_host_clang := true
endif
+adb_version := $(shell git -C $(LOCAL_PATH) rev-parse --short=12 HEAD 2>/dev/null)-android
+
+ADB_COMMON_CFLAGS := \
+ -Wall -Werror \
+ -Wno-unused-parameter \
+ -DADB_REVISION='"$(adb_version)"' \
+
# libadb
# =========================================================
@@ -37,8 +44,7 @@
transport_test.cpp \
LIBADB_CFLAGS := \
- -Wall -Werror \
- -Wno-unused-parameter \
+ $(ADB_COMMON_CFLAGS) \
-Wno-missing-field-initializers \
-fvisibility=hidden \
@@ -103,6 +109,7 @@
LOCAL_SHARED_LIBRARIES := liblog libbase libcutils
include $(BUILD_NATIVE_TEST)
+ifneq ($(HOST_OS),windows)
include $(CLEAR_VARS)
LOCAL_CLANG := $(adb_host_clang)
LOCAL_MODULE := adb_test
@@ -115,38 +122,54 @@
libcutils \
ifeq ($(HOST_OS),linux)
- LOCAL_LDLIBS += -lrt -ldl -lpthread
+ LOCAL_LDLIBS += -lrt -ldl -lpthread
endif
ifeq ($(HOST_OS),darwin)
- LOCAL_LDLIBS += -framework CoreFoundation -framework IOKit
+ LOCAL_LDLIBS += -framework CoreFoundation -framework IOKit
endif
include $(BUILD_HOST_NATIVE_TEST)
+endif
+
+# adb device tracker (used by ddms) test tool
+# =========================================================
+
+ifeq ($(HOST_OS),linux)
+include $(CLEAR_VARS)
+LOCAL_CLANG := $(adb_host_clang)
+LOCAL_MODULE := adb_device_tracker_test
+LOCAL_CFLAGS := -DADB_HOST=1 $(LIBADB_CFLAGS)
+LOCAL_SRC_FILES := test_track_devices.cpp
+LOCAL_SHARED_LIBRARIES := liblog libbase
+LOCAL_STATIC_LIBRARIES := libadb libcrypto_static libcutils
+LOCAL_LDLIBS += -lrt -ldl -lpthread
+include $(BUILD_HOST_EXECUTABLE)
+endif
# adb host tool
# =========================================================
include $(CLEAR_VARS)
ifeq ($(HOST_OS),linux)
- LOCAL_LDLIBS += -lrt -ldl -lpthread
- LOCAL_CFLAGS += -DWORKAROUND_BUG6558362
+ LOCAL_LDLIBS += -lrt -ldl -lpthread
+ LOCAL_CFLAGS += -DWORKAROUND_BUG6558362
endif
ifeq ($(HOST_OS),darwin)
- LOCAL_LDLIBS += -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
- LOCAL_CFLAGS += -Wno-sizeof-pointer-memaccess -Wno-unused-parameter
+ LOCAL_LDLIBS += -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
+ LOCAL_CFLAGS += -Wno-sizeof-pointer-memaccess -Wno-unused-parameter
endif
ifeq ($(HOST_OS),windows)
- LOCAL_LDLIBS += -lws2_32 -lgdi32
- EXTRA_STATIC_LIBS := AdbWinApi
+ LOCAL_LDLIBS += -lws2_32 -lgdi32
+ EXTRA_STATIC_LIBS := AdbWinApi
endif
LOCAL_CLANG := $(adb_host_clang)
LOCAL_SRC_FILES := \
- adb_main.cpp \
+ client/main.cpp \
console.cpp \
commandline.cpp \
adb_client.cpp \
@@ -154,8 +177,7 @@
file_sync_client.cpp \
LOCAL_CFLAGS += \
- -Wall -Werror \
- -Wno-unused-parameter \
+ $(ADB_COMMON_CFLAGS) \
-D_GNU_SOURCE \
-DADB_HOST=1 \
@@ -199,7 +221,7 @@
LOCAL_CLANG := true
LOCAL_SRC_FILES := \
- adb_main.cpp \
+ daemon/main.cpp \
services.cpp \
file_sync_service.cpp \
framebuffer_service.cpp \
@@ -207,10 +229,9 @@
set_verity_enable_state_service.cpp \
LOCAL_CFLAGS := \
+ $(ADB_COMMON_CFLAGS) \
-DADB_HOST=0 \
-D_GNU_SOURCE \
- -Wall -Werror \
- -Wno-unused-parameter \
-Wno-deprecated-declarations \
ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
diff --git a/adb/CPPLINT.cfg b/adb/CPPLINT.cfg
index 9b906e8..f496490 100644
--- a/adb/CPPLINT.cfg
+++ b/adb/CPPLINT.cfg
@@ -1,2 +1,2 @@
set noparent
-filter=-build/header_guard,-build/include,-readability/function
+filter=-build/header_guard,-build/include,-readability/function,-whitespace/indent
diff --git a/adb/adb.cpp b/adb/adb.cpp
index e526914..3d1b7b4 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -48,9 +48,7 @@
#include <sys/mount.h>
#endif
-#if ADB_TRACE
ADB_MUTEX_DEFINE( D_lock );
-#endif
int HOST = 0;
@@ -91,10 +89,8 @@
char timestamp[PATH_MAX];
strftime(timestamp, sizeof(timestamp), "%Y-%m-%d-%H-%M-%S", &now);
- char path[PATH_MAX];
- snprintf(path, sizeof(path), "/data/adb/adb-%s-%d", timestamp, getpid());
-
- int fd = unix_open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0640);
+ std::string path = android::base::StringPrintf("/data/adb/adb-%s-%d", timestamp, getpid());
+ int fd = unix_open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0640);
if (fd == -1) {
return;
}
@@ -322,28 +318,6 @@
#endif
}
-#if !ADB_HOST
-static void send_msg_with_header(int fd, const char* msg, size_t msglen) {
- char header[5];
- if (msglen > 0xffff)
- msglen = 0xffff;
- snprintf(header, sizeof(header), "%04x", (unsigned)msglen);
- WriteFdExactly(fd, header, 4);
- WriteFdExactly(fd, msg, msglen);
-}
-#endif
-
-#if ADB_HOST
-static void send_msg_with_okay(int fd, const char* msg, size_t msglen) {
- char header[9];
- if (msglen > 0xffff)
- msglen = 0xffff;
- snprintf(header, sizeof(header), "OKAY%04x", (unsigned)msglen);
- WriteFdExactly(fd, header, 8);
- WriteFdExactly(fd, msg, msglen);
-}
-#endif // ADB_HOST
-
void send_connect(atransport *t)
{
D("Calling send_connect \n");
@@ -356,32 +330,6 @@
send_packet(cp, t);
}
-#if ADB_HOST
-static const char* connection_state_name(atransport *t)
-{
- if (t == NULL) {
- return "unknown";
- }
-
- switch(t->connection_state) {
- case CS_BOOTLOADER:
- return "bootloader";
- case CS_DEVICE:
- return "device";
- case CS_RECOVERY:
- return "recovery";
- case CS_SIDELOAD:
- return "sideload";
- case CS_OFFLINE:
- return "offline";
- case CS_UNAUTHORIZED:
- return "unauthorized";
- default:
- return "unknown";
- }
-}
-#endif // ADB_HOST
-
// qual_overwrite is used to overwrite a qualifier string. dst is a
// pointer to a char pointer. It is assumed that if *dst is non-NULL, it
// was malloc'ed and needs to freed. *dst will be set to a dup of src.
@@ -421,24 +369,24 @@
const std::string& type = pieces[0];
if (type == "bootloader") {
- D("setting connection_state to CS_BOOTLOADER\n");
- t->connection_state = CS_BOOTLOADER;
+ D("setting connection_state to kCsBootloader\n");
+ t->connection_state = kCsBootloader;
update_transports();
} else if (type == "device") {
- D("setting connection_state to CS_DEVICE\n");
- t->connection_state = CS_DEVICE;
+ D("setting connection_state to kCsDevice\n");
+ t->connection_state = kCsDevice;
update_transports();
} else if (type == "recovery") {
- D("setting connection_state to CS_RECOVERY\n");
- t->connection_state = CS_RECOVERY;
+ D("setting connection_state to kCsRecovery\n");
+ t->connection_state = kCsRecovery;
update_transports();
} else if (type == "sideload") {
- D("setting connection_state to CS_SIDELOAD\n");
- t->connection_state = CS_SIDELOAD;
+ D("setting connection_state to kCsSideload\n");
+ t->connection_state = kCsSideload;
update_transports();
} else {
- D("setting connection_state to CS_HOST\n");
- t->connection_state = CS_HOST;
+ D("setting connection_state to kCsHost\n");
+ t->connection_state = kCsHost;
}
}
@@ -458,7 +406,7 @@
send_packet(p, t);
if(HOST) send_connect(t);
} else {
- t->connection_state = CS_OFFLINE;
+ t->connection_state = kCsOffline;
handle_offline(t);
send_packet(p, t);
}
@@ -466,8 +414,8 @@
case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */
/* XXX verify version, etc */
- if(t->connection_state != CS_OFFLINE) {
- t->connection_state = CS_OFFLINE;
+ if(t->connection_state != kCsOffline) {
+ t->connection_state = kCsOffline;
handle_offline(t);
}
@@ -483,7 +431,7 @@
case A_AUTH:
if (p->msg.arg0 == ADB_AUTH_TOKEN) {
- t->connection_state = CS_UNAUTHORIZED;
+ t->connection_state = kCsUnauthorized;
t->key = adb_auth_nextkey(t->key);
if (t->key) {
send_auth_response(p->data, p->msg.data_length, t);
@@ -748,24 +696,15 @@
// Try to handle a network forwarding request.
// This returns 1 on success, 0 on failure, and -1 to indicate this is not
// a forwarding-related request.
-int handle_forward_request(const char* service, transport_type ttype, char* serial, int reply_fd)
+int handle_forward_request(const char* service, TransportType type, const char* serial, int reply_fd)
{
if (!strcmp(service, "list-forward")) {
// Create the list of forward redirections.
- int buffer_size = format_listeners(NULL, 0);
- // Add one byte for the trailing zero.
- char* buffer = reinterpret_cast<char*>(malloc(buffer_size + 1));
- if (buffer == nullptr) {
- sendfailmsg(reply_fd, "not enough memory");
- return 1;
- }
- (void) format_listeners(buffer, buffer_size + 1);
+ std::string listeners = format_listeners();
#if ADB_HOST
- send_msg_with_okay(reply_fd, buffer, buffer_size);
-#else
- send_msg_with_header(reply_fd, buffer, buffer_size);
+ SendOkay(reply_fd);
#endif
- free(buffer);
+ SendProtocolString(reply_fd, listeners);
return 1;
}
@@ -773,9 +712,9 @@
remove_all_listeners();
#if ADB_HOST
/* On the host: 1st OKAY is connect, 2nd OKAY is status */
- adb_write(reply_fd, "OKAY", 4);
+ SendOkay(reply_fd);
#endif
- adb_write(reply_fd, "OKAY", 4);
+ SendOkay(reply_fd);
return 1;
}
@@ -800,31 +739,31 @@
if (createForward) {
// Check forward: parameter format: '<local>;<remote>'
if(remote == 0) {
- sendfailmsg(reply_fd, "malformed forward spec");
+ SendFail(reply_fd, "malformed forward spec");
return 1;
}
*remote++ = 0;
if((local[0] == 0) || (remote[0] == 0) || (remote[0] == '*')) {
- sendfailmsg(reply_fd, "malformed forward spec");
+ SendFail(reply_fd, "malformed forward spec");
return 1;
}
} else {
// Check killforward: parameter format: '<local>'
if (local[0] == 0) {
- sendfailmsg(reply_fd, "malformed forward spec");
+ SendFail(reply_fd, "malformed forward spec");
return 1;
}
}
std::string error_msg;
- transport = acquire_one_transport(CS_ANY, ttype, serial, &error_msg);
+ transport = acquire_one_transport(kCsAny, type, serial, &error_msg);
if (!transport) {
- sendfailmsg(reply_fd, error_msg.c_str());
+ SendFail(reply_fd, error_msg);
return 1;
}
- install_status_t r;
+ InstallStatus r;
if (createForward) {
r = install_listener(local, remote, transport, no_rebind);
} else {
@@ -833,9 +772,9 @@
if (r == INSTALL_STATUS_OK) {
#if ADB_HOST
/* On the host: 1st OKAY is connect, 2nd OKAY is status */
- WriteFdExactly(reply_fd, "OKAY", 4);
+ SendOkay(reply_fd);
#endif
- WriteFdExactly(reply_fd, "OKAY", 4);
+ SendOkay(reply_fd);
return 1;
}
@@ -851,19 +790,18 @@
break;
case INSTALL_STATUS_LISTENER_NOT_FOUND: message = "listener not found"; break;
}
- sendfailmsg(reply_fd, message.c_str());
+ SendFail(reply_fd, message);
return 1;
}
return 0;
}
-int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s)
-{
- if(!strcmp(service, "kill")) {
- fprintf(stderr,"adb server killed by remote request\n");
+int handle_host_request(const char* service, TransportType type,
+ const char* serial, int reply_fd, asocket* s) {
+ if (strcmp(service, "kill") == 0) {
+ fprintf(stderr, "adb server killed by remote request\n");
fflush(stdout);
- adb_write(reply_fd, "OKAY", 4);
- usb_cleanup();
+ SendOkay(reply_fd);
exit(0);
}
@@ -874,7 +812,7 @@
// "transport-local:" is used for switching transport to the only local transport
// "transport-any:" is used for switching transport to the only transport
if (!strncmp(service, "transport", strlen("transport"))) {
- transport_type type = kTransportAny;
+ TransportType type = kTransportAny;
if (!strncmp(service, "transport-usb", strlen("transport-usb"))) {
type = kTransportUsb;
@@ -888,36 +826,36 @@
}
std::string error_msg = "unknown failure";
- transport = acquire_one_transport(CS_ANY, type, serial, &error_msg);
+ transport = acquire_one_transport(kCsAny, type, serial, &error_msg);
if (transport) {
s->transport = transport;
- adb_write(reply_fd, "OKAY", 4);
+ SendOkay(reply_fd);
} else {
- sendfailmsg(reply_fd, error_msg.c_str());
+ SendFail(reply_fd, error_msg);
}
return 1;
}
// return a list of all connected devices
if (!strncmp(service, "devices", 7)) {
- char buffer[4096];
- int use_long = !strcmp(service+7, "-l");
- if (use_long || service[7] == 0) {
- memset(buffer, 0, sizeof(buffer));
- D("Getting device list \n");
- list_transports(buffer, sizeof(buffer), use_long);
- D("Wrote device list \n");
- send_msg_with_okay(reply_fd, buffer, strlen(buffer));
+ bool long_listing = (strcmp(service+7, "-l") == 0);
+ if (long_listing || service[7] == 0) {
+ 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 1;
}
// remove TCP transport
if (!strncmp(service, "disconnect:", 11)) {
char buffer[4096];
memset(buffer, 0, sizeof(buffer));
- char* serial = service + 11;
+ const char* serial = service + 11;
if (serial[0] == 0) {
// disconnect from all TCP devices
unregister_all_tcp_transports();
@@ -937,34 +875,36 @@
}
}
- send_msg_with_okay(reply_fd, buffer, strlen(buffer));
+ SendOkay(reply_fd);
+ SendProtocolString(reply_fd, buffer);
return 0;
}
// returns our value for ADB_SERVER_VERSION
if (!strcmp(service, "version")) {
- char version[12];
- snprintf(version, sizeof version, "%04x", ADB_SERVER_VERSION);
- send_msg_with_okay(reply_fd, version, strlen(version));
+ SendOkay(reply_fd);
+ SendProtocolString(reply_fd, android::base::StringPrintf("%04x", ADB_SERVER_VERSION));
return 0;
}
if(!strncmp(service,"get-serialno",strlen("get-serialno"))) {
const char *out = "unknown";
- transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
+ transport = acquire_one_transport(kCsAny, type, serial, NULL);
if (transport && transport->serial) {
out = transport->serial;
}
- send_msg_with_okay(reply_fd, out, strlen(out));
+ SendOkay(reply_fd);
+ SendProtocolString(reply_fd, out);
return 0;
}
if(!strncmp(service,"get-devpath",strlen("get-devpath"))) {
const char *out = "unknown";
- transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
+ transport = acquire_one_transport(kCsAny, type, serial, NULL);
if (transport && transport->devpath) {
out = transport->devpath;
}
- send_msg_with_okay(reply_fd, out, strlen(out));
+ SendOkay(reply_fd);
+ SendProtocolString(reply_fd, out);
return 0;
}
// indicates a new emulator instance has started
@@ -976,14 +916,14 @@
}
if(!strncmp(service,"get-state",strlen("get-state"))) {
- transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
- const char *state = connection_state_name(transport);
- send_msg_with_okay(reply_fd, state, strlen(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, ttype, serial, reply_fd);
+ int ret = handle_forward_request(service, type, serial, reply_fd);
if (ret >= 0)
return ret - 1;
return -1;
diff --git a/adb/adb.h b/adb/adb.h
index cb2cf60..e8960e3 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -161,7 +161,7 @@
** object, it's a special value used to indicate that a client wants to
** connect to a service implemented within the ADB server itself.
*/
-enum transport_type {
+enum TransportType {
kTransportUsb,
kTransportLocal,
kTransportAny,
@@ -170,6 +170,18 @@
#define TOKEN_SIZE 20
+enum ConnectionState {
+ kCsAny = -1,
+ kCsOffline = 0,
+ kCsBootloader,
+ kCsDevice,
+ kCsHost,
+ kCsRecovery,
+ kCsNoPerm, // Insufficient permissions to communicate with the device.
+ kCsSideload,
+ kCsUnauthorized,
+};
+
struct atransport
{
atransport *next;
@@ -187,7 +199,7 @@
unsigned sync_token;
int connection_state;
int online;
- transport_type type;
+ TransportType type;
/* usb handle or socket fd as needed */
usb_handle *usb;
@@ -209,6 +221,8 @@
unsigned char token[TOKEN_SIZE];
fdevent auth_fde;
unsigned failed_auth_attempts;
+
+ const char* connection_state_name() const;
};
@@ -243,8 +257,6 @@
void remove_socket(asocket *s);
void close_all_sockets(atransport *t);
-#define LOCAL_CLIENT_PREFIX "emulator-"
-
asocket *create_local_socket(int fd);
asocket *create_local_service_socket(const char *destination);
@@ -266,7 +278,7 @@
int get_available_local_transport_index();
#endif
int init_socket_transport(atransport *t, int s, int port, int local);
-void init_usb_transport(atransport *t, usb_handle *usb, int state);
+void init_usb_transport(atransport *t, usb_handle *usb, ConnectionState state);
#if ADB_HOST
atransport* find_emulator_transport_by_adb_port(int adb_port);
@@ -284,7 +296,7 @@
int create_jdwp_connection_fd(int jdwp_pid);
#endif
-int handle_forward_request(const char* service, transport_type ttype, char* serial, int reply_fd);
+int handle_forward_request(const char* service, TransportType type, const char* serial, int reply_fd);
#if !ADB_HOST
void framebuffer_service(int fd, void *cookie);
@@ -324,7 +336,6 @@
/* usb host/client interface */
void usb_init();
-void usb_cleanup();
int usb_write(usb_handle *h, const void *data, int len);
int usb_read(usb_handle *h, void *data, int len);
int usb_close(usb_handle *h);
@@ -337,27 +348,12 @@
int adb_commandline(int argc, const char **argv);
-int connection_state(atransport *t);
-
-#define CS_ANY -1
-#define CS_OFFLINE 0
-#define CS_BOOTLOADER 1
-#define CS_DEVICE 2
-#define CS_HOST 3
-#define CS_RECOVERY 4
-#define CS_NOPERM 5 /* Insufficient permissions to communicate with the device */
-#define CS_SIDELOAD 6
-#define CS_UNAUTHORIZED 7
+ConnectionState connection_state(atransport *t);
extern const char *adb_device_banner;
extern int HOST;
extern int SHELL_EXIT_NOTIFY_FD;
-enum subproc_mode {
- SUBPROC_PTY = 0,
- SUBPROC_RAW = 1,
-} ;
-
#define CHUNK_SIZE (64*1024)
#if !ADB_HOST
@@ -371,8 +367,7 @@
#define USB_FFS_ADB_IN USB_FFS_ADB_EP(ep2)
#endif
-int sendfailmsg(int fd, const char *reason);
-int handle_host_request(char *service, transport_type ttype, char* serial, int reply_fd, asocket *s);
+int handle_host_request(const char* service, TransportType type, const char* serial, int reply_fd, asocket *s);
void handle_online(atransport *t);
void handle_offline(atransport *t);
diff --git a/adb/adb_auth_host.cpp b/adb/adb_auth_host.cpp
index 510dcc2..61a3777 100644
--- a/adb/adb_auth_host.cpp
+++ b/adb/adb_auth_host.cpp
@@ -173,7 +173,7 @@
return 0;
}
- outfile = fopen(path, "we");
+ outfile = fopen(path, "w");
if (!outfile) {
D("Failed to open '%s'\n", path);
return 0;
@@ -239,7 +239,7 @@
old_mask = umask(077);
- f = fopen(file, "we");
+ f = fopen(file, "w");
if (!f) {
D("Failed to open '%s'\n", file);
umask(old_mask);
@@ -273,7 +273,7 @@
{
D("read_key '%s'\n", file);
- FILE* fp = fopen(file, "re");
+ FILE* fp = fopen(file, "r");
if (!fp) {
D("Failed to open '%s': %s\n", file, strerror(errno));
return 0;
diff --git a/adb/adb_client.cpp b/adb/adb_client.cpp
index 0b2d038..c73d737 100644
--- a/adb/adb_client.cpp
+++ b/adb/adb_client.cpp
@@ -32,16 +32,39 @@
#include <vector>
#include <base/stringprintf.h>
+#include <base/strings.h>
#include "adb_io.h"
-static transport_type __adb_transport = kTransportAny;
+static TransportType __adb_transport = kTransportAny;
static const char* __adb_serial = NULL;
static int __adb_server_port = DEFAULT_ADB_PORT;
static const char* __adb_server_name = NULL;
-void adb_set_transport(transport_type type, const char* serial)
+static std::string perror_str(const char* msg) {
+ return android::base::StringPrintf("%s: %s", msg, strerror(errno));
+}
+
+static bool ReadProtocolString(int fd, std::string* s, std::string* error) {
+ char buf[5];
+ if (!ReadFdExactly(fd, buf, 4)) {
+ *error = perror_str("protocol fault (couldn't read status length)");
+ return false;
+ }
+ buf[4] = 0;
+
+ unsigned long len = strtoul(buf, 0, 16);
+ s->resize(len, '\0');
+ if (!ReadFdExactly(fd, &(*s)[0], len)) {
+ *error = perror_str("protocol fault (couldn't read status message)");
+ return false;
+ }
+
+ return true;
+}
+
+void adb_set_transport(TransportType type, const char* serial)
{
__adb_transport = type;
__adb_serial = serial;
@@ -57,58 +80,6 @@
__adb_server_name = hostname;
}
-int adb_get_emulator_console_port(void)
-{
- const char* serial = __adb_serial;
- int port;
-
- if (serial == NULL) {
- /* if no specific device was specified, we need to look at */
- /* the list of connected devices, and extract an emulator */
- /* name from it. two emulators is an error */
- std::string error;
- char* tmp = adb_query("host:devices", &error);
- char* p = tmp;
- if (!tmp) {
- printf("no emulator connected: %s\n", error.c_str());
- return -1;
- }
- while (*p) {
- char* q = strchr(p, '\n');
- if (q != NULL)
- *q++ = 0;
- else
- q = p + strlen(p);
-
- if (!memcmp(p, LOCAL_CLIENT_PREFIX, sizeof(LOCAL_CLIENT_PREFIX)-1)) {
- if (serial != NULL) { /* more than one emulator listed */
- free(tmp);
- return -2;
- }
- serial = p;
- }
-
- p = q;
- }
- free(tmp);
-
- if (serial == NULL)
- return -1; /* no emulator found */
- }
- else {
- if (memcmp(serial, LOCAL_CLIENT_PREFIX, sizeof(LOCAL_CLIENT_PREFIX)-1) != 0)
- return -1; /* not an emulator */
- }
-
- serial += sizeof(LOCAL_CLIENT_PREFIX)-1;
- port = strtol(serial, NULL, 10);
- return port;
-}
-
-std::string perror_str(const char* msg) {
- return android::base::StringPrintf("%s: %s", msg, strerror(errno));
-}
-
static int switch_socket_transport(int fd, std::string* error) {
std::string service;
if (__adb_serial) {
@@ -134,9 +105,7 @@
service += transport_type;
}
- char tmp[5];
- snprintf(tmp, sizeof(tmp), "%04zx", service.size());
- if (!WriteFdExactly(fd, tmp, 4) || !WriteFdExactly(fd, service.c_str(), service.size())) {
+ if (!SendProtocolString(fd, service)) {
*error = perror_str("write failure during connection");
adb_close(fd);
return -1;
@@ -154,7 +123,6 @@
bool adb_status(int fd, std::string* error) {
char buf[5];
-
if (!ReadFdExactly(fd, buf, 4)) {
*error = perror_str("protocol fault (couldn't read status)");
return false;
@@ -170,47 +138,34 @@
return false;
}
- if (!ReadFdExactly(fd, buf, 4)) {
- *error = perror_str("protocol fault (couldn't read status length)");
- return false;
- }
- buf[4] = 0;
-
- unsigned long len = strtoul(buf, 0, 16);
- error->resize(len + 1, '\0'); // Ensure NUL-termination.
- if (!ReadFdExactly(fd, &(*error)[0], len)) {
- *error = perror_str("protocol fault (couldn't read status message)");
- }
+ ReadProtocolString(fd, error, error);
return false;
}
-int _adb_connect(const char *service, std::string* error) {
- char tmp[5];
- int fd;
-
- D("_adb_connect: %s\n", service);
- size_t len = strlen(service);
- if ((len < 1) || (len > 1024)) {
- *error = android::base::StringPrintf("service name too long (%d)", static_cast<int>(len));
+int _adb_connect(const std::string& service, std::string* error) {
+ D("_adb_connect: %s\n", service.c_str());
+ if (service.empty() || service.size() > 1024) {
+ *error = android::base::StringPrintf("bad service name length (%zd)",
+ service.size());
return -1;
}
- snprintf(tmp, sizeof tmp, "%04zx", len);
- if (__adb_server_name)
+ int fd;
+ if (__adb_server_name) {
fd = socket_network_client(__adb_server_name, __adb_server_port, SOCK_STREAM);
- else
+ } else {
fd = socket_loopback_client(__adb_server_port, SOCK_STREAM);
-
- if(fd < 0) {
+ }
+ if (fd < 0) {
*error = perror_str("cannot connect to daemon");
return -2;
}
- if (memcmp(service,"host",4) != 0 && switch_socket_transport(fd, error)) {
+ if (memcmp(&service[0],"host",4) != 0 && switch_socket_transport(fd, error)) {
return -1;
}
- if(!WriteFdExactly(fd, tmp, 4) || !WriteFdExactly(fd, service, len)) {
+ if(!SendProtocolString(fd, service)) {
*error = perror_str("write failure during connection");
adb_close(fd);
return -1;
@@ -225,11 +180,11 @@
return fd;
}
-int adb_connect(const char* service, std::string* error) {
+int adb_connect(const std::string& service, std::string* error) {
// first query the adb server's version
int fd = _adb_connect("host:version", error);
- D("adb_connect: service %s\n", service);
+ D("adb_connect: service %s\n", service.c_str());
if (fd == -2 && __adb_server_name) {
fprintf(stderr,"** Cannot start server on remote host\n");
return fd;
@@ -248,21 +203,20 @@
// fall through to _adb_connect
} else {
// if server was running, check its version to make sure it is not out of date
- char buf[100];
- size_t n;
int version = ADB_SERVER_VERSION - 1;
// if we have a file descriptor, then parse version result
if (fd >= 0) {
- if(!ReadFdExactly(fd, buf, 4)) goto error;
+ std::string version_string;
+ if (!ReadProtocolString(fd, &version_string, error)) {
+ goto error;
+ }
- buf[4] = 0;
- n = strtoul(buf, 0, 16);
- if(n > sizeof(buf)) goto error;
- if(!ReadFdExactly(fd, buf, n)) goto error;
adb_close(fd);
- if (sscanf(buf, "%04x", &version) != 1) goto error;
+ if (sscanf(&version_string[0], "%04x", &version) != 1) {
+ goto error;
+ }
} else {
// if fd is -1, then check for "unknown host service",
// which would indicate a version of adb that does not support the version command
@@ -271,7 +225,7 @@
}
}
- if(version != ADB_SERVER_VERSION) {
+ if (version != ADB_SERVER_VERSION) {
printf("adb server is out of date. killing...\n");
fd = _adb_connect("host:kill", error);
adb_close(fd);
@@ -283,7 +237,7 @@
}
// if the command is start-server, we are done.
- if (!strcmp(service, "host:start-server")) {
+ if (service == "host:start-server") {
return 0;
}
@@ -302,7 +256,7 @@
}
-int adb_command(const char* service, std::string* error) {
+int adb_command(const std::string& service, std::string* error) {
int fd = adb_connect(service, error);
if (fd < 0) {
fprintf(stderr, "error: %s\n", error->c_str());
@@ -317,39 +271,18 @@
return 0;
}
-char* adb_query(const char* service, std::string* error) {
- char buf[5];
- unsigned long n;
- char* tmp;
-
- D("adb_query: %s\n", service);
+bool adb_query(const std::string& service, std::string* result, std::string* error) {
+ D("adb_query: %s\n", service.c_str());
int fd = adb_connect(service, error);
if (fd < 0) {
fprintf(stderr,"error: %s\n", error->c_str());
return 0;
}
- if (!ReadFdExactly(fd, buf, 4)) goto oops;
-
- buf[4] = 0;
- n = strtoul(buf, 0, 16);
- // TODO: given that we just read a 4-byte hex length 0x????, why the test?
- if (n >= 0xffff) {
- *error = "reply is too long (>= 64KiB)";
- goto oops;
- }
-
- tmp = reinterpret_cast<char*>(malloc(n + 1));
- if(tmp == 0) goto oops;
-
- if(!ReadFdExactly(fd, tmp, n) == 0) {
- tmp[n] = 0;
+ result->clear();
+ if (!ReadProtocolString(fd, result, error)) {
adb_close(fd);
- return tmp;
+ return false;
}
- free(tmp);
-
-oops:
- adb_close(fd);
- return 0;
+ return true;
}
diff --git a/adb/adb_client.h b/adb/adb_client.h
index 5ce7080..9895c49 100644
--- a/adb/adb_client.h
+++ b/adb/adb_client.h
@@ -1,3 +1,19 @@
+/*
+ * 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.
+ */
+
#ifndef _ADB_CLIENT_H_
#define _ADB_CLIENT_H_
@@ -5,51 +21,35 @@
#include <string>
-/* connect to adb, connect to the named service, and return
-** a valid fd for interacting with that service upon success
-** or a negative number on failure
-*/
-int adb_connect(const char* service, std::string* error);
-int _adb_connect(const char* service, std::string* error);
+// Connect to adb, connect to the named service, and return a valid fd for
+// interacting with that service upon success or a negative number on failure.
+int adb_connect(const std::string& service, std::string* error);
+int _adb_connect(const std::string& service, std::string* error);
-/* connect to adb, connect to the named service, return 0 if
-** the connection succeeded AND the service returned OKAY
-*/
-int adb_command(const char* service, std::string* error);
+// Connect to adb, connect to the named service, return 0 if the connection
+// succeeded AND the service returned OKAY.
+int adb_command(const std::string& service, std::string* error);
-/* connect to adb, connect to the named service, return
-** a malloc'd string of its response upon success or NULL
-** on failure.
-*/
-char* adb_query(const char* service, std::string* error);
+// Connects to the named adb service and fills 'result' with the response.
+// Returns true on success; returns false and fills 'error' on failure.
+bool adb_query(const std::string& service, std::string* result, std::string* error);
-/* Set the preferred transport to connect to.
-*/
-void adb_set_transport(transport_type type, const char* serial);
+// Set the preferred transport to connect to.
+void adb_set_transport(TransportType type, const char* serial);
-/* Set TCP specifics of the transport to use
-*/
+// Set TCP specifics of the transport to use.
void adb_set_tcp_specifics(int server_port);
-/* Set TCP Hostname of the transport to use
-*/
+// Set TCP Hostname of the transport to use.
void adb_set_tcp_name(const char* hostname);
-/* Return the console port of the currently connected emulator (if any)
- * of -1 if there is no emulator, and -2 if there is more than one.
- * assumes adb_set_transport() was alled previously...
- */
-int adb_get_emulator_console_port(void);
+// Send commands to the current emulator instance. Will fail if there is not
+// exactly one emulator connected (or if you use -s <serial> with a <serial>
+// that does not designate an emulator).
+int adb_send_emulator_command(int argc, const char** argv, const char* serial);
-/* send commands to the current emulator instance. will fail if there
- * is zero, or more than one emulator connected (or if you use -s <serial>
- * with a <serial> that does not designate an emulator)
- */
-int adb_send_emulator_command(int argc, const char** argv);
-
-// Reads a standard adb status response (OKAY|FAIL) and
-// returns true in the event of OKAY, false in the event of FAIL
-// or protocol error.
+// Reads a standard adb status response (OKAY|FAIL) and returns true in the
+// event of OKAY, false in the event of FAIL or protocol error.
bool adb_status(int fd, std::string* error);
#endif
diff --git a/adb/adb_io.cpp b/adb/adb_io.cpp
index d89f304..5ae6ec3 100644
--- a/adb/adb_io.cpp
+++ b/adb/adb_io.cpp
@@ -16,20 +16,37 @@
#define TRACE_TAG TRACE_RWX
-#include "sysdeps.h"
#include "adb_io.h"
#include <unistd.h>
+#include <base/stringprintf.h>
+
#include "adb_trace.h"
-#include "transport.h"
+#include "adb_utils.h"
+#include "sysdeps.h"
+
+bool SendProtocolString(int fd, const std::string& s) {
+ int length = s.size();
+ if (length > 0xffff) {
+ length = 0xffff;
+ }
+
+ return WriteFdFmt(fd, "%04x", length) && WriteFdExactly(fd, s);
+}
+
+bool SendOkay(int fd) {
+ return WriteFdExactly(fd, "OKAY", 4);
+}
+
+bool SendFail(int fd, const std::string& reason) {
+ return WriteFdExactly(fd, "FAIL", 4) && SendProtocolString(fd, reason);
+}
bool ReadFdExactly(int fd, void* buf, size_t len) {
char* p = reinterpret_cast<char*>(buf);
-#if ADB_TRACE
size_t len0 = len;
-#endif
D("readx: fd=%d wanted=%zu\n", fd, len);
while (len > 0) {
@@ -47,12 +64,10 @@
}
}
-#if ADB_TRACE
D("readx: fd=%d wanted=%zu got=%zu\n", fd, len0, len0 - len);
if (ADB_TRACING) {
dump_hex(reinterpret_cast<const unsigned char*>(buf), len0);
}
-#endif
return true;
}
@@ -61,12 +76,10 @@
const char* p = reinterpret_cast<const char*>(buf);
int r;
-#if ADB_TRACE
D("writex: fd=%d len=%d: ", fd, (int)len);
if (ADB_TRACING) {
dump_hex(reinterpret_cast<const unsigned char*>(buf), len);
}
-#endif
while (len > 0) {
r = adb_write(fd, p, len);
@@ -90,6 +103,21 @@
return true;
}
-bool WriteStringFully(int fd, const char* str) {
+bool WriteFdExactly(int fd, const char* str) {
return WriteFdExactly(fd, str, strlen(str));
}
+
+bool WriteFdExactly(int fd, const std::string& str) {
+ return WriteFdExactly(fd, str.c_str(), str.size());
+}
+
+bool WriteFdFmt(int fd, const char* fmt, ...) {
+ std::string str;
+
+ va_list ap;
+ va_start(ap, fmt);
+ android::base::StringAppendV(&str, fmt, ap);
+ va_end(ap);
+
+ return WriteFdExactly(fd, str);
+}
diff --git a/adb/adb_io.h b/adb/adb_io.h
index 8d237ce..8d50a6d 100644
--- a/adb/adb_io.h
+++ b/adb/adb_io.h
@@ -17,9 +17,19 @@
#ifndef ADB_IO_H
#define ADB_IO_H
-#include <stdbool.h>
#include <sys/types.h>
+#include <string>
+
+// Sends the protocol "OKAY" message.
+bool SendOkay(int fd);
+
+// Sends the protocol "FAIL" message, with the given failure reason.
+bool SendFail(int fd, const std::string& reason);
+
+// Writes a protocol-format string; a four hex digit length followed by the string data.
+bool SendProtocolString(int fd, const std::string& s);
+
/*
* Reads exactly len bytes from fd into buf.
*
@@ -37,9 +47,13 @@
* completed. If the other end of the fd (such as in a socket, pipe, or fifo),
* is closed, errno will be set to 0.
*/
-bool WriteFdExactly(int fd, const void *buf, size_t len);
+bool WriteFdExactly(int fd, const void* buf, size_t len);
-/* Same as WriteFdExactly, but with an implicit len = strlen(buf). */
-bool WriteStringFully(int fd, const char* str);
+// Same as above, but for strings.
+bool WriteFdExactly(int fd, const char* s);
+bool WriteFdExactly(int fd, const std::string& s);
+
+// Same as above, but formats the string to send.
+bool WriteFdFmt(int fd, const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3)));
#endif /* ADB_IO_H */
diff --git a/adb/adb_io_test.cpp b/adb/adb_io_test.cpp
index da340b2..8fd5cbf 100644
--- a/adb/adb_io_test.cpp
+++ b/adb/adb_io_test.cpp
@@ -139,16 +139,29 @@
ASSERT_EQ(ENOSPC, errno);
}
-TEST(io, WriteStringFully) {
+TEST(io, WriteFdExactly_string) {
const char str[] = "Foobar";
TemporaryFile tf;
ASSERT_NE(-1, tf.fd);
// Test writing a partial string to the file.
- ASSERT_TRUE(WriteStringFully(tf.fd, str)) << strerror(errno);
+ ASSERT_TRUE(WriteFdExactly(tf.fd, str)) << strerror(errno);
ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0));
std::string s;
ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s));
EXPECT_STREQ(str, s.c_str());
}
+
+TEST(io, WriteFdFmt) {
+ TemporaryFile tf;
+ ASSERT_NE(-1, tf.fd);
+
+ // Test writing a partial string to the file.
+ ASSERT_TRUE(WriteFdFmt(tf.fd, "Foo%s%d", "bar", 123)) << strerror(errno);
+ ASSERT_EQ(0, lseek(tf.fd, SEEK_SET, 0));
+
+ std::string s;
+ ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s));
+ EXPECT_STREQ("Foobar123", s.c_str());
+}
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
index a1a5ddb..cf193ab 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -19,6 +19,8 @@
#include <stdio.h>
#include <stdlib.h>
+#include <base/stringprintf.h>
+
#include "sysdeps.h"
#include "transport.h"
@@ -143,55 +145,22 @@
return -1;
}
-// Write a single line describing a listener to a user-provided buffer.
-// Appends a trailing zero, even in case of truncation, but the function
-// returns the full line length.
-// If |buffer| is NULL, does not write but returns required size.
-static int format_listener(alistener* l, char* buffer, size_t buffer_len) {
- // Format is simply:
- //
- // <device-serial> " " <local-name> " " <remote-name> "\n"
- //
- int local_len = strlen(l->local_name);
- int connect_len = strlen(l->connect_to);
- int serial_len = strlen(l->transport->serial);
-
- if (buffer != NULL) {
- snprintf(buffer, buffer_len, "%s %s %s\n",
- l->transport->serial, l->local_name, l->connect_to);
- }
- // NOTE: snprintf() on Windows returns -1 in case of truncation, so
- // return the computed line length instead.
- return local_len + connect_len + serial_len + 3;
-}
-
-// Write the list of current listeners (network redirections) into a
-// user-provided buffer. Appends a trailing zero, even in case of
-// trunctaion, but return the full size in bytes.
-// If |buffer| is NULL, does not write but returns required size.
-int format_listeners(char* buf, size_t buflen)
-{
- alistener* l;
- int result = 0;
- for (l = listener_list.next; l != &listener_list; l = l->next) {
+// Write the list of current listeners (network redirections) into a string.
+std::string format_listeners() {
+ std::string result;
+ for (alistener* l = listener_list.next; l != &listener_list; l = l->next) {
// Ignore special listeners like those for *smartsocket*
- if (l->connect_to[0] == '*')
- continue;
- int len = format_listener(l, buf, buflen);
- // Ensure there is space for the trailing zero.
- result += len;
- if (buf != NULL) {
- buf += len;
- buflen -= len;
- if (buflen <= 0)
- break;
+ if (l->connect_to[0] == '*') {
+ continue;
}
+ // <device-serial> " " <local-name> " " <remote-name> "\n"
+ android::base::StringAppendF(&result, "%s %s %s\n",
+ l->transport->serial, l->local_name, l->connect_to);
}
return result;
}
-install_status_t remove_listener(const char *local_name, atransport* transport)
-{
+InstallStatus remove_listener(const char *local_name, atransport* transport) {
alistener *l;
for (l = listener_list.next; l != &listener_list; l = l->next) {
@@ -215,13 +184,13 @@
}
}
-install_status_t install_listener(const char *local_name,
+InstallStatus install_listener(const std::string& local_name,
const char *connect_to,
atransport* transport,
int no_rebind)
{
for (alistener* l = listener_list.next; l != &listener_list; l = l->next) {
- if (strcmp(local_name, l->local_name) == 0) {
+ if (local_name == l->local_name) {
char* cto;
/* can't repurpose a smartsocket */
@@ -256,7 +225,7 @@
goto nomem;
}
- listener->local_name = strdup(local_name);
+ listener->local_name = strdup(local_name.c_str());
if (listener->local_name == nullptr) {
goto nomem;
}
@@ -266,9 +235,9 @@
goto nomem;
}
- listener->fd = local_name_to_fd(local_name);
+ listener->fd = local_name_to_fd(listener->local_name);
if (listener->fd < 0) {
- printf("cannot bind '%s': %s\n", local_name, strerror(errno));
+ printf("cannot bind '%s': %s\n", listener->local_name, strerror(errno));
free(listener->local_name);
free(listener->connect_to);
free(listener);
diff --git a/adb/adb_listeners.h b/adb/adb_listeners.h
index f55fdee..9a7ded1 100644
--- a/adb/adb_listeners.h
+++ b/adb/adb_listeners.h
@@ -19,8 +19,10 @@
#include "adb.h"
+#include <string>
+
// error/status codes for install_listener.
-enum install_status_t {
+enum InstallStatus {
INSTALL_STATUS_OK = 0,
INSTALL_STATUS_INTERNAL_ERROR = -1,
INSTALL_STATUS_CANNOT_BIND = -2,
@@ -34,14 +36,14 @@
void listener_event_func(int _fd, unsigned ev, void *_l);
void ss_listener_event_func(int _fd, unsigned ev, void *_l);
-install_status_t install_listener(const char *local_name,
- const char *connect_to,
- atransport* transport,
- int no_rebind);
+InstallStatus install_listener(const std::string& local_name,
+ const char* connect_to,
+ atransport* transport,
+ int no_rebind);
-int format_listeners(char* buf, size_t buflen);
+std::string format_listeners();
-install_status_t remove_listener(const char* local_name, atransport* transport);
+InstallStatus remove_listener(const char* local_name, atransport* transport);
void remove_all_listeners(void);
#endif /* __ADB_LISTENERS_H */
diff --git a/adb/adb_main.cpp b/adb/adb_main.cpp
deleted file mode 100644
index 5acaf80..0000000
--- a/adb/adb_main.cpp
+++ /dev/null
@@ -1,411 +0,0 @@
-/*
- * 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.
- */
-
-#define TRACE_TAG TRACE_ADB
-
-#include "sysdeps.h"
-
-#include <errno.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "adb.h"
-#include "adb_auth.h"
-#include "adb_listeners.h"
-#include "transport.h"
-
-#if !ADB_HOST
-#include <getopt.h>
-#include <sys/prctl.h>
-
-#include "cutils/properties.h"
-#include "private/android_filesystem_config.h"
-#include "selinux/selinux.h"
-
-#include "qemu_tracing.h"
-#endif
-
-static void adb_cleanup(void)
-{
- usb_cleanup();
-}
-
-#if defined(_WIN32)
-static BOOL WINAPI ctrlc_handler(DWORD type)
-{
- exit(STATUS_CONTROL_C_EXIT);
- return TRUE;
-}
-#endif
-
-#if ADB_HOST
-#ifdef WORKAROUND_BUG6558362
-#include <sched.h>
-#define AFFINITY_ENVVAR "ADB_CPU_AFFINITY_BUG6558362"
-void adb_set_affinity(void)
-{
- cpu_set_t cpu_set;
- const char* cpunum_str = getenv(AFFINITY_ENVVAR);
- char* strtol_res;
- int cpu_num;
-
- if (!cpunum_str || !*cpunum_str)
- return;
- cpu_num = strtol(cpunum_str, &strtol_res, 0);
- if (*strtol_res != '\0')
- fatal("bad number (%s) in env var %s. Expecting 0..n.\n", cpunum_str, AFFINITY_ENVVAR);
-
- sched_getaffinity(0, sizeof(cpu_set), &cpu_set);
- D("orig cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]);
- CPU_ZERO(&cpu_set);
- CPU_SET(cpu_num, &cpu_set);
- sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
- sched_getaffinity(0, sizeof(cpu_set), &cpu_set);
- D("new cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]);
-}
-#endif
-#else /* ADB_HOST */
-static const char *root_seclabel = NULL;
-
-static void drop_capabilities_bounding_set_if_needed() {
-#ifdef ALLOW_ADBD_ROOT
- char value[PROPERTY_VALUE_MAX];
- property_get("ro.debuggable", value, "");
- if (strcmp(value, "1") == 0) {
- return;
- }
-#endif
- int i;
- for (i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) {
- if (i == CAP_SETUID || i == CAP_SETGID) {
- // CAP_SETUID CAP_SETGID needed by /system/bin/run-as
- continue;
- }
- int err = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
-
- // Some kernels don't have file capabilities compiled in, and
- // prctl(PR_CAPBSET_DROP) returns EINVAL. Don't automatically
- // die when we see such misconfigured kernels.
- if ((err < 0) && (errno != EINVAL)) {
- exit(1);
- }
- }
-}
-
-static bool should_drop_privileges() {
-#if defined(ALLOW_ADBD_ROOT)
- char value[PROPERTY_VALUE_MAX];
-
- // The emulator is never secure, so don't drop privileges there.
- // TODO: this seems like a bug --- shouldn't the emulator behave like a device?
- property_get("ro.kernel.qemu", value, "");
- if (strcmp(value, "1") == 0) {
- return false;
- }
-
- // The properties that affect `adb root` and `adb unroot` are ro.secure and
- // ro.debuggable. In this context the names don't make the expected behavior
- // particularly obvious.
- //
- // ro.debuggable:
- // Allowed to become root, but not necessarily the default. Set to 1 on
- // eng and userdebug builds.
- //
- // ro.secure:
- // Drop privileges by default. Set to 1 on userdebug and user builds.
- property_get("ro.secure", value, "1");
- bool ro_secure = (strcmp(value, "1") == 0);
-
- property_get("ro.debuggable", value, "");
- bool ro_debuggable = (strcmp(value, "1") == 0);
-
- // Drop privileges if ro.secure is set...
- bool drop = ro_secure;
-
- property_get("service.adb.root", value, "");
- bool adb_root = (strcmp(value, "1") == 0);
- bool adb_unroot = (strcmp(value, "0") == 0);
-
- // ...except "adb root" lets you keep privileges in a debuggable build.
- if (ro_debuggable && adb_root) {
- drop = false;
- }
-
- // ...and "adb unroot" lets you explicitly drop privileges.
- if (adb_unroot) {
- drop = true;
- }
-
- return drop;
-#else
- return true; // "adb root" not allowed, always drop privileges.
-#endif /* ALLOW_ADBD_ROOT */
-}
-#endif /* ADB_HOST */
-
-/* Constructs a local name of form tcp:port.
- * target_str points to the target string, it's content will be overwritten.
- * target_size is the capacity of the target string.
- * server_port is the port number to use for the local name.
- */
-void build_local_name(char* target_str, size_t target_size, int server_port)
-{
- snprintf(target_str, target_size, "tcp:%d", server_port);
-}
-
-void start_logging(void)
-{
-#if defined(_WIN32)
- char temp[ MAX_PATH ];
- FILE* fnul;
- FILE* flog;
-
- GetTempPath( sizeof(temp) - 8, temp );
- strcat( temp, "adb.log" );
-
- /* Win32 specific redirections */
- fnul = fopen( "NUL", "rt" );
- if (fnul != NULL)
- stdin[0] = fnul[0];
-
- flog = fopen( temp, "at" );
- if (flog == NULL)
- flog = fnul;
-
- setvbuf( flog, NULL, _IONBF, 0 );
-
- stdout[0] = flog[0];
- stderr[0] = flog[0];
- fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
-#else
- int fd;
-
- fd = unix_open("/dev/null", O_RDONLY);
- dup2(fd, 0);
- adb_close(fd);
-
- fd = unix_open("/tmp/adb.log", O_WRONLY | O_CREAT | O_APPEND, 0640);
- if(fd < 0) {
- fd = unix_open("/dev/null", O_WRONLY);
- }
- dup2(fd, 1);
- dup2(fd, 2);
- adb_close(fd);
- fprintf(stderr,"--- adb starting (pid %d) ---\n", getpid());
-#endif
-}
-
-int adb_main(int is_daemon, int server_port)
-{
-#if !ADB_HOST
- int port;
- char value[PROPERTY_VALUE_MAX];
-
- umask(000);
-#endif
-
- atexit(adb_cleanup);
-#if defined(_WIN32)
- SetConsoleCtrlHandler( ctrlc_handler, TRUE );
-#else
- // No SIGCHLD. Let the service subproc handle its children.
- signal(SIGPIPE, SIG_IGN);
-#endif
-
- init_transport_registration();
-
-#if ADB_HOST
- HOST = 1;
-
-#ifdef WORKAROUND_BUG6558362
- if(is_daemon) adb_set_affinity();
-#endif
- usb_init();
- local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
- adb_auth_init();
-
- char local_name[30];
- build_local_name(local_name, sizeof(local_name), server_port);
- if(install_listener(local_name, "*smartsocket*", NULL, 0)) {
- exit(1);
- }
-#else
- // We need to call this even if auth isn't enabled because the file
- // descriptor will always be open.
- adbd_cloexec_auth_socket();
-
- property_get("ro.adb.secure", value, "0");
- auth_enabled = !strcmp(value, "1");
- if (auth_enabled)
- 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");
- if (NULL != adb_external_storage) {
- setenv("EXTERNAL_STORAGE", adb_external_storage, 1);
- } else {
- D("Warning: ADB_EXTERNAL_STORAGE is not set. Leaving EXTERNAL_STORAGE"
- " unchanged.\n");
- }
-
- /* add extra groups:
- ** AID_ADB to access the USB driver
- ** AID_LOG to read system logs (adb logcat)
- ** AID_INPUT to diagnose input issues (getevent)
- ** AID_INET to diagnose network issues (ping)
- ** AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump)
- ** AID_SDCARD_R to allow reading from the SD card
- ** AID_SDCARD_RW to allow writing to the SD card
- ** AID_NET_BW_STATS to read out qtaguid statistics
- */
- gid_t groups[] = { AID_ADB, AID_LOG, AID_INPUT, AID_INET, AID_NET_BT,
- AID_NET_BT_ADMIN, AID_SDCARD_R, AID_SDCARD_RW,
- AID_NET_BW_STATS };
- if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
- exit(1);
- }
-
- /* don't listen on a port (default 5037) if running in secure mode */
- /* don't run as root if we are running in secure mode */
- if (should_drop_privileges()) {
- drop_capabilities_bounding_set_if_needed();
-
- /* then switch user and group to "shell" */
- if (setgid(AID_SHELL) != 0) {
- exit(1);
- }
- if (setuid(AID_SHELL) != 0) {
- exit(1);
- }
-
- D("Local port disabled\n");
- } else {
- char local_name[30];
- if ((root_seclabel != NULL) && (is_selinux_enabled() > 0)) {
- // b/12587913: fix setcon to allow const pointers
- if (setcon((char *)root_seclabel) < 0) {
- exit(1);
- }
- }
- build_local_name(local_name, sizeof(local_name), server_port);
- if(install_listener(local_name, "*smartsocket*", NULL, 0)) {
- exit(1);
- }
- }
-
- int usb = 0;
- if (access(USB_ADB_PATH, F_OK) == 0 || access(USB_FFS_ADB_EP0, F_OK) == 0) {
- // listen on USB
- usb_init();
- usb = 1;
- }
-
- // If one of these properties is set, also listen on that port
- // If one of the properties isn't set and we couldn't listen on usb,
- // listen on the default port.
- property_get("service.adb.tcp.port", value, "");
- if (!value[0]) {
- property_get("persist.adb.tcp.port", value, "");
- }
- if (sscanf(value, "%d", &port) == 1 && port > 0) {
- printf("using port=%d\n", port);
- // listen on TCP port specified by service.adb.tcp.port property
- local_init(port);
- } else if (!usb) {
- // listen on default port
- local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
- }
-
- D("adb_main(): pre init_jdwp()\n");
- init_jdwp();
- D("adb_main(): post init_jdwp()\n");
-#endif
-
- if (is_daemon)
- {
- // inform our parent that we are up and running.
-#if defined(_WIN32)
- DWORD count;
- WriteFile( GetStdHandle( STD_OUTPUT_HANDLE ), "OK\n", 3, &count, NULL );
-#else
- fprintf(stderr, "OK\n");
-#endif
- start_logging();
- }
- D("Event loop starting\n");
-
- fdevent_loop();
-
- usb_cleanup();
-
- return 0;
-}
-
-#if !ADB_HOST
-void close_stdin() {
- int fd = unix_open("/dev/null", O_RDONLY);
- if (fd == -1) {
- perror("failed to open /dev/null, stdin will remain open");
- return;
- }
- dup2(fd, 0);
- adb_close(fd);
-}
-#endif
-
-int main(int argc, char **argv) {
-#if ADB_HOST
- adb_sysdeps_init();
-#else
- close_stdin();
-#endif
- adb_trace_init();
-
-#if ADB_HOST
- D("Handling commandline()\n");
- return adb_commandline(argc - 1, const_cast<const char**>(argv + 1));
-#else
- /* If adbd runs inside the emulator this will enable adb tracing via
- * adb-debug qemud service in the emulator. */
- adb_qemu_trace_init();
- while (true) {
- int c;
- int option_index = 0;
- static struct option opts[] = {
- {"root_seclabel", required_argument, 0, 's' },
- {"device_banner", required_argument, 0, 'b' }
- };
- c = getopt_long(argc, argv, "", opts, &option_index);
- if (c == -1)
- break;
- switch (c) {
- case 's':
- root_seclabel = optarg;
- break;
- case 'b':
- adb_device_banner = optarg;
- break;
- default:
- break;
- }
- }
-
- D("Handling main()\n");
- return adb_main(0, DEFAULT_ADB_PORT);
-#endif
-}
diff --git a/adb/adb_trace.h b/adb/adb_trace.h
index 32b6ae4..63d4151 100644
--- a/adb/adb_trace.h
+++ b/adb/adb_trace.h
@@ -23,9 +23,6 @@
#include <stdio.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
@@ -45,8 +42,6 @@
TRACE_FDEVENT,
} ;
-#if ADB_TRACE
-
#if !ADB_HOST
/*
* When running inside the emulator, guest's adbd can connect to 'adb-debug'
@@ -97,19 +92,6 @@
errno = save_errno; \
} \
} while (0)
-# define DD(...) \
- do { \
- int save_errno = errno; \
- adb_mutex_lock(&D_lock); \
- fprintf(stderr, "%16s: %5d:%5lu | ", \
- __FUNCTION__, \
- getpid(), adb_thread_id()); \
- errno = save_errno; \
- fprintf(stderr, __VA_ARGS__ ); \
- fflush(stderr); \
- adb_mutex_unlock(&D_lock); \
- errno = save_errno; \
- } while (0)
#else
# define D(...) \
do { \
@@ -129,19 +111,6 @@
__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 */
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index f10c143..604bd57 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define TRACE_TAG TRACE_ADB
+
#include "adb_utils.h"
#include <stdlib.h>
@@ -21,6 +23,11 @@
#include <sys/types.h>
#include <unistd.h>
+#include <algorithm>
+
+#include <base/stringprintf.h>
+
+#include "adb_trace.h"
#include "sysdeps.h"
bool getcwd(std::string* s) {
@@ -38,11 +45,16 @@
std::string escape_arg(const std::string& s) {
std::string result = s;
- // Insert a \ before any ' in the string.
- for (auto it = result.begin(); it != result.end(); ++it) {
- if (*it == '\'') {
- it = result.insert(it, '\\') + 1;
- }
+ // Escape any ' in the string (before we single-quote the whole thing).
+ // The correct way to do this for the shell is to replace ' with '\'' --- that is,
+ // close the existing single-quoted string, escape a single single-quote, and start
+ // a new single-quoted string. Like the C preprocessor, the shell will concatenate
+ // these pieces into one string.
+ for (size_t i = 0; i < s.size(); ++i) {
+ if (s[i] == '\'') {
+ result.insert(i, "'\\'");
+ i += 2;
+ }
}
// Prefix and suffix the whole string with '.
@@ -50,3 +62,25 @@
result.push_back('\'');
return result;
}
+
+void dump_hex(const void* data, size_t byte_count) {
+ byte_count = std::min(byte_count, size_t(16));
+
+ const uint8_t* p = reinterpret_cast<const uint8_t*>(data);
+
+ std::string line;
+ for (size_t i = 0; i < byte_count; ++i) {
+ android::base::StringAppendF(&line, "%02x", p[i]);
+ }
+ line.push_back(' ');
+
+ for (size_t i = 0; i < byte_count; ++i) {
+ int c = p[i];
+ if (c < 32 || c > 127) {
+ c = '.';
+ }
+ line.push_back(c);
+ }
+
+ DR("%s\n", line.c_str());
+}
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index 4b64afa..84f7d0c 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -24,4 +24,6 @@
std::string escape_arg(const std::string& s);
+void dump_hex(const void* ptr, size_t byte_count);
+
#endif
diff --git a/adb/adb_utils_test.cpp b/adb/adb_utils_test.cpp
index a395079..052aea5 100644
--- a/adb/adb_utils_test.cpp
+++ b/adb/adb_utils_test.cpp
@@ -30,21 +30,21 @@
ASSERT_EQ(R"('abc')", escape_arg("abc"));
ASSERT_EQ(R"(' abc')", escape_arg(" abc"));
- ASSERT_EQ(R"('\'abc')", escape_arg("'abc"));
+ ASSERT_EQ(R"(''\''abc')", escape_arg("'abc"));
ASSERT_EQ(R"('"abc')", escape_arg("\"abc"));
ASSERT_EQ(R"('\abc')", escape_arg("\\abc"));
ASSERT_EQ(R"('(abc')", escape_arg("(abc"));
ASSERT_EQ(R"(')abc')", escape_arg(")abc"));
ASSERT_EQ(R"('abc abc')", escape_arg("abc abc"));
- ASSERT_EQ(R"('abc\'abc')", escape_arg("abc'abc"));
+ ASSERT_EQ(R"('abc'\''abc')", escape_arg("abc'abc"));
ASSERT_EQ(R"('abc"abc')", escape_arg("abc\"abc"));
ASSERT_EQ(R"('abc\abc')", escape_arg("abc\\abc"));
ASSERT_EQ(R"('abc(abc')", escape_arg("abc(abc"));
ASSERT_EQ(R"('abc)abc')", escape_arg("abc)abc"));
ASSERT_EQ(R"('abc ')", escape_arg("abc "));
- ASSERT_EQ(R"('abc\'')", escape_arg("abc'"));
+ ASSERT_EQ(R"('abc'\''')", escape_arg("abc'"));
ASSERT_EQ(R"('abc"')", escape_arg("abc\""));
ASSERT_EQ(R"('abc\')", escape_arg("abc\\"));
ASSERT_EQ(R"('abc(')", escape_arg("abc("));
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
new file mode 100644
index 0000000..f48182d
--- /dev/null
+++ b/adb/client/main.cpp
@@ -0,0 +1,184 @@
+/*
+ * 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.
+ */
+
+#define TRACE_TAG TRACE_ADB
+
+#include "sysdeps.h"
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+// We only build the affinity WAR code for Linux.
+#if defined(__linux__)
+#include <sched.h>
+#endif
+
+#include "base/file.h"
+#include "base/logging.h"
+#include "base/stringprintf.h"
+
+#include "adb.h"
+#include "adb_auth.h"
+#include "adb_listeners.h"
+#include "transport.h"
+
+#if defined(WORKAROUND_BUG6558362) && defined(__linux__)
+static const bool kWorkaroundBug6558362 = true;
+#else
+static const bool kWorkaroundBug6558362 = false;
+#endif
+
+static void adb_workaround_affinity(void) {
+#if defined(__linux__)
+ const char affinity_env[] = "ADB_CPU_AFFINITY_BUG6558362";
+ const char* cpunum_str = getenv(affinity_env);
+ if (cpunum_str == nullptr || *cpunum_str == '\0') {
+ return;
+ }
+
+ char* strtol_res;
+ int cpu_num = strtol(cpunum_str, &strtol_res, 0);
+ if (*strtol_res != '\0') {
+ fatal("bad number (%s) in env var %s. Expecting 0..n.\n", cpunum_str,
+ affinity_env);
+ }
+
+ cpu_set_t cpu_set;
+ sched_getaffinity(0, sizeof(cpu_set), &cpu_set);
+ D("orig cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]);
+
+ CPU_ZERO(&cpu_set);
+ CPU_SET(cpu_num, &cpu_set);
+ sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
+
+ sched_getaffinity(0, sizeof(cpu_set), &cpu_set);
+ D("new cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]);
+#else
+ // No workaround was ever implemented for the other platforms.
+#endif
+}
+
+#if defined(_WIN32)
+static const char kNullFileName[] = "NUL";
+
+static BOOL WINAPI ctrlc_handler(DWORD type) {
+ exit(STATUS_CONTROL_C_EXIT);
+ return TRUE;
+}
+
+static std::string GetLogFilePath() {
+ const char log_name[] = "adb.log";
+ char temp_path[MAX_PATH - sizeof(log_name) + 1];
+
+ // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364992%28v=vs.85%29.aspx
+ DWORD nchars = GetTempPath(sizeof(temp_path), temp_path);
+ CHECK_LE(nchars, sizeof(temp_path));
+ if (nchars == 0) {
+ // TODO(danalbert): Log the error message from FormatError().
+ // Windows unfortunately has two errnos, errno and GetLastError(), so
+ // I'm not sure what to do about PLOG here. Probably better to just
+ // ignore it and add a simplified version of FormatError() for use in
+ // log messages.
+ LOG(ERROR) << "Error creating log file";
+ }
+
+ return std::string(temp_path) + log_name;
+}
+#else
+static const char kNullFileName[] = "/dev/null";
+
+static std::string GetLogFilePath() {
+ return std::string("/tmp/adb.log");
+}
+#endif
+
+static void close_stdin() {
+ int fd = unix_open(kNullFileName, O_RDONLY);
+ CHECK_NE(fd, -1);
+ dup2(fd, STDIN_FILENO);
+ adb_close(fd);
+}
+
+static void setup_daemon_logging(void) {
+ int fd = unix_open(GetLogFilePath().c_str(), O_WRONLY | O_CREAT | O_APPEND,
+ 0640);
+ if (fd == -1) {
+ fd = unix_open(kNullFileName, O_WRONLY);
+ }
+ dup2(fd, STDOUT_FILENO);
+ dup2(fd, STDERR_FILENO);
+ adb_close(fd);
+ fprintf(stderr, "--- adb starting (pid %d) ---\n", getpid());
+}
+
+int adb_main(int is_daemon, int server_port) {
+ HOST = 1;
+
+#if defined(_WIN32)
+ SetConsoleCtrlHandler(ctrlc_handler, TRUE);
+#else
+ signal(SIGPIPE, SIG_IGN);
+#endif
+
+ init_transport_registration();
+
+ if (kWorkaroundBug6558362 && is_daemon) {
+ adb_workaround_affinity();
+ }
+
+ usb_init();
+ local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
+ adb_auth_init();
+
+ std::string local_name = android::base::StringPrintf("tcp:%d", server_port);
+ if (install_listener(local_name, "*smartsocket*", nullptr, 0)) {
+ LOG(FATAL) << "Could not install *smartsocket* listener";
+ }
+
+ if (is_daemon) {
+ // Inform our parent that we are up and running.
+ // TODO(danalbert): Can't use SendOkay because we're sending "OK\n", not
+ // "OKAY".
+ // TODO(danalbert): Why do we use stdout for Windows?
+#if defined(_WIN32)
+ int reply_fd = STDOUT_FILENO;
+ // Change stdout mode to binary so \n => \r\n translation does not
+ // occur. In a moment stdout will be reopened to the daemon log file
+ // anyway.
+ _setmode(reply_fd, _O_BINARY);
+#else
+ int reply_fd = STDERR_FILENO;
+#endif
+ android::base::WriteStringToFd("OK\n", reply_fd);
+ close_stdin();
+ setup_daemon_logging();
+ }
+
+ D("Event loop starting\n");
+ fdevent_loop();
+
+ return 0;
+}
+
+int main(int argc, char** argv) {
+ adb_sysdeps_init();
+
+ android::base::InitLogging(argv);
+ adb_trace_init();
+ D("Handling commandline()\n");
+ return adb_commandline(argc - 1, const_cast<const char**>(argv + 1));
+}
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index b5015ea..d7bee91 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -47,14 +47,9 @@
#include "adb_utils.h"
#include "file_sync_service.h"
-static int do_cmd(transport_type ttype, const char* serial, const char *cmd, ...);
-
-static int install_app(transport_type transport, const char* serial, int argc,
- const char** argv);
-static int install_multiple_app(transport_type transport, const char* serial, int argc,
- const char** argv);
-static int uninstall_app(transport_type transport, const char* serial, int argc,
- const char** argv);
+static int install_app(TransportType t, const char* serial, int argc, const char** argv);
+static int install_multiple_app(TransportType t, const char* serial, int argc, const char** argv);
+static int uninstall_app(TransportType t, const char* serial, int argc, const char** argv);
static std::string gProductOutPath;
extern int gListenAll;
@@ -71,8 +66,8 @@
}
static void version(FILE* out) {
- fprintf(out, "Android Debug Bridge version %d.%d.%d\n",
- ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION);
+ fprintf(out, "Android Debug Bridge version %d.%d.%d\nRevision %s\n",
+ ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION, ADB_REVISION);
}
static void help() {
@@ -201,7 +196,6 @@
" adb get-state - prints: offline | bootloader | device\n"
" 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, /vendor (if present) and /oem (if present) partitions on the device read-write\n"
" adb reboot [bootloader|recovery]\n"
" - reboots the device, optionally into the bootloader or recovery program.\n"
@@ -269,23 +263,16 @@
}
#endif
-static void read_and_dump(int fd)
-{
- char buf[4096];
- int len;
-
- while(fd >= 0) {
+static void read_and_dump(int fd) {
+ while (fd >= 0) {
D("read_and_dump(): pre adb_read(fd=%d)\n", fd);
- len = adb_read(fd, buf, 4096);
+ char buf[BUFSIZ];
+ int len = adb_read(fd, buf, sizeof(buf));
D("read_and_dump(): post adb_read(fd=%d): len=%d\n", fd, len);
- if(len == 0) {
+ if (len <= 0) {
break;
}
- if(len < 0) {
- if(errno == EINTR) continue;
- break;
- }
fwrite(buf, 1, len, stdout);
fflush(stdout);
}
@@ -409,7 +396,6 @@
}
static int interactive_shell() {
- adb_thread_t thr;
int fdi;
std::string error;
@@ -430,38 +416,33 @@
fds[1] = fdi;
stdin_raw_init(fdi);
- adb_thread_create(&thr, stdin_read_thread, fds);
+
+ adb_thread_create(stdin_read_thread, fds);
read_and_dump(fd);
stdin_raw_restore(fdi);
return 0;
}
-static void format_host_command(char* buffer, size_t buflen, const char* command, transport_type ttype, const char* serial)
-{
+static std::string format_host_command(const char* command, TransportType type, const char* serial) {
if (serial) {
- snprintf(buffer, buflen, "host-serial:%s:%s", serial, command);
- } else {
- const char* prefix = "host";
- if (ttype == kTransportUsb)
- prefix = "host-usb";
- else if (ttype == kTransportLocal)
- prefix = "host-local";
-
- snprintf(buffer, buflen, "%s:%s", prefix, command);
+ return android::base::StringPrintf("host-serial:%s:%s", serial, command);
}
+
+ const char* prefix = "host";
+ if (type == kTransportUsb) {
+ prefix = "host-usb";
+ } else if (type == kTransportLocal) {
+ prefix = "host-local";
+ }
+ return android::base::StringPrintf("%s:%s", prefix, command);
}
-static int adb_download_buffer(const char *service, const char *fn, const void* data, int sz,
+static int adb_download_buffer(const char *service, const char *fn, const void* data, unsigned sz,
bool show_progress)
{
- char buf[4096];
- unsigned total;
-
- sprintf(buf,"%s:%d", service, sz);
-
std::string error;
- int fd = adb_connect(buf, &error);
+ int fd = adb_connect(android::base::StringPrintf("%s:%d", service, sz), &error);
if (fd < 0) {
fprintf(stderr,"error: %s\n", error.c_str());
return -1;
@@ -470,7 +451,7 @@
int opt = CHUNK_SIZE;
opt = adb_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt));
- total = sz;
+ unsigned total = sz;
const uint8_t* ptr = reinterpret_cast<const uint8_t*>(data);
if (show_progress) {
@@ -478,7 +459,7 @@
if(x) service = x + 1;
}
- while(sz > 0) {
+ while (sz > 0) {
unsigned xfer = (sz > CHUNK_SIZE) ? CHUNK_SIZE : sz;
if (!WriteFdExactly(fd, ptr, xfer)) {
std::string error;
@@ -497,15 +478,8 @@
printf("\n");
}
- if(!ReadFdExactly(fd, buf, 4)){
- fprintf(stderr,"* error reading response *\n");
- adb_close(fd);
- return -1;
- }
- if(memcmp(buf, "OKAY", 4)) {
- buf[4] = 0;
- fprintf(stderr,"* error response '%s' *\n", buf);
- adb_close(fd);
+ if (!adb_status(fd, &error)) {
+ fprintf(stderr,"* error response '%s' *\n", error.c_str());
return -1;
}
@@ -550,10 +524,10 @@
return -1;
}
- char buf[100];
- sprintf(buf, "sideload-host:%d:%d", sz, SIDELOAD_HOST_BLOCK_SIZE);
+ std::string service =
+ android::base::StringPrintf("sideload-host:%d:%d", sz, SIDELOAD_HOST_BLOCK_SIZE);
std::string error;
- int fd = adb_connect(buf, &error);
+ int fd = adb_connect(service, &error);
if (fd < 0) {
// Try falling back to the older sideload method. Maybe this
// is an older device that doesn't support sideload-host.
@@ -565,18 +539,19 @@
opt = adb_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt));
while (true) {
+ char buf[9];
if (!ReadFdExactly(fd, buf, 8)) {
fprintf(stderr, "* failed to read command: %s\n", strerror(errno));
status = -1;
goto done;
}
+ buf[8] = '\0';
- if (strncmp("DONEDONE", buf, 8) == 0) {
+ if (strcmp("DONEDONE", buf) == 0) {
status = 0;
break;
}
- buf[8] = '\0';
int block = strtol(buf, NULL, 10);
size_t offset = block * SIDELOAD_HOST_BLOCK_SIZE;
@@ -622,51 +597,6 @@
return status;
}
-static void status_window(transport_type ttype, const char* serial)
-{
- char command[4096];
- char *state = 0;
- char *laststate = 0;
-
- /* silence stderr */
-#ifdef _WIN32
- /* XXX: TODO */
-#else
- int fd;
- fd = unix_open("/dev/null", O_WRONLY);
- dup2(fd, 2);
- adb_close(fd);
-#endif
-
- format_host_command(command, sizeof command, "get-state", ttype, serial);
-
- while (true) {
- adb_sleep_ms(250);
-
- if (state) {
- free(state);
- state = 0;
- }
-
- std::string error;
- state = adb_query(command, &error);
-
- if (state) {
- if (laststate && !strcmp(state,laststate)){
- continue;
- } else {
- if (laststate) free(laststate);
- laststate = strdup(state);
- }
- }
-
- printf("%c[2J%c[2H", 27, 27);
- printf("Android Debug Bridge\n");
- printf("State: %s\n", state ? state : "offline");
- fflush(stdout);
- }
-}
-
/**
* Run ppp in "notty" mode against a resource listed as the first parameter
* eg:
@@ -736,18 +666,42 @@
#endif /* !defined(_WIN32) */
}
-static int send_shell_command(transport_type transport, const char* serial,
+static bool wait_for_device(const char* service, TransportType t, const char* serial) {
+ // Was the caller vague about what they'd like us to wait for?
+ // If so, check they weren't more specific in their choice of transport type.
+ if (strcmp(service, "wait-for-device") == 0) {
+ if (t == kTransportUsb) {
+ service = "wait-for-usb";
+ } else if (t == kTransportLocal) {
+ service = "wait-for-local";
+ } else {
+ service = "wait-for-any";
+ }
+ }
+
+ std::string cmd = format_host_command(service, t, serial);
+ std::string error;
+ if (adb_command(cmd, &error)) {
+ D("failure: %s *\n", error.c_str());
+ fprintf(stderr,"error: %s\n", error.c_str());
+ return false;
+ }
+
+ return true;
+}
+
+static int send_shell_command(TransportType transport_type, const char* serial,
const std::string& command) {
int fd;
while (true) {
std::string error;
- fd = adb_connect(command.c_str(), &error);
+ fd = adb_connect(command, &error);
if (fd >= 0) {
break;
}
fprintf(stderr,"- waiting for device -\n");
adb_sleep_ms(1000);
- do_cmd(transport, serial, "wait-for-device", 0);
+ wait_for_device("wait-for-device", transport_type, serial);
}
read_and_dump(fd);
@@ -758,7 +712,7 @@
return rc;
}
-static int logcat(transport_type transport, const char* serial, int argc, const char** argv) {
+static int logcat(TransportType transport, const char* serial, int argc, const char** argv) {
char* log_tags = getenv("ANDROID_LOG_TAGS");
std::string quoted = escape_arg(log_tags == nullptr ? "" : log_tags);
@@ -835,7 +789,7 @@
D("backup. filename=%s cmd=%s\n", filename, cmd.c_str());
std::string error;
- int fd = adb_connect(cmd.c_str(), &error);
+ int fd = adb_connect(cmd, &error);
if (fd < 0) {
fprintf(stderr, "adb: unable to connect for backup: %s\n", error.c_str());
adb_close(outFd);
@@ -964,29 +918,35 @@
}
}
-static int adb_connect_command(const char* command) {
+static int adb_connect_command(const std::string& command) {
std::string error;
int fd = adb_connect(command, &error);
- if (fd != -1) {
- read_and_dump(fd);
- adb_close(fd);
- return 0;
+ if (fd < 0) {
+ fprintf(stderr, "error: %s\n", error.c_str());
+ return 1;
}
- fprintf(stderr, "Error: %s\n", error.c_str());
- return 1;
+ read_and_dump(fd);
+ adb_close(fd);
+ return 0;
}
-int adb_commandline(int argc, const char **argv)
-{
- char buf[4096];
+static int adb_query_command(const std::string& command) {
+ std::string result;
+ std::string error;
+ if (!adb_query(command, &result, &error)) {
+ fprintf(stderr, "error: %s\n", error.c_str());
+ return 1;
+ }
+ printf("%s\n", result.c_str());
+ return 0;
+}
+
+int adb_commandline(int argc, const char **argv) {
int no_daemon = 0;
int is_daemon = 0;
int is_server = 0;
- int persist = 0;
int r;
- transport_type ttype = kTransportAny;
- const char* serial = NULL;
- const char* server_port_str = NULL;
+ TransportType transport_type = kTransportAny;
// If defined, this should be an absolute path to
// the directory containing all of the various system images
@@ -999,10 +959,10 @@
}
// TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
- serial = getenv("ANDROID_SERIAL");
+ const char* serial = getenv("ANDROID_SERIAL");
/* Validate and assign the server port */
- server_port_str = getenv("ANDROID_ADB_SERVER_PORT");
+ const char* server_port_str = getenv("ANDROID_ADB_SERVER_PORT");
int server_port = DEFAULT_ADB_PORT;
if (server_port_str && strlen(server_port_str) > 0) {
server_port = (int) strtol(server_port_str, NULL, 0);
@@ -1023,8 +983,6 @@
} else if (!strcmp(argv[0], "fork-server")) {
/* this is a special flag used only when the ADB client launches the ADB Server */
is_daemon = 1;
- } else if (!strcmp(argv[0],"persist")) {
- persist = 1;
} else if (!strncmp(argv[0], "-p", 2)) {
const char *product = NULL;
if (argv[0][2] == '\0') {
@@ -1050,9 +1008,9 @@
argv++;
}
} else if (!strcmp(argv[0],"-d")) {
- ttype = kTransportUsb;
+ transport_type = kTransportUsb;
} else if (!strcmp(argv[0],"-e")) {
- ttype = kTransportLocal;
+ transport_type = kTransportLocal;
} else if (!strcmp(argv[0],"-a")) {
gListenAll = 1;
} else if (!strncmp(argv[0], "-H", 2)) {
@@ -1097,7 +1055,7 @@
argv++;
}
- adb_set_transport(ttype, serial);
+ adb_set_transport(transport_type, serial);
adb_set_tcp_specifics(server_port);
if (is_server) {
@@ -1119,28 +1077,13 @@
/* handle wait-for-* prefix */
if (!strncmp(argv[0], "wait-for-", strlen("wait-for-"))) {
const char* service = argv[0];
- if (!strncmp(service, "wait-for-device", strlen("wait-for-device"))) {
- if (ttype == kTransportUsb) {
- service = "wait-for-usb";
- } else if (ttype == kTransportLocal) {
- service = "wait-for-local";
- } else {
- service = "wait-for-any";
- }
- }
- format_host_command(buf, sizeof buf, service, ttype, serial);
-
- std::string error;
- if (adb_command(buf, &error)) {
- D("failure: %s *\n", error.c_str());
- fprintf(stderr,"error: %s\n", error.c_str());
+ if (!wait_for_device(service, transport_type, serial)) {
return 1;
}
- /* Allow a command to be run after wait-for-device,
- * e.g. 'adb wait-for-device shell'.
- */
+ // Allow a command to be run after wait-for-device,
+ // e.g. 'adb wait-for-device shell'.
if (argc == 1) {
return 0;
}
@@ -1152,65 +1095,41 @@
/* adb_connect() commands */
if (!strcmp(argv[0], "devices")) {
- char *tmp;
const char *listopt;
- if (argc < 2)
+ if (argc < 2) {
listopt = "";
- else if (argc == 2 && !strcmp(argv[1], "-l"))
+ } else if (argc == 2 && !strcmp(argv[1], "-l")) {
listopt = argv[1];
- else {
+ } else {
fprintf(stderr, "Usage: adb devices [-l]\n");
return 1;
}
- snprintf(buf, sizeof buf, "host:%s%s", argv[0], listopt);
- std::string error;
- tmp = adb_query(buf, &error);
- if (tmp) {
- printf("List of devices attached \n");
- printf("%s\n", tmp);
- return 0;
- } else {
- return 1;
- }
+
+ std::string query = android::base::StringPrintf("host:%s%s", argv[0], listopt);
+ printf("List of devices attached\n");
+ return adb_query_command(query);
}
else if (!strcmp(argv[0], "connect")) {
- char *tmp;
if (argc != 2) {
fprintf(stderr, "Usage: adb connect <host>[:<port>]\n");
return 1;
}
- snprintf(buf, sizeof buf, "host:connect:%s", argv[1]);
- std::string error;
- tmp = adb_query(buf, &error);
- if (tmp) {
- printf("%s\n", tmp);
- return 0;
- } else {
- return 1;
- }
+
+ std::string query = android::base::StringPrintf("host:connect:%s", argv[1]);
+ return adb_query_command(query);
}
else if (!strcmp(argv[0], "disconnect")) {
- char *tmp;
if (argc > 2) {
fprintf(stderr, "Usage: adb disconnect [<host>[:<port>]]\n");
return 1;
}
- if (argc == 2) {
- snprintf(buf, sizeof buf, "host:disconnect:%s", argv[1]);
- } else {
- snprintf(buf, sizeof buf, "host:disconnect:");
- }
- std::string error;
- tmp = adb_query(buf, &error);
- if (tmp) {
- printf("%s\n", tmp);
- return 0;
- } else {
- return 1;
- }
+
+ std::string query = android::base::StringPrintf("host:disconnect:%s",
+ (argc == 2) ? argv[1] : "");
+ return adb_query_command(query);
}
else if (!strcmp(argv[0], "emu")) {
- return adb_send_emulator_command(argc, argv);
+ return adb_send_emulator_command(argc, argv, serial);
}
else if (!strcmp(argv[0], "shell") || !strcmp(argv[0], "hell")) {
char h = (argv[0][0] == 'h');
@@ -1231,17 +1150,18 @@
}
std::string cmd = "shell:";
- cmd += argv[1];
- argc -= 2;
- argv += 2;
+ --argc;
+ ++argv;
while (argc-- > 0) {
- cmd += " " + escape_arg(*argv++);
+ // We don't escape here, just like ssh(1). http://b/20564385.
+ cmd += *argv++;
+ if (*argv) cmd += " ";
}
while (true) {
D("interactive shell loop. cmd=%s\n", cmd.c_str());
std::string error;
- int fd = adb_connect(cmd.c_str(), &error);
+ int fd = adb_connect(cmd, &error);
int r;
if (fd >= 0) {
D("about to read_and_dump(fd=%d)\n", fd);
@@ -1254,18 +1174,12 @@
r = -1;
}
- if (persist) {
- fprintf(stderr,"\n- waiting for device -\n");
- adb_sleep_ms(1000);
- do_cmd(ttype, serial, "wait-for-device", 0);
- } else {
- if (h) {
- printf("\x1b[0m");
- fflush(stdout);
- }
- D("interactive shell loop. return r=%d\n", r);
- return r;
+ if (h) {
+ printf("\x1b[0m");
+ fflush(stdout);
}
+ D("interactive shell loop. return r=%d\n", r);
+ return r;
}
}
else if (!strcmp(argv[0], "exec-in") || !strcmp(argv[0], "exec-out")) {
@@ -1280,7 +1194,7 @@
}
std::string error;
- int fd = adb_connect(cmd.c_str(), &error);
+ int fd = adb_connect(cmd, &error);
if (fd < 0) {
fprintf(stderr, "error: %s\n", error.c_str());
return -1;
@@ -1321,23 +1235,23 @@
!strcmp(argv[0], "unroot") ||
!strcmp(argv[0], "disable-verity") ||
!strcmp(argv[0], "enable-verity")) {
- char command[100];
+ std::string command;
if (!strcmp(argv[0], "reboot-bootloader")) {
- snprintf(command, sizeof(command), "reboot:bootloader");
+ command = "reboot:bootloader";
} else if (argc > 1) {
- snprintf(command, sizeof(command), "%s:%s", argv[0], argv[1]);
+ command = android::base::StringPrintf("%s:%s", argv[0], argv[1]);
} else {
- snprintf(command, sizeof(command), "%s:", argv[0]);
+ command = android::base::StringPrintf("%s:", argv[0]);
}
return adb_connect_command(command);
}
else if (!strcmp(argv[0], "bugreport")) {
if (argc != 1) return usage();
- do_cmd(ttype, serial, "shell", "bugreport", 0);
- return 0;
+ return send_shell_command(transport_type, serial, "shell:bugreport");
}
/* adb_command() wrapper commands */
else if (!strcmp(argv[0], "forward") || !strcmp(argv[0], "reverse")) {
+ std::string cmd;
char host_prefix[64];
char reverse = (char) !strcmp(argv[0], "reverse");
char remove = 0;
@@ -1374,9 +1288,9 @@
if (serial) {
snprintf(host_prefix, sizeof host_prefix, "host-serial:%s",
serial);
- } else if (ttype == kTransportUsb) {
+ } else if (transport_type == kTransportUsb) {
snprintf(host_prefix, sizeof host_prefix, "host-usb");
- } else if (ttype == kTransportLocal) {
+ } else if (transport_type == kTransportLocal) {
snprintf(host_prefix, sizeof host_prefix, "host-local");
} else {
snprintf(host_prefix, sizeof host_prefix, "host");
@@ -1385,47 +1299,37 @@
// Implement forward --list
if (list) {
- if (argc != 1)
+ if (argc != 1) {
return usage();
- snprintf(buf, sizeof buf, "%s:list-forward", host_prefix);
- std::string error;
- char* forwards = adb_query(buf, &error);
- if (forwards == NULL) {
- fprintf(stderr, "error: %s\n", error.c_str());
- return 1;
}
- printf("%s", forwards);
- free(forwards);
- return 0;
+
+ std::string query = android::base::StringPrintf("%s:list-forward", host_prefix);
+ return adb_query_command(query);
}
// Implement forward --remove-all
else if (remove_all) {
- if (argc != 1)
- return usage();
- snprintf(buf, sizeof buf, "%s:killforward-all", host_prefix);
+ if (argc != 1) return usage();
+ cmd = android::base::StringPrintf("%s:killforward-all", host_prefix);
}
// Implement forward --remove <local>
else if (remove) {
- if (argc != 2)
- return usage();
- snprintf(buf, sizeof buf, "%s:killforward:%s", host_prefix, argv[1]);
+ if (argc != 2) return usage();
+ cmd = android::base::StringPrintf("%s:killforward:%s", host_prefix, argv[1]);
}
// Or implement one of:
// forward <local> <remote>
// forward --no-rebind <local> <remote>
- else
- {
- if (argc != 3)
- return usage();
- const char* command = no_rebind ? "forward:norebind" : "forward";
- snprintf(buf, sizeof buf, "%s:%s:%s;%s", host_prefix, command, argv[1], argv[2]);
+ else {
+ if (argc != 3) return usage();
+ const char* command = no_rebind ? "forward:norebind" : "forward";
+ cmd = android::base::StringPrintf("%s:%s:%s;%s", host_prefix, command, argv[1], argv[2]);
}
std::string error;
- if (adb_command(buf, &error)) {
- fprintf(stderr,"error: %s\n", error.c_str());
+ if (adb_command(cmd, &error)) {
+ fprintf(stderr, "error: %s\n", error.c_str());
return 1;
}
return 0;
@@ -1463,15 +1367,15 @@
}
else if (!strcmp(argv[0], "install")) {
if (argc < 2) return usage();
- return install_app(ttype, serial, argc, argv);
+ return install_app(transport_type, serial, argc, argv);
}
else if (!strcmp(argv[0], "install-multiple")) {
if (argc < 2) return usage();
- return install_multiple_app(ttype, serial, argc, argv);
+ return install_multiple_app(transport_type, serial, argc, argv);
}
else if (!strcmp(argv[0], "uninstall")) {
if (argc < 2) return usage();
- return uninstall_app(ttype, serial, argc, argv);
+ return uninstall_app(transport_type, serial, argc, argv);
}
else if (!strcmp(argv[0], "sync")) {
std::string src;
@@ -1523,23 +1427,11 @@
!strcmp(argv[0],"get-serialno") ||
!strcmp(argv[0],"get-devpath"))
{
- format_host_command(buf, sizeof buf, argv[0], ttype, serial);
- std::string error;
- char* tmp = adb_query(buf, &error);
- if (tmp) {
- printf("%s\n", tmp);
- return 0;
- } else {
- return 1;
- }
+ return adb_query_command(format_host_command(argv[0], transport_type, serial));
}
/* other commands */
- else if (!strcmp(argv[0],"status-window")) {
- status_window(ttype, serial);
- return 0;
- }
else if (!strcmp(argv[0],"logcat") || !strcmp(argv[0],"lolcat") || !strcmp(argv[0],"longcat")) {
- return logcat(ttype, serial, argc, argv);
+ return logcat(transport_type, serial, argc, argv);
}
else if (!strcmp(argv[0],"ppp")) {
return ppp(argc, argv);
@@ -1575,45 +1467,7 @@
return 1;
}
-#define MAX_ARGV_LENGTH 16
-static int do_cmd(transport_type ttype, const char* serial, const char *cmd, ...)
-{
- const char *argv[MAX_ARGV_LENGTH];
- int argc;
- va_list ap;
-
- va_start(ap, cmd);
- argc = 0;
-
- if (serial) {
- argv[argc++] = "-s";
- argv[argc++] = serial;
- } else if (ttype == kTransportUsb) {
- argv[argc++] = "-d";
- } else if (ttype == kTransportLocal) {
- argv[argc++] = "-e";
- }
-
- argv[argc++] = cmd;
- while(argc < MAX_ARGV_LENGTH &&
- (argv[argc] = va_arg(ap, char*)) != 0) argc++;
- assert(argc < MAX_ARGV_LENGTH);
- va_end(ap);
-
-#if 0
- int n;
- fprintf(stderr,"argc = %d\n",argc);
- for(n = 0; n < argc; n++) {
- fprintf(stderr,"argv[%d] = \"%s\"\n", n, argv[n]);
- }
-#endif
-
- return adb_commandline(argc, argv);
-}
-
-static int pm_command(transport_type transport, const char* serial,
- int argc, const char** argv)
-{
+static int pm_command(TransportType transport, const char* serial, int argc, const char** argv) {
std::string cmd = "shell:pm";
while (argc-- > 0) {
@@ -1623,9 +1477,7 @@
return send_shell_command(transport, serial, cmd);
}
-static int uninstall_app(transport_type transport, const char* serial, int argc,
- const char** argv)
-{
+static int uninstall_app(TransportType transport, const char* serial, int argc, const char** argv) {
/* if the user choose the -k option, we refuse to do it until devices are
out with the option to uninstall the remaining data somehow (adb/ui) */
if (argc == 3 && strcmp(argv[1], "-k") == 0)
@@ -1642,8 +1494,7 @@
return pm_command(transport, serial, argc, argv);
}
-static int delete_file(transport_type transport, const char* serial, char* filename)
-{
+static int delete_file(TransportType transport, const char* serial, char* filename) {
std::string cmd = "shell:rm -f " + escape_arg(filename);
return send_shell_command(transport, serial, cmd);
}
@@ -1659,9 +1510,7 @@
}
}
-static int install_app(transport_type transport, const char* serial, int argc,
- const char** argv)
-{
+static int install_app(TransportType transport, const char* serial, int argc, const 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;
@@ -1713,7 +1562,7 @@
return err;
}
-static int install_multiple_app(transport_type transport, const char* serial, int argc,
+static int install_multiple_app(TransportType transport, const char* serial, int argc,
const char** argv)
{
int i;
@@ -1744,18 +1593,14 @@
return 1;
}
-#if defined(_WIN32) // Remove when we're using clang for Win32.
- std::string cmd = android::base::StringPrintf("exec:pm install-create -S %u", (unsigned) total_size);
-#else
std::string cmd = android::base::StringPrintf("exec:pm install-create -S %" PRIu64, total_size);
-#endif
for (i = 1; i < first_apk; i++) {
cmd += " " + escape_arg(argv[i]);
}
// Create install session
std::string error;
- int fd = adb_connect(cmd.c_str(), &error);
+ int fd = adb_connect(cmd, &error);
if (fd < 0) {
fprintf(stderr, "Connect error for create: %s\n", error.c_str());
return -1;
@@ -1789,15 +1634,9 @@
goto finalize_session;
}
-#if defined(_WIN32) // Remove when we're using clang for Win32.
- std::string cmd = android::base::StringPrintf(
- "exec:pm install-write -S %u %d %d_%s -",
- (unsigned) sb.st_size, session_id, i, get_basename(file));
-#else
std::string cmd = android::base::StringPrintf(
"exec:pm install-write -S %" PRIu64 " %d %d_%s -",
static_cast<uint64_t>(sb.st_size), session_id, i, get_basename(file));
-#endif
int localFd = adb_open(file, O_RDONLY);
if (localFd < 0) {
@@ -1807,7 +1646,7 @@
}
std::string error;
- int remoteFd = adb_connect(cmd.c_str(), &error);
+ int remoteFd = adb_connect(cmd, &error);
if (remoteFd < 0) {
fprintf(stderr, "Connect error for write: %s\n", error.c_str());
adb_close(localFd);
@@ -1831,13 +1670,10 @@
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, &error);
+ std::string service =
+ android::base::StringPrintf("exec:pm install-%s %d",
+ success ? "commit" : "abandon", session_id);
+ fd = adb_connect(service, &error);
if (fd < 0) {
fprintf(stderr, "Connect error for finalize: %s\n", error.c_str());
return -1;
diff --git a/adb/console.cpp b/adb/console.cpp
index 452ee41..0707960 100644
--- a/adb/console.cpp
+++ b/adb/console.cpp
@@ -1,44 +1,115 @@
+/*
+ * 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.
+ */
+
#include "sysdeps.h"
-#include "adb.h"
-#include "adb_client.h"
+
#include <stdio.h>
-static int connect_to_console(void)
-{
- int fd, port;
+#include "base/file.h"
+#include "base/logging.h"
+#include "base/strings.h"
- port = adb_get_emulator_console_port();
- if (port < 0) {
- if (port == -2)
- fprintf(stderr, "error: more than one emulator detected. use -s option\n");
- else
- fprintf(stderr, "error: no emulator detected\n");
+#include "adb.h"
+#include "adb_client.h"
+
+// Return the console port of the currently connected emulator (if any) or -1 if
+// there is no emulator, and -2 if there is more than one.
+static int adb_get_emulator_console_port(const char* serial) {
+ if (serial) {
+ // The user specified a serial number; is it an emulator?
+ int port;
+ return (sscanf(serial, "emulator-%d", &port) == 1) ? port : -1;
+ }
+
+ // No specific device was given, so get the list of connected devices and
+ // search for emulators. If there's one, we'll take it. If there are more
+ // than one, that's an error.
+ std::string devices;
+ std::string error;
+ if (!adb_query("host:devices", &devices, &error)) {
+ fprintf(stderr, "error: no emulator connected: %s\n", error.c_str());
return -1;
}
- fd = socket_loopback_client( port, SOCK_STREAM );
- if (fd < 0) {
+
+ int port;
+ size_t emulator_count = 0;
+ for (const auto& device : android::base::Split(devices, "\n")) {
+ if (sscanf(device.c_str(), "emulator-%d", &port) == 1) {
+ if (++emulator_count > 1) {
+ fprintf(
+ stderr, "error: more than one emulator detected; use -s\n");
+ return -1;
+ }
+ }
+ }
+
+ if (emulator_count == 0) {
+ fprintf(stderr, "error: no emulator detected\n");
+ return -1;
+ }
+
+ return port;
+}
+
+static int connect_to_console(const char* serial) {
+ int port = adb_get_emulator_console_port(serial);
+ if (port == -1) {
+ return -1;
+ }
+
+ int fd = socket_loopback_client(port, SOCK_STREAM);
+ if (fd == -1) {
fprintf(stderr, "error: could not connect to TCP port %d\n", port);
return -1;
}
- return fd;
+ return fd;
}
-
-int adb_send_emulator_command(int argc, const char** argv)
-{
- int fd, nn;
-
- fd = connect_to_console();
- if (fd < 0)
+int adb_send_emulator_command(int argc, const char** argv, const char* serial) {
+ int fd = connect_to_console(serial);
+ if (fd == -1) {
return 1;
-
-#define QUIT "quit\n"
-
- for (nn = 1; nn < argc; nn++) {
- adb_write( fd, argv[nn], strlen(argv[nn]) );
- adb_write( fd, (nn == argc-1) ? "\n" : " ", 1 );
}
- adb_write( fd, QUIT, sizeof(QUIT)-1 );
+
+ for (int i = 1; i < argc; i++) {
+ adb_write(fd, argv[i], strlen(argv[i]));
+ adb_write(fd, i == argc - 1 ? "\n" : " ", 1);
+ }
+
+ const char disconnect_command[] = "quit\n";
+ if (adb_write(fd, disconnect_command, sizeof(disconnect_command) - 1) == -1) {
+ LOG(FATAL) << "Could not finalize emulator command";
+ }
+
+ // Drain output that the emulator console has sent us to prevent a problem
+ // on Windows where if adb closes the socket without reading all the data,
+ // the emulator's next call to recv() will have an ECONNABORTED error,
+ // preventing the emulator from reading the command that adb has sent.
+ // https://code.google.com/p/android/issues/detail?id=21021
+ int result;
+ do {
+ char buf[BUFSIZ];
+ result = adb_read(fd, buf, sizeof(buf));
+ // Keep reading until zero bytes (EOF) or an error. If 'adb emu kill'
+ // is executed, the emulator calls exit() which causes adb to get
+ // ECONNRESET. Any other emu command is followed by the quit command
+ // that we sent above, and that causes the emulator to close the socket
+ // which should cause zero bytes (EOF) to be returned.
+ } while (result > 0);
+
adb_close(fd);
return 0;
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
new file mode 100644
index 0000000..99ff539
--- /dev/null
+++ b/adb/daemon/main.cpp
@@ -0,0 +1,276 @@
+/*
+ * 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.
+ */
+
+#define TRACE_TAG TRACE_ADB
+
+#include "sysdeps.h"
+
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <sys/prctl.h>
+
+#include "base/logging.h"
+#include "base/stringprintf.h"
+#include "cutils/properties.h"
+#include "private/android_filesystem_config.h"
+#include "selinux/selinux.h"
+
+#include "adb.h"
+#include "adb_auth.h"
+#include "adb_listeners.h"
+#include "transport.h"
+#include "qemu_tracing.h"
+
+static const char* root_seclabel = nullptr;
+
+static void drop_capabilities_bounding_set_if_needed() {
+#ifdef ALLOW_ADBD_ROOT
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.debuggable", value, "");
+ if (strcmp(value, "1") == 0) {
+ return;
+ }
+#endif
+ for (int i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) {
+ if (i == CAP_SETUID || i == CAP_SETGID) {
+ // CAP_SETUID CAP_SETGID needed by /system/bin/run-as
+ continue;
+ }
+
+ int err = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
+
+ // Some kernels don't have file capabilities compiled in, and
+ // prctl(PR_CAPBSET_DROP) returns EINVAL. Don't automatically
+ // die when we see such misconfigured kernels.
+ if ((err < 0) && (errno != EINVAL)) {
+ PLOG(FATAL) << "Could not drop capabilities";
+ }
+ }
+}
+
+static bool should_drop_privileges() {
+#if defined(ALLOW_ADBD_ROOT)
+ char value[PROPERTY_VALUE_MAX];
+
+ // The emulator is never secure, so don't drop privileges there.
+ // TODO: this seems like a bug --- shouldn't the emulator behave like a device?
+ property_get("ro.kernel.qemu", value, "");
+ if (strcmp(value, "1") == 0) {
+ return false;
+ }
+
+ // The properties that affect `adb root` and `adb unroot` are ro.secure and
+ // ro.debuggable. In this context the names don't make the expected behavior
+ // particularly obvious.
+ //
+ // ro.debuggable:
+ // Allowed to become root, but not necessarily the default. Set to 1 on
+ // eng and userdebug builds.
+ //
+ // ro.secure:
+ // Drop privileges by default. Set to 1 on userdebug and user builds.
+ property_get("ro.secure", value, "1");
+ bool ro_secure = (strcmp(value, "1") == 0);
+
+ property_get("ro.debuggable", value, "");
+ bool ro_debuggable = (strcmp(value, "1") == 0);
+
+ // Drop privileges if ro.secure is set...
+ bool drop = ro_secure;
+
+ property_get("service.adb.root", value, "");
+ bool adb_root = (strcmp(value, "1") == 0);
+ bool adb_unroot = (strcmp(value, "0") == 0);
+
+ // ...except "adb root" lets you keep privileges in a debuggable build.
+ if (ro_debuggable && adb_root) {
+ drop = false;
+ }
+
+ // ...and "adb unroot" lets you explicitly drop privileges.
+ if (adb_unroot) {
+ drop = true;
+ }
+
+ return drop;
+#else
+ return true; // "adb root" not allowed, always drop privileges.
+#endif // ALLOW_ADBD_ROOT
+}
+
+int adbd_main(int server_port) {
+ umask(0);
+
+ signal(SIGPIPE, SIG_IGN);
+
+ init_transport_registration();
+
+ // We need to call this even if auth isn't enabled because the file
+ // 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();
+ }
+
+ // 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");
+ if (adb_external_storage != nullptr) {
+ setenv("EXTERNAL_STORAGE", adb_external_storage, 1);
+ } else {
+ D("Warning: ADB_EXTERNAL_STORAGE is not set. Leaving EXTERNAL_STORAGE"
+ " unchanged.\n");
+ }
+
+ // Add extra groups:
+ // AID_ADB to access the USB driver
+ // AID_LOG to read system logs (adb logcat)
+ // AID_INPUT to diagnose input issues (getevent)
+ // AID_INET to diagnose network issues (ping)
+ // AID_NET_BT and AID_NET_BT_ADMIN to diagnose bluetooth (hcidump)
+ // AID_SDCARD_R to allow reading from the SD card
+ // AID_SDCARD_RW to allow writing to the SD card
+ // AID_NET_BW_STATS to read out qtaguid statistics
+ gid_t groups[] = {AID_ADB, AID_LOG, AID_INPUT,
+ AID_INET, AID_NET_BT, AID_NET_BT_ADMIN,
+ AID_SDCARD_R, AID_SDCARD_RW, AID_NET_BW_STATS};
+ if (setgroups(sizeof(groups) / sizeof(groups[0]), groups) != 0) {
+ PLOG(FATAL) << "Could not set supplental groups";
+ }
+
+ /* don't listen on a port (default 5037) if running in secure mode */
+ /* don't run as root if we are running in secure mode */
+ if (should_drop_privileges()) {
+ drop_capabilities_bounding_set_if_needed();
+
+ /* then switch user and group to "shell" */
+ if (setgid(AID_SHELL) != 0) {
+ PLOG(FATAL) << "Could not setgid";
+ }
+ if (setuid(AID_SHELL) != 0) {
+ PLOG(FATAL) << "Could not setuid";
+ }
+
+ D("Local port disabled\n");
+ } else {
+ if ((root_seclabel != nullptr) && (is_selinux_enabled() > 0)) {
+ if (setcon(root_seclabel) < 0) {
+ LOG(FATAL) << "Could not set selinux context";
+ }
+ }
+ std::string local_name =
+ android::base::StringPrintf("tcp:%d", server_port);
+ if (install_listener(local_name, "*smartsocket*", nullptr, 0)) {
+ LOG(FATAL) << "Could not install *smartsocket* listener";
+ }
+ }
+
+ bool is_usb = false;
+ if (access(USB_ADB_PATH, F_OK) == 0 || access(USB_FFS_ADB_EP0, F_OK) == 0) {
+ // Listen on USB.
+ usb_init();
+ is_usb = true;
+ }
+
+ // If one of these properties is set, also listen on that port.
+ // If one of the properties isn't set and we couldn't listen on usb, listen
+ // on the default port.
+ char prop_port[PROPERTY_VALUE_MAX];
+ property_get("service.adb.tcp.port", prop_port, "");
+ if (prop_port[0] == '\0') {
+ property_get("persist.adb.tcp.port", prop_port, "");
+ }
+
+ int port;
+ if (sscanf(prop_port, "%d", &port) == 1 && port > 0) {
+ printf("using port=%d\n", port);
+ // Listen on TCP port specified by service.adb.tcp.port property.
+ local_init(port);
+ } else if (!is_usb) {
+ // Listen on default port.
+ local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
+ }
+
+ D("adbd_main(): pre init_jdwp()\n");
+ init_jdwp();
+ D("adbd_main(): post init_jdwp()\n");
+
+ D("Event loop starting\n");
+ fdevent_loop();
+
+ return 0;
+}
+
+static void close_stdin() {
+ int fd = unix_open("/dev/null", O_RDONLY);
+ if (fd == -1) {
+ perror("failed to open /dev/null, stdin will remain open");
+ return;
+ }
+ dup2(fd, STDIN_FILENO);
+ adb_close(fd);
+}
+
+int main(int argc, char** argv) {
+ android::base::InitLogging(argv);
+
+ while (true) {
+ static struct option opts[] = {
+ {"root_seclabel", required_argument, nullptr, 's'},
+ {"device_banner", required_argument, nullptr, 'b'},
+ {"version", no_argument, nullptr, 'v'},
+ };
+
+ int option_index = 0;
+ int c = getopt_long(argc, argv, "", opts, &option_index);
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 's':
+ root_seclabel = optarg;
+ break;
+ case 'b':
+ adb_device_banner = optarg;
+ break;
+ case 'v':
+ printf("Android Debug Bridge Daemon version %d.%d.%d %s\n",
+ ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION,
+ ADB_REVISION);
+ return 0;
+ default:
+ // getopt already prints "adbd: invalid option -- %c" for us.
+ return 1;
+ }
+ }
+
+ close_stdin();
+
+ adb_trace_init();
+
+ /* If adbd runs inside the emulator this will enable adb tracing via
+ * adb-debug qemud service in the emulator. */
+ adb_qemu_trace_init();
+
+ D("Handling main()\n");
+ return adbd_main(DEFAULT_ADB_PORT);
+}
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index aded301..1dc711ae 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -16,6 +16,7 @@
#include <dirent.h>
#include <errno.h>
+#include <inttypes.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
@@ -63,13 +64,12 @@
total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
}
-static const char* transfer_progress_format = "\rTransferring: %llu/%llu (%d%%)";
-
-static void print_transfer_progress(unsigned long long bytes_current,
- unsigned long long bytes_total) {
+static void print_transfer_progress(uint64_t bytes_current,
+ uint64_t bytes_total) {
if (bytes_total == 0) return;
- fprintf(stderr, transfer_progress_format, bytes_current, bytes_total,
+ fprintf(stderr, "\rTransferring: %" PRIu64 "/%" PRIu64 " (%d%%)",
+ bytes_current, bytes_total,
(int) (bytes_current * 100 / bytes_total));
if (bytes_current == bytes_total) {
@@ -79,8 +79,7 @@
fflush(stderr);
}
-void sync_quit(int fd)
-{
+static void sync_quit(int fd) {
syncmsg msg;
msg.req.id = ID_QUIT;
@@ -91,8 +90,7 @@
typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char *name, void *cookie);
-int sync_ls(int fd, const char *path, sync_ls_cb func, void *cookie)
-{
+static int sync_ls(int fd, const char* path, sync_ls_cb func, void* cookie) {
syncmsg msg;
char buf[257];
int len;
@@ -138,9 +136,7 @@
static syncsendbuf send_buffer;
-int sync_readtime(int fd, const char *path, unsigned int *timestamp,
- unsigned int *mode)
-{
+static int sync_readtime(int fd, const char* path, unsigned int* timestamp, unsigned int* mode) {
syncmsg msg;
int len = strlen(path);
@@ -199,8 +195,7 @@
return 0;
}
-int sync_readmode(int fd, const char *path, unsigned *mode)
-{
+static int sync_readmode(int fd, const char* path, unsigned* mode) {
syncmsg msg;
int len = strlen(path);
@@ -419,8 +414,7 @@
return 0;
}
-int sync_recv(int fd, const char *rpath, const char *lpath, int show_progress)
-{
+static int sync_recv(int fd, const char* rpath, const char* lpath, int show_progress) {
syncmsg msg;
int len;
int lfd = -1;
@@ -566,17 +560,14 @@
int flag;
};
-copyinfo *mkcopyinfo(const char *spath, const char *dpath,
- const char *name, int isdir)
-{
+static copyinfo* mkcopyinfo(const char* spath, const char* dpath, const char* name, int isdir) {
int slen = strlen(spath);
int dlen = strlen(dpath);
int nlen = strlen(name);
int ssize = slen + nlen + 2;
int dsize = dlen + nlen + 2;
- copyinfo *ci = reinterpret_cast<copyinfo*>(
- malloc(sizeof(copyinfo) + ssize + dsize));
+ copyinfo *ci = reinterpret_cast<copyinfo*>(malloc(sizeof(copyinfo) + ssize + dsize));
if(ci == 0) {
fprintf(stderr,"out of memory\n");
abort();
@@ -807,9 +798,8 @@
const char *lpath;
};
-void
-sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time,
- const char *name, void *cookie)
+static void sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time,
+ const char* name, void* cookie)
{
sync_ls_build_list_cb_args *args = (sync_ls_build_list_cb_args *)cookie;
copyinfo *ci;
diff --git a/adb/remount_service.cpp b/adb/remount_service.cpp
index 1eaee73..7a3b89a 100644
--- a/adb/remount_service.cpp
+++ b/adb/remount_service.cpp
@@ -34,114 +34,89 @@
#include "adb_utils.h"
#include "cutils/properties.h"
-static int system_ro = 1;
-static int vendor_ro = 1;
-static int oem_ro = 1;
-
-/* Returns the device used to mount a directory in /proc/mounts */
-static std::string find_mount(const char *dir) {
- FILE* fp;
- struct mntent* mentry;
- char* device = NULL;
-
- if ((fp = setmntent("/proc/mounts", "r")) == NULL) {
- return NULL;
+// Returns the device used to mount a directory in /proc/mounts.
+static std::string find_mount(const char* dir) {
+ std::unique_ptr<FILE, int(*)(FILE*)> fp(setmntent("/proc/mounts", "r"), endmntent);
+ if (!fp) {
+ return "";
}
- while ((mentry = getmntent(fp)) != NULL) {
- if (strcmp(dir, mentry->mnt_dir) == 0) {
- device = mentry->mnt_fsname;
- break;
+
+ mntent* e;
+ while ((e = getmntent(fp.get())) != nullptr) {
+ if (strcmp(dir, e->mnt_dir) == 0) {
+ return e->mnt_fsname;
}
}
- endmntent(fp);
- return device;
+ return "";
}
-int make_block_device_writable(const std::string& dev) {
+bool make_block_device_writable(const std::string& dev) {
int fd = unix_open(dev.c_str(), O_RDONLY | O_CLOEXEC);
if (fd == -1) {
- return -1;
+ return false;
}
- int result = -1;
int OFF = 0;
- if (!ioctl(fd, BLKROSET, &OFF)) {
- result = 0;
- }
+ bool result = (ioctl(fd, BLKROSET, &OFF) != -1);
adb_close(fd);
-
return result;
}
-// Init mounts /system as read only, remount to enable writes.
-static int remount(const char* dir, int* dir_ro) {
- std::string dev(find_mount(dir));
- if (dev.empty() || make_block_device_writable(dev)) {
- return -1;
+static bool remount_partition(int fd, const char* dir) {
+ if (!directory_exists(dir)) {
+ return true;
}
-
- int rc = mount(dev.c_str(), dir, "none", MS_REMOUNT, NULL);
- *dir_ro = rc;
- return rc;
-}
-
-static bool remount_partition(int fd, const char* partition, int* ro) {
- if (!directory_exists(partition)) {
+ std::string dev = find_mount(dir);
+ if (dev.empty()) {
+ return true;
+ }
+ if (!make_block_device_writable(dev)) {
+ WriteFdFmt(fd, "remount of %s failed; couldn't make block device %s writable: %s\n",
+ dir, dev.c_str(), strerror(errno));
+ return false;
+ }
+ if (mount(dev.c_str(), dir, "none", MS_REMOUNT, nullptr) == -1) {
+ WriteFdFmt(fd, "remount of %s failed: %s\n", dir, strerror(errno));
+ return false;
+ }
return true;
- }
- if (remount(partition, ro)) {
- char buf[200];
- snprintf(buf, sizeof(buf), "remount of %s failed: %s\n", partition, strerror(errno));
- WriteStringFully(fd, buf);
- return false;
- }
- return true;
}
void remount_service(int fd, void* cookie) {
- char prop_buf[PROPERTY_VALUE_MAX];
-
if (getuid() != 0) {
- WriteStringFully(fd, "Not running as root. Try \"adb root\" first.\n");
+ WriteFdExactly(fd, "Not running as root. Try \"adb root\" first.\n");
adb_close(fd);
return;
}
- bool system_verified = false, vendor_verified = false;
+ char prop_buf[PROPERTY_VALUE_MAX];
property_get("partition.system.verified", prop_buf, "");
- if (strlen(prop_buf) > 0) {
- system_verified = true;
- }
+ bool system_verified = (strlen(prop_buf) > 0);
property_get("partition.vendor.verified", prop_buf, "");
- if (strlen(prop_buf) > 0) {
- vendor_verified = true;
- }
+ bool vendor_verified = (strlen(prop_buf) > 0);
if (system_verified || vendor_verified) {
// Allow remount but warn of likely bad effects
bool both = system_verified && vendor_verified;
- char buffer[200];
- snprintf(buffer, sizeof(buffer),
- "dm_verity is enabled on the %s%s%s partition%s.\n",
- system_verified ? "system" : "",
- both ? " and " : "",
- vendor_verified ? "vendor" : "",
- both ? "s" : "");
- WriteStringFully(fd, buffer);
- snprintf(buffer, sizeof(buffer),
- "Use \"adb disable-verity\" to disable verity.\n"
- "If you do not, remount may succeed, however, you will still "
- "not be able to write to these volumes.\n");
- WriteStringFully(fd, buffer);
+ WriteFdFmt(fd,
+ "dm_verity is enabled on the %s%s%s partition%s.\n",
+ system_verified ? "system" : "",
+ both ? " and " : "",
+ vendor_verified ? "vendor" : "",
+ both ? "s" : "");
+ WriteFdExactly(fd,
+ "Use \"adb disable-verity\" to disable verity.\n"
+ "If you do not, remount may succeed, however, you will still "
+ "not be able to write to these volumes.\n");
}
bool success = true;
- success &= remount_partition(fd, "/system", &system_ro);
- success &= remount_partition(fd, "/vendor", &vendor_ro);
- success &= remount_partition(fd, "/oem", &oem_ro);
+ success &= remount_partition(fd, "/system");
+ success &= remount_partition(fd, "/vendor");
+ success &= remount_partition(fd, "/oem");
- WriteStringFully(fd, success ? "remount succeeded\n" : "remount failed\n");
+ WriteFdExactly(fd, success ? "remount succeeded\n" : "remount failed\n");
adb_close(fd);
}
diff --git a/adb/remount_service.h b/adb/remount_service.h
index e1763cf..7bda1be 100644
--- a/adb/remount_service.h
+++ b/adb/remount_service.h
@@ -19,7 +19,7 @@
#include <string>
-int make_block_device_writable(const std::string&);
+bool make_block_device_writable(const std::string&);
void remount_service(int, void*);
#endif
diff --git a/adb/services.cpp b/adb/services.cpp
index e6c84a4..a9edbe5 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -24,6 +24,11 @@
#include <stdlib.h>
#include <string.h>
+#if !ADB_HOST
+#include <pty.h>
+#include <termios.h>
+#endif
+
#ifndef _WIN32
#include <netdb.h>
#include <netinet/in.h>
@@ -31,10 +36,11 @@
#include <unistd.h>
#endif
+#include <base/file.h>
#include <base/stringprintf.h>
+#include <base/strings.h>
#if !ADB_HOST
-#include "base/file.h"
#include "cutils/android_reboot.h"
#include "cutils/properties.h"
#endif
@@ -62,74 +68,54 @@
#if !ADB_HOST
-void restart_root_service(int fd, void *cookie)
-{
- char buf[100];
- char value[PROPERTY_VALUE_MAX];
-
+void restart_root_service(int fd, void *cookie) {
if (getuid() == 0) {
- snprintf(buf, sizeof(buf), "adbd is already running as root\n");
- WriteFdExactly(fd, buf, strlen(buf));
+ WriteFdExactly(fd, "adbd is already running as root\n");
adb_close(fd);
} else {
+ char value[PROPERTY_VALUE_MAX];
property_get("ro.debuggable", value, "");
if (strcmp(value, "1") != 0) {
- snprintf(buf, sizeof(buf), "adbd cannot run as root in production builds\n");
- WriteFdExactly(fd, buf, strlen(buf));
+ WriteFdExactly(fd, "adbd cannot run as root in production builds\n");
adb_close(fd);
return;
}
property_set("service.adb.root", "1");
- snprintf(buf, sizeof(buf), "restarting adbd as root\n");
- WriteFdExactly(fd, buf, strlen(buf));
+ WriteFdExactly(fd, "restarting adbd as root\n");
adb_close(fd);
}
}
-void restart_unroot_service(int fd, void *cookie)
-{
- char buf[100];
-
+void restart_unroot_service(int fd, void *cookie) {
if (getuid() != 0) {
- snprintf(buf, sizeof(buf), "adbd not running as root\n");
- WriteFdExactly(fd, buf, strlen(buf));
+ WriteFdExactly(fd, "adbd not running as root\n");
adb_close(fd);
} else {
property_set("service.adb.root", "0");
- snprintf(buf, sizeof(buf), "restarting adbd as non root\n");
- WriteFdExactly(fd, buf, strlen(buf));
+ WriteFdExactly(fd, "restarting adbd as non root\n");
adb_close(fd);
}
}
-void restart_tcp_service(int fd, void *cookie)
-{
- char buf[100];
- char value[PROPERTY_VALUE_MAX];
+void restart_tcp_service(int fd, void *cookie) {
int port = (int) (uintptr_t) cookie;
-
if (port <= 0) {
- snprintf(buf, sizeof(buf), "invalid port\n");
- WriteFdExactly(fd, buf, strlen(buf));
+ WriteFdFmt(fd, "invalid port %d\n", port);
adb_close(fd);
return;
}
+ char value[PROPERTY_VALUE_MAX];
snprintf(value, sizeof(value), "%d", port);
property_set("service.adb.tcp.port", value);
- snprintf(buf, sizeof(buf), "restarting in TCP mode port: %d\n", port);
- WriteFdExactly(fd, buf, strlen(buf));
+ WriteFdFmt(fd, "restarting in TCP mode port: %d\n", port);
adb_close(fd);
}
-void restart_usb_service(int fd, void *cookie)
-{
- char buf[100];
-
+void restart_usb_service(int fd, void *cookie) {
property_set("service.adb.tcp.port", "0");
- snprintf(buf, sizeof(buf), "restarting in USB mode\n");
- WriteFdExactly(fd, buf, strlen(buf));
+ WriteFdExactly(fd, "restarting in USB mode\n");
adb_close(fd);
}
@@ -142,13 +128,11 @@
reboot_arg = "sideload";
}
- char buf[100];
// It reboots into sideload mode by setting "--sideload" or "--sideload_auto_reboot"
// in the command file.
if (strcmp(reboot_arg, "sideload") == 0) {
if (getuid() != 0) {
- snprintf(buf, sizeof(buf), "'adb root' is required for 'adb reboot sideload'.\n");
- WriteStringFully(fd, buf);
+ WriteFdExactly(fd, "'adb root' is required for 'adb reboot sideload'.\n");
return false;
}
@@ -174,15 +158,13 @@
char property_val[PROPERTY_VALUE_MAX];
int ret = snprintf(property_val, sizeof(property_val), "reboot,%s", reboot_arg);
if (ret >= static_cast<int>(sizeof(property_val))) {
- snprintf(buf, sizeof(buf), "reboot string too long. length=%d\n", ret);
- WriteStringFully(fd, buf);
+ WriteFdFmt(fd, "reboot string too long: %d\n", ret);
return false;
}
ret = property_set(ANDROID_RB_PROPERTY, property_val);
if (ret < 0) {
- snprintf(buf, sizeof(buf), "reboot failed: %d\n", ret);
- WriteStringFully(fd, buf);
+ WriteFdFmt(fd, "reboot failed: %d\n", ret);
return false;
}
@@ -208,7 +190,7 @@
const char* command = reinterpret_cast<const char*>(arg);
if (handle_forward_request(command, kTransportAny, NULL, fd) < 0) {
- sendfailmsg(fd, "not a reverse forwarding command");
+ SendFail(fd, "not a reverse forwarding command");
}
free(arg);
adb_close(fd);
@@ -233,8 +215,7 @@
sti->cookie = cookie;
sti->fd = s[1];
- adb_thread_t t;
- if (adb_thread_create(&t, service_bootstrap_func, sti)) {
+ if (!adb_thread_create(service_bootstrap_func, sti)) {
free(sti);
adb_close(s[0]);
adb_close(s[1]);
@@ -262,30 +243,14 @@
}
}
-static int create_subproc_pty(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
-{
+#if !ADB_HOST
+static int create_subproc_pty(const char* cmd, const char* arg0,
+ const char* arg1, pid_t* pid) {
D("create_subproc_pty(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1);
-#if defined(_WIN32)
- fprintf(stderr, "error: create_subproc_pty not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
- return -1;
-#else
+ char pts_name[PATH_MAX];
int ptm;
-
- ptm = unix_open("/dev/ptmx", O_RDWR | O_CLOEXEC); // | O_NOCTTY);
- if(ptm < 0){
- printf("[ cannot open /dev/ptmx - %s ]\n",strerror(errno));
- return -1;
- }
-
- char devname[64];
- if(grantpt(ptm) || unlockpt(ptm) || ptsname_r(ptm, devname, sizeof(devname)) != 0) {
- printf("[ trouble with /dev/ptmx - %s ]\n", strerror(errno));
- adb_close(ptm);
- return -1;
- }
-
- *pid = fork();
- if(*pid < 0) {
+ *pid = forkpty(&ptm, pts_name, nullptr, nullptr);
+ if (*pid == -1) {
printf("- fork failed: %s -\n", strerror(errno));
adb_close(ptm);
return -1;
@@ -294,12 +259,33 @@
if (*pid == 0) {
init_subproc_child();
- int pts = unix_open(devname, O_RDWR | O_CLOEXEC);
- if (pts < 0) {
- fprintf(stderr, "child failed to open pseudo-term slave: %s\n", devname);
+ int pts = unix_open(pts_name, O_RDWR | O_CLOEXEC);
+ if (pts == -1) {
+ fprintf(stderr, "child failed to open pseudo-term slave %s: %s\n",
+ pts_name, strerror(errno));
+ adb_close(ptm);
exit(-1);
}
+ // arg0 is "-c" in batch mode and "-" in interactive mode.
+ if (strcmp(arg0, "-c") == 0) {
+ termios tattr;
+ if (tcgetattr(pts, &tattr) == -1) {
+ fprintf(stderr, "tcgetattr failed: %s\n", strerror(errno));
+ adb_close(pts);
+ adb_close(ptm);
+ exit(-1);
+ }
+
+ cfmakeraw(&tattr);
+ if (tcsetattr(pts, TCSADRAIN, &tattr) == -1) {
+ fprintf(stderr, "tcsetattr failed: %s\n", strerror(errno));
+ adb_close(pts);
+ adb_close(ptm);
+ exit(-1);
+ }
+ }
+
dup2(pts, STDIN_FILENO);
dup2(pts, STDOUT_FILENO);
dup2(pts, STDERR_FILENO);
@@ -307,15 +293,15 @@
adb_close(pts);
adb_close(ptm);
- execl(cmd, cmd, arg0, arg1, NULL);
+ execl(cmd, cmd, arg0, arg1, nullptr);
fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
cmd, strerror(errno), errno);
exit(-1);
} else {
return ptm;
}
-#endif /* !defined(_WIN32) */
}
+#endif // !ADB_HOST
static int create_subproc_raw(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
{
@@ -401,12 +387,7 @@
}
}
-static int create_subproc_thread(const char *name, const subproc_mode mode)
-{
- adb_thread_t t;
- int ret_fd;
- pid_t pid = -1;
-
+static int create_subproc_thread(const char *name, bool pty = false) {
const char *arg0, *arg1;
if (name == 0 || *name == 0) {
arg0 = "-"; arg1 = 0;
@@ -414,16 +395,12 @@
arg0 = "-c"; arg1 = name;
}
- switch (mode) {
- case SUBPROC_PTY:
+ pid_t pid = -1;
+ int ret_fd;
+ if (pty) {
ret_fd = create_subproc_pty(SHELL_COMMAND, arg0, arg1, &pid);
- break;
- case SUBPROC_RAW:
+ } else {
ret_fd = create_subproc_raw(SHELL_COMMAND, arg0, arg1, &pid);
- break;
- default:
- fprintf(stderr, "invalid subproc_mode %d\n", mode);
- return -1;
}
D("create_subproc ret_fd=%d pid=%d\n", ret_fd, pid);
@@ -433,7 +410,7 @@
sti->cookie = (void*) (uintptr_t) pid;
sti->fd = ret_fd;
- if (adb_thread_create(&t, service_bootstrap_func, sti)) {
+ if (!adb_thread_create(service_bootstrap_func, sti)) {
free(sti);
adb_close(ret_fd);
fprintf(stderr, "cannot create service thread\n");
@@ -485,9 +462,9 @@
} else if (!strncmp(name, "jdwp:", 5)) {
ret = create_jdwp_connection_fd(atoi(name+5));
} else if(!HOST && !strncmp(name, "shell:", 6)) {
- ret = create_subproc_thread(name + 6, SUBPROC_PTY);
+ ret = create_subproc_thread(name + 6, true);
} else if(!HOST && !strncmp(name, "exec:", 5)) {
- ret = create_subproc_thread(name + 5, SUBPROC_RAW);
+ ret = create_subproc_thread(name + 5);
} else if(!strncmp(name, "sync:", 5)) {
ret = create_service_thread(file_sync_service, NULL);
} else if(!strncmp(name, "remount:", 8)) {
@@ -502,9 +479,9 @@
ret = create_service_thread(restart_unroot_service, NULL);
} else if(!strncmp(name, "backup:", 7)) {
ret = create_subproc_thread(android::base::StringPrintf("/system/bin/bu backup %s",
- (name + 7)).c_str(), SUBPROC_RAW);
+ (name + 7)).c_str());
} else if(!strncmp(name, "restore:", 8)) {
- ret = create_subproc_thread("/system/bin/bu restore", SUBPROC_RAW);
+ ret = create_subproc_thread("/system/bin/bu restore");
} else if(!strncmp(name, "tcpip:", 6)) {
int port;
if (sscanf(name + 6, "%d", &port) != 1) {
@@ -537,9 +514,9 @@
#if ADB_HOST
struct state_info {
- transport_type transport;
+ TransportType transport_type;
char* serial;
- int state;
+ ConnectionState state;
};
static void wait_for_state(int fd, void* cookie)
@@ -549,11 +526,12 @@
D("wait_for_state %d\n", sinfo->state);
std::string error_msg = "unknown error";
- atransport* t = acquire_one_transport(sinfo->state, sinfo->transport, sinfo->serial, &error_msg);
+ atransport* t = acquire_one_transport(sinfo->state, sinfo->transport_type, sinfo->serial,
+ &error_msg);
if (t != 0) {
- WriteFdExactly(fd, "OKAY", 4);
+ SendOkay(fd);
} else {
- sendfailmsg(fd, error_msg.c_str());
+ SendFail(fd, error_msg);
}
if (sinfo->serial)
@@ -563,35 +541,31 @@
D("wait_for_state is done\n");
}
-static void connect_device(char* host, char* buffer, int buffer_size)
-{
- int port, fd;
- char* portstr = strchr(host, ':');
- char hostbuf[100];
- char serial[100];
- int ret;
-
- strncpy(hostbuf, host, sizeof(hostbuf) - 1);
- if (portstr) {
- if (portstr - host >= (ptrdiff_t)sizeof(hostbuf)) {
- snprintf(buffer, buffer_size, "bad host name %s", host);
- return;
- }
- // zero terminate the host at the point we found the colon
- hostbuf[portstr - host] = 0;
- if (sscanf(portstr + 1, "%d", &port) != 1) {
- snprintf(buffer, buffer_size, "bad port number %s", portstr);
- return;
- }
- } else {
- port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
+static void connect_device(const std::string& host, std::string* response) {
+ if (host.empty()) {
+ *response = "empty host name";
+ return;
}
- snprintf(serial, sizeof(serial), "%s:%d", hostbuf, port);
+ std::vector<std::string> pieces = android::base::Split(host, ":");
+ const std::string& hostname = pieces[0];
- fd = socket_network_client_timeout(hostbuf, port, SOCK_STREAM, 10);
+ int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
+ if (pieces.size() > 1) {
+ if (sscanf(pieces[1].c_str(), "%d", &port) != 1) {
+ *response = android::base::StringPrintf("bad port number %s", pieces[1].c_str());
+ return;
+ }
+ }
+
+ // This may look like we're putting 'host' back together,
+ // but we're actually inserting the default port if necessary.
+ std::string serial = android::base::StringPrintf("%s:%d", hostname.c_str(), port);
+
+ int fd = socket_network_client_timeout(hostname.c_str(), port, SOCK_STREAM, 10);
if (fd < 0) {
- snprintf(buffer, buffer_size, "unable to connect to %s:%d", host, port);
+ *response = android::base::StringPrintf("unable to connect to %s:%d",
+ hostname.c_str(), port);
return;
}
@@ -599,85 +573,73 @@
close_on_exec(fd);
disable_tcp_nagle(fd);
- ret = register_socket_transport(fd, serial, port, 0);
+ int ret = register_socket_transport(fd, serial.c_str(), port, 0);
if (ret < 0) {
adb_close(fd);
- snprintf(buffer, buffer_size, "already connected to %s", serial);
+ *response = android::base::StringPrintf("already connected to %s", serial.c_str());
} else {
- snprintf(buffer, buffer_size, "connected to %s", serial);
+ *response = android::base::StringPrintf("connected to %s", serial.c_str());
}
}
-void connect_emulator(char* port_spec, char* buffer, int buffer_size)
-{
- char* port_separator = strchr(port_spec, ',');
- if (!port_separator) {
- snprintf(buffer, buffer_size,
- "unable to parse '%s' as <console port>,<adb port>",
- port_spec);
+void connect_emulator(const std::string& port_spec, std::string* response) {
+ std::vector<std::string> pieces = android::base::Split(port_spec, ",");
+ if (pieces.size() != 2) {
+ *response = android::base::StringPrintf("unable to parse '%s' as <console port>,<adb port>",
+ port_spec.c_str());
return;
}
- // Zero-terminate console port and make port_separator point to 2nd port.
- *port_separator++ = 0;
- int console_port = strtol(port_spec, NULL, 0);
- int adb_port = strtol(port_separator, NULL, 0);
- if (!(console_port > 0 && adb_port > 0)) {
- *(port_separator - 1) = ',';
- snprintf(buffer, buffer_size,
- "Invalid port numbers: Expected positive numbers, got '%s'",
- port_spec);
+ int console_port = strtol(pieces[0].c_str(), NULL, 0);
+ int adb_port = strtol(pieces[1].c_str(), NULL, 0);
+ if (console_port <= 0 || adb_port <= 0) {
+ *response = android::base::StringPrintf("Invalid port numbers: %s", port_spec.c_str());
return;
}
- /* Check if the emulator is already known.
- * Note: There's a small but harmless race condition here: An emulator not
- * present just yet could be registered by another invocation right
- * after doing this check here. However, local_connect protects
- * against double-registration too. From here, a better error message
- * can be produced. In the case of the race condition, the very specific
- * error message won't be shown, but the data doesn't get corrupted. */
+ // Check if the emulator is already known.
+ // Note: There's a small but harmless race condition here: An emulator not
+ // present just yet could be registered by another invocation right
+ // after doing this check here. However, local_connect protects
+ // against double-registration too. From here, a better error message
+ // can be produced. In the case of the race condition, the very specific
+ // error message won't be shown, but the data doesn't get corrupted.
atransport* known_emulator = find_emulator_transport_by_adb_port(adb_port);
- if (known_emulator != NULL) {
- snprintf(buffer, buffer_size,
- "Emulator on port %d already registered.", adb_port);
+ if (known_emulator != nullptr) {
+ *response = android::base::StringPrintf("Emulator already registered on port %d", adb_port);
return;
}
- /* Check if more emulators can be registered. Similar unproblematic
- * race condition as above. */
+ // Check if more emulators can be registered. Similar unproblematic
+ // race condition as above.
int candidate_slot = get_available_local_transport_index();
if (candidate_slot < 0) {
- snprintf(buffer, buffer_size, "Cannot accept more emulators.");
+ *response = "Cannot accept more emulators";
return;
}
- /* Preconditions met, try to connect to the emulator. */
+ // Preconditions met, try to connect to the emulator.
if (!local_connect_arbitrary_ports(console_port, adb_port)) {
- snprintf(buffer, buffer_size,
- "Connected to emulator on ports %d,%d", console_port, adb_port);
+ *response = android::base::StringPrintf("Connected to emulator on ports %d,%d",
+ console_port, adb_port);
} else {
- snprintf(buffer, buffer_size,
- "Could not connect to emulator on ports %d,%d",
- console_port, adb_port);
+ *response = android::base::StringPrintf("Could not connect to emulator on ports %d,%d",
+ console_port, adb_port);
}
}
-static void connect_service(int fd, void* cookie)
-{
- char buf[4096];
- char resp[4096];
- char *host = reinterpret_cast<char*>(cookie);
-
+static void connect_service(int fd, void* data) {
+ char* host = reinterpret_cast<char*>(data);
+ std::string response;
if (!strncmp(host, "emu:", 4)) {
- connect_emulator(host + 4, buf, sizeof(buf));
+ connect_emulator(host + 4, &response);
} else {
- connect_device(host, buf, sizeof(buf));
+ connect_device(host, &response);
}
+ free(host);
// Send response for emulator and device
- snprintf(resp, sizeof(resp), "%04x%s",(unsigned)strlen(buf), buf);
- WriteFdExactly(fd, resp, strlen(resp));
+ SendProtocolString(fd, response);
adb_close(fd);
}
#endif
@@ -702,15 +664,18 @@
name += strlen("wait-for-");
if (!strncmp(name, "local", strlen("local"))) {
- sinfo->transport = kTransportLocal;
- sinfo->state = CS_DEVICE;
+ sinfo->transport_type = kTransportLocal;
+ sinfo->state = kCsDevice;
} else if (!strncmp(name, "usb", strlen("usb"))) {
- sinfo->transport = kTransportUsb;
- sinfo->state = CS_DEVICE;
+ sinfo->transport_type = kTransportUsb;
+ sinfo->state = kCsDevice;
} else if (!strncmp(name, "any", strlen("any"))) {
- sinfo->transport = kTransportAny;
- sinfo->state = CS_DEVICE;
+ sinfo->transport_type = kTransportAny;
+ sinfo->state = kCsDevice;
} else {
+ if (sinfo->serial) {
+ free(sinfo->serial);
+ }
free(sinfo);
return NULL;
}
@@ -718,8 +683,8 @@
int fd = create_service_thread(wait_for_state, sinfo);
return create_local_socket(fd);
} else if (!strncmp(name, "connect:", 8)) {
- const char *host = name + 8;
- int fd = create_service_thread(connect_service, (void *)host);
+ char* host = strdup(name + 8);
+ int fd = create_service_thread(connect_service, host);
return create_local_socket(fd);
}
return NULL;
diff --git a/adb/set_verity_enable_state_service.cpp b/adb/set_verity_enable_state_service.cpp
index b75ed4c..bae38cf 100644
--- a/adb/set_verity_enable_state_service.cpp
+++ b/adb/set_verity_enable_state_service.cpp
@@ -21,13 +21,13 @@
#include <fcntl.h>
#include <inttypes.h>
#include <stdarg.h>
-#include <stdbool.h>
#include <stdio.h>
#include <sys/stat.h>
#include "cutils/properties.h"
#include "adb.h"
+#include "adb_io.h"
#include "ext4_sb.h"
#include "fs_mgr.h"
#include "remount_service.h"
@@ -41,18 +41,6 @@
static const bool kAllowDisableVerity = false;
#endif
-__attribute__((__format__(printf, 2, 3))) __nonnull((2))
-static void write_console(int fd, const char* format, ...)
-{
- char buffer[256];
- va_list args;
- va_start (args, format);
- vsnprintf (buffer, sizeof(buffer), format, args);
- va_end (args);
-
- adb_write(fd, buffer, strnlen(buffer, sizeof(buffer)));
-}
-
static int get_target_device_size(int fd, const char *blk_device,
uint64_t *device_size)
{
@@ -64,18 +52,18 @@
data_device = adb_open(blk_device, O_RDONLY | O_CLOEXEC);
if (data_device < 0) {
- write_console(fd, "Error opening block device (%s)\n", strerror(errno));
+ WriteFdFmt(fd, "Error opening block device (%s)\n", strerror(errno));
return -1;
}
if (lseek64(data_device, 1024, SEEK_SET) < 0) {
- write_console(fd, "Error seeking to superblock\n");
+ WriteFdFmt(fd, "Error seeking to superblock\n");
adb_close(data_device);
return -1;
}
if (adb_read(data_device, &sb, sizeof(sb)) != sizeof(sb)) {
- write_console(fd, "Error reading superblock\n");
+ WriteFdFmt(fd, "Error reading superblock\n");
adb_close(data_device);
return -1;
}
@@ -98,74 +86,65 @@
int device = -1;
int retval = -1;
- if (make_block_device_writable(block_device)) {
- write_console(fd, "Could not make block device %s writable (%s).\n",
- block_device, strerror(errno));
+ if (!make_block_device_writable(block_device)) {
+ WriteFdFmt(fd, "Could not make block device %s writable (%s).\n",
+ block_device, strerror(errno));
goto errout;
}
device = adb_open(block_device, O_RDWR | O_CLOEXEC);
if (device == -1) {
- write_console(fd, "Could not open block device %s (%s).\n",
- block_device, strerror(errno));
- write_console(fd, "Maybe run adb remount?\n");
+ WriteFdFmt(fd, "Could not open block device %s (%s).\n", block_device, strerror(errno));
+ WriteFdFmt(fd, "Maybe run adb remount?\n");
goto errout;
}
// find the start of the verity metadata
if (get_target_device_size(fd, (char*)block_device, &device_length) < 0) {
- write_console(fd, "Could not get target device size.\n");
+ WriteFdFmt(fd, "Could not get target device size.\n");
goto errout;
}
if (lseek64(device, device_length, SEEK_SET) < 0) {
- write_console(fd,
- "Could not seek to start of verity metadata block.\n");
+ WriteFdFmt(fd, "Could not seek to start of verity metadata block.\n");
goto errout;
}
// check the magic number
- if (adb_read(device, &magic_number, sizeof(magic_number))
- != sizeof(magic_number)) {
- write_console(fd, "Couldn't read magic number!\n");
+ if (adb_read(device, &magic_number, sizeof(magic_number)) != sizeof(magic_number)) {
+ WriteFdFmt(fd, "Couldn't read magic number!\n");
goto errout;
}
if (!enable && magic_number == VERITY_METADATA_MAGIC_DISABLE) {
- write_console(fd, "Verity already disabled on %s\n", mount_point);
+ WriteFdFmt(fd, "Verity already disabled on %s\n", mount_point);
goto errout;
}
if (enable && magic_number == VERITY_METADATA_MAGIC_NUMBER) {
- write_console(fd, "Verity already enabled on %s\n", mount_point);
+ WriteFdFmt(fd, "Verity already enabled on %s\n", mount_point);
goto errout;
}
if (magic_number != VERITY_METADATA_MAGIC_NUMBER
&& magic_number != VERITY_METADATA_MAGIC_DISABLE) {
- write_console(fd,
- "Couldn't find verity metadata at offset %" PRIu64 "!\n",
- device_length);
+ WriteFdFmt(fd, "Couldn't find verity metadata at offset %" PRIu64 "!\n", device_length);
goto errout;
}
if (lseek64(device, device_length, SEEK_SET) < 0) {
- write_console(fd,
- "Could not seek to start of verity metadata block.\n");
+ WriteFdFmt(fd, "Could not seek to start of verity metadata block.\n");
goto errout;
}
if (adb_write(device, &new_magic, sizeof(new_magic)) != sizeof(new_magic)) {
- write_console(
- fd, "Could not set verity %s flag on device %s with error %s\n",
- enable ? "enabled" : "disabled",
- block_device, strerror(errno));
+ WriteFdFmt(fd, "Could not set verity %s flag on device %s with error %s\n",
+ enable ? "enabled" : "disabled",
+ block_device, strerror(errno));
goto errout;
}
- write_console(fd, "Verity %s on %s\n",
- enable ? "enabled" : "disabled",
- mount_point);
+ WriteFdFmt(fd, "Verity %s on %s\n", enable ? "enabled" : "disabled", mount_point);
retval = 0;
errout:
if (device != -1)
@@ -184,14 +163,13 @@
property_get("ro.secure", propbuf, "0");
if (strcmp(propbuf, "1")) {
- write_console(fd, "verity not enabled - ENG build\n");
+ WriteFdFmt(fd, "verity not enabled - ENG build\n");
goto errout;
}
property_get("ro.debuggable", propbuf, "0");
if (strcmp(propbuf, "1")) {
- write_console(
- fd, "verity cannot be disabled/enabled - USER build\n");
+ WriteFdFmt(fd, "verity cannot be disabled/enabled - USER build\n");
goto errout;
}
@@ -201,8 +179,7 @@
fstab = fs_mgr_read_fstab(fstab_filename);
if (!fstab) {
- write_console(fd, "Failed to open %s\nMaybe run adb root?\n",
- fstab_filename);
+ WriteFdFmt(fd, "Failed to open %s\nMaybe run adb root?\n", fstab_filename);
goto errout;
}
@@ -218,12 +195,11 @@
}
if (any_changed) {
- write_console(
- fd, "Now reboot your device for settings to take effect\n");
+ WriteFdFmt(fd, "Now reboot your device for settings to take effect\n");
}
} else {
- write_console(fd, "%s-verity only works for userdebug builds\n",
- enable ? "enable" : "disable");
+ WriteFdFmt(fd, "%s-verity only works for userdebug builds\n",
+ enable ? "enable" : "disable");
}
errout:
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index f468029..621944e 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -37,23 +37,6 @@
static void local_socket_close_locked(asocket *s);
-int sendfailmsg(int fd, const char *reason)
-{
- char buf[9];
- int len;
- len = strlen(reason);
- if (len > 0xffff) {
- len = 0xffff;
- }
-
- snprintf(buf, sizeof buf, "FAIL%04x", len);
- if (!WriteFdExactly(fd, buf, 8)) {
- return -1;
- }
-
- return WriteFdExactly(fd, reason, len) ? 0 : -1;
-}
-
static unsigned local_socket_next_id = 1;
static asocket local_socket_list = {
@@ -608,7 +591,7 @@
s->ready = local_socket_ready;
s->shutdown = NULL;
s->close = local_socket_close;
- adb_write(s->fd, "OKAY", 4);
+ SendOkay(s->fd);
s->ready(s);
}
@@ -620,11 +603,11 @@
s->ready = local_socket_ready;
s->shutdown = NULL;
s->close = local_socket_close;
- sendfailmsg(s->fd, "closed");
+ SendFail(s->fd, "closed");
s->close(s);
}
-unsigned unhex(unsigned char *s, int len)
+static unsigned unhex(unsigned char *s, int len)
{
unsigned n = 0, c;
@@ -654,6 +637,8 @@
return n;
}
+#if ADB_HOST
+
#define PREFIX(str) { str, sizeof(str) - 1 }
static const struct prefix_struct {
const char *str;
@@ -670,7 +655,7 @@
skipping over the 'serial' parameter in the ADB protocol,
where parameter string may be a host:port string containing
the protocol delimiter (colon). */
-char *skip_host_serial(char *service) {
+static char *skip_host_serial(char *service) {
char *first_colon, *serial_end;
int i;
@@ -698,13 +683,15 @@
return serial_end;
}
+#endif // ADB_HOST
+
static int smart_socket_enqueue(asocket *s, apacket *p)
{
unsigned len;
#if ADB_HOST
char *service = NULL;
char* serial = NULL;
- transport_type ttype = kTransportAny;
+ TransportType type = kTransportAny;
#endif
D("SS(%d): enqueue %d\n", s->id, p->len);
@@ -761,13 +748,13 @@
service = serial_end + 1;
}
} else if (!strncmp(service, "host-usb:", strlen("host-usb:"))) {
- ttype = kTransportUsb;
+ type = kTransportUsb;
service += strlen("host-usb:");
} else if (!strncmp(service, "host-local:", strlen("host-local:"))) {
- ttype = kTransportLocal;
+ type = kTransportLocal;
service += strlen("host-local:");
} else if (!strncmp(service, "host:", strlen("host:"))) {
- ttype = kTransportAny;
+ type = kTransportAny;
service += strlen("host:");
} else {
service = NULL;
@@ -781,7 +768,7 @@
** the OKAY or FAIL message and all we have to do
** is clean up.
*/
- if(handle_host_request(service, ttype, serial, s->peer->fd, s) == 0) {
+ if(handle_host_request(service, type, serial, s->peer->fd, s) == 0) {
/* XXX fail message? */
D( "SS(%d): handled host service '%s'\n", s->id, service );
goto fail;
@@ -799,7 +786,7 @@
s2 = create_host_service_socket(service, serial);
if(s2 == 0) {
D( "SS(%d): couldn't create host service '%s'\n", s->id, service );
- sendfailmsg(s->peer->fd, "unknown host service");
+ SendFail(s->peer->fd, "unknown host service");
goto fail;
}
@@ -810,7 +797,7 @@
** connection, and close this smart socket now
** that its work is done.
*/
- adb_write(s->peer->fd, "OKAY", 4);
+ SendOkay(s->peer->fd);
s->peer->ready = local_socket_ready;
s->peer->shutdown = NULL;
@@ -828,20 +815,21 @@
#else /* !ADB_HOST */
if (s->transport == NULL) {
std::string error_msg = "unknown failure";
- s->transport = acquire_one_transport(CS_ANY, kTransportAny, NULL, &error_msg);
+ s->transport =
+ acquire_one_transport(kCsAny, kTransportAny, NULL, &error_msg);
if (s->transport == NULL) {
- sendfailmsg(s->peer->fd, error_msg.c_str());
+ SendFail(s->peer->fd, error_msg);
goto fail;
}
}
#endif
- if(!(s->transport) || (s->transport->connection_state == CS_OFFLINE)) {
+ if(!(s->transport) || (s->transport->connection_state == kCsOffline)) {
/* if there's no remote we fail the connection
** right here and terminate it
*/
- sendfailmsg(s->peer->fd, "device offline (x)");
+ SendFail(s->peer->fd, "device offline (x)");
goto fail;
}
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 59e5b0b..0aa1570 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -79,19 +79,13 @@
LeaveCriticalSection( lock );
}
-typedef struct { unsigned tid; } adb_thread_t;
-
typedef void* (*adb_thread_func_t)(void* arg);
typedef void (*win_thread_func_t)(void* arg);
-static __inline__ int adb_thread_create( adb_thread_t *thread, adb_thread_func_t func, void* arg)
-{
- thread->tid = _beginthread( (win_thread_func_t)func, 0, arg );
- if (thread->tid == (unsigned)-1L) {
- return -1;
- }
- return 0;
+static __inline__ bool adb_thread_create(adb_thread_func_t func, void* arg) {
+ uintptr_t tid = _beginthread((win_thread_func_t)func, 0, arg);
+ return (tid != static_cast<uintptr_t>(-1L));
}
static __inline__ unsigned long adb_thread_id()
@@ -429,18 +423,16 @@
#define unix_write adb_write
#define unix_close adb_close
-typedef pthread_t adb_thread_t;
-
typedef void* (*adb_thread_func_t)( void* arg );
-static __inline__ int adb_thread_create( adb_thread_t *pthread, adb_thread_func_t start, void* arg )
-{
- pthread_attr_t attr;
+static __inline__ bool adb_thread_create(adb_thread_func_t start, void* arg) {
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- pthread_attr_init (&attr);
- pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
-
- return pthread_create( pthread, &attr, start, arg );
+ pthread_t thread;
+ errno = pthread_create(&thread, &attr, start, arg);
+ return (errno == 0);
}
static __inline__ int adb_socket_setbufsize( int fd, int bufsize )
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index 633f6f5..a21272f 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -22,7 +22,6 @@
#include <windows.h>
#include <errno.h>
-#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/adb/test_track_devices.cpp b/adb/test_track_devices.cpp
index 77b3ad9..f78daeb 100644
--- a/adb/test_track_devices.cpp
+++ b/adb/test_track_devices.cpp
@@ -1,3 +1,5 @@
+// TODO: replace this with a shell/python script.
+
/* a simple test program, connects to ADB server, and opens a track-devices session */
#include <netdb.h>
#include <sys/socket.h>
@@ -6,6 +8,8 @@
#include <errno.h>
#include <memory.h>
+#include <base/file.h>
+
static void
panic( const char* msg )
{
@@ -13,85 +17,52 @@
exit(1);
}
-static int
-unix_write( int fd, const char* buf, int len )
-{
- int result = 0;
- while (len > 0) {
- int len2 = write(fd, buf, len);
- if (len2 < 0) {
- if (errno == EINTR || errno == EAGAIN)
- continue;
- return -1;
- }
- result += len2;
- len -= len2;
- buf += len2;
+int main(int argc, char* argv[]) {
+ const char* request = "host:track-devices";
+
+ if (argv[1] && strcmp(argv[1], "--jdwp") == 0) {
+ request = "track-jdwp";
}
- return result;
-}
-static int
-unix_read( int fd, char* buf, int len )
-{
- int result = 0;
- while (len > 0) {
- int len2 = read(fd, buf, len);
- if (len2 < 0) {
- if (errno == EINTR || errno == EAGAIN)
- continue;
- return -1;
- }
- result += len2;
- len -= len2;
- buf += len2;
- }
- return result;
-}
-
-
-int main( void )
-{
- int ret, s;
+ int ret;
struct sockaddr_in server;
char buffer[1024];
- const char* request = "host:track-devices";
- int len;
memset( &server, 0, sizeof(server) );
server.sin_family = AF_INET;
server.sin_port = htons(5037);
server.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- s = socket( PF_INET, SOCK_STREAM, 0 );
+ int s = socket( PF_INET, SOCK_STREAM, 0 );
ret = connect( s, (struct sockaddr*) &server, sizeof(server) );
if (ret < 0) panic( "could not connect to server" );
/* send the request */
- len = snprintf( buffer, sizeof buffer, "%04x%s", strlen(request), request );
- if (unix_write(s, buffer, len) < 0)
+ int len = snprintf(buffer, sizeof(buffer), "%04zx%s", strlen(request), request);
+ if (!android::base::WriteFully(s, buffer, len))
panic( "could not send request" );
/* read the OKAY answer */
- if (unix_read(s, buffer, 4) != 4)
+ if (!android::base::ReadFully(s, buffer, 4))
panic( "could not read request" );
printf( "server answer: %.*s\n", 4, buffer );
/* now loop */
- for (;;) {
+ while (true) {
char head[5] = "0000";
- if (unix_read(s, head, 4) < 0)
+ if (!android::base::ReadFully(s, head, 4))
panic("could not read length");
- if ( sscanf( head, "%04x", &len ) != 1 )
+ int len;
+ if (sscanf(head, "%04x", &len) != 1 )
panic("could not decode length");
- if (unix_read(s, buffer, len) != len)
+ if (!android::base::ReadFully(s, buffer, len))
panic("could not read data");
- printf( "received header %.*s (%d bytes):\n%.*s", 4, head, len, len, buffer );
+ printf( "received header %.*s (%d bytes):\n%.*s----\n", 4, head, len, len, buffer );
}
close(s);
}
diff --git a/adb/test_track_jdwp.cpp b/adb/test_track_jdwp.cpp
deleted file mode 100644
index 8ecc6b8..0000000
--- a/adb/test_track_jdwp.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-/* a simple test program, connects to ADB server, and opens a track-devices session */
-#include <netdb.h>
-#include <sys/socket.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <memory.h>
-
-static void
-panic( const char* msg )
-{
- fprintf(stderr, "PANIC: %s: %s\n", msg, strerror(errno));
- exit(1);
-}
-
-static int
-unix_write( int fd, const char* buf, int len )
-{
- int result = 0;
- while (len > 0) {
- int len2 = write(fd, buf, len);
- if (len2 < 0) {
- if (errno == EINTR || errno == EAGAIN)
- continue;
- return -1;
- }
- result += len2;
- len -= len2;
- buf += len2;
- }
- return result;
-}
-
-static int
-unix_read( int fd, char* buf, int len )
-{
- int result = 0;
- while (len > 0) {
- int len2 = read(fd, buf, len);
- if (len2 < 0) {
- if (errno == EINTR || errno == EAGAIN)
- continue;
- return -1;
- }
- result += len2;
- len -= len2;
- buf += len2;
- }
- return result;
-}
-
-
-int main( void )
-{
- int ret, s;
- struct sockaddr_in server;
- char buffer[1024];
- const char* request = "track-jdwp";
- int len;
-
- memset( &server, 0, sizeof(server) );
- server.sin_family = AF_INET;
- server.sin_port = htons(5037);
- server.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-
- s = socket( PF_INET, SOCK_STREAM, 0 );
- ret = connect( s, (struct sockaddr*) &server, sizeof(server) );
- if (ret < 0) panic( "could not connect to server" );
-
- /* send the request */
- len = snprintf( buffer, sizeof buffer, "%04x%s", strlen(request), request );
- if (unix_write(s, buffer, len) < 0)
- panic( "could not send request" );
-
- /* read the OKAY answer */
- if (unix_read(s, buffer, 4) != 4)
- panic( "could not read request" );
-
- printf( "server answer: %.*s\n", 4, buffer );
-
- /* now loop */
- for (;;) {
- char head[5] = "0000";
-
- if (unix_read(s, head, 4) < 0)
- panic("could not read length");
-
- if ( sscanf( head, "%04x", &len ) != 1 )
- panic("could not decode length");
-
- if (unix_read(s, buffer, len) != len)
- panic("could not read data");
-
- printf( "received header %.*s (%d bytes):\n%.*s", 4, head, len, len, buffer );
- }
- close(s);
-}
diff --git a/adb/tests/test_adb.py b/adb/tests/test_adb.py
index 52d8056..4eccc8c 100755
--- a/adb/tests/test_adb.py
+++ b/adb/tests/test_adb.py
@@ -6,6 +6,7 @@
"""
import hashlib
import os
+import pipes
import random
import re
import shlex
@@ -162,6 +163,10 @@
def shell_nocheck(self, cmd):
return call_combined(self.adb_cmd + "shell " + cmd)
+ def install(self, filename):
+ return call_checked(
+ self.adb_cmd + "install {}".format(pipes.quote(filename)))
+
def push(self, local, remote):
return call_checked(self.adb_cmd + "push {} {}".format(local, remote))
@@ -272,13 +277,43 @@
adb = AdbWrapper()
# http://b/19734868
+ # Note that this actually matches ssh(1)'s behavior --- it's
+ # converted to "sh -c echo hello; echo world" which sh interprets
+ # as "sh -c echo" (with an argument to that shell of "hello"),
+ # and then "echo world" back in the first shell.
result = adb.shell("sh -c 'echo hello; echo world'").splitlines()
+ self.assertEqual(["", "world"], result)
+ # If you really wanted "hello" and "world", here's what you'd do:
+ result = adb.shell(r"echo hello\;echo world").splitlines()
self.assertEqual(["hello", "world"], result)
# http://b/15479704
self.assertEqual('t', adb.shell("'true && echo t'").strip())
self.assertEqual('t', adb.shell("sh -c 'true && echo t'").strip())
+ # http://b/20564385
+ self.assertEqual('t', adb.shell("FOO=a BAR=b echo t").strip())
+ self.assertEqual('123Linux', adb.shell(r"echo -n 123\;uname").strip())
+
+ def test_install_argument_escaping(self):
+ """Make sure that install argument escaping works."""
+ adb = AdbWrapper()
+
+ # http://b/20323053
+ tf = tempfile.NamedTemporaryFile("w", suffix="-text;ls;1.apk")
+ self.assertIn("-text;ls;1.apk", adb.install(tf.name))
+
+ # http://b/3090932
+ tf = tempfile.NamedTemporaryFile("w", suffix="-Live Hold'em.apk")
+ self.assertIn("-Live Hold'em.apk", adb.install(tf.name))
+
+ def test_line_endings(self):
+ """Ensure that line ending translation is not happening in the pty.
+
+ Bug: http://b/19735063
+ """
+ self.assertFalse(AdbWrapper().shell("uname").endswith("\r\n"))
+
class AdbFile(unittest.TestCase):
SCRATCH_DIR = "/data/local/tmp"
diff --git a/adb/transport.cpp b/adb/transport.cpp
index d395a80..818ed97 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -26,7 +26,10 @@
#include <string.h>
#include <unistd.h>
+#include <base/stringprintf.h>
+
#include "adb.h"
+#include "adb_utils.h"
static void transport_unref(atransport *t);
@@ -42,34 +45,6 @@
ADB_MUTEX_DEFINE( transport_lock );
-#if ADB_TRACE
-#define MAX_DUMP_HEX_LEN 16
-void dump_hex(const unsigned char* ptr, size_t len)
-{
- int nn, len2 = len;
- // Build a string instead of logging each character.
- // MAX chars in 2 digit hex, one space, MAX chars, one '\0'.
- char buffer[MAX_DUMP_HEX_LEN *2 + 1 + MAX_DUMP_HEX_LEN + 1 ], *pb = buffer;
-
- if (len2 > MAX_DUMP_HEX_LEN) len2 = MAX_DUMP_HEX_LEN;
-
- for (nn = 0; nn < len2; nn++) {
- sprintf(pb, "%02x", ptr[nn]);
- pb += 2;
- }
- sprintf(pb++, " ");
-
- for (nn = 0; nn < len2; nn++) {
- int c = ptr[nn];
- if (c < 32 || c > 127)
- c = '.';
- *pb++ = c;
- }
- *pb++ = '\0';
- DR("%s\n", buffer);
-}
-#endif
-
void kick_transport(atransport* t)
{
if (t && !t->kicked)
@@ -117,10 +92,7 @@
}
}
-#if ADB_TRACE
-static void
-dump_packet(const char* name, const char* func, apacket* p)
-{
+static void dump_packet(const char* name, const char* func, apacket* p) {
unsigned command = p->msg.command;
int len = p->msg.data_length;
char cmd[9];
@@ -155,7 +127,6 @@
name, func, cmd, arg0, arg1, len);
dump_hex(p->data, len);
}
-#endif /* ADB_TRACE */
static int
read_packet(int fd, const char* name, apacket** ppacket)
@@ -180,11 +151,9 @@
}
}
-#if ADB_TRACE
if (ADB_TRACING) {
dump_packet(name, "from remote", *ppacket);
}
-#endif
return 0;
}
@@ -199,11 +168,9 @@
name = buff;
}
-#if ADB_TRACE
if (ADB_TRACING) {
dump_packet(name, "to remote", *ppacket);
}
-#endif
len = sizeof(ppacket);
while(len > 0) {
r = adb_write(fd, p, len);
@@ -389,17 +356,6 @@
#if ADB_HOST
-static int list_transports_msg(char* buffer, size_t bufferlen)
-{
- char head[5];
- int len;
-
- len = list_transports(buffer+4, bufferlen-4, 0);
- snprintf(head, sizeof(head), "%04x", len);
- memcpy(buffer, head, 4);
- len += 4;
- return len;
-}
/* this adds support required by the 'track-devices' service.
* this is used to send the content of "list_transport" to any
@@ -457,39 +413,29 @@
return -1;
}
-static int
-device_tracker_send( device_tracker* tracker,
- const char* buffer,
- int len )
-{
- apacket* p = get_apacket();
- asocket* peer = tracker->socket.peer;
+static int device_tracker_send(device_tracker* tracker, const std::string& string) {
+ apacket* p = get_apacket();
+ asocket* peer = tracker->socket.peer;
- memcpy(p->data, buffer, len);
- p->len = len;
- return peer->enqueue( peer, p );
+ snprintf(reinterpret_cast<char*>(p->data), 5, "%04x", static_cast<int>(string.size()));
+ memcpy(&p->data[4], string.data(), string.size());
+ p->len = 4 + string.size();
+ return peer->enqueue(peer, p);
}
+static void device_tracker_ready(asocket* socket) {
+ device_tracker* tracker = reinterpret_cast<device_tracker*>(socket);
-static void
-device_tracker_ready( asocket* socket )
-{
- device_tracker* tracker = (device_tracker*) socket;
-
- /* we want to send the device list when the tracker connects
- * for the first time, even if no update occured */
+ // We want to send the device list when the tracker connects
+ // for the first time, even if no update occurred.
if (tracker->update_needed > 0) {
- char buffer[1024];
- int len;
-
tracker->update_needed = 0;
- len = list_transports_msg(buffer, sizeof(buffer));
- device_tracker_send(tracker, buffer, len);
+ std::string transports = list_transports(false);
+ device_tracker_send(tracker, transports);
}
}
-
asocket*
create_device_tracker(void)
{
@@ -510,27 +456,25 @@
}
-/* call this function each time the transport list has changed */
-void update_transports(void) {
- char buffer[1024];
- int len;
- device_tracker* tracker;
+// Call this function each time the transport list has changed.
+void update_transports() {
+ std::string transports = list_transports(false);
- len = list_transports_msg(buffer, sizeof(buffer));
-
- tracker = device_tracker_list;
- while (tracker != NULL) {
- device_tracker* next = tracker->next;
- /* note: this may destroy the tracker if the connection is closed */
- device_tracker_send(tracker, buffer, len);
+ device_tracker* tracker = device_tracker_list;
+ while (tracker != nullptr) {
+ device_tracker* next = tracker->next;
+ // This may destroy the tracker if the connection is closed.
+ device_tracker_send(tracker, transports);
tracker = next;
}
}
+
#else
-void update_transports(void)
-{
- // nothing to do on the device side
+
+void update_transports() {
+ // Nothing to do on the device side.
}
+
#endif // ADB_HOST
struct tmsg
@@ -586,8 +530,6 @@
static void transport_registration_func(int _fd, unsigned ev, void *data)
{
tmsg m;
- adb_thread_t output_thread_ptr;
- adb_thread_t input_thread_ptr;
int s[2];
atransport *t;
@@ -636,7 +578,7 @@
}
/* don't create transport threads for inaccessible devices */
- if (t->connection_state != CS_NOPERM) {
+ if (t->connection_state != kCsNoPerm) {
/* initial references are the two threads */
t->ref_count = 2;
@@ -656,11 +598,11 @@
fdevent_set(&(t->transport_fde), FDE_READ);
- if(adb_thread_create(&input_thread_ptr, input_thread, t)){
+ if (!adb_thread_create(input_thread, t)) {
fatal_errno("cannot create input thread");
}
- if(adb_thread_create(&output_thread_ptr, output_thread, t)){
+ if (!adb_thread_create(output_thread, t)) {
fatal_errno("cannot create output thread");
}
}
@@ -796,19 +738,18 @@
return !*to_test;
}
-atransport* acquire_one_transport(int state, transport_type ttype,
- const char* serial, std::string* error_out)
-{
+atransport* acquire_one_transport(ConnectionState state, TransportType type,
+ const char* serial, std::string* error_out) {
atransport *t;
atransport *result = NULL;
int ambiguous = 0;
retry:
- if (error_out) *error_out = "device not found";
+ if (error_out) *error_out = android::base::StringPrintf("device '%s' not found", serial);
adb_mutex_lock(&transport_lock);
for (t = transport_list.next; t != &transport_list; t = t->next) {
- if (t->connection_state == CS_NOPERM) {
+ if (t->connection_state == kCsNoPerm) {
if (error_out) *error_out = "insufficient permissions for device";
continue;
}
@@ -829,7 +770,7 @@
result = t;
}
} else {
- if (ttype == kTransportUsb && t->type == kTransportUsb) {
+ if (type == kTransportUsb && t->type == kTransportUsb) {
if (result) {
if (error_out) *error_out = "more than one device";
ambiguous = 1;
@@ -837,7 +778,7 @@
break;
}
result = t;
- } else if (ttype == kTransportLocal && t->type == kTransportLocal) {
+ } else if (type == kTransportLocal && t->type == kTransportLocal) {
if (result) {
if (error_out) *error_out = "more than one emulator";
ambiguous = 1;
@@ -845,9 +786,9 @@
break;
}
result = t;
- } else if (ttype == kTransportAny) {
+ } else if (type == kTransportAny) {
if (result) {
- if (error_out) *error_out = "more than one device and emulator";
+ if (error_out) *error_out = "more than one device/emulator";
ambiguous = 1;
result = NULL;
break;
@@ -859,7 +800,7 @@
adb_mutex_unlock(&transport_lock);
if (result) {
- if (result->connection_state == CS_UNAUTHORIZED) {
+ if (result->connection_state == kCsUnauthorized) {
if (error_out) {
*error_out = "device unauthorized.\n";
char* ADB_VENDOR_KEYS = getenv("ADB_VENDOR_KEYS");
@@ -872,13 +813,13 @@
}
/* offline devices are ignored -- they are either being born or dying */
- if (result && result->connection_state == CS_OFFLINE) {
+ if (result && result->connection_state == kCsOffline) {
if (error_out) *error_out = "device offline";
result = NULL;
}
/* check for required connection state */
- if (result && state != CS_ANY && result->connection_state != state) {
+ if (result && state != kCsAny && result->connection_state != state) {
if (error_out) *error_out = "invalid device state";
result = NULL;
}
@@ -887,7 +828,7 @@
if (result) {
/* found one that we can take */
if (error_out) *error_out = "success";
- } else if (state != CS_ANY && (serial || !ambiguous)) {
+ } else if (state != kCsAny && (serial || !ambiguous)) {
adb_sleep_ms(1000);
goto retry;
}
@@ -895,100 +836,72 @@
return result;
}
-#if ADB_HOST
-static const char *statename(atransport *t)
-{
- switch(t->connection_state){
- case CS_OFFLINE: return "offline";
- case CS_BOOTLOADER: return "bootloader";
- case CS_DEVICE: return "device";
- case CS_HOST: return "host";
- case CS_RECOVERY: return "recovery";
- case CS_SIDELOAD: return "sideload";
- case CS_NOPERM: return "no permissions";
- case CS_UNAUTHORIZED: return "unauthorized";
+const char* atransport::connection_state_name() const {
+ switch (connection_state) {
+ case kCsOffline: return "offline";
+ case kCsBootloader: return "bootloader";
+ case kCsDevice: return "device";
+ case kCsHost: return "host";
+ case kCsRecovery: return "recovery";
+ case kCsNoPerm: return "no permissions";
+ case kCsSideload: return "sideload";
+ case kCsUnauthorized: return "unauthorized";
default: return "unknown";
}
}
-static void add_qual(char **buf, size_t *buf_size,
- const char *prefix, const char *qual, bool sanitize_qual)
-{
- if (!buf || !*buf || !buf_size || !*buf_size || !qual || !*qual)
+#if ADB_HOST
+
+static void append_transport_info(std::string* result, const char* key,
+ const char* value, bool sanitize) {
+ if (value == nullptr || *value == '\0') {
return;
-
- int prefix_len;
- size_t len = snprintf(*buf, *buf_size, "%s%n%s", prefix, &prefix_len, qual);
-
- if (sanitize_qual) {
- for (char* cp = *buf + prefix_len; cp < *buf + len; cp++) {
- if (!isalnum(*cp))
- *cp = '_';
- }
}
- *buf_size -= len;
- *buf += len;
+ *result += ' ';
+ *result += key;
+
+ for (const char* p = value; *p; ++p) {
+ result->push_back((!sanitize || isalnum(*p)) ? *p : '_');
+ }
}
-static size_t format_transport(atransport *t, char *buf, size_t bufsize,
- int long_listing)
-{
+static void append_transport(atransport* t, std::string* result, bool long_listing) {
const char* serial = t->serial;
- if (!serial || !serial[0])
- serial = "????????????";
+ if (!serial || !serial[0]) {
+ serial = "(no serial number)";
+ }
if (!long_listing) {
- return snprintf(buf, bufsize, "%s\t%s\n", serial, statename(t));
+ *result += serial;
+ *result += '\t';
+ *result += t->connection_state_name();
} else {
- size_t len, remaining = bufsize;
+ android::base::StringAppendF(result, "%-22s %s", serial, t->connection_state_name());
- len = snprintf(buf, remaining, "%-22s %s", serial, statename(t));
- remaining -= len;
- buf += len;
-
- add_qual(&buf, &remaining, " ", t->devpath, false);
- add_qual(&buf, &remaining, " product:", t->product, false);
- add_qual(&buf, &remaining, " model:", t->model, true);
- add_qual(&buf, &remaining, " device:", t->device, false);
-
- len = snprintf(buf, remaining, "\n");
- remaining -= len;
-
- return bufsize - remaining;
+ append_transport_info(result, "", t->devpath, false);
+ append_transport_info(result, "product:", t->product, false);
+ append_transport_info(result, "model:", t->model, true);
+ append_transport_info(result, "device:", t->device, false);
}
+ *result += '\n';
}
-int list_transports(char *buf, size_t bufsize, int long_listing)
-{
- char* p = buf;
- char* end = buf + bufsize;
- int len;
- atransport *t;
-
- /* XXX OVERRUN PROBLEMS XXX */
+std::string list_transports(bool long_listing) {
+ std::string result;
adb_mutex_lock(&transport_lock);
- for(t = transport_list.next; t != &transport_list; t = t->next) {
- len = format_transport(t, p, end - p, long_listing);
- if (p + len >= end) {
- /* discard last line if buffer is too short */
- break;
- }
- p += len;
+ for (atransport* t = transport_list.next; t != &transport_list; t = t->next) {
+ append_transport(t, &result, long_listing);
}
- p[0] = 0;
adb_mutex_unlock(&transport_lock);
- return p - buf;
+ return result;
}
-
/* hack for osx */
void close_usb_devices()
{
- atransport *t;
-
adb_mutex_lock(&transport_lock);
- for(t = transport_list.next; t != &transport_list; t = t->next) {
+ for (atransport* t = transport_list.next; t != &transport_list; t = t->next) {
if ( !t->kicked ) {
t->kicked = 1;
t->kick(t);
@@ -1107,7 +1020,7 @@
if (t == nullptr) fatal("cannot allocate USB atransport");
D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb,
serial ? serial : "");
- init_usb_transport(t, usb, (writeable ? CS_OFFLINE : CS_NOPERM));
+ init_usb_transport(t, usb, (writeable ? kCsOffline : kCsNoPerm));
if(serial) {
t->serial = strdup(serial);
}
@@ -1125,18 +1038,17 @@
register_transport(t);
}
-/* this should only be used for transports with connection_state == CS_NOPERM */
-void unregister_usb_transport(usb_handle *usb)
-{
- atransport *t;
+// This should only be used for transports with connection_state == kCsNoPerm.
+void unregister_usb_transport(usb_handle* usb) {
adb_mutex_lock(&transport_lock);
- for(t = transport_list.next; t != &transport_list; t = t->next) {
- if (t->usb == usb && t->connection_state == CS_NOPERM) {
+ for (atransport* t = transport_list.next; t != &transport_list;
+ t = t->next) {
+ if (t->usb == usb && t->connection_state == kCsNoPerm) {
t->next->prev = t->prev;
t->prev->next = t->next;
break;
}
- }
+ }
adb_mutex_unlock(&transport_lock);
}
diff --git a/adb/transport.h b/adb/transport.h
index a2077e8..538f63e 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -23,17 +23,13 @@
#include "adb.h"
-#if ADB_TRACE
-void dump_hex(const unsigned char* ptr, size_t len);
-#endif
-
/*
* Obtain a transport from the available transports.
- * If state is != CS_ANY, only transports in that state are considered.
+ * If state is != kCsAny, only transports in that state are considered.
* If serial is non-NULL then only the device with that serial will be chosen.
* If no suitable transport is found, error is set.
*/
-atransport* acquire_one_transport(int state, transport_type ttype,
+atransport* acquire_one_transport(ConnectionState state, TransportType type,
const char* serial, std::string* error_out);
void add_transport_disconnect(atransport* t, adisconnect* dis);
void remove_transport_disconnect(atransport* t, adisconnect* dis);
@@ -45,7 +41,7 @@
** get_device_transport does an acquire on your behalf before returning
*/
void init_transport_registration(void);
-int list_transports(char* buf, size_t bufsize, int long_listing);
+std::string list_transports(bool long_listing);
atransport* find_transport(const char* serial);
void register_usb_transport(usb_handle* h, const char* serial,
@@ -54,7 +50,7 @@
/* cause new transports to be init'd and added to the list */
int register_socket_transport(int s, const char* serial, int port, int local);
-/* this should only be used for transports with connection_state == CS_NOPERM */
+// This should only be used for transports with connection_state == kCsNoPerm.
void unregister_usb_transport(usb_handle* usb);
/* these should only be used for the "adb disconnect" command */
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index 30e6bf5..d3c4c30 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -25,6 +25,8 @@
#include <string.h>
#include <sys/types.h>
+#include <base/stringprintf.h>
+
#if !ADB_HOST
#include "cutils/properties.h"
#endif
@@ -88,7 +90,6 @@
int local_connect_arbitrary_ports(int console_port, int adb_port)
{
- char buf[64];
int fd = -1;
#if ADB_HOST
@@ -105,8 +106,8 @@
D("client: connected on remote on fd %d\n", fd);
close_on_exec(fd);
disable_tcp_nagle(fd);
- snprintf(buf, sizeof buf, "%s%d", LOCAL_CLIENT_PREFIX, console_port);
- register_socket_transport(fd, buf, adb_port, 1);
+ std::string serial = android::base::StringPrintf("emulator-%d", console_port);
+ register_socket_transport(fd, serial.c_str(), adb_port, 1);
return 0;
}
return -1;
@@ -233,9 +234,8 @@
if (fd < 0) {
/* This could be an older version of the emulator, that doesn't
* implement adb QEMUD service. Fall back to the old TCP way. */
- adb_thread_t thr;
D("adb service is not available. Falling back to TCP socket.\n");
- adb_thread_create(&thr, server_socket_thread, arg);
+ adb_thread_create(server_socket_thread, arg);
return 0;
}
@@ -278,7 +278,6 @@
void local_init(int port)
{
- adb_thread_t thr;
void* (*func)(void *);
if(HOST) {
@@ -303,9 +302,8 @@
D("transport: local %s init\n", HOST ? "client" : "server");
- if(adb_thread_create(&thr, func, (void *) (uintptr_t) port)) {
- fatal_errno("cannot create local socket %s thread",
- HOST ? "client" : "server");
+ if (!adb_thread_create(func, (void *) (uintptr_t) port)) {
+ fatal_errno("cannot create local socket %s thread", HOST ? "client" : "server");
}
}
@@ -389,7 +387,7 @@
t->write_to_remote = remote_write;
t->sfd = s;
t->sync_token = 1;
- t->connection_state = CS_OFFLINE;
+ t->connection_state = kCsOffline;
t->type = kTransportLocal;
t->adb_port = 0;
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index cdabffe..eb3454d 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -80,7 +80,7 @@
usb_kick(t->usb);
}
-void init_usb_transport(atransport *t, usb_handle *h, int state)
+void init_usb_transport(atransport *t, usb_handle *h, ConnectionState state)
{
D("transport: usb\n");
t->close = remote_close;
diff --git a/adb/usb_linux.cpp b/adb/usb_linux.cpp
index 999eb11..1e5d5c8 100644
--- a/adb/usb_linux.cpp
+++ b/adb/usb_linux.cpp
@@ -310,10 +310,6 @@
closedir(busdir);
}
-void usb_cleanup()
-{
-}
-
static int usb_bulk_write(usb_handle *h, const void *data, int len)
{
struct usbdevfs_urb *urb = &h->urb_out;
@@ -569,16 +565,15 @@
static void register_device(const char* dev_name, const char* dev_path,
unsigned char ep_in, unsigned char ep_out,
- int interface, int serial_index, unsigned zero_mask)
-{
- /* Since Linux will not reassign the device ID (and dev_name)
- ** as long as the device is open, we can add to the list here
- ** once we open it and remove from the list when we're finally
- ** closed and everything will work out fine.
- **
- ** If we have a usb_handle on the list 'o handles with a matching
- ** name, we have no further work to do.
- */
+ int interface, int serial_index,
+ unsigned zero_mask) {
+ // Since Linux will not reassign the device ID (and dev_name) as long as the
+ // device is open, we can add to the list here once we open it and remove
+ // from the list when we're finally closed and everything will work out
+ // fine.
+ //
+ // If we have a usb_handle on the list 'o handles with a matching name, we
+ // have no further work to do.
adb_mutex_lock(&usb_lock);
for (usb_handle* usb = handle_list.next; usb != &handle_list; usb = usb->next) {
if (!strcmp(usb->fname, dev_name)) {
@@ -599,7 +594,8 @@
adb_cond_init(&usb->notify, 0);
adb_mutex_init(&usb->lock, 0);
- /* initialize mark to 1 so we don't get garbage collected after the device scan */
+ // Initialize mark to 1 so we don't get garbage collected after the device
+ // scan.
usb->mark = 1;
usb->reaper_thread = 0;
@@ -615,11 +611,13 @@
usb->writeable = 0;
}
- D("[ usb opened %s%s, fd=%d]\n", usb->fname, (usb->writeable ? "" : " (read-only)"), usb->desc);
+ D("[ usb opened %s%s, fd=%d]\n", usb->fname,
+ (usb->writeable ? "" : " (read-only)"), usb->desc);
if (usb->writeable) {
if (ioctl(usb->desc, USBDEVFS_CLAIMINTERFACE, &interface) != 0) {
- D("[ usb ioctl(%d, USBDEVFS_CLAIMINTERFACE) failed: %s]\n", usb->desc, strerror(errno));
+ D("[ usb ioctl(%d, USBDEVFS_CLAIMINTERFACE) failed: %s]\n",
+ usb->desc, strerror(errno));
adb_close(usb->desc);
free(usb);
return;
@@ -627,18 +625,19 @@
}
// Read the device's serial number.
- std::string serial_path =
- android::base::StringPrintf("/sys/bus/usb/devices/%s/serial", dev_path + 4);
+ std::string serial_path = android::base::StringPrintf(
+ "/sys/bus/usb/devices/%s/serial", dev_path + 4);
std::string serial;
if (!android::base::ReadFileToString(serial_path, &serial)) {
D("[ usb read %s failed: %s ]\n", serial_path.c_str(), strerror(errno));
- adb_close(usb->desc);
- free(usb);
- return;
+ // We don't actually want to treat an unknown serial as an error because
+ // devices aren't able to communicate a serial number in early bringup.
+ // http://b/20883914
+ serial = "";
}
serial = android::base::Trim(serial);
- /* add to the end of the active handles */
+ // Add to the end of the active handles.
adb_mutex_lock(&usb_lock);
usb->next = &handle_list;
usb->prev = handle_list.prev;
@@ -649,26 +648,23 @@
register_usb_transport(usb, serial.c_str(), dev_path, usb->writeable);
}
-static void* device_poll_thread(void* unused)
-{
+static void* device_poll_thread(void* unused) {
D("Created device thread\n");
- for(;;) {
- /* XXX use inotify */
+ while (true) {
+ // TODO: Use inotify.
find_usb_device("/dev/bus/usb", register_device);
kick_disconnected_devices();
sleep(1);
}
- return NULL;
+ return nullptr;
}
-static void sigalrm_handler(int signo)
-{
+static void sigalrm_handler(int signo) {
// don't need to do anything here
}
void usb_init()
{
- adb_thread_t tid;
struct sigaction actions;
memset(&actions, 0, sizeof(actions));
@@ -677,7 +673,7 @@
actions.sa_handler = sigalrm_handler;
sigaction(SIGALRM,& actions, NULL);
- if(adb_thread_create(&tid, device_poll_thread, NULL)){
+ if (!adb_thread_create(device_poll_thread, nullptr)) {
fatal_errno("cannot create input thread");
}
}
diff --git a/adb/usb_linux_client.cpp b/adb/usb_linux_client.cpp
index 18289e2..63bb1c7 100644
--- a/adb/usb_linux_client.cpp
+++ b/adb/usb_linux_client.cpp
@@ -82,7 +82,7 @@
struct func_desc fs_descs, hs_descs;
} __attribute__((packed));
-struct func_desc fs_descriptors = {
+static struct func_desc fs_descriptors = {
.intf = {
.bLength = sizeof(fs_descriptors.intf),
.bDescriptorType = USB_DT_INTERFACE,
@@ -109,7 +109,7 @@
},
};
-struct func_desc hs_descriptors = {
+static struct func_desc hs_descriptors = {
.intf = {
.bLength = sizeof(hs_descriptors.intf),
.bDescriptorType = USB_DT_INTERFACE,
@@ -264,8 +264,7 @@
}
D("[ usb_init - starting thread ]\n");
- adb_thread_t tid;
- if(adb_thread_create(&tid, usb_adb_open_thread, h)){
+ if (!adb_thread_create(usb_adb_open_thread, h)) {
fatal_errno("cannot create usb thread");
}
}
@@ -483,8 +482,7 @@
adb_mutex_init(&h->lock, 0);
D("[ usb_init - starting thread ]\n");
- adb_thread_t tid;
- if (adb_thread_create(&tid, usb_ffs_open_thread, h)){
+ if (!adb_thread_create(usb_ffs_open_thread, h)) {
fatal_errno("[ cannot create usb thread ]\n");
}
}
@@ -497,10 +495,6 @@
usb_adb_init();
}
-void usb_cleanup()
-{
-}
-
int usb_write(usb_handle *h, const void *data, int len)
{
return h->write(h, data, len);
diff --git a/adb/usb_osx.cpp b/adb/usb_osx.cpp
index a795ce3..af65130 100644
--- a/adb/usb_osx.cpp
+++ b/adb/usb_osx.cpp
@@ -398,22 +398,27 @@
IONotificationPortDestroy(notificationPort);
DBG("RunLoopThread done\n");
- return NULL;
+ return NULL;
}
+static void usb_cleanup() {
+ DBG("usb_cleanup\n");
+ close_usb_devices();
+ if (currentRunLoop)
+ CFRunLoopStop(currentRunLoop);
+}
-static int initialized = 0;
-void usb_init()
-{
- if (!initialized)
- {
- adb_thread_t tid;
+void usb_init() {
+ static bool initialized = false;
+ if (!initialized) {
+ atexit(usb_cleanup);
adb_mutex_init(&start_lock, NULL);
adb_cond_init(&start_cond, NULL);
- if(adb_thread_create(&tid, RunLoopThread, NULL))
+ if (!adb_thread_create(RunLoopThread, nullptr)) {
fatal_errno("cannot create input thread");
+ }
// Wait for initialization to finish
adb_mutex_lock(&start_lock);
@@ -423,18 +428,10 @@
adb_mutex_destroy(&start_lock);
adb_cond_destroy(&start_cond);
- initialized = 1;
+ initialized = true;
}
}
-void usb_cleanup()
-{
- DBG("usb_cleanup\n");
- close_usb_devices();
- if (currentRunLoop)
- CFRunLoopStop(currentRunLoop);
-}
-
int usb_write(usb_handle *handle, const void *buf, int len)
{
IOReturn result;
diff --git a/adb/usb_windows.cpp b/adb/usb_windows.cpp
index d2bd58c..25deb1b 100644
--- a/adb/usb_windows.cpp
+++ b/adb/usb_windows.cpp
@@ -93,9 +93,6 @@
/// Initializes this module
void usb_init();
-/// Cleans up this module
-void usb_cleanup();
-
/// Opens usb interface (device) by interface (device) name.
usb_handle* do_usb_open(const wchar_t* interface_name);
@@ -181,16 +178,11 @@
}
void usb_init() {
- adb_thread_t tid;
-
- if(adb_thread_create(&tid, device_poll_thread, NULL)) {
+ if (!adb_thread_create(device_poll_thread, nullptr)) {
fatal_errno("cannot create input thread");
}
}
-void usb_cleanup() {
-}
-
usb_handle* do_usb_open(const wchar_t* interface_name) {
// Allocate our handle
usb_handle* ret = (usb_handle*)malloc(sizeof(usb_handle));
diff --git a/base/file.cpp b/base/file.cpp
index 6b19818..9a340b7 100644
--- a/base/file.cpp
+++ b/base/file.cpp
@@ -51,7 +51,7 @@
return false;
}
bool result = ReadFdToString(fd, content);
- TEMP_FAILURE_RETRY(close(fd));
+ close(fd);
return result;
}
@@ -102,7 +102,7 @@
ALOGE("android::WriteStringToFile write failed: %s", strerror(errno));
return CleanUpAfterFailedWrite(path);
}
- TEMP_FAILURE_RETRY(close(fd));
+ close(fd);
return true;
}
#endif
@@ -116,7 +116,7 @@
}
bool result = WriteStringToFd(content, fd);
- TEMP_FAILURE_RETRY(close(fd));
+ close(fd);
return result || CleanUpAfterFailedWrite(path);
}
diff --git a/base/file_test.cpp b/base/file_test.cpp
index cbb2751..b138094 100644
--- a/base/file_test.cpp
+++ b/base/file_test.cpp
@@ -66,7 +66,7 @@
<< strerror(errno);
struct stat sb;
ASSERT_EQ(0, stat(tf.filename, &sb));
- ASSERT_EQ(0660U, (sb.st_mode & ~S_IFMT));
+ ASSERT_EQ(0660U, static_cast<unsigned int>(sb.st_mode & ~S_IFMT));
ASSERT_EQ(getuid(), sb.st_uid);
ASSERT_EQ(getgid(), sb.st_gid);
std::string s;
diff --git a/base/include/base/logging.h b/base/include/base/logging.h
index 230adb8..283a7bc 100644
--- a/base/include/base/logging.h
+++ b/base/include/base/logging.h
@@ -13,10 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
#ifndef BASE_LOGGING_H
#define BASE_LOGGING_H
+// NOTE: For Windows, you must include logging.h after windows.h to allow the
+// following code to suppress the evil ERROR macro:
+#ifdef _WIN32
+// windows.h includes wingdi.h which defines an evil macro ERROR.
+#ifdef ERROR
+#undef ERROR
+#endif
+#endif
+
#include <functional>
#include <memory>
#include <ostream>
diff --git a/base/include/base/stringprintf.h b/base/include/base/stringprintf.h
index 195c1dec..d68af87 100644
--- a/base/include/base/stringprintf.h
+++ b/base/include/base/stringprintf.h
@@ -23,16 +23,32 @@
namespace android {
namespace base {
+// These printf-like functions are implemented in terms of vsnprintf, so they
+// use the same attribute for compile-time format string checking. On Windows,
+// if the mingw version of vsnprintf is used, use `gnu_printf' which allows z
+// in %zd and PRIu64 (and related) to be recognized by the compile-time
+// checking.
+#define FORMAT_ARCHETYPE __printf__
+#ifdef __USE_MINGW_ANSI_STDIO
+#if __USE_MINGW_ANSI_STDIO
+#undef FORMAT_ARCHETYPE
+#define FORMAT_ARCHETYPE gnu_printf
+#endif
+#endif
+
// Returns a string corresponding to printf-like formatting of the arguments.
std::string StringPrintf(const char* fmt, ...)
- __attribute__((__format__(__printf__, 1, 2)));
+ __attribute__((__format__(FORMAT_ARCHETYPE, 1, 2)));
// Appends a printf-like formatting of the arguments to 'dst'.
void StringAppendF(std::string* dst, const char* fmt, ...)
- __attribute__((__format__(__printf__, 2, 3)));
+ __attribute__((__format__(FORMAT_ARCHETYPE, 2, 3)));
// Appends a printf-like formatting of the arguments to 'dst'.
-void StringAppendV(std::string* dst, const char* format, va_list ap);
+void StringAppendV(std::string* dst, const char* format, va_list ap)
+ __attribute__((__format__(FORMAT_ARCHETYPE, 2, 0)));
+
+#undef FORMAT_ARCHETYPE
} // namespace base
} // namespace android
diff --git a/base/logging.cpp b/base/logging.cpp
index 83957b3..34229a2 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
#include "base/logging.h"
#include <libgen.h>
@@ -34,9 +38,6 @@
#ifndef _WIN32
#include <mutex>
-#else
-#define NOGDI // Suppress the evil ERROR macro.
-#include <windows.h>
#endif
#include "base/macros.h"
diff --git a/debuggerd/backtrace.cpp b/debuggerd/backtrace.cpp
index c2a1dbc..b8084c5 100644
--- a/debuggerd/backtrace.cpp
+++ b/debuggerd/backtrace.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "DEBUG"
+
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
@@ -26,8 +28,11 @@
#include <sys/types.h>
#include <sys/ptrace.h>
+#include <memory>
+
#include <backtrace/Backtrace.h>
-#include <UniquePtr.h>
+
+#include <log/log.h>
#include "backtrace.h"
@@ -92,9 +97,11 @@
return;
}
- UniquePtr<Backtrace> backtrace(Backtrace::Create(tid, BACKTRACE_CURRENT_THREAD));
+ std::unique_ptr<Backtrace> backtrace(Backtrace::Create(tid, BACKTRACE_CURRENT_THREAD));
if (backtrace->Unwind(0)) {
dump_backtrace_to_log(backtrace.get(), log, " ");
+ } else {
+ ALOGE("Unwind failed: tid = %d", tid);
}
if (!attached && ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index 094ab48..ccdfe85 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -32,6 +32,9 @@
#include <sys/stat.h>
#include <sys/un.h>
+#include <memory>
+#include <string>
+
#include <private/android_filesystem_config.h>
#include <base/stringprintf.h>
@@ -45,10 +48,6 @@
#include <selinux/android.h>
-#include <UniquePtr.h>
-
-#include <string>
-
#include "backtrace.h"
#include "elf_utils.h"
#include "machine.h"
@@ -371,7 +370,8 @@
} else {
line += '-';
}
- line += android::base::StringPrintf(" %8" PRIxPTR, it->end - it->start);
+ line += android::base::StringPrintf(" %8" PRIxPTR " %8" PRIxPTR,
+ it->offset, it->end - it->start);
if (it->name.length() > 0) {
line += " " + it->name;
std::string build_id;
@@ -379,6 +379,9 @@
line += " (BuildId: " + build_id + ")";
}
}
+ if (it->load_base != 0) {
+ line += android::base::StringPrintf(" (load base 0x%" PRIxPTR ")", it->load_base);
+ }
_LOG(log, logtype::MAPS, "%s\n", line.c_str());
}
if (print_fault_address_marker) {
@@ -441,9 +444,11 @@
dump_thread_info(log, pid, new_tid);
dump_registers(log, new_tid);
- UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, new_tid, map));
+ std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, new_tid, map));
if (backtrace->Unwind(0)) {
dump_backtrace_and_stack(backtrace.get(), log);
+ } else {
+ ALOGE("Unwind of sibling failed: pid = %d, tid = %d", pid, new_tid);
}
log->current_tid = log->crashed_tid;
@@ -640,15 +645,19 @@
dump_signal_info(log, tid, signal, si_code);
}
- UniquePtr<BacktraceMap> map(BacktraceMap::Create(pid));
- UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get()));
+ std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(pid));
+ std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get()));
dump_abort_message(backtrace.get(), log, abort_msg_address);
dump_registers(log, tid);
if (backtrace->Unwind(0)) {
dump_backtrace_and_stack(backtrace.get(), log);
+ } else {
+ ALOGE("Unwind failed: pid = %d, tid = %d", pid, tid);
}
dump_memory_and_code(log, tid);
- dump_all_maps(backtrace.get(), map.get(), log, tid);
+ if (map.get() != nullptr) {
+ dump_all_maps(backtrace.get(), map.get(), log, tid);
+ }
if (want_logs) {
dump_logs(log, pid, 5);
@@ -792,7 +801,7 @@
*detach_failed = dump_crash(&log, pid, tid, signal, original_si_code, abort_msg_address,
dump_sibling_threads, total_sleep_time_usec);
- ALOGI("\nTombstone written to: %s\n", path);
+ _LOG(&log, logtype::BACKTRACE, "\nTombstone written to: %s\n", path);
// Either of these file descriptors can be -1, any error is ignored.
close(amfd);
diff --git a/debuggerd/utility.cpp b/debuggerd/utility.cpp
index d6a6d2e..e722f82 100644
--- a/debuggerd/utility.cpp
+++ b/debuggerd/utility.cpp
@@ -67,7 +67,7 @@
}
if (write_to_logcat) {
- __android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_INFO, LOG_TAG, buf);
+ __android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_FATAL, LOG_TAG, buf);
if (write_to_activitymanager) {
if (!android::base::WriteFully(log->amfd, buf, len)) {
// timeout or other failure on write; stop informing the activity manager
diff --git a/fastboot/engineering_key.p12 b/fastboot/engineering_key.p12
deleted file mode 100644
index d8183b0..0000000
--- a/fastboot/engineering_key.p12
+++ /dev/null
Binary files differ
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index e139bcd..7acfd6e 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -280,6 +280,17 @@
" 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"
@@ -1201,6 +1212,16 @@
wants_reboot = 1;
} else if(!strcmp(*argv, "oem")) {
argc = do_oem_command(argc, argv);
+ } else if(!strcmp(*argv, "flashing") && argc == 2) {
+ if(!strcmp(*(argv+1), "unlock") || !strcmp(*(argv+1), "lock")
+ || !strcmp(*(argv+1), "unlock_critical")
+ || !strcmp(*(argv+1), "lock_critical")
+ || !strcmp(*(argv+1), "get_unlock_ability")) {
+ argc = do_oem_command(argc, argv);
+ } else {
+ usage();
+ return 1;
+ }
} else {
usage();
return 1;
diff --git a/fastboot/p12topem.sh b/fastboot/p12topem.sh
deleted file mode 100755
index f081eb5..0000000
--- a/fastboot/p12topem.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/bash
-
-if [ $# -ne 2 ]
-then
- echo "Usage: $0 alias passphrase"
- exit -1
-fi
-
-openssl pkcs12 -passin pass:"$2" -passout pass:"$2" -in $1.p12 -out $1.pem
diff --git a/fastboot/signfile.sh b/fastboot/signfile.sh
deleted file mode 100755
index 3188d2d..0000000
--- a/fastboot/signfile.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/bin/bash
-
-if [ $# -ne 3 ]
-then
- echo "Usage: $0 alias filename passpharse"
- exit -1
-fi
-
-openssl dgst -passin pass:"$3" -binary -sha1 -sign $1.pem $2 > $2.sign
-
diff --git a/fs_mgr/fs_mgr_verity.c b/fs_mgr/fs_mgr_verity.c
index 6ef46ba..63b23b9 100644
--- a/fs_mgr/fs_mgr_verity.c
+++ b/fs_mgr/fs_mgr_verity.c
@@ -934,10 +934,6 @@
struct dm_ioctl *io = (struct dm_ioctl *) buffer;
char *mount_point = basename(fstab->mount_point);
- // set the dm_ioctl flags
- io->flags |= 1;
- io->target_count = 1;
-
// get verity filesystem size
if (get_fs_size(fstab->fs_type, fstab->blk_device, &device_size) < 0) {
return retval;
diff --git a/include/backtrace/BacktraceMap.h b/include/backtrace/BacktraceMap.h
index da96307..784bc03 100644
--- a/include/backtrace/BacktraceMap.h
+++ b/include/backtrace/BacktraceMap.h
@@ -37,6 +37,8 @@
uintptr_t start;
uintptr_t end;
+ uintptr_t offset;
+ uintptr_t load_base;
int flags;
std::string name;
};
@@ -82,6 +84,14 @@
return map.end > 0;
}
+ static uintptr_t GetRelativePc(const backtrace_map_t& map, uintptr_t pc) {
+ if (IsValid(map)) {
+ return pc - map.start + map.load_base;
+ } else {
+ return pc;
+ }
+ }
+
protected:
BacktraceMap(pid_t pid);
diff --git a/include/log/log.h b/include/log/log.h
index f9299b0..0b17574 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -598,6 +598,7 @@
LOG_ID_EVENTS = 2,
LOG_ID_SYSTEM = 3,
LOG_ID_CRASH = 4,
+ LOG_ID_KERNEL = 5,
#endif
LOG_ID_MAX
diff --git a/include/log/logprint.h b/include/log/logprint.h
index 1e42b47..96249e9 100644
--- a/include/log/logprint.h
+++ b/include/log/logprint.h
@@ -36,7 +36,9 @@
FORMAT_TIME,
FORMAT_THREADTIME,
FORMAT_LONG,
- FORMAT_COLOR,
+ /* The following two are modifiers to above formats */
+ FORMAT_MODIFIER_COLOR, /* converts priority to color */
+ FORMAT_MODIFIER_TIME_USEC, /* switches from msec to usec time precision */
} AndroidLogPrintFormat;
typedef struct AndroidLogFormat_t AndroidLogFormat;
@@ -56,7 +58,8 @@
void android_log_format_free(AndroidLogFormat *p_format);
-void android_log_setPrintFormat(AndroidLogFormat *p_format,
+/* currently returns 0 if format is a modifier, 1 if not */
+int android_log_setPrintFormat(AndroidLogFormat *p_format,
AndroidLogPrintFormat format);
/**
@@ -64,7 +67,7 @@
*/
AndroidLogPrintFormat android_log_formatFromString(const char *s);
-/**
+/**
* filterExpression: a single filter expression
* eg "AT:d"
*
@@ -74,12 +77,12 @@
*
*/
-int android_log_addFilterRule(AndroidLogFormat *p_format,
+int android_log_addFilterRule(AndroidLogFormat *p_format,
const char *filterExpression);
-/**
- * filterString: a whitespace-separated set of filter expressions
+/**
+ * filterString: a whitespace-separated set of filter expressions
* eg "AT:d *:i"
*
* returns 0 on success and -1 on invalid expression
@@ -92,7 +95,7 @@
const char *filterString);
-/**
+/**
* returns 1 if this log line should be printed based on its priority
* and tag, and 0 if it should not
*/
@@ -129,7 +132,7 @@
* Returns NULL on malloc error
*/
-char *android_log_formatLogLine (
+char *android_log_formatLogLine (
AndroidLogFormat *p_format,
char *defaultBuffer,
size_t defaultBufferSize,
diff --git a/include/system/audio.h b/include/system/audio.h
index 181a171..8d9ec88 100644
--- a/include/system/audio.h
+++ b/include/system/audio.h
@@ -1102,8 +1102,10 @@
static inline bool audio_is_remote_submix_device(audio_devices_t device)
{
- if ((device & AUDIO_DEVICE_OUT_REMOTE_SUBMIX) == AUDIO_DEVICE_OUT_REMOTE_SUBMIX
- || (device & AUDIO_DEVICE_IN_REMOTE_SUBMIX) == AUDIO_DEVICE_IN_REMOTE_SUBMIX)
+ if ((audio_is_output_devices(device) &&
+ (device & AUDIO_DEVICE_OUT_REMOTE_SUBMIX) == AUDIO_DEVICE_OUT_REMOTE_SUBMIX)
+ || (!audio_is_output_devices(device) &&
+ (device & AUDIO_DEVICE_IN_REMOTE_SUBMIX) == AUDIO_DEVICE_IN_REMOTE_SUBMIX))
return true;
else
return false;
diff --git a/init/Android.mk b/init/Android.mk
index 0dc257d..b14f9b5 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -50,7 +50,10 @@
watchdogd.cpp \
LOCAL_MODULE:= init
-LOCAL_C_INCLUDES += system/extras/ext4_utils
+LOCAL_C_INCLUDES += \
+ system/extras/ext4_utils \
+ system/core/mkbootimg
+
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED)
diff --git a/init/builtins.cpp b/init/builtins.cpp
index d772383..9e5f9ff 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -57,8 +57,14 @@
static int insmod(const char *filename, char *options)
{
+ char filename_val[PROP_VALUE_MAX];
+ if (expand_props(filename_val, filename, sizeof(filename_val)) == -1) {
+ ERROR("insmod: cannot expand '%s'\n", filename);
+ return -EINVAL;
+ }
+
std::string module;
- if (!read_file(filename, &module)) {
+ if (!read_file(filename_val, &module)) {
return -1;
}
diff --git a/init/init.cpp b/init/init.cpp
index 68c8b7f..60fcf64 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -43,6 +43,7 @@
#include <base/file.h>
#include <base/stringprintf.h>
+#include <base/strings.h>
#include <cutils/android_reboot.h>
#include <cutils/fs.h>
#include <cutils/iosched_policy.h>
@@ -205,16 +206,15 @@
return;
}
- struct stat s;
- if (stat(svc->args[0], &s) != 0) {
- ERROR("cannot find '%s', disabling '%s'\n", svc->args[0], svc->name);
+ struct stat sb;
+ if (stat(svc->args[0], &sb) == -1) {
+ ERROR("cannot find '%s' (%s), disabling '%s'\n", svc->args[0], strerror(errno), svc->name);
svc->flags |= SVC_DISABLED;
return;
}
if ((!(svc->flags & SVC_ONESHOT)) && dynamic_args) {
- ERROR("service '%s' must be one-shot to use dynamic args, disabling\n",
- svc->args[0]);
+ ERROR("service '%s' must be one-shot to use dynamic args, disabling\n", svc->args[0]);
svc->flags |= SVC_DISABLED;
return;
}
@@ -618,7 +618,10 @@
Timer t;
NOTICE("Waiting for %s...\n", COLDBOOT_DONE);
- if (wait_for_file(COLDBOOT_DONE, COMMAND_RETRY_TIMEOUT)) {
+ // Any longer than 1s is an unreasonable length of time to delay booting.
+ // If you're hitting this timeout, check that you didn't make your
+ // sepolicy regular expressions too expensive (http://b/19899875).
+ if (wait_for_file(COLDBOOT_DONE, 1)) {
ERROR("Timed out waiting for %s\n", COLDBOOT_DONE);
}
@@ -746,36 +749,20 @@
return 0;
}
-static void import_kernel_nv(char *name, bool for_emulator)
-{
- char *value = strchr(name, '=');
- int name_len = strlen(name);
-
- if (value == 0) return;
- *value++ = 0;
- if (name_len == 0) return;
+static void import_kernel_nv(const std::string& key, const std::string& value, bool for_emulator) {
+ if (key.empty()) return;
if (for_emulator) {
- /* in the emulator, export any kernel option with the
- * ro.kernel. prefix */
- char buff[PROP_NAME_MAX];
- int len = snprintf( buff, sizeof(buff), "ro.kernel.%s", name );
-
- if (len < (int)sizeof(buff))
- property_set( buff, value );
+ // In the emulator, export any kernel option with the "ro.kernel." prefix.
+ property_set(android::base::StringPrintf("ro.kernel.%s", key.c_str()).c_str(), value.c_str());
return;
}
- if (!strcmp(name,"qemu")) {
- strlcpy(qemu, value, sizeof(qemu));
- } else if (!strncmp(name, "androidboot.", 12) && name_len > 12) {
- const char *boot_prop_name = name + 12;
- char prop[PROP_NAME_MAX];
- int cnt;
-
- cnt = snprintf(prop, sizeof(prop), "ro.boot.%s", boot_prop_name);
- if (cnt < PROP_NAME_MAX)
- property_set(prop, value);
+ if (key == "qemu") {
+ strlcpy(qemu, value.c_str(), sizeof(qemu));
+ } else if (android::base::StartsWith(key, "androidboot.")) {
+ property_set(android::base::StringPrintf("ro.boot.%s", key.c_str() + 12).c_str(),
+ value.c_str());
}
}
@@ -799,8 +786,7 @@
}
}
-static void process_kernel_dt(void)
-{
+static void process_kernel_dt() {
static const char android_dir[] = "/proc/device-tree/firmware/android";
std::string file_name = android::base::StringPrintf("%s/compatible", android_dir);
@@ -813,13 +799,13 @@
}
std::unique_ptr<DIR, int(*)(DIR*)>dir(opendir(android_dir), closedir);
- if (!dir)
- return;
+ if (!dir) return;
struct dirent *dp;
while ((dp = readdir(dir.get())) != NULL) {
- if (dp->d_type != DT_REG || !strcmp(dp->d_name, "compatible"))
+ if (dp->d_type != DT_REG || !strcmp(dp->d_name, "compatible")) {
continue;
+ }
file_name = android::base::StringPrintf("%s/%s", android_dir, dp->d_name);
@@ -831,18 +817,15 @@
}
}
-static void process_kernel_cmdline(void)
-{
- /* don't expose the raw commandline to nonpriv processes */
+static void process_kernel_cmdline() {
+ // Don't expose the raw commandline to unprivileged processes.
chmod("/proc/cmdline", 0440);
- /* first pass does the common stuff, and finds if we are in qemu.
- * second pass is only necessary for qemu to export all kernel params
- * as props.
- */
+ // The first pass does the common stuff, and finds if we are in qemu.
+ // The second pass is only necessary for qemu to export all kernel params
+ // as properties.
import_kernel_cmdline(false, import_kernel_nv);
- if (qemu[0])
- import_kernel_cmdline(true, import_kernel_nv);
+ if (qemu[0]) import_kernel_cmdline(true, import_kernel_nv);
}
static int queue_property_triggers_action(int nargs, char **args)
@@ -865,17 +848,11 @@
static selinux_enforcing_status selinux_status_from_cmdline() {
selinux_enforcing_status status = SELINUX_ENFORCING;
- std::function<void(char*,bool)> fn = [&](char* name, bool in_qemu) {
- char *value = strchr(name, '=');
- if (value == nullptr) { return; }
- *value++ = '\0';
- if (strcmp(name, "androidboot.selinux") == 0) {
- if (strcmp(value, "permissive") == 0) {
- status = SELINUX_PERMISSIVE;
- }
+ import_kernel_cmdline(false, [&](const std::string& key, const std::string& value, bool in_qemu) {
+ if (key == "androidboot.selinux" && value == "permissive") {
+ status = SELINUX_PERMISSIVE;
}
- };
- import_kernel_cmdline(false, fn);
+ });
return status;
}
@@ -989,7 +966,7 @@
klog_init();
klog_set_level(KLOG_NOTICE_LEVEL);
- NOTICE("init%s started!\n", is_first_stage ? "" : " second stage");
+ NOTICE("init %s started!\n", is_first_stage ? "first stage" : "second stage");
if (!is_first_stage) {
// Indicate that booting is in progress to background fw loaders, etc.
@@ -1002,7 +979,7 @@
process_kernel_dt();
process_kernel_cmdline();
- // Propogate the kernel variables to internal variables
+ // Propagate the kernel variables to internal variables
// used by init as well as the current required properties.
export_kernel_boot_props();
}
@@ -1028,7 +1005,7 @@
// These directories were necessarily created before initial policy load
// and therefore need their security context restored to the proper value.
// This must happen before /dev is populated by ueventd.
- INFO("Running restorecon...\n");
+ NOTICE("Running restorecon...\n");
restorecon("/dev");
restorecon("/dev/socket");
restorecon("/dev/__properties__");
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index b76b04e..df049ed 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -382,13 +382,13 @@
static void parse_config(const char *fn, const std::string& data)
{
- struct parse_state state;
struct listnode import_list;
struct listnode *node;
char *args[INIT_PARSER_MAXARGS];
- int nargs;
- nargs = 0;
+ int nargs = 0;
+
+ parse_state state;
state.filename = fn;
state.line = 0;
state.ptr = strdup(data.c_str()); // TODO: fix this code!
@@ -426,29 +426,28 @@
parser_done:
list_for_each(node, &import_list) {
- struct import *import = node_to_item(node, struct import, list);
- int ret;
-
- ret = init_parse_config_file(import->filename);
- if (ret)
- ERROR("could not import file '%s' from '%s'\n",
- import->filename, fn);
+ struct import* import = node_to_item(node, struct import, list);
+ if (!init_parse_config_file(import->filename)) {
+ ERROR("could not import file '%s' from '%s': %s\n",
+ import->filename, fn, strerror(errno));
+ }
}
}
-int init_parse_config_file(const char* path) {
+bool init_parse_config_file(const char* path) {
INFO("Parsing %s...\n", path);
Timer t;
std::string data;
if (!read_file(path, &data)) {
- return -1;
+ return false;
}
+ data.push_back('\n'); // TODO: fix parse_config.
parse_config(path, data);
dump_parser_state();
NOTICE("(Parsing %s took %.2fs.)\n", path, t.duration());
- return 0;
+ return true;
}
static int valid_name(const char *name)
diff --git a/init/init_parser.h b/init/init_parser.h
index 6348607..90f880f 100644
--- a/init/init_parser.h
+++ b/init/init_parser.h
@@ -31,7 +31,7 @@
void queue_all_property_triggers();
void queue_builtin_action(int (*func)(int nargs, char **args), const char *name);
-int init_parse_config_file(const char *fn);
+bool init_parse_config_file(const char* path);
int expand_props(char *dst, const char *src, int len);
service* make_exec_oneshot_service(int argc, char** argv);
diff --git a/init/log.cpp b/init/log.cpp
index d32f2da..eb5ec42 100644
--- a/init/log.cpp
+++ b/init/log.cpp
@@ -14,30 +14,35 @@
* limitations under the License.
*/
+#include "log.h"
+
#include <stdlib.h>
#include <string.h>
#include <sys/uio.h>
#include <selinux/selinux.h>
-#include "log.h"
+#include <base/stringprintf.h>
static void init_klog_vwrite(int level, const char* fmt, va_list ap) {
static const char* tag = basename(getprogname());
- char prefix[64];
- snprintf(prefix, sizeof(prefix), "<%d>%s: ", level, tag);
+ // The kernel's printk buffer is only 1024 bytes.
+ // TODO: should we automatically break up long lines into multiple lines?
+ // Or we could log but with something like "..." at the end?
+ char buf[1024];
+ size_t prefix_size = snprintf(buf, sizeof(buf), "<%d>%s: ", level, tag);
+ size_t msg_size = vsnprintf(buf + prefix_size, sizeof(buf) - prefix_size, fmt, ap);
+ if (msg_size >= sizeof(buf) - prefix_size) {
+ msg_size = snprintf(buf + prefix_size, sizeof(buf) - prefix_size,
+ "(%zu-byte message too long for printk)\n", msg_size);
+ }
- char msg[512];
- vsnprintf(msg, sizeof(msg), fmt, ap);
+ iovec iov[1];
+ iov[0].iov_base = buf;
+ iov[0].iov_len = prefix_size + msg_size;
- iovec iov[2];
- iov[0].iov_base = prefix;
- iov[0].iov_len = strlen(prefix);
- iov[1].iov_base = msg;
- iov[1].iov_len = strlen(msg);
-
- klog_writev(level, iov, 2);
+ klog_writev(level, iov, 1);
}
void init_klog_write(int level, const char* fmt, ...) {
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 930ef82..0ee0351 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -46,12 +46,18 @@
#include <selinux/selinux.h>
#include <selinux/label.h>
+#include <fs_mgr.h>
+#include <base/file.h>
+#include "bootimg.h"
+
#include "property_service.h"
#include "init.h"
#include "util.h"
#include "log.h"
#define PERSISTENT_PROPERTY_DIR "/data/property"
+#define FSTAB_PREFIX "/fstab."
+#define RECOVERY_MOUNT_POINT "/recovery"
static int persistent_properties_loaded = 0;
static bool property_area_initialized = false;
@@ -414,6 +420,7 @@
Timer t;
std::string data;
if (read_file(filename, &data)) {
+ data.push_back('\n');
load_properties(&data[0], filter);
}
NOTICE("(Loading properties from %s took %.2fs.)\n", filename, t.duration());
@@ -506,16 +513,57 @@
load_persistent_properties();
}
+void load_recovery_id_prop() {
+ char fstab_filename[PROP_VALUE_MAX + sizeof(FSTAB_PREFIX)];
+ char propbuf[PROP_VALUE_MAX];
+ int ret = property_get("ro.hardware", propbuf);
+ if (!ret) {
+ ERROR("ro.hardware not set - unable to load recovery id\n");
+ return;
+ }
+ snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX "%s", propbuf);
+
+ std::unique_ptr<fstab, void(*)(fstab*)> tab(fs_mgr_read_fstab(fstab_filename),
+ fs_mgr_free_fstab);
+ if (!tab) {
+ ERROR("unable to read fstab %s: %s\n", fstab_filename, strerror(errno));
+ return;
+ }
+
+ fstab_rec* rec = fs_mgr_get_entry_for_mount_point(tab.get(), RECOVERY_MOUNT_POINT);
+ if (rec == NULL) {
+ ERROR("/recovery not specified in fstab\n");
+ return;
+ }
+
+ int fd = open(rec->blk_device, O_RDONLY);
+ if (fd == -1) {
+ ERROR("error opening block device %s: %s\n", rec->blk_device, strerror(errno));
+ return;
+ }
+
+ boot_img_hdr hdr;
+ if (android::base::ReadFully(fd, &hdr, sizeof(hdr))) {
+ std::string hex = bytes_to_hex(reinterpret_cast<uint8_t*>(hdr.id), sizeof(hdr.id));
+ property_set("ro.recovery_id", hex.c_str());
+ } else {
+ ERROR("error reading /recovery: %s\n", strerror(errno));
+ }
+
+ close(fd);
+}
+
void load_all_props() {
load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL);
load_properties_from_file(PROP_PATH_VENDOR_BUILD, NULL);
- load_properties_from_file(PROP_PATH_BOOTIMAGE_BUILD, NULL);
load_properties_from_file(PROP_PATH_FACTORY, "ro.*");
load_override_properties();
/* Read persistent properties after all default values have been loaded. */
load_persistent_properties();
+
+ load_recovery_id_prop();
}
void start_property_service() {
diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp
index 7a4841f..497c606 100644
--- a/init/ueventd_parser.cpp
+++ b/init/ueventd_parser.cpp
@@ -193,10 +193,10 @@
static void parse_config(const char *fn, const std::string& data)
{
- struct parse_state state;
char *args[UEVENTD_PARSER_MAXARGS];
- int nargs;
- nargs = 0;
+
+ int nargs = 0;
+ parse_state state;
state.filename = fn;
state.line = 1;
state.ptr = strdup(data.c_str()); // TODO: fix this code!
@@ -231,6 +231,7 @@
return -1;
}
+ data.push_back('\n'); // TODO: fix parse_config.
parse_config(fn, data);
dump_parser_state();
return 0;
diff --git a/init/util.cpp b/init/util.cpp
index 9343145..9c62f68 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -33,9 +33,11 @@
#include <sys/un.h>
#include <base/file.h>
+#include <base/strings.h>
/* for ANDROID_SOCKET_* */
#include <cutils/sockets.h>
+#include <base/stringprintf.h>
#include <private/android_filesystem_config.h>
@@ -170,9 +172,6 @@
bool okay = android::base::ReadFdToString(fd, content);
TEMP_FAILURE_RETRY(close(fd));
- if (okay) {
- content->append("\n", 1);
- }
return okay;
}
@@ -403,32 +402,16 @@
}
}
-void import_kernel_cmdline(bool in_qemu, std::function<void(char*,bool)> import_kernel_nv)
-{
- char cmdline[2048];
- char *ptr;
- int fd;
+void import_kernel_cmdline(bool in_qemu,
+ std::function<void(const std::string&, const std::string&, bool)> fn) {
+ std::string cmdline;
+ android::base::ReadFileToString("/proc/cmdline", &cmdline);
- fd = open("/proc/cmdline", O_RDONLY | O_CLOEXEC);
- if (fd >= 0) {
- int n = read(fd, cmdline, sizeof(cmdline) - 1);
- if (n < 0) n = 0;
-
- /* get rid of trailing newline, it happens */
- if (n > 0 && cmdline[n-1] == '\n') n--;
-
- cmdline[n] = 0;
- close(fd);
- } else {
- cmdline[0] = 0;
- }
-
- ptr = cmdline;
- while (ptr && *ptr) {
- char *x = strchr(ptr, ' ');
- if (x != 0) *x++ = 0;
- import_kernel_nv(ptr, in_qemu);
- ptr = x;
+ for (const auto& entry : android::base::Split(android::base::Trim(cmdline), " ")) {
+ std::vector<std::string> pieces = android::base::Split(entry, "=");
+ if (pieces.size() == 2) {
+ fn(pieces[0], pieces[1], in_qemu);
+ }
}
}
@@ -464,3 +447,13 @@
{
return selinux_android_restorecon(pathname, SELINUX_ANDROID_RESTORECON_RECURSE);
}
+
+/*
+ * Writes hex_len hex characters (1/2 byte) to hex from bytes.
+ */
+std::string bytes_to_hex(const uint8_t* bytes, size_t bytes_len) {
+ std::string hex("0x");
+ for (size_t i = 0; i < bytes_len; i++)
+ android::base::StringAppendF(&hex, "%02x", bytes[i]);
+ return hex;
+}
diff --git a/init/util.h b/init/util.h
index 6864acf..3aba599 100644
--- a/init/util.h
+++ b/init/util.h
@@ -58,8 +58,10 @@
void remove_link(const char *oldpath, const char *newpath);
int wait_for_file(const char *filename, int timeout);
void open_devnull_stdio(void);
-void import_kernel_cmdline(bool in_qemu, std::function<void(char*,bool)>);
+void import_kernel_cmdline(bool in_qemu,
+ std::function<void(const std::string&, const std::string&, bool)>);
int make_dir(const char *path, mode_t mode);
int restorecon(const char *pathname);
int restorecon_recursive(const char *pathname);
+std::string bytes_to_hex(const uint8_t *bytes, size_t bytes_len);
#endif
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
index 54cace9..be8b803 100644
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -51,18 +51,10 @@
UnwindMap.cpp \
UnwindPtrace.cpp \
-libbacktrace_shared_libraries_target := \
- libcutils \
-
libbacktrace_shared_libraries := \
libbase \
- libunwind \
-
-libbacktrace_shared_libraries_host := \
liblog \
-
-libbacktrace_static_libraries_host := \
- libcutils \
+ libunwind \
libbacktrace_ldlibs_host := \
-lpthread \
@@ -118,12 +110,14 @@
backtrace_test_shared_libraries := \
libbacktrace_test \
libbacktrace \
-
-backtrace_test_shared_libraries_target := \
+ libbase \
libcutils \
-backtrace_test_static_libraries_host := \
- libcutils \
+backtrace_test_shared_libraries_target += \
+ libdl \
+
+backtrace_test_ldlibs_host += \
+ -ldl \
module := backtrace_test
module_tag := debug
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index 91ca8b7..128bb04 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -27,6 +27,8 @@
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
+#include <cutils/threads.h>
+
#include "BacktraceLog.h"
#include "thread_utils.h"
#include "UnwindCurrent.h"
@@ -97,12 +99,7 @@
map_name = "<unknown>";
}
- uintptr_t relative_pc;
- if (BacktraceMap::IsValid(frame->map)) {
- relative_pc = frame->pc - frame->map.start;
- } else {
- relative_pc = frame->pc;
- }
+ uintptr_t relative_pc = BacktraceMap::GetRelativePc(frame->map, frame->pc);
std::string line(StringPrintf("#%02zu pc %" PRIPTR " %s", frame->num, relative_pc, map_name));
if (!frame->func_name.empty()) {
@@ -117,7 +114,9 @@
}
void Backtrace::FillInMap(uintptr_t pc, backtrace_map_t* map) {
- map_->FillIn(pc, map);
+ if (map_ != nullptr) {
+ map_->FillIn(pc, map);
+ }
}
Backtrace* Backtrace::Create(pid_t pid, pid_t tid, BacktraceMap* map) {
diff --git a/libbacktrace/BacktraceCurrent.cpp b/libbacktrace/BacktraceCurrent.cpp
index fd1f4da..95cd4d1 100644
--- a/libbacktrace/BacktraceCurrent.cpp
+++ b/libbacktrace/BacktraceCurrent.cpp
@@ -29,6 +29,8 @@
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
+#include <cutils/threads.h>
+
#include "BacktraceCurrent.h"
#include "BacktraceLog.h"
#include "ThreadEntry.h"
@@ -63,6 +65,11 @@
}
bool BacktraceCurrent::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
+ if (GetMap() == nullptr) {
+ // Without a map object, we can't do anything.
+ return false;
+ }
+
if (ucontext) {
return UnwindFromContext(num_ignore_frames, ucontext);
}
diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
index b0ada46..ca47f67 100644
--- a/libbacktrace/BacktraceMap.cpp
+++ b/libbacktrace/BacktraceMap.cpp
@@ -135,7 +135,7 @@
#if defined(__APPLE__)
// Corkscrew and libunwind don't compile on the mac, so create a generic
// map object.
-BacktraceMap* BacktraceMap::Create(pid_t pid, bool uncached) {
+BacktraceMap* BacktraceMap::Create(pid_t pid, bool /*uncached*/) {
BacktraceMap* map = new BacktraceMap(pid);
if (!map->Build()) {
delete map;
diff --git a/libbacktrace/BacktracePtrace.cpp b/libbacktrace/BacktracePtrace.cpp
index 6134438..e10cce1 100644
--- a/libbacktrace/BacktracePtrace.cpp
+++ b/libbacktrace/BacktracePtrace.cpp
@@ -83,13 +83,12 @@
if (!PtraceRead(Tid(), addr & ~(sizeof(word_t) - 1), &data_word)) {
return 0;
}
- align_bytes = sizeof(word_t) - align_bytes;
- memcpy(buffer, reinterpret_cast<uint8_t*>(&data_word) + sizeof(word_t) - align_bytes,
- align_bytes);
- addr += align_bytes;
- buffer += align_bytes;
- bytes -= align_bytes;
- bytes_read += align_bytes;
+ size_t copy_bytes = MIN(sizeof(word_t) - align_bytes, bytes);
+ memcpy(buffer, reinterpret_cast<uint8_t*>(&data_word) + align_bytes, copy_bytes);
+ addr += copy_bytes;
+ buffer += copy_bytes;
+ bytes -= copy_bytes;
+ bytes_read += copy_bytes;
}
size_t num_words = bytes / sizeof(word_t);
diff --git a/libbacktrace/UnwindMap.cpp b/libbacktrace/UnwindMap.cpp
index fa59d07..879fea5 100644
--- a/libbacktrace/UnwindMap.cpp
+++ b/libbacktrace/UnwindMap.cpp
@@ -51,6 +51,8 @@
map.start = unw_map.start;
map.end = unw_map.end;
+ map.offset = unw_map.offset;
+ map.load_base = unw_map.load_base;
map.flags = unw_map.flags;
map.name = unw_map.path;
@@ -91,6 +93,8 @@
map.start = unw_map.start;
map.end = unw_map.end;
+ map.offset = unw_map.offset;
+ map.load_base = unw_map.load_base;
map.flags = unw_map.flags;
map.name = unw_map.path;
diff --git a/libbacktrace/UnwindPtrace.cpp b/libbacktrace/UnwindPtrace.cpp
index a7c3de5..07c2430 100644
--- a/libbacktrace/UnwindPtrace.cpp
+++ b/libbacktrace/UnwindPtrace.cpp
@@ -48,6 +48,11 @@
}
bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
+ if (GetMap() == nullptr) {
+ // Without a map object, we can't do anything.
+ return false;
+ }
+
if (ucontext) {
BACK_LOGW("Unwinding from a specified context not supported yet.");
return false;
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index 4af6592..760f5cc 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -16,7 +16,9 @@
#define _GNU_SOURCE 1
#include <dirent.h>
+#include <dlfcn.h>
#include <errno.h>
+#include <fcntl.h>
#include <inttypes.h>
#include <pthread.h>
#include <signal.h>
@@ -25,25 +27,29 @@
#include <stdlib.h>
#include <string.h>
#include <sys/ptrace.h>
+#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
-
-// For the THREAD_SIGNAL definition.
-#include "BacktraceCurrent.h"
-
-#include <cutils/atomic.h>
-#include <gtest/gtest.h>
-
#include <algorithm>
+#include <list>
#include <memory>
#include <string>
#include <vector>
+#include <backtrace/Backtrace.h>
+#include <backtrace/BacktraceMap.h>
+
+#include <base/stringprintf.h>
+#include <cutils/atomic.h>
+#include <cutils/threads.h>
+
+#include <gtest/gtest.h>
+
+// For the THREAD_SIGNAL definition.
+#include "BacktraceCurrent.h"
#include "thread_utils.h"
// Number of microseconds per milliseconds.
@@ -771,6 +777,7 @@
// Check map name empty, but exists.
frame.map.start = 1;
frame.map.end = 1;
+ frame.map.load_base = 0;
#if defined(__LP64__)
EXPECT_EQ("#01 pc 0000000000000001 <unknown>",
#else
@@ -808,6 +815,16 @@
EXPECT_EQ("#01 pc 12345678 MapFake (ProcFake+645)",
#endif
backtrace->FormatFrameData(&frame));
+
+ // Check func_name is set, func offset is non-zero, and load_base is non-zero.
+ frame.func_offset = 645;
+ frame.map.load_base = 100;
+#if defined(__LP64__)
+ EXPECT_EQ("#01 pc 00000000123456dc MapFake (ProcFake+645)",
+#else
+ EXPECT_EQ("#01 pc 123456dc MapFake (ProcFake+645)",
+#endif
+ backtrace->FormatFrameData(&frame));
}
struct map_test_t {
@@ -871,6 +888,17 @@
ASSERT_EQ(waitpid(pid, nullptr, 0), pid);
}
+void InitMemory(uint8_t* memory, size_t bytes) {
+ for (size_t i = 0; i < bytes; i++) {
+ memory[i] = i;
+ if (memory[i] == '\0') {
+ // Don't use '\0' in our data so we can verify that an overread doesn't
+ // occur by using a '\0' as the character after the read data.
+ memory[i] = 23;
+ }
+ }
+}
+
void* ThreadReadTest(void* data) {
thread_t* thread_data = reinterpret_cast<thread_t*>(data);
@@ -889,9 +917,7 @@
}
// Set up a simple pattern in memory.
- for (size_t i = 0; i < pagesize; i++) {
- memory[i] = i;
- }
+ InitMemory(memory, pagesize);
thread_data->data = memory;
@@ -919,9 +945,8 @@
// Create a page of data to use to do quick compares.
uint8_t* expected = new uint8_t[pagesize];
- for (size_t i = 0; i < pagesize; i++) {
- expected[i] = i;
- }
+ InitMemory(expected, pagesize);
+
uint8_t* data = new uint8_t[2*pagesize];
// Verify that we can only read one page worth of data.
size_t bytes_read = backtrace->Read(read_addr, data, 2 * pagesize);
@@ -935,6 +960,20 @@
ASSERT_TRUE(memcmp(data, &expected[i], 2 * sizeof(word_t)) == 0)
<< "Offset at " << i << " failed";
}
+
+ // Verify small unaligned reads.
+ for (size_t i = 1; i < sizeof(word_t); i++) {
+ for (size_t j = 1; j < sizeof(word_t); j++) {
+ // Set one byte past what we expect to read, to guarantee we don't overread.
+ data[j] = '\0';
+ bytes_read = backtrace->Read(read_addr + i, data, j);
+ ASSERT_EQ(j, bytes_read);
+ ASSERT_TRUE(memcmp(data, &expected[i], j) == 0)
+ << "Offset at " << i << " length " << j << " miscompared";
+ ASSERT_EQ('\0', data[j])
+ << "Offset at " << i << " length " << j << " wrote too much data";
+ }
+ }
delete data;
delete expected;
}
@@ -978,9 +1017,7 @@
}
// Set up a simple pattern in memory.
- for (size_t i = 0; i < pagesize; i++) {
- memory[i] = i;
- }
+ InitMemory(memory, pagesize);
g_addr = reinterpret_cast<uintptr_t>(memory);
g_ready = 1;
@@ -991,6 +1028,7 @@
}
TEST(libbacktrace, process_read) {
+ g_ready = 0;
pid_t pid;
if ((pid = fork()) == 0) {
ForkedReadTest();
@@ -1037,6 +1075,297 @@
ASSERT_TRUE(test_executed);
}
+void VerifyFunctionsFound(const std::vector<std::string>& found_functions) {
+ // We expect to find these functions in libbacktrace_test. If we don't
+ // find them, that's a bug in the memory read handling code in libunwind.
+ std::list<std::string> expected_functions;
+ expected_functions.push_back("test_recursive_call");
+ expected_functions.push_back("test_level_one");
+ expected_functions.push_back("test_level_two");
+ expected_functions.push_back("test_level_three");
+ expected_functions.push_back("test_level_four");
+ for (const auto& found_function : found_functions) {
+ for (const auto& expected_function : expected_functions) {
+ if (found_function == expected_function) {
+ expected_functions.remove(found_function);
+ break;
+ }
+ }
+ }
+ ASSERT_TRUE(expected_functions.empty()) << "Not all functions found in shared library.";
+}
+
+const char* CopySharedLibrary() {
+#if defined(__LP64__)
+ const char* lib_name = "lib64";
+#else
+ const char* lib_name = "lib";
+#endif
+
+#if defined(__BIONIC__)
+ const char* tmp_so_name = "/data/local/tmp/libbacktrace_test.so";
+ std::string cp_cmd = android::base::StringPrintf("cp /system/%s/libbacktrace_test.so %s",
+ lib_name, tmp_so_name);
+#else
+ const char* tmp_so_name = "/tmp/libbacktrace_test.so";
+ if (getenv("ANDROID_HOST_OUT") == NULL) {
+ fprintf(stderr, "ANDROID_HOST_OUT not set, make sure you run lunch.");
+ return nullptr;
+ }
+ std::string cp_cmd = android::base::StringPrintf("cp %s/%s/libbacktrace_test.so %s",
+ getenv("ANDROID_HOST_OUT"), lib_name,
+ tmp_so_name);
+#endif
+
+ // Copy the shared so to a tempory directory.
+ system(cp_cmd.c_str());
+
+ return tmp_so_name;
+}
+
+TEST(libbacktrace, check_unreadable_elf_local) {
+ const char* tmp_so_name = CopySharedLibrary();
+ ASSERT_TRUE(tmp_so_name != nullptr);
+
+ struct stat buf;
+ ASSERT_TRUE(stat(tmp_so_name, &buf) != -1);
+ uintptr_t map_size = buf.st_size;
+
+ int fd = open(tmp_so_name, O_RDONLY);
+ ASSERT_TRUE(fd != -1);
+
+ void* map = mmap(NULL, map_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ ASSERT_TRUE(map != MAP_FAILED);
+ close(fd);
+ ASSERT_TRUE(unlink(tmp_so_name) != -1);
+
+ std::vector<std::string> found_functions;
+ std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS,
+ BACKTRACE_CURRENT_THREAD));
+ ASSERT_TRUE(backtrace.get() != nullptr);
+
+ // Needed before GetFunctionName will work.
+ backtrace->Unwind(0);
+
+ // Loop through the entire map, and get every function we can find.
+ map_size += reinterpret_cast<uintptr_t>(map);
+ std::string last_func;
+ for (uintptr_t read_addr = reinterpret_cast<uintptr_t>(map);
+ read_addr < map_size; read_addr += 4) {
+ uintptr_t offset;
+ std::string func_name = backtrace->GetFunctionName(read_addr, &offset);
+ if (!func_name.empty() && last_func != func_name) {
+ found_functions.push_back(func_name);
+ }
+ last_func = func_name;
+ }
+
+ ASSERT_TRUE(munmap(map, map_size - reinterpret_cast<uintptr_t>(map)) == 0);
+
+ VerifyFunctionsFound(found_functions);
+}
+
+TEST(libbacktrace, check_unreadable_elf_remote) {
+ const char* tmp_so_name = CopySharedLibrary();
+ ASSERT_TRUE(tmp_so_name != nullptr);
+
+ g_ready = 0;
+
+ struct stat buf;
+ ASSERT_TRUE(stat(tmp_so_name, &buf) != -1);
+ uintptr_t map_size = buf.st_size;
+
+ pid_t pid;
+ if ((pid = fork()) == 0) {
+ int fd = open(tmp_so_name, O_RDONLY);
+ if (fd == -1) {
+ fprintf(stderr, "Failed to open file %s: %s\n", tmp_so_name, strerror(errno));
+ unlink(tmp_so_name);
+ exit(0);
+ }
+
+ void* map = mmap(NULL, map_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (map == MAP_FAILED) {
+ fprintf(stderr, "Failed to map in memory: %s\n", strerror(errno));
+ unlink(tmp_so_name);
+ exit(0);
+ }
+ close(fd);
+ if (unlink(tmp_so_name) == -1) {
+ fprintf(stderr, "Failed to unlink: %s\n", strerror(errno));
+ exit(0);
+ }
+
+ g_addr = reinterpret_cast<uintptr_t>(map);
+ g_ready = 1;
+ while (true) {
+ usleep(US_PER_MSEC);
+ }
+ exit(0);
+ }
+ ASSERT_TRUE(pid > 0);
+
+ std::vector<std::string> found_functions;
+ uint64_t start = NanoTime();
+ while (true) {
+ ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) == 0);
+
+ // Wait for the process to get to a stopping point.
+ WaitForStop(pid);
+
+ std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, BACKTRACE_CURRENT_THREAD));
+ ASSERT_TRUE(backtrace.get() != nullptr);
+
+ uintptr_t read_addr;
+ ASSERT_EQ(sizeof(uintptr_t), backtrace->Read(reinterpret_cast<uintptr_t>(&g_ready), reinterpret_cast<uint8_t*>(&read_addr), sizeof(uintptr_t)));
+ if (read_addr) {
+ ASSERT_EQ(sizeof(uintptr_t), backtrace->Read(reinterpret_cast<uintptr_t>(&g_addr), reinterpret_cast<uint8_t*>(&read_addr), sizeof(uintptr_t)));
+
+ // Needed before GetFunctionName will work.
+ backtrace->Unwind(0);
+
+ // Loop through the entire map, and get every function we can find.
+ map_size += read_addr;
+ std::string last_func;
+ for (; read_addr < map_size; read_addr += 4) {
+ uintptr_t offset;
+ std::string func_name = backtrace->GetFunctionName(read_addr, &offset);
+ if (!func_name.empty() && last_func != func_name) {
+ found_functions.push_back(func_name);
+ }
+ last_func = func_name;
+ }
+ break;
+ }
+ ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
+
+ if ((NanoTime() - start) > 5 * NS_PER_SEC) {
+ break;
+ }
+ usleep(US_PER_MSEC);
+ }
+
+ kill(pid, SIGKILL);
+ ASSERT_EQ(waitpid(pid, nullptr, 0), pid);
+
+ VerifyFunctionsFound(found_functions);
+}
+
+bool FindFuncFrameInBacktrace(Backtrace* backtrace, uintptr_t test_func, size_t* frame_num) {
+ backtrace_map_t map;
+ backtrace->FillInMap(test_func, &map);
+ if (!BacktraceMap::IsValid(map)) {
+ return false;
+ }
+
+ // Loop through the frames, and find the one that is in the map.
+ *frame_num = 0;
+ for (Backtrace::const_iterator it = backtrace->begin(); it != backtrace->end(); ++it) {
+ if (BacktraceMap::IsValid(it->map) && map.start == it->map.start &&
+ it->pc >= test_func) {
+ *frame_num = it->num;
+ return true;
+ }
+ }
+ return false;
+}
+
+void VerifyUnreadableElfFrame(Backtrace* backtrace, uintptr_t test_func, size_t frame_num) {
+ ASSERT_LT(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES))
+ << DumpFrames(backtrace);
+
+ ASSERT_TRUE(frame_num != 0) << DumpFrames(backtrace);
+ // Make sure that there is at least one more frame above the test func call.
+ ASSERT_LT(frame_num, backtrace->NumFrames()) << DumpFrames(backtrace);
+
+ uintptr_t diff = backtrace->GetFrame(frame_num)->pc - test_func;
+ ASSERT_LT(diff, 200U) << DumpFrames(backtrace);
+}
+
+void VerifyUnreadableElfBacktrace(uintptr_t test_func) {
+ std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS,
+ BACKTRACE_CURRENT_THREAD));
+ ASSERT_TRUE(backtrace.get() != nullptr);
+ ASSERT_TRUE(backtrace->Unwind(0));
+
+ size_t frame_num;
+ ASSERT_TRUE(FindFuncFrameInBacktrace(backtrace.get(), test_func, &frame_num));
+
+ VerifyUnreadableElfFrame(backtrace.get(), test_func, frame_num);
+}
+
+typedef int (*test_func_t)(int, int, int, int, void (*)(uintptr_t), uintptr_t);
+
+TEST(libbacktrace, unwind_through_unreadable_elf_local) {
+ const char* tmp_so_name = CopySharedLibrary();
+ ASSERT_TRUE(tmp_so_name != nullptr);
+ void* lib_handle = dlopen(tmp_so_name, RTLD_NOW);
+ ASSERT_TRUE(lib_handle != nullptr);
+ ASSERT_TRUE(unlink(tmp_so_name) != -1);
+
+ test_func_t test_func;
+ test_func = reinterpret_cast<test_func_t>(dlsym(lib_handle, "test_level_one"));
+ ASSERT_TRUE(test_func != nullptr);
+
+ ASSERT_NE(test_func(1, 2, 3, 4, VerifyUnreadableElfBacktrace,
+ reinterpret_cast<uintptr_t>(test_func)), 0);
+
+ ASSERT_TRUE(dlclose(lib_handle) == 0);
+}
+
+TEST(libbacktrace, unwind_through_unreadable_elf_remote) {
+ const char* tmp_so_name = CopySharedLibrary();
+ ASSERT_TRUE(tmp_so_name != nullptr);
+ void* lib_handle = dlopen(tmp_so_name, RTLD_NOW);
+ ASSERT_TRUE(lib_handle != nullptr);
+ ASSERT_TRUE(unlink(tmp_so_name) != -1);
+
+ test_func_t test_func;
+ test_func = reinterpret_cast<test_func_t>(dlsym(lib_handle, "test_level_one"));
+ ASSERT_TRUE(test_func != nullptr);
+
+ pid_t pid;
+ if ((pid = fork()) == 0) {
+ test_func(1, 2, 3, 4, 0, 0);
+ exit(0);
+ }
+ ASSERT_TRUE(pid > 0);
+ ASSERT_TRUE(dlclose(lib_handle) == 0);
+
+ uint64_t start = NanoTime();
+ bool done = false;
+ while (!done) {
+ ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) == 0);
+
+ // Wait for the process to get to a stopping point.
+ WaitForStop(pid);
+
+ std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, BACKTRACE_CURRENT_THREAD));
+ ASSERT_TRUE(backtrace.get() != nullptr);
+ ASSERT_TRUE(backtrace->Unwind(0));
+
+ size_t frame_num;
+ if (FindFuncFrameInBacktrace(backtrace.get(),
+ reinterpret_cast<uintptr_t>(test_func), &frame_num)) {
+
+ VerifyUnreadableElfFrame(backtrace.get(), reinterpret_cast<uintptr_t>(test_func), frame_num);
+ done = true;
+ }
+
+ ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
+
+ if ((NanoTime() - start) > 5 * NS_PER_SEC) {
+ break;
+ }
+ usleep(US_PER_MSEC);
+ }
+
+ kill(pid, SIGKILL);
+ ASSERT_EQ(waitpid(pid, nullptr, 0), pid);
+
+ ASSERT_TRUE(done) << "Test function never found in unwind.";
+}
+
#if defined(ENABLE_PSS_TESTS)
#include "GetPss.h"
@@ -1110,3 +1439,4 @@
ASSERT_EQ(waitpid(pid, nullptr, 0), pid);
}
#endif
+
diff --git a/libbacktrace/thread_utils.c b/libbacktrace/thread_utils.c
index 6f4cd3c..e75f56e 100644
--- a/libbacktrace/thread_utils.c
+++ b/libbacktrace/thread_utils.c
@@ -16,25 +16,12 @@
#include "thread_utils.h"
-#if defined(__APPLE__)
+#if !defined(__BIONIC__)
-#include <sys/syscall.h>
-
-// Mac OS >= 10.6 has a system call equivalent to Linux's gettid().
-pid_t gettid() {
- return syscall(SYS_thread_selfid);
-}
-
-#elif !defined(__BIONIC__)
-
-// glibc doesn't implement or export either gettid or tgkill.
+// glibc doesn't implement or export tgkill.
#include <unistd.h>
#include <sys/syscall.h>
-pid_t gettid() {
- return syscall(__NR_gettid);
-}
-
int tgkill(int tgid, int tid, int sig) {
return syscall(__NR_tgkill, tgid, tid, sig);
}
diff --git a/libbacktrace/thread_utils.h b/libbacktrace/thread_utils.h
index ae4c929..df83581 100644
--- a/libbacktrace/thread_utils.h
+++ b/libbacktrace/thread_utils.h
@@ -23,8 +23,6 @@
int tgkill(int tgid, int tid, int sig);
-pid_t gettid();
-
__END_DECLS
#endif /* _LIBBACKTRACE_THREAD_UTILS_H */
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 9dc15d1..d5a9050 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -106,9 +106,6 @@
trace-dev.c \
uevent.c \
-# arch-arm/memset32.S does not compile with Clang.
-LOCAL_CLANG_ASFLAGS_arm += -no-integrated-as
-
LOCAL_SRC_FILES_arm += arch-arm/memset32.S
LOCAL_SRC_FILES_arm64 += arch-arm64/android_memset.S
diff --git a/libcutils/arch-arm/memset32.S b/libcutils/arch-arm/memset32.S
index 6efab9f..1e89636 100644
--- a/libcutils/arch-arm/memset32.S
+++ b/libcutils/arch-arm/memset32.S
@@ -18,6 +18,8 @@
*
*/
+ .syntax unified
+
.text
.align
@@ -45,7 +47,7 @@
/* align to 32 bits */
tst r0, #2
- strneh r1, [r0], #2
+ strhne r1, [r0], #2
subne r2, r2, #2
.fnend
@@ -68,27 +70,27 @@
/* conditionally writes 0 to 7 words (length in r3) */
movs r3, r3, lsl #28
- stmcsia r0!, {r1, lr}
- stmcsia r0!, {r1, lr}
- stmmiia r0!, {r1, lr}
+ stmiacs r0!, {r1, lr}
+ stmiacs r0!, {r1, lr}
+ stmiami r0!, {r1, lr}
movs r3, r3, lsl #2
strcs r1, [r0], #4
.Laligned32:
mov r3, r1
1: subs r2, r2, #32
- stmhsia r0!, {r1,r3,r12,lr}
- stmhsia r0!, {r1,r3,r12,lr}
+ stmiahs r0!, {r1,r3,r12,lr}
+ stmiahs r0!, {r1,r3,r12,lr}
bhs 1b
add r2, r2, #32
/* conditionally stores 0 to 30 bytes */
movs r2, r2, lsl #28
- stmcsia r0!, {r1,r3,r12,lr}
- stmmiia r0!, {r1,lr}
+ stmiacs r0!, {r1,r3,r12,lr}
+ stmiami r0!, {r1,lr}
movs r2, r2, lsl #2
strcs r1, [r0], #4
- strmih lr, [r0], #2
+ strhmi lr, [r0], #2
ldr lr, [sp], #4
.cfi_def_cfa_offset 0
diff --git a/libcutils/klog.c b/libcutils/klog.c
index f574f08..710dc66 100644
--- a/libcutils/klog.c
+++ b/libcutils/klog.c
@@ -40,6 +40,11 @@
void klog_init(void) {
if (klog_fd >= 0) return; /* Already initialized */
+ klog_fd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC);
+ if (klog_fd >= 0) {
+ return;
+ }
+
static const char* name = "/dev/__kmsg__";
if (mknod(name, S_IFCHR | 0600, (1 << 8) | 11) == 0) {
klog_fd = open(name, O_WRONLY | O_CLOEXEC);
diff --git a/libcutils/threads.c b/libcutils/threads.c
index 3d8dd48..036f8c5 100644
--- a/libcutils/threads.c
+++ b/libcutils/threads.c
@@ -35,12 +35,7 @@
#ifndef __ANDROID__
pid_t gettid() {
#if defined(__APPLE__)
- uint64_t owner;
- int rc = pthread_threadid_np(NULL, &owner);
- if (rc != 0) {
- abort();
- }
- return owner;
+ return syscall(SYS_thread_selfid);
#elif defined(__linux__)
return syscall(__NR_gettid);
#elif defined(_WIN32)
diff --git a/liblog/Android.mk b/liblog/Android.mk
index 70aff83..d7766f5 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -85,7 +85,7 @@
LOCAL_CFLAGS := -Werror $(liblog_cflags)
# TODO: This is to work around b/19059885. Remove after root cause is fixed
-LOCAL_LDFLAGS_arm := -Wl,--hash-style=sysv
+LOCAL_LDFLAGS_arm := -Wl,--hash-style=both
include $(BUILD_SHARED_LIBRARY)
diff --git a/liblog/log_read.c b/liblog/log_read.c
index 5364e4f..9c4af30 100644
--- a/liblog/log_read.c
+++ b/liblog/log_read.c
@@ -208,6 +208,7 @@
[LOG_ID_EVENTS] = "events",
[LOG_ID_SYSTEM] = "system",
[LOG_ID_CRASH] = "crash",
+ [LOG_ID_KERNEL] = "kernel",
};
const char *android_log_id_to_name(log_id_t log_id)
diff --git a/liblog/log_read_kern.c b/liblog/log_read_kern.c
index bdc7b18..69b405c 100644
--- a/liblog/log_read_kern.c
+++ b/liblog/log_read_kern.c
@@ -62,7 +62,8 @@
[LOG_ID_RADIO] = "radio",
[LOG_ID_EVENTS] = "events",
[LOG_ID_SYSTEM] = "system",
- [LOG_ID_CRASH] = "crash"
+ [LOG_ID_CRASH] = "crash",
+ [LOG_ID_KERNEL] = "kernel",
};
const char *android_log_id_to_name(log_id_t log_id)
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index c62a246..bdee28f 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -310,7 +310,8 @@
[LOG_ID_RADIO] = "radio",
[LOG_ID_EVENTS] = "events",
[LOG_ID_SYSTEM] = "system",
- [LOG_ID_CRASH] = "crash"
+ [LOG_ID_CRASH] = "crash",
+ [LOG_ID_KERNEL] = "kernel",
};
const char *android_log_id_to_name(log_id_t log_id)
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 0f01542..a3f1d7e 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -43,6 +43,7 @@
FilterInfo *filters;
AndroidLogPrintFormat format;
bool colored_output;
+ bool usec_time_output;
};
/*
@@ -185,6 +186,7 @@
p_ret->global_pri = ANDROID_LOG_VERBOSE;
p_ret->format = FORMAT_BRIEF;
p_ret->colored_output = false;
+ p_ret->usec_time_output = false;
return p_ret;
}
@@ -207,13 +209,19 @@
-void android_log_setPrintFormat(AndroidLogFormat *p_format,
+int android_log_setPrintFormat(AndroidLogFormat *p_format,
AndroidLogPrintFormat format)
{
- if (format == FORMAT_COLOR)
+ if (format == FORMAT_MODIFIER_COLOR) {
p_format->colored_output = true;
- else
- p_format->format = format;
+ return 0;
+ }
+ if (format == FORMAT_MODIFIER_TIME_USEC) {
+ p_format->usec_time_output = true;
+ return 0;
+ }
+ p_format->format = format;
+ return 1;
}
/**
@@ -231,7 +239,8 @@
else if (strcmp(formatString, "time") == 0) format = FORMAT_TIME;
else if (strcmp(formatString, "threadtime") == 0) format = FORMAT_THREADTIME;
else if (strcmp(formatString, "long") == 0) format = FORMAT_LONG;
- else if (strcmp(formatString, "color") == 0) format = FORMAT_COLOR;
+ else if (strcmp(formatString, "color") == 0) format = FORMAT_MODIFIER_COLOR;
+ else if (strcmp(formatString, "usec") == 0) format = FORMAT_MODIFIER_TIME_USEC;
else format = FORMAT_OFF;
return format;
@@ -745,7 +754,7 @@
struct tm tmBuf;
#endif
struct tm* ptm;
- char timeBuf[32];
+ char timeBuf[32]; /* good margin, 23+nul for msec, 26+nul for usec */
char prefixBuf[128], suffixBuf[128];
char priChar;
int prefixSuffixIsHeaderFooter = 0;
@@ -771,6 +780,14 @@
#endif
//strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", ptm);
strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
+ len = strlen(timeBuf);
+ if (p_format->usec_time_output) {
+ snprintf(timeBuf + len, sizeof(timeBuf) - len,
+ ".%06ld", entry->tv_nsec / 1000);
+ } else {
+ snprintf(timeBuf + len, sizeof(timeBuf) - len,
+ ".%03ld", entry->tv_nsec / 1000000);
+ }
/*
* Construct a buffer containing the log header and log message.
@@ -811,23 +828,21 @@
break;
case FORMAT_TIME:
len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
- "%s.%03ld %c/%-8s(%5d): ", timeBuf, entry->tv_nsec / 1000000,
- priChar, entry->tag, entry->pid);
+ "%s %c/%-8s(%5d): ", timeBuf, priChar, entry->tag, entry->pid);
strcpy(suffixBuf + suffixLen, "\n");
++suffixLen;
break;
case FORMAT_THREADTIME:
len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
- "%s.%03ld %5d %5d %c %-8s: ", timeBuf, entry->tv_nsec / 1000000,
+ "%s %5d %5d %c %-8s: ", timeBuf,
entry->pid, entry->tid, priChar, entry->tag);
strcpy(suffixBuf + suffixLen, "\n");
++suffixLen;
break;
case FORMAT_LONG:
len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
- "[ %s.%03ld %5d:%5d %c/%-8s ]\n",
- timeBuf, entry->tv_nsec / 1000000, entry->pid,
- entry->tid, priChar, entry->tag);
+ "[ %s %5d:%5d %c/%-8s ]\n",
+ timeBuf, entry->pid, entry->tid, priChar, entry->tag);
strcpy(suffixBuf + suffixLen, "\n\n");
suffixLen += 2;
prefixSuffixIsHeaderFooter = 1;
diff --git a/liblog/tests/libc_test.cpp b/liblog/tests/libc_test.cpp
index 29501be..0e84f4e 100644
--- a/liblog/tests/libc_test.cpp
+++ b/liblog/tests/libc_test.cpp
@@ -136,3 +136,12 @@
android_logger_list_close(logger_list);
}
+
+TEST(libc, __pstore_append) {
+ FILE *fp;
+ ASSERT_TRUE(NULL != (fp = fopen("/dev/pmsg0", "a")));
+ static const char message[] = "libc.__pstore_append\n";
+ ASSERT_EQ((size_t)1, fwrite(message, sizeof(message), 1, fp));
+ ASSERT_EQ(0, fclose(fp));
+ fprintf(stderr, "Reboot, ensure string libc.__pstore_append is in /sys/fs/pstore/pmsg-ramoops-0\n");
+}
diff --git a/libmincrypt/Android.mk b/libmincrypt/Android.mk
index 503bcb4..7906986 100644
--- a/libmincrypt/Android.mk
+++ b/libmincrypt/Android.mk
@@ -6,8 +6,6 @@
LOCAL_MODULE := libmincrypt
LOCAL_SRC_FILES := dsa_sig.c p256.c p256_ec.c p256_ecdsa.c rsa.c sha.c sha256.c
LOCAL_CFLAGS := -Wall -Werror
-# Clang's slp-vectorize phase has segmentation fault when compiling p256_ec.c.
-LOCAL_CLANG_CFLAGS += -fno-slp-vectorize
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 2b19b93..2c2d785 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -235,7 +235,7 @@
" -r <kbytes> Rotate log every kbytes. Requires -f\n"
" -n <count> Sets max number of rotated logs to <count>, default 4\n"
" -v <format> Sets the log print format, where <format> is:\n\n"
- " brief color long process raw tag thread threadtime time\n\n"
+ " brief color long process raw tag thread threadtime time usec\n\n"
" -D print dividers between each log buffer\n"
" -c clear (flush) the entire log and exit\n"
" -d dump the log and then exit (don't block)\n"
@@ -291,9 +291,7 @@
return -1;
}
- android_log_setPrintFormat(g_logformat, format);
-
- return 0;
+ return android_log_setPrintFormat(g_logformat, format);
}
static const char multipliers[][2] = {
@@ -569,10 +567,7 @@
if (err < 0) {
logcat_panic(true, "Invalid parameter %s to -v\n", optarg);
}
-
- if (strcmp("color", optarg)) { // exception for modifiers
- hasSetLogFormat = 1;
- }
+ hasSetLogFormat |= err;
break;
case 'Q':
diff --git a/logd/Android.mk b/logd/Android.mk
index e65e9ff..73da8dc 100644
--- a/logd/Android.mk
+++ b/logd/Android.mk
@@ -18,6 +18,7 @@
LogWhiteBlackList.cpp \
libaudit.c \
LogAudit.cpp \
+ LogKlog.cpp \
event.logtags
LOCAL_SHARED_LIBRARIES := \
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index bdfed3b..5489cc9 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -33,9 +33,9 @@
#include "LogCommand.h"
CommandListener::CommandListener(LogBuffer *buf, LogReader * /*reader*/,
- LogListener * /*swl*/)
- : FrameworkListener(getLogSocket())
- , mBuf(*buf) {
+ LogListener * /*swl*/) :
+ FrameworkListener(getLogSocket()),
+ mBuf(*buf) {
// registerCmd(new ShutdownCmd(buf, writer, swl));
registerCmd(new ClearCmd(buf));
registerCmd(new GetBufSizeCmd(buf));
@@ -48,12 +48,12 @@
}
CommandListener::ShutdownCmd::ShutdownCmd(LogBuffer *buf, LogReader *reader,
- LogListener *swl)
- : LogCommand("shutdown")
- , mBuf(*buf)
- , mReader(*reader)
- , mSwl(*swl)
-{ }
+ LogListener *swl) :
+ LogCommand("shutdown"),
+ mBuf(*buf),
+ mReader(*reader),
+ mSwl(*swl) {
+}
int CommandListener::ShutdownCmd::runCommand(SocketClient * /*cli*/,
int /*argc*/,
@@ -63,10 +63,10 @@
exit(0);
}
-CommandListener::ClearCmd::ClearCmd(LogBuffer *buf)
- : LogCommand("clear")
- , mBuf(*buf)
-{ }
+CommandListener::ClearCmd::ClearCmd(LogBuffer *buf) :
+ LogCommand("clear"),
+ mBuf(*buf) {
+}
static void setname() {
static bool name_set;
@@ -100,10 +100,10 @@
return 0;
}
-CommandListener::GetBufSizeCmd::GetBufSizeCmd(LogBuffer *buf)
- : LogCommand("getLogSize")
- , mBuf(*buf)
-{ }
+CommandListener::GetBufSizeCmd::GetBufSizeCmd(LogBuffer *buf) :
+ LogCommand("getLogSize"),
+ mBuf(*buf) {
+}
int CommandListener::GetBufSizeCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
@@ -126,10 +126,10 @@
return 0;
}
-CommandListener::SetBufSizeCmd::SetBufSizeCmd(LogBuffer *buf)
- : LogCommand("setLogSize")
- , mBuf(*buf)
-{ }
+CommandListener::SetBufSizeCmd::SetBufSizeCmd(LogBuffer *buf) :
+ LogCommand("setLogSize"),
+ mBuf(*buf) {
+}
int CommandListener::SetBufSizeCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
@@ -160,10 +160,10 @@
return 0;
}
-CommandListener::GetBufSizeUsedCmd::GetBufSizeUsedCmd(LogBuffer *buf)
- : LogCommand("getLogSizeUsed")
- , mBuf(*buf)
-{ }
+CommandListener::GetBufSizeUsedCmd::GetBufSizeUsedCmd(LogBuffer *buf) :
+ LogCommand("getLogSizeUsed"),
+ mBuf(*buf) {
+}
int CommandListener::GetBufSizeUsedCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
@@ -186,10 +186,10 @@
return 0;
}
-CommandListener::GetStatisticsCmd::GetStatisticsCmd(LogBuffer *buf)
- : LogCommand("getStatistics")
- , mBuf(*buf)
-{ }
+CommandListener::GetStatisticsCmd::GetStatisticsCmd(LogBuffer *buf) :
+ LogCommand("getStatistics"),
+ mBuf(*buf) {
+}
static void package_string(char **strp) {
const char *a = *strp;
@@ -243,10 +243,10 @@
return 0;
}
-CommandListener::GetPruneListCmd::GetPruneListCmd(LogBuffer *buf)
- : LogCommand("getPruneList")
- , mBuf(*buf)
-{ }
+CommandListener::GetPruneListCmd::GetPruneListCmd(LogBuffer *buf) :
+ LogCommand("getPruneList"),
+ mBuf(*buf) {
+}
int CommandListener::GetPruneListCmd::runCommand(SocketClient *cli,
int /*argc*/, char ** /*argv*/) {
@@ -263,10 +263,10 @@
return 0;
}
-CommandListener::SetPruneListCmd::SetPruneListCmd(LogBuffer *buf)
- : LogCommand("setPruneList")
- , mBuf(*buf)
-{ }
+CommandListener::SetPruneListCmd::SetPruneListCmd(LogBuffer *buf) :
+ LogCommand("setPruneList"),
+ mBuf(*buf) {
+}
int CommandListener::SetPruneListCmd::runCommand(SocketClient *cli,
int argc, char **argv) {
@@ -301,9 +301,8 @@
return 0;
}
-CommandListener::ReinitCmd::ReinitCmd()
- : LogCommand("reinit")
-{ }
+CommandListener::ReinitCmd::ReinitCmd() : LogCommand("reinit") {
+}
int CommandListener::ReinitCmd::runCommand(SocketClient *cli,
int /*argc*/, char ** /*argv*/) {
diff --git a/logd/FlushCommand.cpp b/logd/FlushCommand.cpp
index 26a1861..d584925 100644
--- a/logd/FlushCommand.cpp
+++ b/logd/FlushCommand.cpp
@@ -27,14 +27,14 @@
unsigned long tail,
unsigned int logMask,
pid_t pid,
- uint64_t start)
- : mReader(reader)
- , mNonBlock(nonBlock)
- , mTail(tail)
- , mLogMask(logMask)
- , mPid(pid)
- , mStart(start)
-{ }
+ uint64_t start) :
+ mReader(reader),
+ mNonBlock(nonBlock),
+ mTail(tail),
+ mLogMask(logMask),
+ mPid(pid),
+ mStart(start) {
+}
// runSocketCommand is called once for every open client on the
// log reader socket. Here we manage and associated the reader
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index caae54b..4ec2e59 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -29,6 +29,7 @@
#include "libaudit.h"
#include "LogAudit.h"
+#include "LogKlog.h"
#define KMSG_PRIORITY(PRI) \
'<', \
@@ -36,12 +37,12 @@
'0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) % 10, \
'>'
-LogAudit::LogAudit(LogBuffer *buf, LogReader *reader, int fdDmesg)
- : SocketListener(getLogSocket(), false)
- , logbuf(buf)
- , reader(reader)
- , fdDmesg(fdDmesg)
- , initialized(false) {
+LogAudit::LogAudit(LogBuffer *buf, LogReader *reader, int fdDmesg) :
+ SocketListener(getLogSocket(), false),
+ logbuf(buf),
+ reader(reader),
+ fdDmesg(fdDmesg),
+ initialized(false) {
static const char auditd_message[] = { KMSG_PRIORITY(LOG_INFO),
'l', 'o', 'g', 'd', '.', 'a', 'u', 'd', 'i', 't', 'd', ':',
' ', 's', 't', 'a', 'r', 't', '\n' };
@@ -121,6 +122,15 @@
&& (*cp == ':')) {
memcpy(timeptr + sizeof(audit_str) - 1, "0.0", 3);
memmove(timeptr + sizeof(audit_str) - 1 + 3, cp, strlen(cp) + 1);
+ //
+ // We are either in 1970ish (MONOTONIC) or 2015+ish (REALTIME) so to
+ // differentiate without prejudice, we use 1980 to delineate, earlier
+ // is monotonic, later is real.
+ //
+# define EPOCH_PLUS_10_YEARS (10 * 1461 / 4 * 24 * 60 * 60)
+ if (now.tv_sec < EPOCH_PLUS_10_YEARS) {
+ LogKlog::convertMonotonicToReal(now);
+ }
} else {
now.strptime("", ""); // side effect of setting CLOCK_REALTIME
}
@@ -223,7 +233,7 @@
int LogAudit::log(char *buf) {
char *audit = strstr(buf, " audit(");
if (!audit) {
- return -EXDEV;
+ return 0;
}
*audit = '\0';
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 1dced11..8c0a0be 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -126,8 +126,7 @@
}
}
-LogBuffer::LogBuffer(LastLogTimes *times)
- : mTimes(*times) {
+LogBuffer::LogBuffer(LastLogTimes *times) : mTimes(*times) {
pthread_mutex_init(&mLogElementsLock, NULL);
init();
@@ -295,7 +294,9 @@
uint64_t current = e->getRealTime().nsec() - NS_PER_SEC;
ssize_t index = -1;
while((index = next(index)) >= 0) {
- if (current > editEntryAt(index).getLast()->getRealTime().nsec()) {
+ LogBufferElement *l = editEntryAt(index).getLast();
+ if ((l->getDropped() >= EXPIRE_THRESHOLD)
+ && (current > l->getRealTime().nsec())) {
removeAt(index);
index = -1;
}
@@ -387,6 +388,7 @@
bool kick = false;
bool leading = true;
LogBufferElementLast last;
+ log_time start(log_time::EPOCH);
for(it = mLogElements.begin(); it != mLogElements.end();) {
LogBufferElement *e = *it;
@@ -446,11 +448,29 @@
}
if (e->getUid() != worst) {
+ if (start != log_time::EPOCH) {
+ static const timespec too_old = {
+ EXPIRE_HOUR_THRESHOLD * 60 * 60, 0
+ };
+ start = e->getRealTime() + too_old;
+ }
last.clear(e);
++it;
continue;
}
+ if ((start != log_time::EPOCH) && (e->getRealTime() > start)) {
+ // KISS. Really a heuristic rather than algorithmically strong,
+ // a crude mechanism, the following loops will move the oldest
+ // watermark possibly wiping out the extra EXPIRE_HOUR_THRESHOLD
+ // we just thought we were preserving. We count on the typical
+ // pruneRows of 10% of total not being a sledgehammer.
+ // A stronger algorithm would have us loop back to the top if
+ // we have worst-UID enabled and we start expiring messages
+ // below less than EXPIRE_HOUR_THRESHOLD old.
+ break;
+ }
+
pruneRows--;
if (pruneRows == 0) {
break;
@@ -630,7 +650,7 @@
pthread_mutex_unlock(&mLogElementsLock);
// range locking in LastLogTimes looks after us
- max = element->flushTo(reader);
+ max = element->flushTo(reader, this);
if (max == element->FLUSH_ERROR) {
return max;
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index 9ee243d..00b19b6 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -74,6 +74,7 @@
// helper
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); }
private:
void maybePrune(log_id_t id);
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index a173e63..3d7237e 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -14,7 +14,9 @@
* limitations under the License.
*/
+#include <ctype.h>
#include <endian.h>
+#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
@@ -32,14 +34,14 @@
LogBufferElement::LogBufferElement(log_id_t log_id, log_time realtime,
uid_t uid, pid_t pid, pid_t tid,
- const char *msg, unsigned short len)
- : mLogId(log_id)
- , mUid(uid)
- , mPid(pid)
- , mTid(tid)
- , mMsgLen(len)
- , mSequence(sequence.fetch_add(1, memory_order_relaxed))
- , mRealTime(realtime) {
+ const char *msg, unsigned short len) :
+ mLogId(log_id),
+ mUid(uid),
+ mPid(pid),
+ mTid(tid),
+ mMsgLen(len),
+ mSequence(sequence.fetch_add(1, memory_order_relaxed)),
+ mRealTime(realtime) {
mMsg = new char[len];
memcpy(mMsg, msg, len);
}
@@ -48,18 +50,95 @@
delete [] mMsg;
}
-// assumption: mMsg == NULL
-size_t LogBufferElement::populateDroppedMessage(char *&buffer, bool privileged) {
- static const char format_uid[] = "uid=%u dropped=%u";
- static const size_t unprivileged_offset = 7;
- static const char tag[] = "logd";
-
- size_t len;
- if (privileged) {
- len = snprintf(NULL, 0, format_uid, mUid, mDropped);
- } else {
- len = snprintf(NULL, 0, format_uid + unprivileged_offset, mDropped);
+uint32_t LogBufferElement::getTag() const {
+ if ((mLogId != LOG_ID_EVENTS) || !mMsg || (mMsgLen < sizeof(uint32_t))) {
+ return 0;
}
+ return le32toh(reinterpret_cast<android_event_header_t *>(mMsg)->tag);
+}
+
+// caller must own and free character string
+char *android::tidToName(pid_t tid) {
+ char *retval = NULL;
+ char buffer[256];
+ snprintf(buffer, sizeof(buffer), "/proc/%u/comm", tid);
+ int fd = open(buffer, O_RDONLY);
+ if (fd >= 0) {
+ ssize_t ret = read(fd, buffer, sizeof(buffer));
+ if (ret >= (ssize_t)sizeof(buffer)) {
+ ret = sizeof(buffer) - 1;
+ }
+ while ((ret > 0) && isspace(buffer[ret - 1])) {
+ --ret;
+ }
+ if (ret > 0) {
+ buffer[ret] = '\0';
+ retval = strdup(buffer);
+ }
+ close(fd);
+ }
+
+ // if nothing for comm, check out cmdline
+ char *name = android::pidToName(tid);
+ if (!retval) {
+ retval = name;
+ name = NULL;
+ }
+
+ // check if comm is truncated, see if cmdline has full representation
+ if (name) {
+ // impossible for retval to be NULL if name not NULL
+ size_t retval_len = strlen(retval);
+ size_t name_len = strlen(name);
+ // KISS: ToDo: Only checks prefix truncated, not suffix, or both
+ if ((retval_len < name_len) && !strcmp(retval, name + name_len - retval_len)) {
+ free(retval);
+ retval = name;
+ } else {
+ free(name);
+ }
+ }
+ return retval;
+}
+
+// assumption: mMsg == NULL
+size_t LogBufferElement::populateDroppedMessage(char *&buffer,
+ LogBuffer *parent) {
+ static const char tag[] = "logd";
+ static const char format_uid[] = "uid=%u%s too chatty%s, expire %u line%s";
+
+ char *name = parent->uidToName(mUid);
+ char *commName = android::tidToName(mTid);
+ if (!commName && (mTid != mPid)) {
+ commName = android::tidToName(mPid);
+ }
+ if (!commName) {
+ commName = parent->pidToName(mPid);
+ }
+ if (name && commName && !strcmp(name, commName)) {
+ free(commName);
+ commName = NULL;
+ }
+ if (name) {
+ char *p = NULL;
+ asprintf(&p, "(%s)", name);
+ if (p) {
+ free(name);
+ name = p;
+ }
+ }
+ if (commName) {
+ char *p = NULL;
+ asprintf(&p, " comm=%s", commName);
+ if (p) {
+ free(commName);
+ commName = p;
+ }
+ }
+ // identical to below to calculate the buffer size required
+ size_t len = snprintf(NULL, 0, format_uid, mUid, name ? name : "",
+ commName ? commName : "",
+ mDropped, (mDropped > 1) ? "s" : "");
size_t hdrLen;
if (mLogId == LOG_ID_EVENTS) {
@@ -70,6 +149,8 @@
buffer = static_cast<char *>(calloc(1, hdrLen + len + 1));
if (!buffer) {
+ free(name);
+ free(commName);
return 0;
}
@@ -86,16 +167,16 @@
strcpy(buffer + 1, tag);
}
- if (privileged) {
- snprintf(buffer + hdrLen, len + 1, format_uid, mUid, mDropped);
- } else {
- snprintf(buffer + hdrLen, len + 1, format_uid + unprivileged_offset, mDropped);
- }
+ snprintf(buffer + hdrLen, len + 1, format_uid, mUid, name ? name : "",
+ commName ? commName : "",
+ mDropped, (mDropped > 1) ? "s" : "");
+ free(name);
+ free(commName);
return retval;
}
-uint64_t LogBufferElement::flushTo(SocketClient *reader) {
+uint64_t LogBufferElement::flushTo(SocketClient *reader, LogBuffer *parent) {
struct logger_entry_v3 entry;
memset(&entry, 0, sizeof(struct logger_entry_v3));
@@ -114,7 +195,7 @@
char *buffer = NULL;
if (!mMsg) {
- entry.len = populateDroppedMessage(buffer, clientHasLogCredentials(reader));
+ entry.len = populateDroppedMessage(buffer, parent);
if (!entry.len) {
return mSequence;
}
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
index 7b6456d..3dcf9d1 100644
--- a/logd/LogBufferElement.h
+++ b/logd/LogBufferElement.h
@@ -25,18 +25,34 @@
#include <log/log.h>
#include <log/log_read.h>
+// Hijack this header as a common include file used by most all sources
+// to report some utilities defined here and there.
+
namespace android {
// Furnished in main.cpp. Caller must own and free returned value
-// This function is designed for a single caller and is NOT thread-safe
char *uidToName(uid_t uid);
+// Furnished in LogStatistics.cpp. Caller must own and free returned value
+char *pidToName(pid_t pid);
+char *tidToName(pid_t tid);
+
+// Furnished in main.cpp. Thread safe.
+const char *tagToName(uint32_t tag);
+
}
static inline bool worstUidEnabledForLogid(log_id_t id) {
- return (id != LOG_ID_CRASH) && (id != LOG_ID_EVENTS);
+ return (id != LOG_ID_CRASH) && (id != LOG_ID_KERNEL) && (id != LOG_ID_EVENTS);
}
+class LogBuffer;
+
+#define EXPIRE_HOUR_THRESHOLD 24 // Only expire chatty UID logs to preserve
+ // non-chatty UIDs less than this age in hours
+#define EXPIRE_THRESHOLD 4 // A smaller expire count is considered too
+ // chatty for the temporal expire messages
+
class LogBufferElement {
const log_id_t mLogId;
const uid_t mUid;
@@ -52,7 +68,8 @@
static atomic_int_fast64_t sequence;
// assumption: mMsg == NULL
- size_t populateDroppedMessage(char *&buffer, bool privileged);
+ size_t populateDroppedMessage(char *&buffer,
+ LogBuffer *parent);
public:
LogBufferElement(log_id_t log_id, log_time realtime,
@@ -77,8 +94,10 @@
static uint64_t getCurrentSequence(void) { return sequence.load(memory_order_relaxed); }
log_time getRealTime(void) const { return mRealTime; }
+ uint32_t getTag(void) const;
+
static const uint64_t FLUSH_ERROR;
- uint64_t flushTo(SocketClient *writer);
+ uint64_t flushTo(SocketClient *writer, LogBuffer *parent);
};
#endif
diff --git a/logd/LogCommand.cpp b/logd/LogCommand.cpp
index b78c0e0..06d865c 100644
--- a/logd/LogCommand.cpp
+++ b/logd/LogCommand.cpp
@@ -23,8 +23,7 @@
#include "LogCommand.h"
-LogCommand::LogCommand(const char *cmd)
- : FrameworkCommand(cmd) {
+LogCommand::LogCommand(const char *cmd) : FrameworkCommand(cmd) {
}
// gets a list of supplementary group IDs associated with
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
new file mode 100644
index 0000000..8df0d0a
--- /dev/null
+++ b/logd/LogKlog.cpp
@@ -0,0 +1,454 @@
+/*
+ * 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.
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <sys/prctl.h>
+#include <sys/uio.h>
+#include <syslog.h>
+
+#include <log/logger.h>
+
+#include "LogKlog.h"
+
+#define KMSG_PRIORITY(PRI) \
+ '<', \
+ '0' + (LOG_SYSLOG | (PRI)) / 10, \
+ '0' + (LOG_SYSLOG | (PRI)) % 10, \
+ '>'
+
+static const char priority_message[] = { KMSG_PRIORITY(LOG_INFO), '\0' };
+
+log_time LogKlog::correction = log_time(CLOCK_REALTIME) - log_time(CLOCK_MONOTONIC);
+
+LogKlog::LogKlog(LogBuffer *buf, LogReader *reader, int fdWrite, int fdRead, bool auditd) :
+ SocketListener(fdRead, false),
+ logbuf(buf),
+ reader(reader),
+ signature(CLOCK_MONOTONIC),
+ fdWrite(fdWrite),
+ fdRead(fdRead),
+ initialized(false),
+ enableLogging(true),
+ auditd(auditd) {
+ static const char klogd_message[] = "%slogd.klogd: %" PRIu64 "\n";
+ char buffer[sizeof(priority_message) + sizeof(klogd_message) + 20 - 4];
+ snprintf(buffer, sizeof(buffer), klogd_message, priority_message,
+ signature.nsec());
+ write(fdWrite, buffer, strlen(buffer));
+}
+
+bool LogKlog::onDataAvailable(SocketClient *cli) {
+ if (!initialized) {
+ prctl(PR_SET_NAME, "logd.klogd");
+ initialized = true;
+ enableLogging = false;
+ }
+
+ char buffer[LOGGER_ENTRY_MAX_PAYLOAD];
+ size_t len = 0;
+
+ for(;;) {
+ ssize_t retval = 0;
+ if ((sizeof(buffer) - 1 - len) > 0) {
+ retval = read(cli->getSocket(), buffer + len, sizeof(buffer) - 1 - len);
+ }
+ if ((retval == 0) && (len == 0)) {
+ break;
+ }
+ if (retval < 0) {
+ return false;
+ }
+ len += retval;
+ bool full = len == (sizeof(buffer) - 1);
+ char *ep = buffer + len;
+ *ep = '\0';
+ len = 0;
+ for(char *ptr, *tok = buffer;
+ ((tok = strtok_r(tok, "\r\n", &ptr)));
+ tok = NULL) {
+ if (((tok + strlen(tok)) == ep) && (retval != 0) && full) {
+ len = strlen(tok);
+ memmove(buffer, tok, len);
+ break;
+ }
+ if (*tok) {
+ log(tok);
+ }
+ }
+ }
+
+ return true;
+}
+
+
+void LogKlog::calculateCorrection(const log_time &monotonic,
+ const char *real_string) {
+ log_time real;
+ if (!real.strptime(real_string, "%Y-%m-%d %H:%M:%S.%09q UTC")) {
+ return;
+ }
+ // kernel report UTC, log_time::strptime is localtime from calendar.
+ // Bionic and liblog strptime does not support %z or %Z to pick up
+ // timezone so we are calculating our own correction.
+ time_t now = real.tv_sec;
+ struct tm tm;
+ memset(&tm, 0, sizeof(tm));
+ tm.tm_isdst = -1;
+ localtime_r(&now, &tm);
+ real.tv_sec += tm.tm_gmtoff;
+ correction = real - monotonic;
+}
+
+void LogKlog::sniffTime(log_time &now, const char **buf, bool reverse) {
+ const char *cp;
+ if ((cp = now.strptime(*buf, "[ %s.%q]"))) {
+ static const char suspend[] = "PM: suspend entry ";
+ static const char resume[] = "PM: suspend exit ";
+ static const char suspended[] = "Suspended for ";
+
+ if (isspace(*cp)) {
+ ++cp;
+ }
+ if (!strncmp(cp, suspend, sizeof(suspend) - 1)) {
+ calculateCorrection(now, cp + sizeof(suspend) - 1);
+ } else if (!strncmp(cp, resume, sizeof(resume) - 1)) {
+ calculateCorrection(now, cp + sizeof(resume) - 1);
+ } else if (!strncmp(cp, suspended, sizeof(suspended) - 1)) {
+ log_time real;
+ char *endp;
+ real.tv_sec = strtol(cp + sizeof(suspended) - 1, &endp, 10);
+ if (*endp == '.') {
+ real.tv_nsec = strtol(endp + 1, &endp, 10) * 1000000L;
+ if (reverse) {
+ correction -= real;
+ } else {
+ correction += real;
+ }
+ }
+ }
+
+ convertMonotonicToReal(now);
+ *buf = cp;
+ } else {
+ now = log_time(CLOCK_REALTIME);
+ }
+}
+
+// Passed the entire SYSLOG_ACTION_READ_ALL buffer and interpret a
+// compensated start time.
+void LogKlog::synchronize(const char *buf) {
+ const char *cp = strstr(buf, "] PM: suspend e");
+ if (!cp) {
+ return;
+ }
+
+ do {
+ --cp;
+ } while ((cp > buf) && (isdigit(*cp) || isspace(*cp) || (*cp == '.')));
+
+ log_time now;
+ sniffTime(now, &cp, true);
+
+ char *suspended = strstr(buf, "] Suspended for ");
+ if (!suspended || (suspended > cp)) {
+ return;
+ }
+ cp = suspended;
+
+ do {
+ --cp;
+ } while ((cp > buf) && (isdigit(*cp) || isspace(*cp) || (*cp == '.')));
+
+ sniffTime(now, &cp, true);
+}
+
+// kernel log prefix, convert to a kernel log priority number
+static int parseKernelPrio(const char **buf) {
+ int pri = LOG_USER | LOG_INFO;
+ const char *cp = *buf;
+ if (*cp == '<') {
+ pri = 0;
+ while(isdigit(*++cp)) {
+ pri = (pri * 10) + *cp - '0';
+ }
+ if (*cp == '>') {
+ ++cp;
+ } else {
+ cp = *buf;
+ pri = LOG_USER | LOG_INFO;
+ }
+ *buf = cp;
+ }
+ return pri;
+}
+
+// Convert kernel log priority number into an Android Logger priority number
+static int convertKernelPrioToAndroidPrio(int pri) {
+ switch(pri & LOG_PRIMASK) {
+ case LOG_EMERG:
+ // FALLTHRU
+ case LOG_ALERT:
+ // FALLTHRU
+ case LOG_CRIT:
+ return ANDROID_LOG_FATAL;
+
+ case LOG_ERR:
+ return ANDROID_LOG_ERROR;
+
+ case LOG_WARNING:
+ return ANDROID_LOG_WARN;
+
+ default:
+ // FALLTHRU
+ case LOG_NOTICE:
+ // FALLTHRU
+ case LOG_INFO:
+ break;
+
+ case LOG_DEBUG:
+ return ANDROID_LOG_DEBUG;
+ }
+
+ return ANDROID_LOG_INFO;
+}
+
+//
+// log a message into the kernel log buffer
+//
+// Filter rules to parse <PRI> <TIME> <tag> and <message> in order for
+// them to appear correct in the logcat output:
+//
+// LOG_KERN (0):
+// <PRI>[<TIME>] <tag> ":" <message>
+// <PRI>[<TIME>] <tag> <tag> ":" <message>
+// <PRI>[<TIME>] <tag> <tag>_work ":" <message>
+// <PRI>[<TIME>] <tag> '<tag>.<num>' ":" <message>
+// <PRI>[<TIME>] <tag> '<tag><num>' ":" <message>
+// <PRI>[<TIME>] <tag>_host '<tag>.<num>' ":" <message>
+// (unimplemented) <PRI>[<TIME>] <tag> '<num>.<tag>' ":" <message>
+// <PRI>[<TIME>] "[INFO]"<tag> : <message>
+// <PRI>[<TIME>] "------------[ cut here ]------------" (?)
+// <PRI>[<TIME>] "---[ end trace 3225a3070ca3e4ac ]---" (?)
+// LOG_USER, LOG_MAIL, LOG_DAEMON, LOG_AUTH, LOG_SYSLOG, LOG_LPR, LOG_NEWS
+// LOG_UUCP, LOG_CRON, LOG_AUTHPRIV, LOG_FTP:
+// <PRI+TAG>[<TIME>] (see sys/syslog.h)
+// Observe:
+// Minimum tag length = 3 NB: drops things like r5:c00bbadf, but allow PM:
+// Maximum tag words = 2
+// Maximum tag length = 16 NB: we are thinking of how ugly logcat can get.
+// Not a Tag if there is no message content.
+// leading additional spaces means no tag, inherit last tag.
+// Not a Tag if <tag>: is "ERROR:", "WARNING:", "INFO:" or "CPU:"
+// Drop:
+// empty messages
+// messages with ' audit(' in them if auditd is running
+// logd.klogd:
+// return -1 if message logd.klogd: <signature>
+//
+int LogKlog::log(const char *buf) {
+ if (auditd && strstr(buf, " audit(")) {
+ return 0;
+ }
+
+ int pri = parseKernelPrio(&buf);
+
+ log_time now;
+ sniffTime(now, &buf, false);
+
+ // sniff for start marker
+ const char klogd_message[] = "logd.klogd: ";
+ if (!strncmp(buf, klogd_message, sizeof(klogd_message) - 1)) {
+ char *endp;
+ uint64_t sig = strtoll(buf + sizeof(klogd_message) - 1, &endp, 10);
+ if (sig == signature.nsec()) {
+ if (initialized) {
+ enableLogging = true;
+ } else {
+ enableLogging = false;
+ }
+ return -1;
+ }
+ return 0;
+ }
+
+ if (!enableLogging) {
+ return 0;
+ }
+
+ // Parse pid, tid and uid (not possible)
+ const pid_t pid = 0;
+ const pid_t tid = 0;
+ const uid_t uid = 0;
+
+ // Parse (rules at top) to pull out a tag from the incoming kernel message.
+ // Some may view the following as an ugly heuristic, the desire is to
+ // beautify the kernel logs into an Android Logging format; the goal is
+ // admirable but costly.
+ while (isspace(*buf)) {
+ ++buf;
+ }
+ if (!*buf) {
+ return 0;
+ }
+ const char *start = buf;
+ const char *tag = "";
+ const char *etag = tag;
+ if (!isspace(*buf)) {
+ const char *bt, *et, *cp;
+
+ bt = buf;
+ if (!strncmp(buf, "[INFO]", 6)) {
+ // <PRI>[<TIME>] "[INFO]"<tag> ":" message
+ bt = buf + 6;
+ }
+ for(et = bt; *et && (*et != ':') && !isspace(*et); ++et);
+ for(cp = et; isspace(*cp); ++cp);
+ size_t size;
+
+ if (*cp == ':') {
+ // One Word
+ tag = bt;
+ etag = et;
+ buf = cp + 1;
+ } else {
+ size = et - bt;
+ if (strncmp(bt, cp, size)) {
+ // <PRI>[<TIME>] <tag>_host '<tag>.<num>' : message
+ if (!strncmp(bt + size - 5, "_host", 5)
+ && !strncmp(bt, cp, size - 5)) {
+ const char *b = cp;
+ cp += size - 5;
+ if (*cp == '.') {
+ while (!isspace(*++cp) && (*cp != ':'));
+ const char *e;
+ for(e = cp; isspace(*cp); ++cp);
+ if (*cp == ':') {
+ tag = b;
+ etag = e;
+ buf = cp + 1;
+ }
+ }
+ } else {
+ while (!isspace(*++cp) && (*cp != ':'));
+ const char *e;
+ for(e = cp; isspace(*cp); ++cp);
+ // Two words
+ if (*cp == ':') {
+ tag = bt;
+ etag = e;
+ buf = cp + 1;
+ }
+ }
+ } else if (isspace(cp[size])) {
+ const char *b = cp;
+ cp += size;
+ while (isspace(*++cp));
+ // <PRI>[<TIME>] <tag> <tag> : message
+ if (*cp == ':') {
+ tag = bt;
+ etag = et;
+ buf = cp + 1;
+ }
+ } else if (cp[size] == ':') {
+ // <PRI>[<TIME>] <tag> <tag> : message
+ tag = bt;
+ etag = et;
+ buf = cp + size + 1;
+ } else if ((cp[size] == '.') || isdigit(cp[size])) {
+ // <PRI>[<TIME>] <tag> '<tag>.<num>' : message
+ // <PRI>[<TIME>] <tag> '<tag><num>' : message
+ const char *b = cp;
+ cp += size;
+ while (!isspace(*++cp) && (*cp != ':'));
+ const char *e = cp;
+ while (isspace(*cp)) {
+ ++cp;
+ }
+ if (*cp == ':') {
+ tag = b;
+ etag = e;
+ buf = cp + 1;
+ }
+ } else {
+ while (!isspace(*++cp) && (*cp != ':'));
+ const char *e = cp;
+ while (isspace(*cp)) {
+ ++cp;
+ }
+ // Two words
+ if (*cp == ':') {
+ tag = bt;
+ etag = e;
+ buf = cp + 1;
+ }
+ }
+ }
+ size = etag - tag;
+ if ((size <= 1)
+ || ((size == 2) && (isdigit(tag[0]) || isdigit(tag[1])))
+ || ((size == 3) && !strncmp(tag, "CPU", 3))
+ || ((size == 7) && !strncmp(tag, "WARNING", 7))
+ || ((size == 5) && !strncmp(tag, "ERROR", 5))
+ || ((size == 4) && !strncmp(tag, "INFO", 4))) {
+ buf = start;
+ etag = tag = "";
+ }
+ }
+ size_t l = etag - tag;
+ while (isspace(*buf)) {
+ ++buf;
+ }
+ size_t n = 1 + l + 1 + strlen(buf) + 1;
+
+ // Allocate a buffer to hold the interpreted log message
+ int rc = n;
+ char *newstr = reinterpret_cast<char *>(malloc(n));
+ if (!newstr) {
+ rc = -ENOMEM;
+ return rc;
+ }
+ char *np = newstr;
+
+ // Convert priority into single-byte Android logger priority
+ *np = convertKernelPrioToAndroidPrio(pri);
+ ++np;
+
+ // Copy parsed tag following priority
+ strncpy(np, tag, l);
+ np += l;
+ *np = '\0';
+ ++np;
+
+ // Copy main message to the remainder
+ strcpy(np, buf);
+
+ // Log message
+ rc = logbuf->log(LOG_ID_KERNEL, now, uid, pid, tid, newstr,
+ (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
+ free(newstr);
+
+ // notify readers
+ if (!rc) {
+ reader->notifyNewLog();
+ }
+
+ return rc;
+}
diff --git a/logd/LogKlog.h b/logd/LogKlog.h
new file mode 100644
index 0000000..8de9c87
--- /dev/null
+++ b/logd/LogKlog.h
@@ -0,0 +1,55 @@
+/*
+ * 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 _LOGD_LOG_KLOG_H__
+#define _LOGD_LOG_KLOG_H__
+
+#include <sysutils/SocketListener.h>
+#include <log/log_read.h>
+#include "LogReader.h"
+
+class LogKlog : public SocketListener {
+ LogBuffer *logbuf;
+ LogReader *reader;
+ const log_time signature;
+ const int fdWrite; // /dev/kmsg
+ const int fdRead; // /proc/kmsg
+ // Set once thread is started, separates KLOG_ACTION_READ_ALL
+ // and KLOG_ACTION_READ phases.
+ bool initialized;
+ // Used during each of the above phases to control logging.
+ bool enableLogging;
+ // set if we are also running auditd, to filter out audit reports from
+ // our copy of the kernel log
+ bool auditd;
+
+ static log_time correction;
+
+public:
+ LogKlog(LogBuffer *buf, LogReader *reader, int fdWrite, int fdRead, bool auditd);
+ int log(const char *buf);
+ void synchronize(const char *buf);
+
+ static void convertMonotonicToReal(log_time &real) { real += correction; }
+
+protected:
+ void sniffTime(log_time &now, const char **buf, bool reverse);
+ void calculateCorrection(const log_time &monotonic, const char *real_string);
+ virtual bool onDataAvailable(SocketClient *cli);
+
+};
+
+#endif
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
index 05ced06..b29f5ab 100644
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -28,11 +28,11 @@
#include "LogListener.h"
-LogListener::LogListener(LogBuffer *buf, LogReader *reader)
- : SocketListener(getLogSocket(), false)
- , logbuf(buf)
- , reader(reader)
-{ }
+LogListener::LogListener(LogBuffer *buf, LogReader *reader) :
+ SocketListener(getLogSocket(), false),
+ logbuf(buf),
+ reader(reader) {
+}
bool LogListener::onDataAvailable(SocketClient *cli) {
static bool name_set;
@@ -88,7 +88,7 @@
}
android_log_header_t *header = reinterpret_cast<android_log_header_t *>(buffer);
- if (/* header->id < LOG_ID_MIN || */ header->id >= LOG_ID_MAX) {
+ if (/* header->id < LOG_ID_MIN || */ header->id >= LOG_ID_MAX || header->id == LOG_ID_KERNEL) {
return false;
}
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index 745e847..c7deec0 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -24,10 +24,10 @@
#include "LogReader.h"
#include "FlushCommand.h"
-LogReader::LogReader(LogBuffer *logbuf)
- : SocketListener(getLogSocket(), true)
- , mLogbuf(*logbuf)
-{ }
+LogReader::LogReader(LogBuffer *logbuf) :
+ SocketListener(getLogSocket(), true),
+ mLogbuf(*logbuf) {
+}
// When we are notified a new log entry is available, inform
// all of our listening sockets.
@@ -116,14 +116,14 @@
uint64_t last;
public:
- LogFindStart(unsigned logMask, pid_t pid, log_time &start, uint64_t &sequence)
- : mPid(pid)
- , mLogMask(logMask)
- , startTimeSet(false)
- , start(start)
- , sequence(sequence)
- , last(sequence)
- { }
+ LogFindStart(unsigned logMask, pid_t pid, log_time &start, uint64_t &sequence) :
+ mPid(pid),
+ mLogMask(logMask),
+ startTimeSet(false),
+ start(start),
+ sequence(sequence),
+ last(sequence) {
+ }
static int callback(const LogBufferElement *element, void *obj) {
LogFindStart *me = reinterpret_cast<LogFindStart *>(obj);
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index eadc4dd..90c49c0 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -26,8 +26,7 @@
#include "LogStatistics.h"
-LogStatistics::LogStatistics()
- : enable(false) {
+LogStatistics::LogStatistics() : enable(false) {
log_id_for_each(id) {
mSizes[id] = 0;
mElements[id] = 0;
@@ -39,10 +38,10 @@
namespace android {
// caller must own and free character string
-static char *pidToName(pid_t pid) {
+char *pidToName(pid_t pid) {
char *retval = NULL;
- if (pid == 0) { // special case from auditd for kernel
- retval = strdup("logd.auditd");
+ if (pid == 0) { // special case from auditd/klogd for kernel
+ retval = strdup("logd");
} else {
char buffer[512];
snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid);
@@ -70,50 +69,25 @@
mSizes[log_id] += size;
++mElements[log_id];
- uid_t uid = e->getUid();
- unsigned short dropped = e->getDropped();
- android::hash_t hash = android::hash_type(uid);
- uidTable_t &table = uidTable[log_id];
- ssize_t index = table.find(-1, hash, uid);
- if (index == -1) {
- UidEntry initEntry(uid);
- initEntry.add(size);
- initEntry.add_dropped(dropped);
- table.add(hash, initEntry);
- } else {
- UidEntry &entry = table.editEntryAt(index);
- entry.add(size);
- entry.add_dropped(dropped);
- }
-
mSizesTotal[log_id] += size;
++mElementsTotal[log_id];
+ if (log_id == LOG_ID_KERNEL) {
+ return;
+ }
+
+ uidTable[log_id].add(e->getUid(), e);
+
if (!enable) {
return;
}
- pid_t pid = e->getPid();
- hash = android::hash_type(pid);
- index = pidTable.find(-1, hash, pid);
- if (index == -1) {
- PidEntry initEntry(pid, uid, android::pidToName(pid));
- initEntry.add(size);
- initEntry.add_dropped(dropped);
- pidTable.add(hash, initEntry);
- } else {
- PidEntry &entry = pidTable.editEntryAt(index);
- if (entry.getUid() != uid) {
- entry.setUid(uid);
- entry.setName(android::pidToName(pid));
- } else if (!entry.getName()) {
- char *name = android::pidToName(pid);
- if (name) {
- entry.setName(name);
- }
- }
- entry.add(size);
- entry.add_dropped(dropped);
+ pidTable.add(e->getPid(), e);
+ tidTable.add(e->getTid(), e);
+
+ uint32_t tag = e->getTag();
+ if (tag) {
+ tagTable.add(tag, e);
}
}
@@ -123,30 +97,22 @@
mSizes[log_id] -= size;
--mElements[log_id];
- uid_t uid = e->getUid();
- unsigned short dropped = e->getDropped();
- android::hash_t hash = android::hash_type(uid);
- uidTable_t &table = uidTable[log_id];
- ssize_t index = table.find(-1, hash, uid);
- if (index != -1) {
- UidEntry &entry = table.editEntryAt(index);
- if (entry.subtract(size) || entry.subtract_dropped(dropped)) {
- table.removeAt(index);
- }
+ if (log_id == LOG_ID_KERNEL) {
+ return;
}
+ uidTable[log_id].subtract(e->getUid(), e);
+
if (!enable) {
return;
}
- pid_t pid = e->getPid();
- hash = android::hash_type(pid);
- index = pidTable.find(-1, hash, pid);
- if (index != -1) {
- PidEntry &entry = pidTable.editEntryAt(index);
- if (entry.subtract(size) || entry.subtract_dropped(dropped)) {
- pidTable.removeAt(index);
- }
+ pidTable.subtract(e->getPid(), e);
+ tidTable.subtract(e->getTid(), e);
+
+ uint32_t tag = e->getTag();
+ if (tag) {
+ tagTable.subtract(tag, e);
}
}
@@ -157,28 +123,14 @@
unsigned short size = e->getMsgLen();
mSizes[log_id] -= size;
- uid_t uid = e->getUid();
- android::hash_t hash = android::hash_type(uid);
- typeof uidTable[0] &table = uidTable[log_id];
- ssize_t index = table.find(-1, hash, uid);
- if (index != -1) {
- UidEntry &entry = table.editEntryAt(index);
- entry.subtract(size);
- entry.add_dropped(1);
- }
+ uidTable[log_id].drop(e->getUid(), e);
if (!enable) {
return;
}
- pid_t pid = e->getPid();
- hash = android::hash_type(pid);
- index = pidTable.find(-1, hash, pid);
- if (index != -1) {
- PidEntry &entry = pidTable.editEntryAt(index);
- entry.subtract(size);
- entry.add_dropped(1);
- }
+ pidTable.drop(e->getPid(), e);
+ tidTable.drop(e->getTid(), e);
}
// caller must own and free character string
@@ -199,7 +151,11 @@
}
// Parse /data/system/packages.list
- char *name = android::uidToName(uid);
+ uid_t userId = uid % AID_USER;
+ char *name = android::uidToName(userId);
+ if (!name && (userId > (AID_SHARED_GID_START - AID_APP))) {
+ name = android::uidToName(userId - (AID_SHARED_GID_START - AID_APP));
+ }
if (name) {
return name;
}
@@ -217,7 +173,8 @@
name = strdup(n);
} else if (strcmp(name, n)) {
free(name);
- return NULL;
+ name = NULL;
+ break;
}
}
}
@@ -379,6 +336,7 @@
}
if (enable) {
+ // Pid table
bool headerPrinted = false;
std::unique_ptr<const PidEntry *[]> sorted = pidTable.sort(maximum_sorted_entries);
ssize_t index = -1;
@@ -435,6 +393,108 @@
}
}
+ if (enable) {
+ // Tid table
+ bool headerPrinted = false;
+ // sort() returns list of references, unique_ptr makes sure self-delete
+ std::unique_ptr<const TidEntry *[]> sorted = tidTable.sort(maximum_sorted_entries);
+ ssize_t index = -1;
+ while ((index = tidTable.next(index, sorted, maximum_sorted_entries)) >= 0) {
+ const TidEntry *entry = sorted[index];
+ uid_t u = entry->getUid();
+ if ((uid != AID_ROOT) && (u != uid)) {
+ continue;
+ }
+
+ if (!headerPrinted) { // Only print header if we have table to print
+ output.appendFormat("\n\n");
+ android::String8 name("Chattiest TIDs:");
+ android::String8 size("Size");
+ android::String8 pruned("Pruned");
+ format_line(output, name, size, pruned);
+
+ name.setTo(" TID/UID COMM");
+ size.setTo("BYTES");
+ pruned.setTo("LINES");
+ format_line(output, name, size, pruned);
+
+ headerPrinted = true;
+ }
+
+ android::String8 name("");
+ name.appendFormat("%5u/%u", entry->getKey(), u);
+ const char *n = entry->getName();
+ if (n) {
+ name.appendFormat("%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", n);
+ } else {
+ // if we do not have a PID name, lets punt to try UID name?
+ char *un = uidToName(u);
+ if (un) {
+ name.appendFormat("%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", un);
+ free(un);
+ }
+ // We tried, better to not have a name at all, we still
+ // have TID/UID by number to report in any case.
+ }
+
+ android::String8 size("");
+ size.appendFormat("%zu", entry->getSizes());
+
+ android::String8 pruned("");
+ size_t dropped = entry->getDropped();
+ if (dropped) {
+ pruned.appendFormat("%zu", dropped);
+ }
+
+ format_line(output, name, size, pruned);
+ }
+ }
+
+ if (enable && (logMask & (1 << LOG_ID_EVENTS))) {
+ // Tag table
+ bool headerPrinted = false;
+ std::unique_ptr<const TagEntry *[]> sorted = tagTable.sort(maximum_sorted_entries);
+ ssize_t index = -1;
+ while ((index = tagTable.next(index, sorted, maximum_sorted_entries)) >= 0) {
+ const TagEntry *entry = sorted[index];
+ uid_t u = entry->getUid();
+ if ((uid != AID_ROOT) && (u != uid)) {
+ continue;
+ }
+
+ android::String8 pruned("");
+
+ if (!headerPrinted) {
+ output.appendFormat("\n\n");
+ android::String8 name("Chattiest events log buffer TAGs:");
+ android::String8 size("Size");
+ format_line(output, name, size, pruned);
+
+ name.setTo(" TAG/UID TAGNAME");
+ size.setTo("BYTES");
+ format_line(output, name, size, pruned);
+
+ headerPrinted = true;
+ }
+
+ android::String8 name("");
+ if (u == (uid_t)-1) {
+ name.appendFormat("%7u", entry->getKey());
+ } else {
+ name.appendFormat("%7u/%u", entry->getKey(), u);
+ }
+ const char *n = entry->getName();
+ if (n) {
+ name.appendFormat("%*s%s", (int)std::max(14 - name.length(), (size_t)1), "", n);
+ }
+
+ android::String8 size("");
+ size.appendFormat("%zu", entry->getSizes());
+
+ format_line(output, name, size, pruned);
+ }
+ }
+
*buf = strdup(output.string());
}
@@ -460,48 +520,14 @@
}
uid_t LogStatistics::pidToUid(pid_t pid) {
- uid_t uid;
- android::hash_t hash = android::hash_type(pid);
- ssize_t index = pidTable.find(-1, hash, pid);
- if (index == -1) {
- uid = android::pidToUid(pid);
- PidEntry initEntry(pid, uid, android::pidToName(pid));
- pidTable.add(hash, initEntry);
- } else {
- PidEntry &entry = pidTable.editEntryAt(index);
- if (!entry.getName()) {
- char *name = android::pidToName(pid);
- if (name) {
- entry.setName(name);
- }
- }
- uid = entry.getUid();
- }
- return uid;
+ return pidTable.entryAt(pidTable.add(pid)).getUid();
}
// caller must free character string
char *LogStatistics::pidToName(pid_t pid) {
- char *name;
-
- android::hash_t hash = android::hash_type(pid);
- ssize_t index = pidTable.find(-1, hash, pid);
- if (index == -1) {
- name = android::pidToName(pid);
- PidEntry initEntry(pid, android::pidToUid(pid), name ? strdup(name) : NULL);
- pidTable.add(hash, initEntry);
- } else {
- PidEntry &entry = pidTable.editEntryAt(index);
- const char *n = entry.getName();
- if (n) {
- name = strdup(n);
- } else {
- name = android::pidToName(pid);
- if (name) {
- entry.setName(strdup(name));
- }
- }
+ const char *name = pidTable.entryAt(pidTable.add(pid)).getName();
+ if (!name) {
+ return NULL;
}
-
- return name;
+ return strdup(name);
}
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index f3110d7..f60f3ed 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -73,52 +73,214 @@
ssize_t next(ssize_t index) {
return android::BasicHashtable<TKey, TEntry>::next(index);
}
+
+ size_t add(TKey key, LogBufferElement *e) {
+ android::hash_t hash = android::hash_type(key);
+ ssize_t index = android::BasicHashtable<TKey, TEntry>::find(-1, hash, key);
+ if (index == -1) {
+ return android::BasicHashtable<TKey, TEntry>::add(hash, TEntry(e));
+ }
+ android::BasicHashtable<TKey, TEntry>::editEntryAt(index).add(e);
+ return index;
+ }
+
+ inline size_t add(TKey key) {
+ android::hash_t hash = android::hash_type(key);
+ ssize_t index = android::BasicHashtable<TKey, TEntry>::find(-1, hash, key);
+ if (index == -1) {
+ return android::BasicHashtable<TKey, TEntry>::add(hash, TEntry(key));
+ }
+ android::BasicHashtable<TKey, TEntry>::editEntryAt(index).add(key);
+ return index;
+ }
+
+ void subtract(TKey key, LogBufferElement *e) {
+ ssize_t index = android::BasicHashtable<TKey, TEntry>::find(-1, android::hash_type(key), key);
+ if ((index != -1)
+ && android::BasicHashtable<TKey, TEntry>::editEntryAt(index).subtract(e)) {
+ android::BasicHashtable<TKey, TEntry>::removeAt(index);
+ }
+ }
+
+ inline void drop(TKey key, LogBufferElement *e) {
+ ssize_t index = android::BasicHashtable<TKey, TEntry>::find(-1, android::hash_type(key), key);
+ if (index != -1) {
+ android::BasicHashtable<TKey, TEntry>::editEntryAt(index).drop(e);
+ }
+ }
+
};
-struct UidEntry {
- const uid_t uid;
+struct EntryBase {
size_t size;
+
+ EntryBase():size(0) { }
+ EntryBase(LogBufferElement *e):size(e->getMsgLen()) { }
+
+ size_t getSizes() const { return size; }
+
+ inline void add(LogBufferElement *e) { size += e->getMsgLen(); }
+ inline bool subtract(LogBufferElement *e) { size -= e->getMsgLen(); return !size; }
+};
+
+struct EntryBaseDropped : public EntryBase {
size_t dropped;
- UidEntry(uid_t uid):uid(uid),size(0),dropped(0) { }
+ EntryBaseDropped():dropped(0) { }
+ EntryBaseDropped(LogBufferElement *e):EntryBase(e),dropped(e->getDropped()){ }
- inline const uid_t&getKey() const { return uid; }
- size_t getSizes() const { return size; }
size_t getDropped() const { return dropped; }
- inline void add(size_t s) { size += s; }
- inline void add_dropped(size_t d) { dropped += d; }
- inline bool subtract(size_t s) { size -= s; return !dropped && !size; }
- inline bool subtract_dropped(size_t d) { dropped -= d; return !dropped && !size; }
+ inline void add(LogBufferElement *e) {
+ dropped += e->getDropped();
+ EntryBase::add(e);
+ }
+ inline bool subtract(LogBufferElement *e) {
+ dropped -= e->getDropped();
+ return EntryBase::subtract(e) && !dropped;
+ }
+ inline void drop(LogBufferElement *e) {
+ dropped += 1;
+ EntryBase::subtract(e);
+ }
};
-struct PidEntry {
+struct UidEntry : public EntryBaseDropped {
+ const uid_t uid;
+
+ UidEntry(LogBufferElement *e):EntryBaseDropped(e),uid(e->getUid()) { }
+
+ inline const uid_t&getKey() const { return uid; }
+};
+
+namespace android {
+uid_t pidToUid(pid_t pid);
+}
+
+struct PidEntry : public EntryBaseDropped {
const pid_t pid;
uid_t uid;
char *name;
- size_t size;
- size_t dropped;
- PidEntry(pid_t p, uid_t u, char *n):pid(p),uid(u),name(n),size(0),dropped(0) { }
+ PidEntry(pid_t p):
+ EntryBaseDropped(),
+ pid(p),
+ uid(android::pidToUid(p)),
+ name(android::pidToName(pid)) { }
+ PidEntry(LogBufferElement *e):
+ EntryBaseDropped(e),
+ pid(e->getPid()),
+ uid(e->getUid()),
+ name(android::pidToName(e->getPid())) { }
PidEntry(const PidEntry &c):
+ EntryBaseDropped(c),
pid(c.pid),
uid(c.uid),
- name(c.name ? strdup(c.name) : NULL),
- size(c.size),
- dropped(c.dropped) { }
+ name(c.name ? strdup(c.name) : NULL) { }
~PidEntry() { free(name); }
const pid_t&getKey() const { return pid; }
const uid_t&getUid() const { return uid; }
- uid_t&setUid(uid_t u) { return uid = u; }
const char*getName() const { return name; }
- char *setName(char *n) { free(name); return name = n; }
- size_t getSizes() const { return size; }
- size_t getDropped() const { return dropped; }
- inline void add(size_t s) { size += s; }
- inline void add_dropped(size_t d) { dropped += d; }
- inline bool subtract(size_t s) { size -= s; return !dropped && !size; }
- inline bool subtract_dropped(size_t d) { dropped -= d; return !dropped && !size; }
+
+ inline void add(pid_t p) {
+ if (name && !strncmp(name, "zygote", 6)) {
+ free(name);
+ name = NULL;
+ }
+ if (!name) {
+ char *n = android::pidToName(p);
+ if (n) {
+ name = n;
+ }
+ }
+ }
+
+ inline void add(LogBufferElement *e) {
+ uid_t u = e->getUid();
+ if (getUid() != u) {
+ uid = u;
+ free(name);
+ name = android::pidToName(e->getPid());
+ } else {
+ add(e->getPid());
+ }
+ EntryBaseDropped::add(e);
+ }
+};
+
+struct TidEntry : public EntryBaseDropped {
+ const pid_t tid;
+ uid_t uid;
+ char *name;
+
+ TidEntry(pid_t t):
+ EntryBaseDropped(),
+ tid(t),
+ uid(android::pidToUid(t)),
+ name(android::tidToName(tid)) { }
+ TidEntry(LogBufferElement *e):
+ EntryBaseDropped(e),
+ tid(e->getTid()),
+ uid(e->getUid()),
+ name(android::tidToName(e->getTid())) { }
+ TidEntry(const TidEntry &c):
+ EntryBaseDropped(c),
+ tid(c.tid),
+ uid(c.uid),
+ name(c.name ? strdup(c.name) : NULL) { }
+ ~TidEntry() { free(name); }
+
+ const pid_t&getKey() const { return tid; }
+ const uid_t&getUid() const { return uid; }
+ const char*getName() const { return name; }
+
+ inline void add(pid_t t) {
+ if (name && !strncmp(name, "zygote", 6)) {
+ free(name);
+ name = NULL;
+ }
+ if (!name) {
+ char *n = android::tidToName(t);
+ if (n) {
+ name = n;
+ }
+ }
+ }
+
+ inline void add(LogBufferElement *e) {
+ uid_t u = e->getUid();
+ if (getUid() != u) {
+ uid = u;
+ free(name);
+ name = android::tidToName(e->getTid());
+ } else {
+ add(e->getTid());
+ }
+ EntryBaseDropped::add(e);
+ }
+};
+
+struct TagEntry : public EntryBase {
+ const uint32_t tag;
+ uid_t uid;
+
+ TagEntry(LogBufferElement *e):
+ EntryBase(e),
+ tag(e->getTag()),
+ uid(e->getUid()) { }
+
+ const uint32_t&getKey() const { return tag; }
+ const uid_t&getUid() const { return uid; }
+ const char*getName() const { return android::tagToName(tag); }
+
+ inline void add(LogBufferElement *e) {
+ uid_t u = e->getUid();
+ if (uid != u) {
+ uid = -1;
+ }
+ EntryBase::add(e);
+ }
};
// Log Statistics
@@ -137,6 +299,14 @@
typedef LogHashtable<pid_t, PidEntry> pidTable_t;
pidTable_t pidTable;
+ // tid to uid list
+ typedef LogHashtable<pid_t, TidEntry> tidTable_t;
+ tidTable_t tidTable;
+
+ // tag list
+ typedef LogHashtable<uint32_t, TagEntry> tagTable_t;
+ tagTable_t tagTable;
+
public:
LogStatistics();
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
index 1b60b7e..ec67c07 100644
--- a/logd/LogTimes.cpp
+++ b/logd/LogTimes.cpp
@@ -26,24 +26,23 @@
LogTimeEntry::LogTimeEntry(LogReader &reader, SocketClient *client,
bool nonBlock, unsigned long tail,
unsigned int logMask, pid_t pid,
- uint64_t start)
- : mRefCount(1)
- , mRelease(false)
- , mError(false)
- , threadRunning(false)
- , mReader(reader)
- , mLogMask(logMask)
- , mPid(pid)
- , mCount(0)
- , mTail(tail)
- , mIndex(0)
- , mClient(client)
- , mStart(start)
- , mNonBlock(nonBlock)
- , mEnd(LogBufferElement::getCurrentSequence())
-{
- pthread_cond_init(&threadTriggeredCondition, NULL);
- cleanSkip_Locked();
+ uint64_t start) :
+ mRefCount(1),
+ mRelease(false),
+ mError(false),
+ threadRunning(false),
+ mReader(reader),
+ mLogMask(logMask),
+ mPid(pid),
+ mCount(0),
+ mTail(tail),
+ mIndex(0),
+ mClient(client),
+ mStart(start),
+ mNonBlock(nonBlock),
+ mEnd(LogBufferElement::getCurrentSequence()) {
+ pthread_cond_init(&threadTriggeredCondition, NULL);
+ cleanSkip_Locked();
}
void LogTimeEntry::startReader_Locked(void) {
diff --git a/logd/LogWhiteBlackList.cpp b/logd/LogWhiteBlackList.cpp
index bee940d..277b3ca 100644
--- a/logd/LogWhiteBlackList.cpp
+++ b/logd/LogWhiteBlackList.cpp
@@ -22,10 +22,8 @@
// White and Black list
-Prune::Prune(uid_t uid, pid_t pid)
- : mUid(uid)
- , mPid(pid)
-{ }
+Prune::Prune(uid_t uid, pid_t pid) : mUid(uid), mPid(pid) {
+}
int Prune::cmp(uid_t uid, pid_t pid) const {
if ((mUid == uid_all) || (mUid == uid)) {
@@ -51,8 +49,7 @@
}
}
-PruneList::PruneList()
- : mWorstUidEnabled(true) {
+PruneList::PruneList() : mWorstUidEnabled(true) {
mNaughty.clear();
mNice.clear();
}
diff --git a/logd/README.property b/logd/README.property
index 60542b2..ad7d0cd 100644
--- a/logd/README.property
+++ b/logd/README.property
@@ -4,9 +4,12 @@
logd.auditd bool true Enable selinux audit daemon
logd.auditd.dmesg bool true selinux audit messages duplicated and
sent on to dmesg log
+logd.klogd bool depends Enable klogd daemon
logd.statistics bool depends Enable logcat -S statistics.
-ro.config.low_ram bool false if true, logd.statistics default false
-ro.build.type string if user, logd.statistics default false
+ro.config.low_ram bool false if true, logd.statistics & logd.klogd
+ default false
+ro.build.type string if user, logd.statistics & logd.klogd
+ default false
persist.logd.size number 256K default size of the buffer for all
log ids at initial startup, at runtime
use: logcat -b all -G <value>
diff --git a/logd/libaudit.c b/logd/libaudit.c
index cf76305..d00d579 100644
--- a/logd/libaudit.c
+++ b/logd/libaudit.c
@@ -177,7 +177,7 @@
*/
status.pid = pid;
status.mask = AUDIT_STATUS_PID | AUDIT_STATUS_RATE_LIMIT;
- status.rate_limit = 5; // audit entries per second
+ status.rate_limit = 20; // audit entries per second
/* Let the kernel know this pid will be registering for audit events */
rc = audit_send(fd, AUDIT_SET, &status, sizeof(status));
diff --git a/logd/main.cpp b/logd/main.cpp
index eb29596..6db819e 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -35,12 +35,14 @@
#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 "CommandListener.h"
#include "LogBuffer.h"
#include "LogListener.h"
#include "LogAudit.h"
+#include "LogKlog.h"
#define KMSG_PRIORITY(PRI) \
'<', \
@@ -210,18 +212,26 @@
return NULL;
}
+static sem_t sem_name;
+
char *android::uidToName(uid_t u) {
if (!u || !reinit_running) {
return NULL;
}
- // Not multi-thread safe, we know there is only one caller
+ sem_wait(&sem_name);
+
+ // Not multi-thread safe, we use sem_name to protect
uid = u;
name = NULL;
sem_post(&reinit);
sem_wait(&uidName);
- return name;
+ char *ret = name;
+
+ sem_post(&sem_name);
+
+ return ret;
}
// Serves as a global method to trigger reinitialization
@@ -230,6 +240,34 @@
sem_post(&reinit);
}
+// tagToName converts an events tag into a name
+const char *android::tagToName(uint32_t tag) {
+ static const EventTagMap *map;
+
+ if (!map) {
+ sem_wait(&sem_name);
+ if (!map) {
+ map = android_openEventTagMap(EVENT_TAG_MAP_FILE);
+ }
+ sem_post(&sem_name);
+ if (!map) {
+ return NULL;
+ }
+ }
+ return android_lookupEventTag(map, tag);
+}
+
+static bool property_get_bool_svelte(const char *key) {
+ bool not_user;
+ {
+ char property[PROPERTY_VALUE_MAX];
+ property_get("ro.build.type", property, "");
+ not_user = !!strcmp(property, "user");
+ }
+ return property_get_bool(key, not_user
+ && !property_get_bool("ro.config.low_ram", false));
+}
+
// 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
@@ -237,6 +275,11 @@
// logging plugins like auditd and restart control. Additional
// transitory per-client threads are created for each reader.
int main(int argc, char *argv[]) {
+ int fdPmesg = -1;
+ bool klogd = property_get_bool_svelte("logd.klogd");
+ if (klogd) {
+ fdPmesg = open("/proc/kmsg", O_RDONLY | O_NDELAY);
+ }
fdDmesg = open("/dev/kmsg", O_WRONLY);
// issue reinit command. KISS argument parsing.
@@ -277,6 +320,7 @@
// Reinit Thread
sem_init(&reinit, 0, 0);
sem_init(&uidName, 0, 0);
+ sem_init(&sem_name, 0, 1);
pthread_attr_t attr;
if (!pthread_attr_init(&attr)) {
struct sched_param param;
@@ -312,14 +356,8 @@
signal(SIGHUP, reinit_signal_handler);
- {
- char property[PROPERTY_VALUE_MAX];
- property_get("ro.build.type", property, "");
- if (property_get_bool("logd.statistics",
- !!strcmp(property, "user")
- && !property_get_bool("ro.config.low_ram", false))) {
- logBuf->enableStatistics();
- }
+ if (property_get_bool_svelte("logd.statistics")) {
+ logBuf->enableStatistics();
}
// LogReader listens on /dev/socket/logdr. When a client
@@ -354,12 +392,18 @@
bool auditd = property_get_bool("logd.auditd", true);
+ LogAudit *al = NULL;
if (auditd) {
bool dmesg = property_get_bool("logd.auditd.dmesg", true);
+ al = new LogAudit(logBuf, reader, dmesg ? fdDmesg : -1);
+ }
- // failure is an option ... messages are in dmesg (required by standard)
- LogAudit *al = new LogAudit(logBuf, reader, dmesg ? fdDmesg : -1);
+ LogKlog *kl = NULL;
+ if (klogd) {
+ kl = new LogKlog(logBuf, reader, fdDmesg, fdPmesg, al != NULL);
+ }
+ if (al || kl) {
int len = klogctl(KLOG_SIZE_BUFFER, NULL, 0);
if (len > 0) {
len++;
@@ -367,16 +411,31 @@
int rc = klogctl(KLOG_READ_ALL, buf, len);
- if (rc >= 0) {
- buf[len - 1] = '\0';
+ buf[len - 1] = '\0';
- for (char *ptr, *tok = buf; (tok = strtok_r(tok, "\r\n", &ptr)); tok = NULL) {
- al->log(tok);
+ if ((rc >= 0) && kl) {
+ kl->synchronize(buf);
+ }
+
+ for (char *ptr, *tok = buf;
+ (rc >= 0) && ((tok = strtok_r(tok, "\r\n", &ptr)));
+ tok = NULL) {
+ if (al) {
+ rc = al->log(tok);
+ }
+ if (kl) {
+ rc = kl->log(tok);
}
}
}
- if (al->startListener()) {
+ // failure is an option ... messages are in dmesg (required by standard)
+
+ if (kl && kl->startListener()) {
+ delete kl;
+ }
+
+ if (al && al->startListener()) {
delete al;
}
}
diff --git a/mkbootimg/bootimg.h b/mkbootimg/bootimg.h
index 9171d85..5ab6195 100644
--- a/mkbootimg/bootimg.h
+++ b/mkbootimg/bootimg.h
@@ -15,6 +15,8 @@
** limitations under the License.
*/
+#include <stdint.h>
+
#ifndef _BOOT_IMAGE_H_
#define _BOOT_IMAGE_H_
@@ -28,31 +30,31 @@
struct boot_img_hdr
{
- unsigned char magic[BOOT_MAGIC_SIZE];
+ uint8_t magic[BOOT_MAGIC_SIZE];
- unsigned kernel_size; /* size in bytes */
- unsigned kernel_addr; /* physical load addr */
+ uint32_t kernel_size; /* size in bytes */
+ uint32_t kernel_addr; /* physical load addr */
- unsigned ramdisk_size; /* size in bytes */
- unsigned ramdisk_addr; /* physical load addr */
+ uint32_t ramdisk_size; /* size in bytes */
+ uint32_t ramdisk_addr; /* physical load addr */
- unsigned second_size; /* size in bytes */
- unsigned second_addr; /* physical load addr */
+ uint32_t second_size; /* size in bytes */
+ uint32_t second_addr; /* physical load addr */
- unsigned tags_addr; /* physical addr for kernel tags */
- unsigned page_size; /* flash page size we assume */
- unsigned unused[2]; /* future expansion: should be 0 */
+ uint32_t tags_addr; /* physical addr for kernel tags */
+ uint32_t page_size; /* flash page size we assume */
+ uint32_t unused[2]; /* future expansion: should be 0 */
- unsigned char name[BOOT_NAME_SIZE]; /* asciiz product name */
+ uint8_t name[BOOT_NAME_SIZE]; /* asciiz product name */
- unsigned char cmdline[BOOT_ARGS_SIZE];
+ uint8_t cmdline[BOOT_ARGS_SIZE];
- unsigned id[8]; /* timestamp / checksum / sha1 / etc */
+ uint32_t id[8]; /* timestamp / checksum / sha1 / etc */
/* Supplemental command line data; kept here to maintain
* binary compatibility with older versions of mkbootimg */
- unsigned char extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
-};
+ uint8_t extra_cmdline[BOOT_EXTRA_ARGS_SIZE];
+} __attribute__((packed));
/*
** +-----------------+
diff --git a/mkbootimg/mkbootimg.c b/mkbootimg/mkbootimg.c
index fc92b4d..40e5261 100644
--- a/mkbootimg/mkbootimg.c
+++ b/mkbootimg/mkbootimg.c
@@ -21,6 +21,7 @@
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
+#include <stdbool.h>
#include "mincrypt/sha.h"
#include "bootimg.h"
@@ -65,6 +66,7 @@
" [ --board <boardname> ]\n"
" [ --base <address> ]\n"
" [ --pagesize <pagesize> ]\n"
+ " [ --id ]\n"
" -o|--output <filename>\n"
);
return 1;
@@ -74,6 +76,14 @@
static unsigned char padding[16384] = { 0, };
+static void print_id(const uint8_t *id, size_t id_len) {
+ printf("0x");
+ for (unsigned i = 0; i < id_len; i++) {
+ printf("%02x", id[i]);
+ }
+ printf("\n");
+}
+
int write_padding(int fd, unsigned pagesize, unsigned itemsize)
{
unsigned pagemask = pagesize - 1;
@@ -96,24 +106,24 @@
{
boot_img_hdr hdr;
- char *kernel_fn = 0;
- void *kernel_data = 0;
- char *ramdisk_fn = 0;
- void *ramdisk_data = 0;
- char *second_fn = 0;
- void *second_data = 0;
+ char *kernel_fn = NULL;
+ void *kernel_data = NULL;
+ char *ramdisk_fn = NULL;
+ void *ramdisk_data = NULL;
+ char *second_fn = NULL;
+ void *second_data = NULL;
char *cmdline = "";
- char *bootimg = 0;
+ char *bootimg = NULL;
char *board = "";
- unsigned pagesize = 2048;
+ uint32_t pagesize = 2048;
int fd;
SHA_CTX ctx;
const uint8_t* sha;
- unsigned base = 0x10000000;
- unsigned kernel_offset = 0x00008000;
- unsigned ramdisk_offset = 0x01000000;
- unsigned second_offset = 0x00f00000;
- unsigned tags_offset = 0x00000100;
+ uint32_t base = 0x10000000U;
+ uint32_t kernel_offset = 0x00008000U;
+ uint32_t ramdisk_offset = 0x01000000U;
+ uint32_t second_offset = 0x00f00000U;
+ uint32_t tags_offset = 0x00000100U;
size_t cmdlen;
argc--;
@@ -121,42 +131,48 @@
memset(&hdr, 0, sizeof(hdr));
+ bool get_id = false;
while(argc > 0){
char *arg = argv[0];
- char *val = argv[1];
- if(argc < 2) {
- return usage();
- }
- argc -= 2;
- argv += 2;
- if(!strcmp(arg, "--output") || !strcmp(arg, "-o")) {
- bootimg = val;
- } else if(!strcmp(arg, "--kernel")) {
- kernel_fn = val;
- } else if(!strcmp(arg, "--ramdisk")) {
- ramdisk_fn = val;
- } else if(!strcmp(arg, "--second")) {
- second_fn = val;
- } else if(!strcmp(arg, "--cmdline")) {
- cmdline = val;
- } else if(!strcmp(arg, "--base")) {
- base = strtoul(val, 0, 16);
- } else if(!strcmp(arg, "--kernel_offset")) {
- kernel_offset = strtoul(val, 0, 16);
- } else if(!strcmp(arg, "--ramdisk_offset")) {
- ramdisk_offset = strtoul(val, 0, 16);
- } else if(!strcmp(arg, "--second_offset")) {
- second_offset = strtoul(val, 0, 16);
- } else if(!strcmp(arg, "--tags_offset")) {
- tags_offset = strtoul(val, 0, 16);
- } else if(!strcmp(arg, "--board")) {
- board = val;
- } else if(!strcmp(arg,"--pagesize")) {
- pagesize = strtoul(val, 0, 10);
- if ((pagesize != 2048) && (pagesize != 4096)
- && (pagesize != 8192) && (pagesize != 16384)) {
- fprintf(stderr,"error: unsupported page size %d\n", pagesize);
- return -1;
+ if (!strcmp(arg, "--id")) {
+ get_id = true;
+ argc -= 1;
+ argv += 1;
+ } else if(argc >= 2) {
+ char *val = argv[1];
+ argc -= 2;
+ argv += 2;
+ if(!strcmp(arg, "--output") || !strcmp(arg, "-o")) {
+ bootimg = val;
+ } else if(!strcmp(arg, "--kernel")) {
+ kernel_fn = val;
+ } else if(!strcmp(arg, "--ramdisk")) {
+ ramdisk_fn = val;
+ } else if(!strcmp(arg, "--second")) {
+ second_fn = val;
+ } else if(!strcmp(arg, "--cmdline")) {
+ cmdline = val;
+ } else if(!strcmp(arg, "--base")) {
+ base = strtoul(val, 0, 16);
+ } else if(!strcmp(arg, "--kernel_offset")) {
+ kernel_offset = strtoul(val, 0, 16);
+ } else if(!strcmp(arg, "--ramdisk_offset")) {
+ ramdisk_offset = strtoul(val, 0, 16);
+ } else if(!strcmp(arg, "--second_offset")) {
+ second_offset = strtoul(val, 0, 16);
+ } else if(!strcmp(arg, "--tags_offset")) {
+ tags_offset = strtoul(val, 0, 16);
+ } else if(!strcmp(arg, "--board")) {
+ board = val;
+ } else if(!strcmp(arg,"--pagesize")) {
+ pagesize = strtoul(val, 0, 10);
+ if ((pagesize != 2048) && (pagesize != 4096)
+ && (pagesize != 8192) && (pagesize != 16384)) {
+ fprintf(stderr,"error: unsupported page size %d\n", pagesize);
+ return -1;
+ }
+ } else {
+ return usage();
}
} else {
return usage();
@@ -266,6 +282,10 @@
if(write_padding(fd, pagesize, hdr.second_size)) goto fail;
}
+ if (get_id) {
+ print_id((uint8_t *) hdr.id, sizeof(hdr.id));
+ }
+
return 0;
fail:
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 3ecb1db..7ab76b8 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -26,7 +26,7 @@
#
# create some directories (some are mount points)
LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
- sbin dev proc sys system data)
+ sbin dev proc sys system data oem)
include $(BUILD_SYSTEM)/base_rules.mk
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 3709b82..9fe1b4f 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -260,6 +260,7 @@
mkdir /data/misc/ethernet 0770 system system
mkdir /data/misc/dhcp 0770 dhcp dhcp
mkdir /data/misc/user 0771 root root
+ mkdir /data/misc/perfprofd 0775 root root
# give system access to wpa_supplicant.conf for backup and restore
chmod 0660 /data/misc/wifi/wpa_supplicant.conf
mkdir /data/local 0751 root root
@@ -643,3 +644,11 @@
class main
disabled
oneshot
+
+on property:ro.debuggable=1
+ start perfprofd
+
+service perfprofd /system/xbin/perfprofd
+ disabled
+ user root
+ oneshot