Merge "ANativeWindow: Add NATIVE_WINDOW_BUFFER_AGE query"
diff --git a/adb/Android.mk b/adb/Android.mk
index 3733ae3..9b6e147 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -5,7 +5,11 @@
LOCAL_PATH:= $(call my-dir)
-ADB_CLANG :=
+ifeq ($(HOST_OS),windows)
+ adb_host_clang := false # libc++ for mingw not ready yet.
+else
+ adb_host_clang := true
+endif
# libadb
# =========================================================
@@ -21,11 +25,17 @@
adb_auth.cpp \
adb_io.cpp \
adb_listeners.cpp \
+ adb_utils.cpp \
sockets.cpp \
transport.cpp \
transport_local.cpp \
transport_usb.cpp \
+LIBADB_TEST_SRCS := \
+ adb_io_test.cpp \
+ adb_utils_test.cpp \
+ transport_test.cpp \
+
LIBADB_CFLAGS := \
-Wall -Werror \
-Wno-unused-parameter \
@@ -34,8 +44,8 @@
LIBADB_darwin_SRC_FILES := \
fdevent.cpp \
- get_my_path_darwin.c \
- usb_osx.c \
+ get_my_path_darwin.cpp \
+ usb_osx.cpp \
LIBADB_linux_SRC_FILES := \
fdevent.cpp \
@@ -44,11 +54,11 @@
LIBADB_windows_SRC_FILES := \
get_my_path_windows.cpp \
- sysdeps_win32.c \
+ sysdeps_win32.cpp \
usb_windows.cpp \
include $(CLEAR_VARS)
-LOCAL_CLANG := $(ADB_CLANG)
+LOCAL_CLANG := true
LOCAL_MODULE := libadbd
LOCAL_CFLAGS := $(LIBADB_CFLAGS) -DADB_HOST=0
LOCAL_SRC_FILES := \
@@ -57,12 +67,14 @@
fdevent.cpp \
jdwp_service.cpp \
qemu_tracing.cpp \
- usb_linux_client.c \
+ usb_linux_client.cpp \
+
+LOCAL_SHARED_LIBRARIES := libbase
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
-LOCAL_CLANG := $(ADB_CLANG)
+LOCAL_CLANG := $(adb_host_clang)
LOCAL_MODULE := libadb
LOCAL_CFLAGS := $(LIBADB_CFLAGS) -DADB_HOST=1
LOCAL_SRC_FILES := \
@@ -70,6 +82,8 @@
$(LIBADB_$(HOST_OS)_SRC_FILES) \
adb_auth_host.cpp \
+LOCAL_SHARED_LIBRARIES := libbase
+
# Even though we're building a static library (and thus there's no link step for
# this to take effect), this adds the SSL includes to our path.
LOCAL_STATIC_LIBRARIES := libcrypto_static
@@ -80,12 +94,8 @@
include $(BUILD_HOST_STATIC_LIBRARY)
-LIBADB_TEST_SRCS := \
- adb_io_test.cpp \
- transport_test.cpp \
-
include $(CLEAR_VARS)
-LOCAL_CLANG := $(ADB_CLANG)
+LOCAL_CLANG := true
LOCAL_MODULE := adbd_test
LOCAL_CFLAGS := -DADB_HOST=0 $(LIBADB_CFLAGS)
LOCAL_SRC_FILES := $(LIBADB_TEST_SRCS)
@@ -94,7 +104,7 @@
include $(BUILD_NATIVE_TEST)
include $(CLEAR_VARS)
-LOCAL_CLANG := $(ADB_CLANG)
+LOCAL_CLANG := $(adb_host_clang)
LOCAL_MODULE := adb_test
LOCAL_CFLAGS := -DADB_HOST=1 $(LIBADB_CFLAGS)
LOCAL_SRC_FILES := $(LIBADB_TEST_SRCS) services.cpp
@@ -108,6 +118,10 @@
LOCAL_LDLIBS += -lrt -ldl -lpthread
endif
+ifeq ($(HOST_OS),darwin)
+ LOCAL_LDLIBS += -framework CoreFoundation -framework IOKit
+endif
+
include $(BUILD_HOST_NATIVE_TEST)
# adb host tool
@@ -125,15 +139,11 @@
endif
ifeq ($(HOST_OS),windows)
+ LOCAL_LDLIBS += -lws2_32 -lgdi32
EXTRA_STATIC_LIBS := AdbWinApi
- ifneq ($(strip $(USE_MINGW)),)
- # MinGW under Linux case
- LOCAL_LDLIBS += -lws2_32 -lgdi32
- USE_SYSDEPS_WIN32 := 1
- endif
endif
-LOCAL_CLANG := $(ADB_CLANG)
+LOCAL_CLANG := $(adb_host_clang)
LOCAL_SRC_FILES := \
adb_main.cpp \
@@ -154,13 +164,22 @@
LOCAL_STATIC_LIBRARIES := \
libadb \
+ libbase \
libcrypto_static \
+ libcutils \
+ liblog \
$(EXTRA_STATIC_LIBS) \
-ifeq ($(USE_SYSDEPS_WIN32),)
- LOCAL_STATIC_LIBRARIES += libcutils
+# libc++ not available on windows yet
+ifneq ($(HOST_OS),windows)
+ LOCAL_CXX_STL := libc++_static
endif
+# Don't add anything here, we don't want additional shared dependencies
+# on the host adb tool, and shared libraries that link against libc++
+# will violate ODR
+LOCAL_SHARED_LIBRARIES :=
+
include $(BUILD_HOST_EXECUTABLE)
$(call dist-for-goals,dist_files sdk,$(LOCAL_BUILT_MODULE))
@@ -177,7 +196,7 @@
include $(CLEAR_VARS)
-LOCAL_CLANG := $(ADB_CLANG)
+LOCAL_CLANG := true
LOCAL_SRC_FILES := \
adb_main.cpp \
diff --git a/adb/adb.cpp b/adb/adb.cpp
index ad85184f..4c90dcc 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -32,6 +32,9 @@
#include <string>
+#include <base/stringprintf.h>
+#include <base/strings.h>
+
#include "adb_auth.h"
#include "adb_io.h"
#include "adb_listeners.h"
@@ -379,84 +382,60 @@
}
#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.
- */
-static void qual_overwrite(char **dst, const char *src)
-{
- if (!dst)
- return;
-
+// 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.
+// TODO: switch to std::string for these atransport fields instead.
+static void qual_overwrite(char** dst, const std::string& src) {
free(*dst);
- *dst = NULL;
-
- if (!src || !*src)
- return;
-
- *dst = strdup(src);
+ *dst = strdup(src.c_str());
}
-void parse_banner(char *banner, atransport *t)
-{
- static const char *prop_seps = ";";
- static const char key_val_sep = '=';
- char *cp;
- char *type;
-
+void parse_banner(const char* banner, atransport* t) {
D("parse_banner: %s\n", banner);
- type = banner;
- cp = strchr(type, ':');
- if (cp) {
- *cp++ = 0;
- /* Nothing is done with second field. */
- cp = strchr(cp, ':');
- if (cp) {
- char *save;
- char *key;
- key = adb_strtok_r(cp + 1, prop_seps, &save);
- while (key) {
- cp = strchr(key, key_val_sep);
- if (cp) {
- *cp++ = '\0';
- if (!strcmp(key, "ro.product.name"))
- qual_overwrite(&t->product, cp);
- else if (!strcmp(key, "ro.product.model"))
- qual_overwrite(&t->model, cp);
- else if (!strcmp(key, "ro.product.device"))
- qual_overwrite(&t->device, cp);
- }
- key = adb_strtok_r(NULL, prop_seps, &save);
+
+ // The format is something like:
+ // "device::ro.product.name=x;ro.product.model=y;ro.product.device=z;".
+ std::vector<std::string> pieces = android::base::Split(banner, ":");
+
+ if (pieces.size() > 2) {
+ const std::string& props = pieces[2];
+ for (auto& prop : android::base::Split(props, ";")) {
+ // The list of properties was traditionally ;-terminated rather than ;-separated.
+ if (prop.empty()) continue;
+
+ std::vector<std::string> key_value = android::base::Split(prop, "=");
+ if (key_value.size() != 2) continue;
+
+ const std::string& key = key_value[0];
+ const std::string& value = key_value[1];
+ if (key == "ro.product.name") {
+ qual_overwrite(&t->product, value);
+ } else if (key == "ro.product.model") {
+ qual_overwrite(&t->model, value);
+ } else if (key == "ro.product.device") {
+ qual_overwrite(&t->device, value);
}
}
}
- if(!strcmp(type, "bootloader")){
+ const std::string& type = pieces[0];
+ if (type == "bootloader") {
D("setting connection_state to CS_BOOTLOADER\n");
t->connection_state = CS_BOOTLOADER;
update_transports();
- return;
- }
-
- if(!strcmp(type, "device")) {
+ } else if (type == "device") {
D("setting connection_state to CS_DEVICE\n");
t->connection_state = CS_DEVICE;
update_transports();
- return;
- }
-
- if(!strcmp(type, "recovery")) {
+ } else if (type == "recovery") {
D("setting connection_state to CS_RECOVERY\n");
t->connection_state = CS_RECOVERY;
update_transports();
- return;
- }
-
- if(!strcmp(type, "sideload")) {
+ } else if (type == "sideload") {
D("setting connection_state to CS_SIDELOAD\n");
t->connection_state = CS_SIDELOAD;
update_transports();
- return;
}
t->connection_state = CS_HOST;
@@ -491,7 +470,7 @@
handle_offline(t);
}
- parse_banner((char*) p->data, t);
+ parse_banner(reinterpret_cast<const char*>(p->data), t);
if (HOST || !auth_enabled) {
handle_online(t);
@@ -802,7 +781,6 @@
if (!strncmp(service, "forward:",8) ||
!strncmp(service, "killforward:",12)) {
char *local, *remote;
- int r;
atransport *transport;
int createForward = strncmp(service, "kill", 4);
@@ -838,19 +816,20 @@
}
}
- const char* err;
- transport = acquire_one_transport(CS_ANY, ttype, serial, &err);
+ std::string error_msg;
+ transport = acquire_one_transport(CS_ANY, ttype, serial, &error_msg);
if (!transport) {
- sendfailmsg(reply_fd, err);
+ sendfailmsg(reply_fd, error_msg.c_str());
return 1;
}
+ install_status_t r;
if (createForward) {
r = install_listener(local, remote, transport, no_rebind);
} else {
r = remove_listener(local, transport);
}
- if(r == 0) {
+ if (r == INSTALL_STATUS_OK) {
#if ADB_HOST
/* On the host: 1st OKAY is connect, 2nd OKAY is status */
WriteFdExactly(reply_fd, "OKAY", 4);
@@ -859,22 +838,19 @@
return 1;
}
- if (createForward) {
- const char* message;
- switch (r) {
- case INSTALL_STATUS_CANNOT_BIND:
- message = "cannot bind to socket";
- break;
- case INSTALL_STATUS_CANNOT_REBIND:
- message = "cannot rebind existing socket";
- break;
- default:
- message = "internal error";
- }
- sendfailmsg(reply_fd, message);
- } else {
- sendfailmsg(reply_fd, "cannot remove listener");
+ std::string message;
+ switch (r) {
+ case INSTALL_STATUS_OK: message = " "; break;
+ case INSTALL_STATUS_INTERNAL_ERROR: message = "internal error"; break;
+ case INSTALL_STATUS_CANNOT_BIND:
+ message = android::base::StringPrintf("cannot bind to socket: %s", strerror(errno));
+ break;
+ case INSTALL_STATUS_CANNOT_REBIND:
+ message = android::base::StringPrintf("cannot rebind existing socket: %s", strerror(errno));
+ break;
+ case INSTALL_STATUS_LISTENER_NOT_FOUND: message = "listener not found"; break;
}
+ sendfailmsg(reply_fd, message.c_str());
return 1;
}
return 0;
@@ -910,14 +886,14 @@
serial = service;
}
- const char* error_string = "unknown failure";
- transport = acquire_one_transport(CS_ANY, type, serial, &error_string);
+ std::string error_msg = "unknown failure";
+ transport = acquire_one_transport(CS_ANY, type, serial, &error_msg);
if (transport) {
s->transport = transport;
adb_write(reply_fd, "OKAY", 4);
} else {
- sendfailmsg(reply_fd, error_string);
+ sendfailmsg(reply_fd, error_msg.c_str());
}
return 1;
}
@@ -975,7 +951,7 @@
if(!strncmp(service,"get-serialno",strlen("get-serialno"))) {
const char *out = "unknown";
transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
- if (transport && transport->serial) {
+ if (transport && transport->serial) {
out = transport->serial;
}
send_msg_with_okay(reply_fd, out, strlen(out));
@@ -984,7 +960,7 @@
if(!strncmp(service,"get-devpath",strlen("get-devpath"))) {
const char *out = "unknown";
transport = acquire_one_transport(CS_ANY, ttype, serial, NULL);
- if (transport && transport->devpath) {
+ if (transport && transport->devpath) {
out = transport->devpath;
}
send_msg_with_okay(reply_fd, out, strlen(out));
diff --git a/adb/adb.h b/adb/adb.h
index 749515c..cb2cf60 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -23,10 +23,6 @@
#include "adb_trace.h"
#include "fdevent.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#define MAX_PAYLOAD 4096
#define A_SYNC 0x434e5953
@@ -47,14 +43,8 @@
// Increment this when we want to force users to start a new adb server.
#define ADB_SERVER_VERSION 32
-typedef struct amessage amessage;
-typedef struct apacket apacket;
-typedef struct asocket asocket;
-typedef struct alistener alistener;
-typedef struct aservice aservice;
-typedef struct atransport atransport;
-typedef struct adisconnect adisconnect;
-typedef struct usb_handle usb_handle;
+struct atransport;
+struct usb_handle;
struct amessage {
unsigned command; /* command identifier constant */
@@ -171,12 +161,12 @@
** object, it's a special value used to indicate that a client wants to
** connect to a service implemented within the ADB server itself.
*/
-typedef enum transport_type {
+enum transport_type {
kTransportUsb,
kTransportLocal,
kTransportAny,
kTransportHost,
-} transport_type;
+};
#define TOKEN_SIZE 20
@@ -363,10 +353,10 @@
extern int HOST;
extern int SHELL_EXIT_NOTIFY_FD;
-typedef enum {
+enum subproc_mode {
SUBPROC_PTY = 0,
SUBPROC_RAW = 1,
-} subproc_mode;
+} ;
#define CHUNK_SIZE (64*1024)
@@ -389,8 +379,4 @@
void send_connect(atransport *t);
-#ifdef __cplusplus
-}
-#endif
-
#endif
diff --git a/adb/adb_auth.h b/adb/adb_auth.h
index 635556e..1e1978d 100644
--- a/adb/adb_auth.h
+++ b/adb/adb_auth.h
@@ -19,10 +19,6 @@
#include "adb.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
extern int auth_enabled;
int adb_auth_keygen(const char* filename);
@@ -68,8 +64,4 @@
#endif // ADB_HOST
-#ifdef __cplusplus
-}
-#endif
-
#endif // __ADB_AUTH_H
diff --git a/adb/adb_auth_host.cpp b/adb/adb_auth_host.cpp
index 7c2bcfb..510dcc2 100644
--- a/adb/adb_auth_host.cpp
+++ b/adb/adb_auth_host.cpp
@@ -43,6 +43,7 @@
#include "mincrypt/rsa.h"
#undef RSA_verify
+#include <base/strings.h>
#include <cutils/list.h>
#include <openssl/evp.h>
@@ -172,7 +173,7 @@
return 0;
}
- outfile = fopen(path, "w");
+ outfile = fopen(path, "we");
if (!outfile) {
D("Failed to open '%s'\n", path);
return 0;
@@ -191,7 +192,7 @@
encoded_length = 1 + ((sizeof(pkey) + 2) / 3 * 4);
#endif
- encoded = reinterpret_cast<uint8_t*>(malloc(encoded_length));
+ encoded = new uint8_t[encoded_length];
if (encoded == nullptr) {
D("Allocation failure");
goto out;
@@ -212,9 +213,7 @@
if (outfile != NULL) {
fclose(outfile);
}
- if (encoded != NULL) {
- free(encoded);
- }
+ delete[] encoded;
return ret;
}
@@ -240,7 +239,7 @@
old_mask = umask(077);
- f = fopen(file, "w");
+ f = fopen(file, "we");
if (!f) {
D("Failed to open '%s'\n", file);
umask(old_mask);
@@ -274,30 +273,24 @@
{
D("read_key '%s'\n", file);
- FILE* f = fopen(file, "r");
- if (!f) {
- D("Failed to open '%s'\n", file);
+ FILE* fp = fopen(file, "re");
+ if (!fp) {
+ D("Failed to open '%s': %s\n", file, strerror(errno));
return 0;
}
- adb_private_key* key = reinterpret_cast<adb_private_key*>(
- malloc(sizeof(adb_private_key)));
- if (!key) {
- D("Failed to alloc key\n");
- fclose(f);
- return 0;
- }
+ adb_private_key* key = new adb_private_key;
key->rsa = RSA_new();
- if (!PEM_read_RSAPrivateKey(f, &key->rsa, NULL, NULL)) {
+ if (!PEM_read_RSAPrivateKey(fp, &key->rsa, NULL, NULL)) {
D("Failed to read key\n");
- fclose(f);
+ fclose(fp);
RSA_free(key->rsa);
- free(key);
+ delete key;
return 0;
}
- fclose(f);
+ fclose(fp);
list_add_tail(list, &key->node);
return 1;
}
@@ -362,29 +355,16 @@
return read_key(path, list);
}
-static void get_vendor_keys(struct listnode *list)
-{
- const char *adb_keys_path;
- char keys_path[MAX_PAYLOAD];
- char *path;
- char *save;
- struct stat buf;
-
- adb_keys_path = getenv("ADB_VENDOR_KEYS");
- if (!adb_keys_path)
+static void get_vendor_keys(struct listnode* key_list) {
+ const char* adb_keys_path = getenv("ADB_VENDOR_KEYS");
+ if (adb_keys_path == nullptr) {
return;
- strncpy(keys_path, adb_keys_path, sizeof(keys_path));
+ }
- path = adb_strtok_r(keys_path, ENV_PATH_SEPARATOR_STR, &save);
- while (path) {
- D("Reading: '%s'\n", path);
-
- if (stat(path, &buf))
- D("Can't read '%s'\n", path);
- else if (!read_key(path, list))
- D("Failed to read '%s'\n", path);
-
- path = adb_strtok_r(NULL, ENV_PATH_SEPARATOR_STR, &save);
+ for (auto& path : android::base::Split(adb_keys_path, ENV_PATH_SEPARATOR_STR)) {
+ if (!read_key(path.c_str(), key_list)) {
+ D("Failed to read '%s'\n", path.c_str());
+ }
}
}
diff --git a/adb/adb_client.cpp b/adb/adb_client.cpp
index 4751bff..0f64998 100644
--- a/adb/adb_client.cpp
+++ b/adb/adb_client.cpp
@@ -28,6 +28,8 @@
#include <sys/stat.h>
#include <sys/types.h>
+#include <string>
+
#include "adb_io.h"
static transport_type __adb_transport = kTransportAny;
@@ -108,44 +110,40 @@
static int switch_socket_transport(int fd)
{
- char service[64];
- char tmp[5];
- int len;
-
- if (__adb_serial)
- snprintf(service, sizeof service, "host:transport:%s", __adb_serial);
- else {
+ std::string service;
+ if (__adb_serial) {
+ service += "host:transport:";
+ service += __adb_serial;
+ } else {
const char* transport_type = "???";
-
- switch (__adb_transport) {
- case kTransportUsb:
- transport_type = "transport-usb";
- break;
- case kTransportLocal:
- transport_type = "transport-local";
- break;
- case kTransportAny:
- transport_type = "transport-any";
- break;
- case kTransportHost:
- // no switch necessary
- return 0;
- break;
+ switch (__adb_transport) {
+ case kTransportUsb:
+ transport_type = "transport-usb";
+ break;
+ case kTransportLocal:
+ transport_type = "transport-local";
+ break;
+ case kTransportAny:
+ transport_type = "transport-any";
+ break;
+ case kTransportHost:
+ // no switch necessary
+ return 0;
}
-
- snprintf(service, sizeof service, "host:%s", transport_type);
+ service += "host:";
+ service += transport_type;
}
- len = strlen(service);
- snprintf(tmp, sizeof tmp, "%04x", len);
- if(!WriteFdExactly(fd, tmp, 4) || !WriteFdExactly(fd, service, len)) {
+ char tmp[5];
+ snprintf(tmp, sizeof(tmp), "%04zx", service.size());
+ if (!WriteFdExactly(fd, tmp, 4) || !WriteFdExactly(fd, service.c_str(), service.size())) {
strcpy(__adb_error, "write failure during connection");
adb_close(fd);
return -1;
}
D("Switch transport in progress\n");
- if(adb_status(fd)) {
+ if (adb_status(fd)) {
adb_close(fd);
D("Switch transport failed\n");
return -1;
diff --git a/adb/adb_client.h b/adb/adb_client.h
index 9af176f..934362a 100644
--- a/adb/adb_client.h
+++ b/adb/adb_client.h
@@ -3,10 +3,6 @@
#include "adb.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/* 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
@@ -58,8 +54,4 @@
*/
int adb_status(int fd);
-#ifdef __cplusplus
-}
-#endif
-
#endif
diff --git a/adb/adb_io.h b/adb/adb_io.h
index 7d09e7b..8d237ce 100644
--- a/adb/adb_io.h
+++ b/adb/adb_io.h
@@ -20,10 +20,6 @@
#include <stdbool.h>
#include <sys/types.h>
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/*
* Reads exactly len bytes from fd into buf.
*
@@ -46,8 +42,4 @@
/* Same as WriteFdExactly, but with an implicit len = strlen(buf). */
bool WriteStringFully(int fd, const char* str);
-#ifdef __cplusplus
-}
-#endif
-
#endif /* ADB_IO_H */
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
index 84b9c64..a1a5ddb 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -190,17 +190,17 @@
return result;
}
-int remove_listener(const char *local_name, atransport* transport)
+install_status_t remove_listener(const char *local_name, atransport* transport)
{
alistener *l;
for (l = listener_list.next; l != &listener_list; l = l->next) {
if (!strcmp(local_name, l->local_name)) {
listener_disconnect(l, l->transport);
- return 0;
+ return INSTALL_STATUS_OK;
}
}
- return -1;
+ return INSTALL_STATUS_LISTENER_NOT_FOUND;
}
void remove_all_listeners(void)
@@ -268,10 +268,10 @@
listener->fd = local_name_to_fd(local_name);
if (listener->fd < 0) {
+ printf("cannot bind '%s': %s\n", local_name, strerror(errno));
free(listener->local_name);
free(listener->connect_to);
free(listener);
- printf("cannot bind '%s'\n", local_name);
return INSTALL_STATUS_CANNOT_BIND;
}
diff --git a/adb/adb_listeners.h b/adb/adb_listeners.h
index 14fdcd6..f55fdee 100644
--- a/adb/adb_listeners.h
+++ b/adb/adb_listeners.h
@@ -19,17 +19,14 @@
#include "adb.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
// error/status codes for install_listener.
-typedef enum {
+enum install_status_t {
INSTALL_STATUS_OK = 0,
INSTALL_STATUS_INTERNAL_ERROR = -1,
INSTALL_STATUS_CANNOT_BIND = -2,
INSTALL_STATUS_CANNOT_REBIND = -3,
-} install_status_t;
+ INSTALL_STATUS_LISTENER_NOT_FOUND = -4,
+};
extern alistener listener_list;
@@ -44,11 +41,7 @@
int format_listeners(char* buf, size_t buflen);
-int remove_listener(const char *local_name, atransport* transport);
+install_status_t remove_listener(const char* local_name, atransport* transport);
void remove_all_listeners(void);
-#ifdef __cplusplus
-}
-#endif
-
#endif /* __ADB_LISTENERS_H */
diff --git a/adb/adb_main.cpp b/adb/adb_main.cpp
index fb17e89..5acaf80 100644
--- a/adb/adb_main.cpp
+++ b/adb/adb_main.cpp
@@ -383,7 +383,7 @@
/* If adbd runs inside the emulator this will enable adb tracing via
* adb-debug qemud service in the emulator. */
adb_qemu_trace_init();
- while (1) {
+ while (true) {
int c;
int option_index = 0;
static struct option opts[] = {
diff --git a/adb/adb_trace.h b/adb/adb_trace.h
index ef5dc24..32b6ae4 100644
--- a/adb/adb_trace.h
+++ b/adb/adb_trace.h
@@ -23,10 +23,6 @@
#include <stdio.h>
#endif
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/* define ADB_TRACE to 1 to enable tracing support, or 0 to disable it */
#define ADB_TRACE 1
@@ -34,7 +30,7 @@
* forget to update the corresponding 'tags' table in
* the adb_trace_init() function implemented in adb.c
*/
-typedef enum {
+enum AdbTrace {
TRACE_ADB = 0, /* 0x001 */
TRACE_SOCKETS,
TRACE_PACKETS,
@@ -47,7 +43,7 @@
TRACE_SERVICES,
TRACE_AUTH,
TRACE_FDEVENT,
-} AdbTrace;
+} ;
#if ADB_TRACE
@@ -148,8 +144,4 @@
# define ADB_TRACING 0
#endif /* ADB_TRACE */
-#ifdef __cplusplus
-}
-#endif
-
#endif /* __ADB_TRACE_H */
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
new file mode 100644
index 0000000..f10c143
--- /dev/null
+++ b/adb/adb_utils.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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 "adb_utils.h"
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "sysdeps.h"
+
+bool getcwd(std::string* s) {
+ char* cwd = getcwd(nullptr, 0);
+ if (cwd != nullptr) *s = cwd;
+ free(cwd);
+ return (cwd != nullptr);
+}
+
+bool directory_exists(const std::string& path) {
+ struct stat sb;
+ return lstat(path.c_str(), &sb) != -1 && S_ISDIR(sb.st_mode);
+}
+
+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;
+ }
+ }
+
+ // Prefix and suffix the whole string with '.
+ result.insert(result.begin(), '\'');
+ result.push_back('\'');
+ return result;
+}
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
new file mode 100644
index 0000000..4b64afa
--- /dev/null
+++ b/adb/adb_utils.h
@@ -0,0 +1,27 @@
+/*
+ * 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_UTILS_H_
+#define _ADB_UTILS_H_
+
+#include <string>
+
+bool getcwd(std::string* cwd);
+bool directory_exists(const std::string& path);
+
+std::string escape_arg(const std::string& s);
+
+#endif
diff --git a/adb/adb_utils_test.cpp b/adb/adb_utils_test.cpp
new file mode 100644
index 0000000..a395079
--- /dev/null
+++ b/adb/adb_utils_test.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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 "adb_utils.h"
+
+#include <gtest/gtest.h>
+
+TEST(adb_utils, directory_exists) {
+ ASSERT_TRUE(directory_exists("/proc"));
+ ASSERT_FALSE(directory_exists("/proc/self")); // Symbolic link.
+ ASSERT_FALSE(directory_exists("/proc/does-not-exist"));
+}
+
+TEST(adb_utils, escape_arg) {
+ ASSERT_EQ(R"('')", escape_arg(""));
+
+ 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 ')", 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/commandline.cpp b/adb/commandline.cpp
index 34efefe..e59a96a 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -21,6 +21,7 @@
#include <assert.h>
#include <ctype.h>
#include <errno.h>
+#include <inttypes.h>
#include <limits.h>
#include <stdarg.h>
#include <stdint.h>
@@ -30,6 +31,10 @@
#include <sys/stat.h>
#include <sys/types.h>
+#include <string>
+
+#include <base/stringprintf.h>
+
#if !defined(_WIN32)
#include <termios.h>
#include <unistd.h>
@@ -39,49 +44,38 @@
#include "adb_auth.h"
#include "adb_client.h"
#include "adb_io.h"
+#include "adb_utils.h"
#include "file_sync_service.h"
static int do_cmd(transport_type ttype, const char* serial, const char *cmd, ...);
-int find_sync_dirs(const char *srcarg,
- char **system_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out,
- char **oem_srcdir_out);
-int install_app(transport_type transport, const char* serial, int argc,
- const char** argv);
-int install_multiple_app(transport_type transport, const char* serial, int argc,
+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);
-int uninstall_app(transport_type transport, const char* serial, int argc,
- const char** argv);
-static const char *gProductOutPath = NULL;
+static std::string gProductOutPath;
extern int gListenAll;
-static char *product_file(const char *extra)
-{
- if (gProductOutPath == NULL) {
+static std::string product_file(const char *extra) {
+ if (gProductOutPath.empty()) {
fprintf(stderr, "adb: Product directory not specified; "
"use -p or define ANDROID_PRODUCT_OUT\n");
exit(1);
}
- int n = strlen(gProductOutPath) + strlen(extra) + 2;
- char* x = reinterpret_cast<char*>(malloc(n));
- if (x == 0) {
- fprintf(stderr, "adb: Out of memory (product_file())\n");
- exit(1);
- }
-
- snprintf(x, (size_t)n, "%s" OS_PATH_SEPARATOR_STR "%s", gProductOutPath, extra);
- return x;
+ return android::base::StringPrintf("%s%s%s",
+ gProductOutPath.c_str(), OS_PATH_SEPARATOR_STR, extra);
}
-void version(FILE * out) {
+static void version(FILE* out) {
fprintf(out, "Android Debug Bridge version %d.%d.%d\n",
- ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION);
+ ADB_VERSION_MAJOR, ADB_VERSION_MINOR, ADB_SERVER_VERSION);
}
-void help()
-{
+static void help() {
version(stderr);
fprintf(stderr,
@@ -241,19 +235,16 @@
);
}
-int usage()
-{
+static int usage() {
help();
return 1;
}
#if defined(_WIN32)
-// Implemented in sysdeps_win32.c.
-extern "C" {
+// Implemented in sysdeps_win32.cpp.
void stdin_raw_init(int fd);
void stdin_raw_restore(int fd);
-}
#else
static termios g_saved_terminal_state;
@@ -321,6 +312,7 @@
static void copy_to_file(int inFd, int outFd) {
const size_t BUFSIZE = 32 * 1024;
char* buf = (char*) malloc(BUFSIZE);
+ if (buf == nullptr) fatal("couldn't allocate buffer for copy_to_file");
int len;
long total = 0;
@@ -330,7 +322,7 @@
stdin_raw_init(STDIN_FILENO);
}
- for (;;) {
+ while (true) {
if (inFd == STDIN_FILENO) {
len = unix_read(inFd, buf, BUFSIZE);
} else {
@@ -416,8 +408,7 @@
return 0;
}
-int interactive_shell(void)
-{
+static int interactive_shell() {
adb_thread_t thr;
int fdi, fd;
@@ -429,6 +420,11 @@
fdi = 0; //dup(0);
int* fds = reinterpret_cast<int*>(malloc(sizeof(int) * 2));
+ if (fds == nullptr) {
+ fprintf(stderr, "couldn't allocate fds array: %s\n", strerror(errno));
+ return 1;
+ }
+
fds[0] = fd;
fds[1] = fdi;
@@ -455,8 +451,8 @@
}
}
-int adb_download_buffer(const char *service, const char *fn, const void* data, int sz,
- unsigned progress)
+static int adb_download_buffer(const char *service, const char *fn, const void* data, int sz,
+ unsigned progress)
{
char buf[4096];
unsigned total;
@@ -514,23 +510,6 @@
return 0;
}
-
-int adb_download(const char *service, const char *fn, unsigned progress)
-{
- void *data;
- unsigned sz;
-
- data = load_file(fn, &sz);
- if(data == 0) {
- fprintf(stderr,"* cannot read '%s' *\n", fn);
- return -1;
- }
-
- int status = adb_download_buffer(service, fn, data, sz, progress);
- free(data);
- return status;
-}
-
#define SIDELOAD_HOST_BLOCK_SIZE (CHUNK_SIZE)
/*
@@ -552,7 +531,7 @@
* - When the other side sends "DONEDONE" instead of a block number,
* we hang up.
*/
-int adb_sideload_host(const char* fn) {
+static int adb_sideload_host(const char* fn) {
unsigned sz;
size_t xfer = 0;
int status;
@@ -581,7 +560,7 @@
opt = adb_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const void *) &opt, sizeof(opt));
- for (;;) {
+ while (true) {
if (!ReadFdExactly(fd, buf, 8)) {
fprintf(stderr, "* failed to read command: %s\n", adb_error());
status = -1;
@@ -683,50 +662,6 @@
}
}
-static int should_escape(const char c)
-{
- return (c == ' ' || c == '\'' || c == '"' || c == '\\' || c == '(' || c == ')');
-}
-
-/* Duplicate and escape given argument. */
-static char *escape_arg(const char *s)
-{
- const char *ts;
- size_t alloc_len;
- char *ret;
- char *dest;
-
- alloc_len = 0;
- for (ts = s; *ts != '\0'; ts++) {
- alloc_len++;
- if (should_escape(*ts)) {
- alloc_len++;
- }
- }
-
- if (alloc_len == 0) {
- // Preserve empty arguments
- ret = (char *) malloc(3);
- ret[0] = '\"';
- ret[1] = '\"';
- ret[2] = '\0';
- return ret;
- }
-
- ret = (char *) malloc(alloc_len + 1);
- dest = ret;
-
- for (ts = s; *ts != '\0'; ts++) {
- if (should_escape(*ts)) {
- *dest++ = '\\';
- }
- *dest++ = *ts;
- }
- *dest++ = '\0';
-
- return ret;
-}
-
/**
* Run ppp in "notty" mode against a resource listed as the first parameter
* eg:
@@ -734,8 +669,7 @@
* ppp dev:/dev/omap_csmi_tty0 <ppp options>
*
*/
-int ppp(int argc, const char **argv)
-{
+static int ppp(int argc, const char** argv) {
#if defined(_WIN32)
fprintf(stderr, "error: adb %s not implemented on Win32\n", argv[0]);
return -1;
@@ -800,14 +734,12 @@
#endif /* !defined(_WIN32) */
}
-static int send_shellcommand(transport_type transport, const char* serial,
- char* buf)
-{
- int fd, ret;
-
- for(;;) {
- fd = adb_connect(buf);
- if(fd >= 0)
+static int send_shell_command(transport_type transport, const char* serial,
+ const std::string& command) {
+ int fd;
+ while (true) {
+ fd = adb_connect(command.c_str());
+ if (fd >= 0)
break;
fprintf(stderr,"- waiting for device -\n");
adb_sleep_ms(1000);
@@ -815,42 +747,30 @@
}
read_and_dump(fd);
- ret = adb_close(fd);
- if (ret)
+ int rc = adb_close(fd);
+ if (rc) {
perror("close");
-
- return ret;
+ }
+ return rc;
}
-static int logcat(transport_type transport, const char* serial, int argc,
- const char** argv)
-{
- char buf[4096];
+static int logcat(transport_type 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);
- char *log_tags;
- char *quoted;
-
- log_tags = getenv("ANDROID_LOG_TAGS");
- quoted = escape_arg(log_tags == NULL ? "" : log_tags);
- snprintf(buf, sizeof(buf),
- "shell:export ANDROID_LOG_TAGS=\"%s\"; exec logcat", quoted);
- free(quoted);
+ std::string cmd = "shell:export ANDROID_LOG_TAGS=\"" + quoted + "\"; exec logcat";
if (!strcmp(argv[0], "longcat")) {
- strncat(buf, " -v long", sizeof(buf) - 1);
+ cmd += " -v long";
}
- argc -= 1;
- argv += 1;
- while(argc-- > 0) {
- quoted = escape_arg(*argv++);
- strncat(buf, " ", sizeof(buf) - 1);
- strncat(buf, quoted, sizeof(buf) - 1);
- free(quoted);
+ --argc;
+ ++argv;
+ while (argc-- > 0) {
+ cmd += " " + escape_arg(*argv++);
}
- send_shellcommand(transport, serial, buf);
- return 0;
+ return send_shell_command(transport, serial, cmd);
}
static int mkdirs(const char *path)
@@ -873,21 +793,17 @@
}
static int backup(int argc, const char** argv) {
- char buf[4096];
- char default_name[32];
- const char* filename = strcpy(default_name, "./backup.ab");
- int fd, outFd;
- int i, j;
+ const char* filename = "./backup.ab";
/* find, extract, and use any -f argument */
- for (i = 1; i < argc; i++) {
+ for (int i = 1; i < argc; i++) {
if (!strcmp("-f", argv[i])) {
if (i == argc-1) {
fprintf(stderr, "adb: -f passed with no filename\n");
return usage();
}
filename = argv[i+1];
- for (j = i+2; j <= argc; ) {
+ for (int j = i+2; j <= argc; ) {
argv[i++] = argv[j++];
}
argc -= 2;
@@ -900,20 +816,21 @@
adb_unlink(filename);
mkdirs(filename);
- outFd = adb_creat(filename, 0640);
+ int outFd = adb_creat(filename, 0640);
if (outFd < 0) {
fprintf(stderr, "adb: unable to open file %s\n", filename);
return -1;
}
- snprintf(buf, sizeof(buf), "backup");
- for (argc--, argv++; argc; argc--, argv++) {
- strncat(buf, ":", sizeof(buf) - strlen(buf) - 1);
- strncat(buf, argv[0], sizeof(buf) - strlen(buf) - 1);
+ std::string cmd = "backup:";
+ --argc;
+ ++argv;
+ while (argc-- > 0) {
+ cmd += " " + escape_arg(*argv++);
}
- D("backup. filename=%s buf=%s\n", filename, buf);
- fd = adb_connect(buf);
+ D("backup. filename=%s cmd=%s\n", filename, cmd.c_str());
+ int fd = adb_connect(cmd.c_str());
if (fd < 0) {
fprintf(stderr, "adb: unable to connect for backup\n");
adb_close(outFd);
@@ -956,81 +873,9 @@
return 0;
}
-#define SENTINEL_FILE "config" OS_PATH_SEPARATOR_STR "envsetup.make"
-static int top_works(const char *top)
-{
- if (top != NULL && adb_is_absolute_host_path(top)) {
- char path_buf[PATH_MAX];
- snprintf(path_buf, sizeof(path_buf),
- "%s" OS_PATH_SEPARATOR_STR SENTINEL_FILE, top);
- return access(path_buf, F_OK) == 0;
- }
- return 0;
-}
-
-static char *find_top_from(const char *indir, char path_buf[PATH_MAX])
-{
- strcpy(path_buf, indir);
- while (1) {
- if (top_works(path_buf)) {
- return path_buf;
- }
- char *s = adb_dirstop(path_buf);
- if (s != NULL) {
- *s = '\0';
- } else {
- path_buf[0] = '\0';
- return NULL;
- }
- }
-}
-
-static char *find_top(char path_buf[PATH_MAX])
-{
- char *top = getenv("ANDROID_BUILD_TOP");
- if (top != NULL && top[0] != '\0') {
- if (!top_works(top)) {
- fprintf(stderr, "adb: bad ANDROID_BUILD_TOP value \"%s\"\n", top);
- return NULL;
- }
- } else {
- top = getenv("TOP");
- if (top != NULL && top[0] != '\0') {
- if (!top_works(top)) {
- fprintf(stderr, "adb: bad TOP value \"%s\"\n", top);
- return NULL;
- }
- } else {
- top = NULL;
- }
- }
-
- if (top != NULL) {
- /* The environment pointed to a top directory that works.
- */
- strcpy(path_buf, top);
- return path_buf;
- }
-
- /* The environment didn't help. Walk up the tree from the CWD
- * to see if we can find the top.
- */
- char dir[PATH_MAX];
- top = find_top_from(getcwd(dir, sizeof(dir)), path_buf);
- if (top == NULL) {
- /* If the CWD isn't under a good-looking top, see if the
- * executable is.
- */
- get_my_path(dir, PATH_MAX);
- top = find_top_from(dir, path_buf);
- }
- return top;
-}
-
/* <hint> may be:
* - A simple product name
* e.g., "sooner"
-TODO: debug? sooner-debug, sooner:debug?
* - A relative path from the CWD to the ANDROID_PRODUCT_OUT dir
* e.g., "out/target/product/sooner"
* - An absolute path to the PRODUCT_OUT dir
@@ -1039,62 +884,52 @@
* Given <hint>, try to construct an absolute path to the
* ANDROID_PRODUCT_OUT dir.
*/
-static const char *find_product_out_path(const char *hint)
-{
- static char path_buf[PATH_MAX];
-
+static std::string find_product_out_path(const char* hint) {
if (hint == NULL || hint[0] == '\0') {
- return NULL;
+ return "";
}
- /* If it's already absolute, don't bother doing any work.
- */
+ // If it's already absolute, don't bother doing any work.
if (adb_is_absolute_host_path(hint)) {
- strcpy(path_buf, hint);
- return path_buf;
+ return hint;
}
- /* If there are any slashes in it, assume it's a relative path;
- * make it absolute.
- */
- if (adb_dirstart(hint) != NULL) {
- if (getcwd(path_buf, sizeof(path_buf)) == NULL) {
- fprintf(stderr, "adb: Couldn't get CWD: %s\n", strerror(errno));
- return NULL;
+ // If there are any slashes in it, assume it's a relative path;
+ // make it absolute.
+ if (adb_dirstart(hint) != nullptr) {
+ std::string cwd;
+ if (!getcwd(&cwd)) {
+ fprintf(stderr, "adb: getcwd failed: %s\n", strerror(errno));
+ return "";
}
- if (strlen(path_buf) + 1 + strlen(hint) >= sizeof(path_buf)) {
- fprintf(stderr, "adb: Couldn't assemble path\n");
- return NULL;
- }
- strcat(path_buf, OS_PATH_SEPARATOR_STR);
- strcat(path_buf, hint);
- return path_buf;
+ return android::base::StringPrintf("%s%s%s", cwd.c_str(), OS_PATH_SEPARATOR_STR, hint);
}
- /* It's a string without any slashes. Try to do something with it.
- *
- * Try to find the root of the build tree, and build a PRODUCT_OUT
- * path from there.
- */
- char top_buf[PATH_MAX];
- const char *top = find_top(top_buf);
- if (top == NULL) {
- fprintf(stderr, "adb: Couldn't find top of build tree\n");
- return NULL;
+ // It's a string without any slashes. Try to do something with it.
+ //
+ // Try to find the root of the build tree, and build a PRODUCT_OUT
+ // path from there.
+ char* top = getenv("ANDROID_BUILD_TOP");
+ if (top == nullptr) {
+ fprintf(stderr, "adb: ANDROID_BUILD_TOP not set!\n");
+ return "";
}
-//TODO: if we have a way to indicate debug, look in out/debug/target/...
- snprintf(path_buf, sizeof(path_buf),
- "%s" OS_PATH_SEPARATOR_STR
- "out" OS_PATH_SEPARATOR_STR
- "target" OS_PATH_SEPARATOR_STR
- "product" OS_PATH_SEPARATOR_STR
- "%s", top_buf, hint);
- if (access(path_buf, F_OK) < 0) {
- fprintf(stderr, "adb: Couldn't find a product dir "
- "based on \"-p %s\"; \"%s\" doesn't exist\n", hint, path_buf);
- return NULL;
+
+ std::string path = top;
+ path += OS_PATH_SEPARATOR_STR;
+ path += "out";
+ path += OS_PATH_SEPARATOR_STR;
+ path += "target";
+ path += OS_PATH_SEPARATOR_STR;
+ path += "product";
+ path += OS_PATH_SEPARATOR_STR;
+ path += hint;
+ if (!directory_exists(path)) {
+ fprintf(stderr, "adb: Couldn't find a product dir based on -p %s; "
+ "\"%s\" doesn't exist\n", hint, path.c_str());
+ return "";
}
- return path_buf;
+ return path;
}
static void parse_push_pull_args(const char **arg, int narg, char const **path1,
@@ -1149,15 +984,14 @@
const char* serial = NULL;
const char* server_port_str = NULL;
- /* If defined, this should be an absolute path to
- * the directory containing all of the various system images
- * for a particular product. If not defined, and the adb
- * command requires this information, then the user must
- * specify the path using "-p".
- */
- gProductOutPath = getenv("ANDROID_PRODUCT_OUT");
- if (gProductOutPath == NULL || gProductOutPath[0] == '\0') {
- gProductOutPath = NULL;
+ // If defined, this should be an absolute path to
+ // the directory containing all of the various system images
+ // for a particular product. If not defined, and the adb
+ // command requires this information, then the user must
+ // specify the path using "-p".
+ char* ANDROID_PRODUCT_OUT = getenv("ANDROID_PRODUCT_OUT");
+ if (ANDROID_PRODUCT_OUT != nullptr) {
+ gProductOutPath = ANDROID_PRODUCT_OUT;
}
// TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
@@ -1198,9 +1032,8 @@
product = argv[0] + 2;
}
gProductOutPath = find_product_out_path(product);
- if (gProductOutPath == NULL) {
- fprintf(stderr, "adb: could not resolve \"-p %s\"\n",
- product);
+ if (gProductOutPath.empty()) {
+ fprintf(stderr, "adb: could not resolve \"-p %s\"\n", product);
return usage();
}
} else if (argv[0][0]=='-' && argv[0][1]=='s') {
@@ -1372,9 +1205,6 @@
return adb_send_emulator_command(argc, argv);
}
else if (!strcmp(argv[0], "shell") || !strcmp(argv[0], "hell")) {
- int r;
- int fd;
-
char h = (argv[0][0] == 'h');
if (h) {
@@ -1392,19 +1222,18 @@
return r;
}
- snprintf(buf, sizeof(buf), "shell:%s", argv[1]);
+ std::string cmd = "shell:";
+ cmd += argv[1];
argc -= 2;
argv += 2;
while (argc-- > 0) {
- char *quoted = escape_arg(*argv++);
- strncat(buf, " ", sizeof(buf) - 1);
- strncat(buf, quoted, sizeof(buf) - 1);
- free(quoted);
+ cmd += " " + escape_arg(*argv++);
}
- for(;;) {
- D("interactive shell loop. buff=%s\n", buf);
- fd = adb_connect(buf);
+ while (true) {
+ D("interactive shell loop. cmd=%s\n", cmd.c_str());
+ int fd = adb_connect(cmd.c_str());
+ int r;
if (fd >= 0) {
D("about to read_and_dump(fd=%d)\n", fd);
read_and_dump(fd);
@@ -1432,19 +1261,16 @@
}
else if (!strcmp(argv[0], "exec-in") || !strcmp(argv[0], "exec-out")) {
int exec_in = !strcmp(argv[0], "exec-in");
- int fd;
- snprintf(buf, sizeof buf, "exec:%s", argv[1]);
+ std::string cmd = "exec:";
+ cmd += argv[1];
argc -= 2;
argv += 2;
while (argc-- > 0) {
- char *quoted = escape_arg(*argv++);
- strncat(buf, " ", sizeof(buf) - 1);
- strncat(buf, quoted, sizeof(buf) - 1);
- free(quoted);
+ cmd += " " + escape_arg(*argv++);
}
- fd = adb_connect(buf);
+ int fd = adb_connect(cmd.c_str());
if (fd < 0) {
fprintf(stderr, "error: %s\n", adb_error());
return -1;
@@ -1636,46 +1462,49 @@
return uninstall_app(ttype, serial, argc, argv);
}
else if (!strcmp(argv[0], "sync")) {
- const char* srcarg;
- char *system_srcpath, *data_srcpath, *vendor_srcpath, *oem_srcpath;
-
- int listonly = 0;
-
- int ret;
+ std::string src;
+ bool list_only = false;
if (argc < 2) {
- /* No local path was specified. */
- srcarg = NULL;
+ // No local path was specified.
+ src = "";
} else if (argc >= 2 && strcmp(argv[1], "-l") == 0) {
- listonly = 1;
+ list_only = true;
if (argc == 3) {
- srcarg = argv[2];
+ src = argv[2];
} else {
- srcarg = NULL;
+ src = "";
}
} else if (argc == 2) {
- /* A local path or "android"/"data" arg was specified. */
- srcarg = argv[1];
+ // A local path or "android"/"data" arg was specified.
+ src = argv[1];
} else {
return usage();
}
- ret = find_sync_dirs(srcarg, &system_srcpath, &data_srcpath, &vendor_srcpath,
- &oem_srcpath);
- if (ret != 0) return usage();
- if (system_srcpath != NULL)
- ret = do_sync_sync(system_srcpath, "/system", listonly);
- if (ret == 0 && vendor_srcpath != NULL)
- ret = do_sync_sync(vendor_srcpath, "/vendor", listonly);
- if(ret == 0 && oem_srcpath != NULL)
- ret = do_sync_sync(oem_srcpath, "/oem", listonly);
- if (ret == 0 && data_srcpath != NULL)
- ret = do_sync_sync(data_srcpath, "/data", listonly);
+ if (src != "" &&
+ src != "system" && src != "data" && src != "vendor" && src != "oem") {
+ return usage();
+ }
- free(system_srcpath);
- free(vendor_srcpath);
- free(oem_srcpath);
- free(data_srcpath);
- return ret;
+ std::string system_src_path = product_file("system");
+ std::string data_src_path = product_file("data");
+ std::string vendor_src_path = product_file("vendor");
+ std::string oem_src_path = product_file("oem");
+
+ int rc = 0;
+ if (rc == 0 && (src.empty() || src == "system")) {
+ rc = do_sync_sync(system_src_path, "/system", list_only);
+ }
+ if (rc == 0 && (src.empty() || src == "vendor") && directory_exists(vendor_src_path)) {
+ rc = do_sync_sync(vendor_src_path, "/vendor", list_only);
+ }
+ if (rc == 0 && (src.empty() || src == "oem") && directory_exists(oem_src_path)) {
+ rc = do_sync_sync(oem_src_path, "/oem", list_only);
+ }
+ if (rc == 0 && (src.empty() || src == "data")) {
+ rc = do_sync_sync(data_src_path, "/data", list_only);
+ }
+ return rc;
}
/* passthrough commands */
else if (!strcmp(argv[0],"get-state") ||
@@ -1770,84 +1599,20 @@
return adb_commandline(argc, argv);
}
-int find_sync_dirs(const char *srcarg,
- char **system_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out,
- char **oem_srcdir_out)
-{
- char *system_srcdir = NULL, *data_srcdir = NULL, *vendor_srcdir = NULL, *oem_srcdir = NULL;
- struct stat st;
-
- if(srcarg == NULL) {
- system_srcdir = product_file("system");
- data_srcdir = product_file("data");
- vendor_srcdir = product_file("vendor");
- oem_srcdir = product_file("oem");
- // Check if vendor partition exists.
- if (lstat(vendor_srcdir, &st) || !S_ISDIR(st.st_mode))
- vendor_srcdir = NULL;
- // Check if oem partition exists.
- if (lstat(oem_srcdir, &st) || !S_ISDIR(st.st_mode))
- oem_srcdir = NULL;
- } else {
- // srcarg may be "data", "system", "vendor", "oem" or NULL.
- // If srcarg is NULL, then all partitions are synced.
- if(strcmp(srcarg, "system") == 0) {
- system_srcdir = product_file("system");
- } else if(strcmp(srcarg, "data") == 0) {
- data_srcdir = product_file("data");
- } else if(strcmp(srcarg, "vendor") == 0) {
- vendor_srcdir = product_file("vendor");
- } else if(strcmp(srcarg, "oem") == 0) {
- oem_srcdir = product_file("oem");
- } else {
- // It's not "system", "data", "vendor", or "oem".
- return 1;
- }
- }
-
- if(system_srcdir_out != NULL)
- *system_srcdir_out = system_srcdir;
- else
- free(system_srcdir);
-
- if(vendor_srcdir_out != NULL)
- *vendor_srcdir_out = vendor_srcdir;
- else
- free(vendor_srcdir);
-
- if(oem_srcdir_out != NULL)
- *oem_srcdir_out = oem_srcdir;
- else
- free(oem_srcdir);
-
- if(data_srcdir_out != NULL)
- *data_srcdir_out = data_srcdir;
- else
- free(data_srcdir);
-
- return 0;
-}
-
static int pm_command(transport_type transport, const char* serial,
int argc, const char** argv)
{
- char buf[4096];
+ std::string cmd = "shell:pm";
- snprintf(buf, sizeof(buf), "shell:pm");
-
- while(argc-- > 0) {
- char *quoted = escape_arg(*argv++);
- strncat(buf, " ", sizeof(buf) - 1);
- strncat(buf, quoted, sizeof(buf) - 1);
- free(quoted);
+ while (argc-- > 0) {
+ cmd += " " + escape_arg(*argv++);
}
- send_shellcommand(transport, serial, buf);
- return 0;
+ return send_shell_command(transport, serial, cmd);
}
-int uninstall_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)
{
/* 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) */
@@ -1867,16 +1632,8 @@
static int delete_file(transport_type transport, const char* serial, char* filename)
{
- char buf[4096];
- char* quoted;
-
- snprintf(buf, sizeof(buf), "shell:rm -f ");
- quoted = escape_arg(filename);
- strncat(buf, quoted, sizeof(buf)-1);
- free(quoted);
-
- send_shellcommand(transport, serial, buf);
- return 0;
+ std::string cmd = "shell:rm -f " + escape_arg(filename);
+ return send_shell_command(transport, serial, cmd);
}
static const char* get_basename(const char* filename)
@@ -1890,8 +1647,8 @@
}
}
-int install_app(transport_type transport, const char* serial, int argc,
- const char** argv)
+static int install_app(transport_type 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";
@@ -1937,20 +1694,19 @@
argv[last_apk] = apk_dest; /* destination name, not source location */
}
- pm_command(transport, serial, argc, argv);
+ err = pm_command(transport, serial, argc, argv);
cleanup_apk:
delete_file(transport, serial, apk_dest);
return err;
}
-int install_multiple_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)
{
- char buf[1024];
int i;
struct stat sb;
- unsigned long long total_size = 0;
+ uint64_t total_size = 0;
// Find all APK arguments starting at end.
// All other arguments passed through verbatim.
@@ -1976,20 +1732,22 @@
return 1;
}
- snprintf(buf, sizeof(buf), "exec:pm install-create -S %lld", total_size);
+#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++) {
- char *quoted = escape_arg(argv[i]);
- strncat(buf, " ", sizeof(buf) - 1);
- strncat(buf, quoted, sizeof(buf) - 1);
- free(quoted);
+ cmd += " " + escape_arg(argv[i]);
}
// Create install session
- int fd = adb_connect(buf);
+ int fd = adb_connect(cmd.c_str());
if (fd < 0) {
fprintf(stderr, "Connect error for create: %s\n", adb_error());
return -1;
}
+ char buf[BUFSIZ];
read_status_line(fd, buf, sizeof(buf));
adb_close(fd);
@@ -2018,8 +1776,15 @@
goto finalize_session;
}
- snprintf(buf, sizeof(buf), "exec:pm install-write -S %lld %d %d_%s -",
- (long long int) sb.st_size, session_id, i, get_basename(file));
+#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) {
@@ -2028,7 +1793,7 @@
goto finalize_session;
}
- int remoteFd = adb_connect(buf);
+ int remoteFd = adb_connect(cmd.c_str());
if (remoteFd < 0) {
fprintf(stderr, "Connect error for write: %s\n", adb_error());
adb_close(localFd);
diff --git a/adb/fdevent.h b/adb/fdevent.h
index a8102ca..8d84b29 100644
--- a/adb/fdevent.h
+++ b/adb/fdevent.h
@@ -19,10 +19,6 @@
#include <stdint.h> /* for int64_t */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/* events that may be observed */
#define FDE_READ 0x0001
#define FDE_WRITE 0x0002
@@ -32,7 +28,7 @@
/* features that may be set (via the events set/add/del interface) */
#define FDE_DONT_CLOSE 0x0080
-typedef struct fdevent fdevent;
+struct fdevent;
typedef void (*fd_func)(int fd, unsigned events, void *userdata);
@@ -82,8 +78,4 @@
void *arg;
};
-#ifdef __cplusplus
-}
-#endif
-
#endif
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index 4ba730b..49d8783 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -130,8 +130,6 @@
return -1;
}
-typedef struct syncsendbuf syncsendbuf;
-
struct syncsendbuf {
unsigned id;
unsigned size;
@@ -557,8 +555,6 @@
}
}
-typedef struct copyinfo copyinfo;
-
struct copyinfo
{
copyinfo *next;
@@ -804,12 +800,12 @@
}
-typedef struct {
+struct sync_ls_build_list_cb_args {
copyinfo **filelist;
copyinfo **dirlist;
const char *rpath;
const char *lpath;
-} sync_ls_build_list_cb_args;
+};
void
sync_ls_build_list_cb(unsigned mode, unsigned size, unsigned time,
@@ -1031,18 +1027,18 @@
}
}
-int do_sync_sync(const char *lpath, const char *rpath, int listonly)
+int do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only)
{
- fprintf(stderr,"syncing %s...\n",rpath);
+ fprintf(stderr, "syncing %s...\n", rpath.c_str());
int fd = adb_connect("sync:");
- if(fd < 0) {
- fprintf(stderr,"error: %s\n", adb_error());
+ if (fd < 0) {
+ fprintf(stderr, "error: %s\n", adb_error());
return 1;
}
BEGIN();
- if(copy_local_dir_remote(fd, lpath, rpath, 1, listonly)){
+ if (copy_local_dir_remote(fd, lpath.c_str(), rpath.c_str(), 1, list_only)) {
return 1;
} else {
END();
diff --git a/adb/file_sync_service.h b/adb/file_sync_service.h
index 5b69a63..344eb98 100644
--- a/adb/file_sync_service.h
+++ b/adb/file_sync_service.h
@@ -17,9 +17,7 @@
#ifndef _FILE_SYNC_SERVICE_H_
#define _FILE_SYNC_SERVICE_H_
-#ifdef __cplusplus
-extern "C" {
-#endif
+#include <string>
#define htoll(x) (x)
#define ltohl(x) (x)
@@ -38,7 +36,7 @@
#define ID_FAIL MKID('F','A','I','L')
#define ID_QUIT MKID('Q','U','I','T')
-typedef union {
+union syncmsg {
unsigned id;
struct {
unsigned id;
@@ -65,19 +63,15 @@
unsigned id;
unsigned msglen;
} status;
-} syncmsg;
+} ;
void file_sync_service(int fd, void *cookie);
int do_sync_ls(const char *path);
int do_sync_push(const char *lpath, const char *rpath, int show_progress);
-int do_sync_sync(const char *lpath, const char *rpath, int listonly);
+int do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only);
int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int pullTime);
#define SYNC_DATA_MAX (64*1024)
-#ifdef __cplusplus
-}
-#endif
-
#endif
diff --git a/adb/get_my_path_darwin.c b/adb/get_my_path_darwin.cpp
similarity index 100%
rename from adb/get_my_path_darwin.c
rename to adb/get_my_path_darwin.cpp
diff --git a/adb/jdwp_service.cpp b/adb/jdwp_service.cpp
index 9cf084e..c0f7ec2 100644
--- a/adb/jdwp_service.cpp
+++ b/adb/jdwp_service.cpp
@@ -121,7 +121,6 @@
#include <sys/socket.h>
#include <sys/un.h>
-typedef struct JdwpProcess JdwpProcess;
struct JdwpProcess {
JdwpProcess* next;
JdwpProcess* prev;
@@ -455,11 +454,10 @@
#define JDWP_CONTROL_NAME "\0jdwp-control"
#define JDWP_CONTROL_NAME_LEN (sizeof(JDWP_CONTROL_NAME)-1)
-typedef struct {
+struct JdwpControl {
int listen_socket;
fdevent* fde;
-
-} JdwpControl;
+};
static void
@@ -570,10 +568,10 @@
** this simply returns the list of known JDWP process pids
**/
-typedef struct {
+struct JdwpSocket {
asocket socket;
int pass;
-} JdwpSocket;
+};
static void
jdwp_socket_close( asocket* s )
@@ -642,8 +640,6 @@
** to the client...
**/
-typedef struct JdwpTracker JdwpTracker;
-
struct JdwpTracker {
asocket socket;
JdwpTracker* next;
@@ -754,4 +750,3 @@
}
#endif /* !ADB_HOST */
-
diff --git a/adb/qemu_tracing.h b/adb/qemu_tracing.h
index bf80457..ff42d4f 100644
--- a/adb/qemu_tracing.h
+++ b/adb/qemu_tracing.h
@@ -21,16 +21,8 @@
#ifndef __QEMU_TRACING_H
#define __QEMU_TRACING_H
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/* Initializes connection with the adb-debug qemud service in the emulator. */
int adb_qemu_trace_init(void);
void adb_qemu_trace(const char* fmt, ...);
-#ifdef __cplusplus
-}
-#endif
-
#endif /* __QEMU_TRACING_H */
diff --git a/adb/remount_service.cpp b/adb/remount_service.cpp
index b150274..1eaee73 100644
--- a/adb/remount_service.cpp
+++ b/adb/remount_service.cpp
@@ -31,6 +31,7 @@
#include "adb.h"
#include "adb_io.h"
+#include "adb_utils.h"
#include "cutils/properties.h"
static int system_ro = 1;
@@ -56,11 +57,6 @@
return device;
}
-static bool has_partition(const char* path) {
- struct stat sb;
- return (lstat(path, &sb) == 0 && S_ISDIR(sb.st_mode));
-}
-
int make_block_device_writable(const std::string& dev) {
int fd = unix_open(dev.c_str(), O_RDONLY | O_CLOEXEC);
if (fd == -1) {
@@ -90,7 +86,7 @@
}
static bool remount_partition(int fd, const char* partition, int* ro) {
- if (!has_partition(partition)) {
+ if (!directory_exists(partition)) {
return true;
}
if (remount(partition, ro)) {
diff --git a/adb/services.cpp b/adb/services.cpp
index 12eb406..e6c84a4 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -31,6 +31,8 @@
#include <unistd.h>
#endif
+#include <base/stringprintf.h>
+
#if !ADB_HOST
#include "base/file.h"
#include "cutils/android_reboot.h"
@@ -43,8 +45,6 @@
#include "remount_service.h"
#include "transport.h"
-typedef struct stinfo stinfo;
-
struct stinfo {
void (*func)(int fd, void *cookie);
int fd;
@@ -194,7 +194,7 @@
if (reboot_service_impl(fd, static_cast<const char*>(arg))) {
// Don't return early. Give the reboot command time to take effect
// to avoid messing up scripts which do "adb reboot && adb wait-for-device"
- while (1) {
+ while (true) {
pause();
}
}
@@ -375,7 +375,7 @@
pid_t pid = (pid_t) (uintptr_t) cookie;
D("entered. fd=%d of pid=%d\n", fd, pid);
- for (;;) {
+ while (true) {
int status;
pid_t p = waitpid(pid, &status, 0);
if (p == pid) {
@@ -501,19 +501,8 @@
} else if(!strncmp(name, "unroot:", 7)) {
ret = create_service_thread(restart_unroot_service, NULL);
} else if(!strncmp(name, "backup:", 7)) {
- char* arg = strdup(name + 7);
- if (arg == NULL) return -1;
- char* c = arg;
- for (; *c != '\0'; c++) {
- if (*c == ':')
- *c = ' ';
- }
- char* cmd;
- if (asprintf(&cmd, "/system/bin/bu backup %s", arg) != -1) {
- ret = create_subproc_thread(cmd, SUBPROC_RAW);
- free(cmd);
- }
- free(arg);
+ ret = create_subproc_thread(android::base::StringPrintf("/system/bin/bu backup %s",
+ (name + 7)).c_str(), SUBPROC_RAW);
} else if(!strncmp(name, "restore:", 8)) {
ret = create_subproc_thread("/system/bin/bu restore", SUBPROC_RAW);
} else if(!strncmp(name, "tcpip:", 6)) {
@@ -559,12 +548,12 @@
D("wait_for_state %d\n", sinfo->state);
- const char* err = "unknown error";
- atransport *t = acquire_one_transport(sinfo->state, sinfo->transport, sinfo->serial, &err);
- if(t != 0) {
+ std::string error_msg = "unknown error";
+ atransport* t = acquire_one_transport(sinfo->state, sinfo->transport, sinfo->serial, &error_msg);
+ if (t != 0) {
WriteFdExactly(fd, "OKAY", 4);
} else {
- sendfailmsg(fd, err);
+ sendfailmsg(fd, error_msg.c_str());
}
if (sinfo->serial)
@@ -700,6 +689,10 @@
return create_device_tracker();
} else if (!strncmp(name, "wait-for-", strlen("wait-for-"))) {
auto sinfo = reinterpret_cast<state_info*>(malloc(sizeof(state_info)));
+ if (sinfo == nullptr) {
+ fprintf(stderr, "couldn't allocate state_info: %s", strerror(errno));
+ return NULL;
+ }
if (serial)
sinfo->serial = strdup(serial);
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index 48d02d6..f468029 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -487,10 +487,10 @@
/* a Remote socket is used to send/receive data to/from a given transport object
** it needs to be closed when the transport is forcibly destroyed by the user
*/
-typedef struct aremotesocket {
+struct aremotesocket {
asocket socket;
adisconnect disconnect;
-} aremotesocket;
+};
static int remote_socket_enqueue(asocket *s, apacket *p)
{
@@ -827,12 +827,11 @@
}
#else /* !ADB_HOST */
if (s->transport == NULL) {
- const char* error_string = "unknown failure";
- s->transport = acquire_one_transport (CS_ANY,
- kTransportAny, NULL, &error_string);
+ std::string error_msg = "unknown failure";
+ s->transport = acquire_one_transport(CS_ANY, kTransportAny, NULL, &error_msg);
if (s->transport == NULL) {
- sendfailmsg(s->peer->fd, error_string);
+ sendfailmsg(s->peer->fd, error_msg.c_str());
goto fail;
}
}
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 2ad28fa..59e5b0b 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -54,10 +54,6 @@
#include "fdevent.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#define OS_PATH_SEPARATOR '\\'
#define OS_PATH_SEPARATOR_STR "\\"
#define ENV_PATH_SEPARATOR_STR ";"
@@ -275,8 +271,6 @@
return isalpha(path[0]) && path[1] == ':' && path[2] == '\\';
}
-extern char* adb_strtok_r(char *str, const char *delim, char **saveptr);
-
#else /* !_WIN32 a.k.a. Unix */
#include "fdevent.h"
@@ -296,10 +290,6 @@
#include <string.h>
#include <unistd.h>
-#ifdef __cplusplus
-extern "C" {
-#endif
-
#define OS_PATH_SEPARATOR '/'
#define OS_PATH_SEPARATOR_STR "/"
#define ENV_PATH_SEPARATOR_STR ":"
@@ -525,23 +515,11 @@
return path[0] == '/';
}
-static __inline__ char* adb_strtok_r(char *str, const char *delim, char **saveptr)
-{
- return strtok_r(str, delim, saveptr);
-}
-
static __inline__ unsigned long adb_thread_id()
{
return (unsigned long)pthread_self();
}
-#undef strtok_r
-#define strtok_r ___xxx_strtok_r
-
#endif /* !_WIN32 */
-#ifdef __cplusplus
-}
-#endif
-
#endif /* _ADB_SYSDEPS_H */
diff --git a/adb/sysdeps_win32.c b/adb/sysdeps_win32.cpp
similarity index 94%
rename from adb/sysdeps_win32.c
rename to adb/sysdeps_win32.cpp
index c2742f1..633f6f5 100644
--- a/adb/sysdeps_win32.c
+++ b/adb/sysdeps_win32.cpp
@@ -30,6 +30,53 @@
extern void fatal(const char *fmt, ...);
+/* forward declarations */
+
+typedef const struct FHClassRec_* FHClass;
+typedef struct FHRec_* FH;
+typedef struct EventHookRec_* EventHook;
+
+typedef struct FHClassRec_ {
+ void (*_fh_init)(FH);
+ int (*_fh_close)(FH);
+ int (*_fh_lseek)(FH, int, int);
+ int (*_fh_read)(FH, void*, int);
+ int (*_fh_write)(FH, const void*, int);
+ void (*_fh_hook)(FH, int, EventHook);
+} FHClassRec;
+
+static void _fh_file_init(FH);
+static int _fh_file_close(FH);
+static int _fh_file_lseek(FH, int, int);
+static int _fh_file_read(FH, void*, int);
+static int _fh_file_write(FH, const void*, int);
+static void _fh_file_hook(FH, int, EventHook);
+
+static const FHClassRec _fh_file_class = {
+ _fh_file_init,
+ _fh_file_close,
+ _fh_file_lseek,
+ _fh_file_read,
+ _fh_file_write,
+ _fh_file_hook
+};
+
+static void _fh_socket_init(FH);
+static int _fh_socket_close(FH);
+static int _fh_socket_lseek(FH, int, int);
+static int _fh_socket_read(FH, void*, int);
+static int _fh_socket_write(FH, const void*, int);
+static void _fh_socket_hook(FH, int, EventHook);
+
+static const FHClassRec _fh_socket_class = {
+ _fh_socket_init,
+ _fh_socket_close,
+ _fh_socket_lseek,
+ _fh_socket_read,
+ _fh_socket_write,
+ _fh_socket_hook
+};
+
#define assert(cond) do { if (!(cond)) fatal( "assertion failed '%s' on %s:%ld\n", #cond, __FILE__, __LINE__ ); } while (0)
/**************************************************************************/
@@ -92,23 +139,6 @@
/**************************************************************************/
/**************************************************************************/
-typedef const struct FHClassRec_* FHClass;
-
-typedef struct FHRec_* FH;
-
-typedef struct EventHookRec_* EventHook;
-
-typedef struct FHClassRec_
-{
- void (*_fh_init) ( FH f );
- int (*_fh_close)( FH f );
- int (*_fh_lseek)( FH f, int pos, int origin );
- int (*_fh_read) ( FH f, void* buf, int len );
- int (*_fh_write)( FH f, const void* buf, int len );
- void (*_fh_hook) ( FH f, int events, EventHook hook );
-
-} FHClassRec;
-
/* used to emulate unix-domain socket pairs */
typedef struct SocketPairRec_* SocketPair;
@@ -220,10 +250,6 @@
return 0;
}
-/* forward definitions */
-static const FHClassRec _fh_file_class;
-static const FHClassRec _fh_socket_class;
-
/**************************************************************************/
/**************************************************************************/
/***** *****/
@@ -232,23 +258,17 @@
/**************************************************************************/
/**************************************************************************/
-static void
-_fh_file_init( FH f )
-{
+static void _fh_file_init( FH f ) {
f->fh_handle = INVALID_HANDLE_VALUE;
}
-static int
-_fh_file_close( FH f )
-{
+static int _fh_file_close( FH f ) {
CloseHandle( f->fh_handle );
f->fh_handle = INVALID_HANDLE_VALUE;
return 0;
}
-static int
-_fh_file_read( FH f, void* buf, int len )
-{
+static int _fh_file_read( FH f, void* buf, int len ) {
DWORD read_bytes;
if ( !ReadFile( f->fh_handle, buf, (DWORD)len, &read_bytes, NULL ) ) {
@@ -261,9 +281,7 @@
return (int)read_bytes;
}
-static int
-_fh_file_write( FH f, const void* buf, int len )
-{
+static int _fh_file_write( FH f, const void* buf, int len ) {
DWORD wrote_bytes;
if ( !WriteFile( f->fh_handle, buf, (DWORD)len, &wrote_bytes, NULL ) ) {
@@ -276,9 +294,7 @@
return (int)wrote_bytes;
}
-static int
-_fh_file_lseek( FH f, int pos, int origin )
-{
+static int _fh_file_lseek( FH f, int pos, int origin ) {
DWORD method;
DWORD result;
@@ -302,17 +318,6 @@
return (int)result;
}
-static void _fh_file_hook( FH f, int event, EventHook eventhook ); /* forward */
-
-static const FHClassRec _fh_file_class =
-{
- _fh_file_init,
- _fh_file_close,
- _fh_file_lseek,
- _fh_file_read,
- _fh_file_write,
- _fh_file_hook
-};
/**************************************************************************/
/**************************************************************************/
@@ -495,9 +500,7 @@
#undef setsockopt
-static void
-_socket_set_errno( void )
-{
+static void _socket_set_errno( void ) {
switch (WSAGetLastError()) {
case 0: errno = 0; break;
case WSAEWOULDBLOCK: errno = EAGAIN; break;
@@ -508,17 +511,13 @@
}
}
-static void
-_fh_socket_init( FH f )
-{
+static void _fh_socket_init( FH f ) {
f->fh_socket = INVALID_SOCKET;
f->event = WSACreateEvent();
f->mask = 0;
}
-static int
-_fh_socket_close( FH f )
-{
+static int _fh_socket_close( FH f ) {
/* gently tell any peer that we're closing the socket */
shutdown( f->fh_socket, SD_BOTH );
closesocket( f->fh_socket );
@@ -528,17 +527,13 @@
return 0;
}
-static int
-_fh_socket_lseek( FH f, int pos, int origin )
-{
+static int _fh_socket_lseek( FH f, int pos, int origin ) {
errno = EPIPE;
return -1;
}
-static int
-_fh_socket_read( FH f, void* buf, int len )
-{
- int result = recv( f->fh_socket, buf, len, 0 );
+static int _fh_socket_read(FH f, void* buf, int len) {
+ int result = recv(f->fh_socket, reinterpret_cast<char*>(buf), len, 0);
if (result == SOCKET_ERROR) {
_socket_set_errno();
result = -1;
@@ -546,10 +541,8 @@
return result;
}
-static int
-_fh_socket_write( FH f, const void* buf, int len )
-{
- int result = send( f->fh_socket, buf, len, 0 );
+static int _fh_socket_write(FH f, const void* buf, int len) {
+ int result = send(f->fh_socket, reinterpret_cast<const char*>(buf), len, 0);
if (result == SOCKET_ERROR) {
_socket_set_errno();
result = -1;
@@ -557,18 +550,6 @@
return result;
}
-static void _fh_socket_hook( FH f, int event, EventHook hook ); /* forward */
-
-static const FHClassRec _fh_socket_class =
-{
- _fh_socket_init,
- _fh_socket_close,
- _fh_socket_lseek,
- _fh_socket_read,
- _fh_socket_write,
- _fh_socket_hook
-};
-
/**************************************************************************/
/**************************************************************************/
/***** *****/
@@ -819,7 +800,7 @@
return -1;
}
- return setsockopt( fh->fh_socket, level, optname, optval, optlen );
+ return setsockopt( fh->fh_socket, level, optname, reinterpret_cast<const char*>(optval), optlen );
}
/**************************************************************************/
@@ -1219,18 +1200,16 @@
};
-int adb_socketpair( int sv[2] )
-{
- FH fa, fb;
- SocketPair pair;
+int adb_socketpair(int sv[2]) {
+ SocketPair pair;
- fa = _fh_alloc( &_fh_socketpair_class );
- fb = _fh_alloc( &_fh_socketpair_class );
+ FH fa = _fh_alloc(&_fh_socketpair_class);
+ FH fb = _fh_alloc(&_fh_socketpair_class);
if (!fa || !fb)
goto Fail;
- pair = malloc( sizeof(*pair) );
+ pair = reinterpret_cast<SocketPair>(malloc(sizeof(*pair)));
if (pair == NULL) {
D("adb_socketpair: not enough memory to allocate pipes\n" );
goto Fail;
@@ -1328,13 +1307,12 @@
static EventHook _free_hooks;
static EventHook
-event_hook_alloc( FH fh )
-{
- EventHook hook = _free_hooks;
- if (hook != NULL)
+event_hook_alloc(FH fh) {
+ EventHook hook = _free_hooks;
+ if (hook != NULL) {
_free_hooks = hook->next;
- else {
- hook = malloc( sizeof(*hook) );
+ } else {
+ hook = reinterpret_cast<EventHook>(malloc(sizeof(*hook)));
if (hook == NULL)
fatal( "could not allocate event hook\n" );
}
@@ -1796,7 +1774,7 @@
while(fd_table_max <= fd) {
fd_table_max *= 2;
}
- fd_table = realloc(fd_table, sizeof(fdevent*) * fd_table_max);
+ fd_table = reinterpret_cast<fdevent**>(realloc(fd_table, sizeof(fdevent*) * fd_table_max));
if(fd_table == 0) {
FATAL("could not expand fd_table to %d entries\n", fd_table_max);
}
@@ -2173,85 +2151,6 @@
InitializeCriticalSection( &_win32_lock );
}
-/* Windows doesn't have strtok_r. Use the one from bionic. */
-
-/*
- * Copyright (c) 1988 Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-char *
-adb_strtok_r(char *s, const char *delim, char **last)
-{
- char *spanp;
- int c, sc;
- char *tok;
-
-
- if (s == NULL && (s = *last) == NULL)
- return (NULL);
-
- /*
- * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
- */
-cont:
- c = *s++;
- for (spanp = (char *)delim; (sc = *spanp++) != 0;) {
- if (c == sc)
- goto cont;
- }
-
- if (c == 0) { /* no non-delimiter characters */
- *last = NULL;
- return (NULL);
- }
- tok = s - 1;
-
- /*
- * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
- * Note that delim must have one NUL; we stop if we see that, too.
- */
- for (;;) {
- c = *s++;
- spanp = (char *)delim;
- do {
- if ((sc = *spanp++) == c) {
- if (c == 0)
- s = NULL;
- else
- s[-1] = 0;
- *last = s;
- return (tok);
- }
- } while (sc != 0);
- }
- /* NOTREACHED */
-}
-
/**************************************************************************/
/**************************************************************************/
/***** *****/
diff --git a/adb/tests/test_adb.py b/adb/tests/test_adb.py
index f111b043..52d8056 100755
--- a/adb/tests/test_adb.py
+++ b/adb/tests/test_adb.py
@@ -267,6 +267,18 @@
adb.unroot()
adb.wait()
+ def test_argument_escaping(self):
+ """Make sure that argument escaping is somewhat sane."""
+ adb = AdbWrapper()
+
+ # http://b/19734868
+ result = adb.shell("sh -c '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())
+
class AdbFile(unittest.TestCase):
SCRATCH_DIR = "/data/local/tmp"
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 4b9eeeb..d395a80 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -406,7 +406,6 @@
* number of client connections that want it through a single
* live TCP connection
*/
-typedef struct device_tracker device_tracker;
struct device_tracker {
asocket socket;
int update_needed;
@@ -494,10 +493,8 @@
asocket*
create_device_tracker(void)
{
- device_tracker* tracker = reinterpret_cast<device_tracker*>(
- calloc(1, sizeof(*tracker)));
-
- if(tracker == 0) fatal("cannot allocate device tracker");
+ device_tracker* tracker = reinterpret_cast<device_tracker*>(calloc(1, sizeof(*tracker)));
+ if (tracker == nullptr) fatal("cannot allocate device tracker");
D( "device tracker %p created\n", tracker);
@@ -536,7 +533,6 @@
}
#endif // ADB_HOST
-typedef struct tmsg tmsg;
struct tmsg
{
atransport *transport;
@@ -800,22 +796,20 @@
return !*to_test;
}
-atransport *acquire_one_transport(int state, transport_type ttype,
- const char* serial, const char** error_out)
+atransport* acquire_one_transport(int state, transport_type ttype,
+ 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 = "device not found";
adb_mutex_lock(&transport_lock);
for (t = transport_list.next; t != &transport_list; t = t->next) {
if (t->connection_state == CS_NOPERM) {
- if (error_out)
- *error_out = "insufficient permissions for device";
+ if (error_out) *error_out = "insufficient permissions for device";
continue;
}
@@ -827,8 +821,7 @@
qual_match(serial, "model:", t->model, true) ||
qual_match(serial, "device:", t->device, false)) {
if (result) {
- if (error_out)
- *error_out = "more than one device";
+ if (error_out) *error_out = "more than one device";
ambiguous = 1;
result = NULL;
break;
@@ -838,8 +831,7 @@
} else {
if (ttype == kTransportUsb && t->type == kTransportUsb) {
if (result) {
- if (error_out)
- *error_out = "more than one device";
+ if (error_out) *error_out = "more than one device";
ambiguous = 1;
result = NULL;
break;
@@ -847,8 +839,7 @@
result = t;
} else if (ttype == kTransportLocal && t->type == kTransportLocal) {
if (result) {
- if (error_out)
- *error_out = "more than one emulator";
+ if (error_out) *error_out = "more than one emulator";
ambiguous = 1;
result = NULL;
break;
@@ -856,8 +847,7 @@
result = t;
} else if (ttype == kTransportAny) {
if (result) {
- if (error_out)
- *error_out = "more than one device and emulator";
+ if (error_out) *error_out = "more than one device and emulator";
ambiguous = 1;
result = NULL;
break;
@@ -870,29 +860,33 @@
if (result) {
if (result->connection_state == CS_UNAUTHORIZED) {
- if (error_out)
- *error_out = "device unauthorized. Please check the confirmation dialog on your device.";
+ if (error_out) {
+ *error_out = "device unauthorized.\n";
+ char* ADB_VENDOR_KEYS = getenv("ADB_VENDOR_KEYS");
+ *error_out += "This adbd's $ADB_VENDOR_KEYS is ";
+ *error_out += ADB_VENDOR_KEYS ? ADB_VENDOR_KEYS : "not set";
+ *error_out += "; try 'adb kill-server' if that seems wrong.\n";
+ *error_out += "Otherwise check for a confirmation dialog on your device.";
+ }
result = NULL;
}
- /* offline devices are ignored -- they are either being born or dying */
+ /* offline devices are ignored -- they are either being born or dying */
if (result && result->connection_state == CS_OFFLINE) {
- if (error_out)
- *error_out = "device offline";
+ if (error_out) *error_out = "device offline";
result = NULL;
}
- /* check for required connection state */
+
+ /* check for required connection state */
if (result && state != CS_ANY && result->connection_state != state) {
- if (error_out)
- *error_out = "invalid device state";
+ if (error_out) *error_out = "invalid device state";
result = NULL;
}
}
if (result) {
/* found one that we can take */
- if (error_out)
- *error_out = NULL;
+ if (error_out) *error_out = "success";
} else if (state != CS_ANY && (serial || !ambiguous)) {
adb_sleep_ms(1000);
goto retry;
@@ -1006,8 +1000,11 @@
int register_socket_transport(int s, const char *serial, int port, int local)
{
- atransport *t = reinterpret_cast<atransport*>(
- calloc(1, sizeof(atransport)));
+ atransport *t = reinterpret_cast<atransport*>(calloc(1, sizeof(atransport)));
+ if (t == nullptr) {
+ return -1;
+ }
+
atransport *n;
char buff[32];
@@ -1106,8 +1103,8 @@
void register_usb_transport(usb_handle *usb, const char *serial, const char *devpath, unsigned writeable)
{
- atransport *t = reinterpret_cast<atransport*>(
- calloc(1, sizeof(atransport)));
+ atransport *t = reinterpret_cast<atransport*>(calloc(1, sizeof(atransport)));
+ 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));
diff --git a/adb/transport.h b/adb/transport.h
index 36a0e40..a2077e8 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -17,14 +17,11 @@
#ifndef __TRANSPORT_H
#define __TRANSPORT_H
-#include <stdbool.h>
#include <sys/types.h>
-#include "adb.h"
+#include <string>
-#ifdef __cplusplus
-extern "C" {
-#endif
+#include "adb.h"
#if ADB_TRACE
void dump_hex(const unsigned char* ptr, size_t len);
@@ -37,7 +34,7 @@
* If no suitable transport is found, error is set.
*/
atransport* acquire_one_transport(int state, transport_type ttype,
- const char* serial, const char** error_out);
+ const char* serial, std::string* error_out);
void add_transport_disconnect(atransport* t, adisconnect* dis);
void remove_transport_disconnect(atransport* t, adisconnect* dis);
void kick_transport(atransport* t);
@@ -74,8 +71,4 @@
asocket* create_device_tracker(void);
-#ifdef __cplusplus
-}
-#endif
-
#endif /* __TRANSPORT_H */
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index fe3c87f..30e6bf5 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -144,7 +144,7 @@
if(serverfd == -1) {
serverfd = socket_inaddr_any_server(port, SOCK_STREAM);
if(serverfd < 0) {
- D("server: cannot bind socket yet\n");
+ D("server: cannot bind socket yet: %s\n", strerror(errno));
adb_sleep_ms(1000);
continue;
}
diff --git a/adb/usb_linux.cpp b/adb/usb_linux.cpp
index 6fd2b40..999eb11 100644
--- a/adb/usb_linux.cpp
+++ b/adb/usb_linux.cpp
@@ -31,11 +31,11 @@
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
#include <linux/usb/ch9.h>
-#else
-#include <linux/usb_ch9.h>
-#endif
+
+#include <base/file.h>
+#include <base/stringprintf.h>
+#include <base/strings.h>
#include "adb.h"
#include "transport.h"
@@ -114,10 +114,6 @@
}
-static void register_device(const char *dev_name, const char *devpath,
- unsigned char ep_in, unsigned char ep_out,
- int ifc, int serial_index, unsigned zero_mask);
-
static inline int badname(const char *name)
{
while(*name) {
@@ -571,13 +567,10 @@
return 0;
}
-static void register_device(const char *dev_name, const char *devpath,
+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)
{
- int n = 0;
- char serial[256];
-
/* 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
@@ -587,8 +580,7 @@
** 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) {
+ for (usb_handle* usb = handle_list.next; usb != &handle_list; usb = usb->next) {
if (!strcmp(usb->fname, dev_name)) {
adb_mutex_unlock(&usb_lock);
return;
@@ -596,10 +588,9 @@
}
adb_mutex_unlock(&usb_lock);
- D("[ usb located new device %s (%d/%d/%d) ]\n",
- dev_name, ep_in, ep_out, interface);
- usb_handle* usb = reinterpret_cast<usb_handle*>(
- calloc(1, sizeof(usb_handle)));
+ D("[ usb located new device %s (%d/%d/%d) ]\n", dev_name, ep_in, ep_out, interface);
+ usb_handle* usb = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle)));
+ if (usb == nullptr) fatal("couldn't allocate usb_handle");
strcpy(usb->fname, dev_name);
usb->ep_in = ep_in;
usb->ep_out = ep_out;
@@ -613,69 +604,40 @@
usb->reaper_thread = 0;
usb->desc = unix_open(usb->fname, O_RDWR | O_CLOEXEC);
- if(usb->desc < 0) {
- /* if we fail, see if have read-only access */
+ if (usb->desc == -1) {
+ // Opening RW failed, so see if we have RO access.
usb->desc = unix_open(usb->fname, O_RDONLY | O_CLOEXEC);
- if(usb->desc < 0) goto fail;
+ if (usb->desc == -1) {
+ D("[ usb open %s failed: %s]\n", usb->fname, strerror(errno));
+ free(usb);
+ return;
+ }
usb->writeable = 0;
- D("[ usb open read-only %s fd = %d]\n", usb->fname, usb->desc);
- } else {
- D("[ usb open %s fd = %d]\n", usb->fname, usb->desc);
- n = ioctl(usb->desc, USBDEVFS_CLAIMINTERFACE, &interface);
- if(n != 0) goto fail;
}
- /* read the device's serial number */
- serial[0] = 0;
- memset(serial, 0, sizeof(serial));
- if (serial_index) {
- struct usbdevfs_ctrltransfer ctrl;
- __u16 buffer[128];
- __u16 languages[128];
- int i, result;
- int languageCount = 0;
+ D("[ usb opened %s%s, fd=%d]\n", usb->fname, (usb->writeable ? "" : " (read-only)"), usb->desc);
- memset(languages, 0, sizeof(languages));
- memset(&ctrl, 0, sizeof(ctrl));
-
- // read list of supported languages
- ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
- ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
- ctrl.wValue = (USB_DT_STRING << 8) | 0;
- ctrl.wIndex = 0;
- ctrl.wLength = sizeof(languages);
- ctrl.data = languages;
- ctrl.timeout = 1000;
-
- result = ioctl(usb->desc, USBDEVFS_CONTROL, &ctrl);
- if (result > 0)
- languageCount = (result - 2) / 2;
-
- for (i = 1; i <= languageCount; i++) {
- memset(buffer, 0, sizeof(buffer));
- memset(&ctrl, 0, sizeof(ctrl));
-
- ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
- ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
- ctrl.wValue = (USB_DT_STRING << 8) | serial_index;
- ctrl.wIndex = __le16_to_cpu(languages[i]);
- ctrl.wLength = sizeof(buffer);
- ctrl.data = buffer;
- ctrl.timeout = 1000;
-
- result = ioctl(usb->desc, USBDEVFS_CONTROL, &ctrl);
- if (result > 0) {
- int i;
- // skip first word, and copy the rest to the serial string, changing shorts to bytes.
- result /= 2;
- for (i = 1; i < result; i++)
- serial[i - 1] = __le16_to_cpu(buffer[i]);
- serial[i - 1] = 0;
- break;
- }
+ if (usb->writeable) {
+ if (ioctl(usb->desc, USBDEVFS_CLAIMINTERFACE, &interface) != 0) {
+ D("[ usb ioctl(%d, USBDEVFS_CLAIMINTERFACE) failed: %s]\n", usb->desc, strerror(errno));
+ adb_close(usb->desc);
+ free(usb);
+ return;
}
}
+ // 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;
+ 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;
+ }
+ serial = android::base::Trim(serial);
+
/* add to the end of the active handles */
adb_mutex_lock(&usb_lock);
usb->next = &handle_list;
@@ -684,19 +646,10 @@
usb->next->prev = usb;
adb_mutex_unlock(&usb_lock);
- register_usb_transport(usb, serial, devpath, usb->writeable);
- return;
-
-fail:
- D("[ usb open %s error=%d, err_str = %s]\n",
- usb->fname, errno, strerror(errno));
- if(usb->desc >= 0) {
- adb_close(usb->desc);
- }
- free(usb);
+ register_usb_transport(usb, serial.c_str(), dev_path, usb->writeable);
}
-void* device_poll_thread(void* unused)
+static void* device_poll_thread(void* unused)
{
D("Created device thread\n");
for(;;) {
diff --git a/adb/usb_linux_client.c b/adb/usb_linux_client.cpp
similarity index 91%
rename from adb/usb_linux_client.c
rename to adb/usb_linux_client.cpp
index 434451c..18289e2 100644
--- a/adb/usb_linux_client.c
+++ b/adb/usb_linux_client.cpp
@@ -18,6 +18,7 @@
#include "sysdeps.h"
+#include <cutils/properties.h>
#include <dirent.h>
#include <errno.h>
#include <linux/usb/ch9.h>
@@ -163,7 +164,7 @@
struct usb_handle *usb = (struct usb_handle *)x;
int fd;
- while (1) {
+ while (true) {
// wait until the USB device needs opening
adb_mutex_lock(&usb->lock);
while (usb->fd != -1)
@@ -239,11 +240,8 @@
static void usb_adb_init()
{
- usb_handle *h;
- adb_thread_t tid;
- int fd;
-
- h = calloc(1, sizeof(usb_handle));
+ usb_handle* h = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle)));
+ if (h == nullptr) fatal("couldn't allocate usb_handle");
h->write = usb_adb_write;
h->read = usb_adb_read;
@@ -253,12 +251,12 @@
adb_cond_init(&h->notify, 0);
adb_mutex_init(&h->lock, 0);
- // Open the file /dev/android_adb_enable to trigger
+ // Open the file /dev/android_adb_enable to trigger
// the enabling of the adb USB function in the kernel.
// We never touch this file again - just leave it open
// indefinitely so the kernel will know when we are running
// and when we are not.
- fd = unix_open("/dev/android_adb_enable", O_RDWR);
+ int fd = unix_open("/dev/android_adb_enable", O_RDWR);
if (fd < 0) {
D("failed to open /dev/android_adb_enable\n");
} else {
@@ -266,6 +264,7 @@
}
D("[ usb_init - starting thread ]\n");
+ adb_thread_t tid;
if(adb_thread_create(&tid, usb_adb_open_thread, h)){
fatal_errno("cannot create usb thread");
}
@@ -351,14 +350,14 @@
{
struct usb_handle *usb = (struct usb_handle *)x;
- while (1) {
+ while (true) {
// wait until the USB device needs opening
adb_mutex_lock(&usb->lock);
while (usb->control != -1 && usb->bulk_in != -1 && usb->bulk_out != -1)
adb_cond_wait(&usb->notify, &usb->lock);
adb_mutex_unlock(&usb->lock);
- while (1) {
+ while (true) {
init_functionfs(usb);
if (usb->control >= 0 && usb->bulk_in >= 0 && usb->bulk_out >= 0)
@@ -366,6 +365,7 @@
adb_sleep_ms(1000);
}
+ property_set("sys.usb.ffs.ready", "1");
D("[ usb_thread - registering device ]\n");
register_usb_transport(usb, 0, 0, 1);
@@ -375,7 +375,7 @@
return 0;
}
-static int bulk_write(int bulk_in, const char *buf, size_t length)
+static int bulk_write(int bulk_in, const uint8_t* buf, size_t length)
{
size_t count = 0;
int ret;
@@ -394,22 +394,19 @@
return count;
}
-static int usb_ffs_write(usb_handle *h, const void *data, int len)
+static int usb_ffs_write(usb_handle* h, const void* data, int len)
{
- int n;
-
D("about to write (fd=%d, len=%d)\n", h->bulk_in, len);
- n = bulk_write(h->bulk_in, data, len);
+ int n = bulk_write(h->bulk_in, reinterpret_cast<const uint8_t*>(data), len);
if (n != len) {
- D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
- h->bulk_in, n, errno, strerror(errno));
+ D("ERROR: fd = %d, n = %d: %s\n", h->bulk_in, n, strerror(errno));
return -1;
}
D("[ done fd=%d ]\n", h->bulk_in);
return 0;
}
-static int bulk_read(int bulk_out, char *buf, size_t length)
+static int bulk_read(int bulk_out, uint8_t* buf, size_t length)
{
size_t count = 0;
int ret;
@@ -430,15 +427,12 @@
return count;
}
-static int usb_ffs_read(usb_handle *h, void *data, int len)
+static int usb_ffs_read(usb_handle* h, void* data, int len)
{
- int n;
-
D("about to read (fd=%d, len=%d)\n", h->bulk_out, len);
- n = bulk_read(h->bulk_out, data, len);
+ int n = bulk_read(h->bulk_out, reinterpret_cast<uint8_t*>(data), len);
if (n != len) {
- D("ERROR: fd = %d, n = %d, errno = %d (%s)\n",
- h->bulk_out, n, errno, strerror(errno));
+ D("ERROR: fd = %d, n = %d: %s\n", h->bulk_out, n, strerror(errno));
return -1;
}
D("[ done fd=%d ]\n", h->bulk_out);
@@ -473,18 +467,15 @@
static void usb_ffs_init()
{
- usb_handle *h;
- adb_thread_t tid;
-
D("[ usb_init - using FunctionFS ]\n");
- h = calloc(1, sizeof(usb_handle));
+ usb_handle* h = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle)));
+ if (h == nullptr) fatal("couldn't allocate usb_handle");
h->write = usb_ffs_write;
h->read = usb_ffs_read;
h->kick = usb_ffs_kick;
-
- h->control = -1;
+ h->control = -1;
h->bulk_out = -1;
h->bulk_out = -1;
@@ -492,6 +483,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)){
fatal_errno("[ cannot create usb thread ]\n");
}
diff --git a/adb/usb_osx.c b/adb/usb_osx.cpp
similarity index 95%
rename from adb/usb_osx.c
rename to adb/usb_osx.cpp
index 94c8cfe..a795ce3 100644
--- a/adb/usb_osx.c
+++ b/adb/usb_osx.cpp
@@ -26,6 +26,7 @@
#include <IOKit/IOMessage.h>
#include <mach/mach_port.h>
+#include <inttypes.h>
#include <stdio.h>
#include "adb.h"
@@ -111,7 +112,7 @@
HRESULT result;
SInt32 score;
UInt32 locationId;
- UInt8 class, subclass, protocol;
+ UInt8 if_class, subclass, protocol;
UInt16 vendor;
UInt16 product;
UInt8 serialIndex;
@@ -132,9 +133,9 @@
}
//* This gets us the interface object
- result = (*plugInInterface)->QueryInterface(plugInInterface,
- CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID)
- &iface);
+ result = (*plugInInterface)->QueryInterface(
+ plugInInterface,
+ CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID*)&iface);
//* We only needed the plugin to get the interface, so discard it
(*plugInInterface)->Release(plugInInterface);
if (result || !iface) {
@@ -142,12 +143,12 @@
continue;
}
- kr = (*iface)->GetInterfaceClass(iface, &class);
+ kr = (*iface)->GetInterfaceClass(iface, &if_class);
kr = (*iface)->GetInterfaceSubClass(iface, &subclass);
kr = (*iface)->GetInterfaceProtocol(iface, &protocol);
- if(class != ADB_CLASS || subclass != ADB_SUBCLASS || protocol != ADB_PROTOCOL) {
+ if(if_class != ADB_CLASS || subclass != ADB_SUBCLASS || protocol != ADB_PROTOCOL) {
// Ignore non-ADB devices.
- DBG("Ignoring interface with incorrect class/subclass/protocol - %d, %d, %d\n", class, subclass, protocol);
+ DBG("Ignoring interface with incorrect class/subclass/protocol - %d, %d, %d\n", if_class, subclass, protocol);
(*iface)->Release(iface);
continue;
}
@@ -177,7 +178,7 @@
}
result = (*plugInInterface)->QueryInterface(plugInInterface,
- CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID) &dev);
+ CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID*)&dev);
//* only needed this to query the plugin
(*plugInInterface)->Release(plugInInterface);
if (result || !dev) {
@@ -334,7 +335,8 @@
interfaceSubClass, interfaceProtocol))
goto err_bad_adb_interface;
- handle = calloc(1, sizeof(usb_handle));
+ handle = reinterpret_cast<usb_handle*>(calloc(1, sizeof(usb_handle)));
+ if (handle == nullptr) goto err_bad_adb_interface;
//* Iterate over the endpoints for this interface and find the first
//* bulk in/out pipes available. These will be our read/write pipes.
diff --git a/base/file.cpp b/base/file.cpp
index a51c5ff..6b19818 100644
--- a/base/file.cpp
+++ b/base/file.cpp
@@ -120,5 +120,29 @@
return result || CleanUpAfterFailedWrite(path);
}
+bool ReadFully(int fd, void* data, size_t byte_count) {
+ uint8_t* p = reinterpret_cast<uint8_t*>(data);
+ size_t remaining = byte_count;
+ while (remaining > 0) {
+ ssize_t n = TEMP_FAILURE_RETRY(read(fd, p, remaining));
+ if (n <= 0) return false;
+ p += n;
+ remaining -= n;
+ }
+ return true;
+}
+
+bool WriteFully(int fd, const void* data, size_t byte_count) {
+ const uint8_t* p = reinterpret_cast<const uint8_t*>(data);
+ size_t remaining = byte_count;
+ while (remaining > 0) {
+ ssize_t n = TEMP_FAILURE_RETRY(write(fd, p, remaining));
+ if (n == -1) return false;
+ p += n;
+ remaining -= n;
+ }
+ return true;
+}
+
} // namespace base
} // namespace android
diff --git a/base/file_test.cpp b/base/file_test.cpp
index fc48b32..e5cf696 100644
--- a/base/file_test.cpp
+++ b/base/file_test.cpp
@@ -79,3 +79,28 @@
ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)) << errno;
EXPECT_EQ("abc", s);
}
+
+TEST(file, ReadFully) {
+ int fd = open("/proc/version", O_RDONLY);
+ ASSERT_NE(-1, fd) << strerror(errno);
+
+ char buf[1024];
+ memset(buf, 0, sizeof(buf));
+ ASSERT_TRUE(android::base::ReadFully(fd, buf, 5));
+ ASSERT_STREQ("Linux", buf);
+
+ ASSERT_EQ(0, lseek(fd, 0, SEEK_SET)) << strerror(errno);
+
+ ASSERT_FALSE(android::base::ReadFully(fd, buf, sizeof(buf)));
+
+ close(fd);
+}
+
+TEST(file, WriteFully) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+ ASSERT_TRUE(android::base::WriteFully(tf.fd, "abc", 3));
+ std::string s;
+ ASSERT_TRUE(android::base::ReadFileToString(tf.filename, &s)) << errno;
+ EXPECT_EQ("abc", s);
+}
diff --git a/base/include/base/file.h b/base/include/base/file.h
index ef97742..acd29b3 100644
--- a/base/include/base/file.h
+++ b/base/include/base/file.h
@@ -34,6 +34,9 @@
mode_t mode, uid_t owner, gid_t group);
#endif
+bool ReadFully(int fd, void* data, size_t byte_count);
+bool WriteFully(int fd, const void* data, size_t byte_count);
+
} // namespace base
} // namespace android
diff --git a/base/include/base/strings.h b/base/include/base/strings.h
index ab56aad..5dbc5fb 100644
--- a/base/include/base/strings.h
+++ b/base/include/base/strings.h
@@ -25,9 +25,7 @@
// Splits a string into a vector of strings.
//
-// The string is split at each occurence of a character in delimiters.
-//
-// Empty splits will be omitted. I.e. Split("a,,b", ",") -> {"a", "b"}
+// The string is split at each occurrence of a character in delimiters.
//
// The empty string is not a valid delimiter list.
std::vector<std::string> Split(const std::string& s,
diff --git a/base/strings.cpp b/base/strings.cpp
index 6f698d9..d3375d9 100644
--- a/base/strings.cpp
+++ b/base/strings.cpp
@@ -32,24 +32,17 @@
const std::string& delimiters) {
CHECK_NE(delimiters.size(), 0U);
- std::vector<std::string> split;
- if (s.size() == 0) {
- // Split("", d) returns {} rather than {""}.
- return split;
- }
+ std::vector<std::string> result;
size_t base = 0;
size_t found;
do {
found = s.find_first_of(delimiters, base);
- if (found != base) {
- split.push_back(s.substr(base, found - base));
- }
-
+ result.push_back(s.substr(base, found - base));
base = found + 1;
} while (found != s.npos);
- return split;
+ return result;
}
std::string Trim(const std::string& s) {
diff --git a/base/strings_test.cpp b/base/strings_test.cpp
index 1bf07a1..46a1ab5 100644
--- a/base/strings_test.cpp
+++ b/base/strings_test.cpp
@@ -23,7 +23,8 @@
TEST(strings, split_empty) {
std::vector<std::string> parts = android::base::Split("", ",");
- ASSERT_EQ(0U, parts.size());
+ ASSERT_EQ(1U, parts.size());
+ ASSERT_EQ("", parts[0]);
}
TEST(strings, split_single) {
@@ -42,9 +43,10 @@
TEST(strings, split_with_empty_part) {
std::vector<std::string> parts = android::base::Split("foo,,bar", ",");
- ASSERT_EQ(2U, parts.size());
+ ASSERT_EQ(3U, parts.size());
ASSERT_EQ("foo", parts[0]);
- ASSERT_EQ("bar", parts[1]);
+ ASSERT_EQ("", parts[1]);
+ ASSERT_EQ("bar", parts[2]);
}
TEST(strings, split_null_char) {
@@ -65,9 +67,10 @@
TEST(strings, split_any_with_empty_part) {
std::vector<std::string> parts = android::base::Split("foo:,bar", ",:");
- ASSERT_EQ(2U, parts.size());
+ ASSERT_EQ(3U, parts.size());
ASSERT_EQ("foo", parts[0]);
- ASSERT_EQ("bar", parts[1]);
+ ASSERT_EQ("", parts[1]);
+ ASSERT_EQ("bar", parts[2]);
}
TEST(strings, trim_empty) {
diff --git a/debuggerd/utility.cpp b/debuggerd/utility.cpp
index e10feff..d6a6d2e 100644
--- a/debuggerd/utility.cpp
+++ b/debuggerd/utility.cpp
@@ -26,25 +26,12 @@
#include <sys/wait.h>
#include <backtrace/Backtrace.h>
+#include <base/file.h>
#include <log/log.h>
const int SLEEP_TIME_USEC = 50000; // 0.05 seconds
const int MAX_TOTAL_SLEEP_USEC = 10000000; // 10 seconds
-static int write_to_am(int fd, const char* buf, int len) {
- int to_write = len;
- while (to_write > 0) {
- int written = TEMP_FAILURE_RETRY(write(fd, buf + len - to_write, to_write));
- if (written < 0) {
- // hard failure
- ALOGE("AM write failure (%d / %s)\n", errno, strerror(errno));
- return -1;
- }
- to_write -= written;
- }
- return len;
-}
-
// Whitelist output desired in the logcat output.
bool is_allowed_in_logcat(enum logtype ltype) {
if ((ltype == ERROR)
@@ -82,9 +69,9 @@
if (write_to_logcat) {
__android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_INFO, LOG_TAG, buf);
if (write_to_activitymanager) {
- int written = write_to_am(log->amfd, buf, len);
- if (written <= 0) {
+ if (!android::base::WriteFully(log->amfd, buf, len)) {
// timeout or other failure on write; stop informing the activity manager
+ ALOGE("AM write failed: %s", strerror(errno));
log->amfd = -1;
}
}
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index b9e957f..dee471a 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -58,7 +58,8 @@
libsparse_host \
libutils \
liblog \
- libz
+ libz \
+ libbase
ifneq ($(HOST_OS),windows)
LOCAL_STATIC_LIBRARIES += libselinux
@@ -74,6 +75,16 @@
LOCAL_STATIC_LIBRARIES += libf2fs_utils_host libf2fs_ioutils_host libf2fs_dlutils_host
endif
+# libc++ not available on windows yet
+ifneq ($(HOST_OS),windows)
+ LOCAL_CXX_STL := libc++_static
+endif
+
+# Don't add anything here, we don't want additional shared dependencies
+# on the host fastboot tool, and shared libraries that link against libc++
+# will violate ODR
+LOCAL_SHARED_LIBRARIES :=
+
include $(BUILD_HOST_EXECUTABLE)
my_dist_files := $(LOCAL_BUILT_MODULE)
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index 273a2ec..d5e94ac 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -31,7 +31,7 @@
#include <dirent.h>
#include <ext4.h>
#include <ext4_sb.h>
-#include <ext4_crypt.h>
+#include <ext4_crypt_init_extensions.h>
#include <linux/loop.h>
#include <private/android_filesystem_config.h>
@@ -117,8 +117,10 @@
* filesytsem due to an error, e2fsck is still run to do a full check
* fix the filesystem.
*/
+ errno = 0;
ret = mount(blk_device, target, fs_type, tmpmnt_flags, tmpmnt_opts);
- INFO("%s(): mount(%s,%s,%s)=%d\n", __func__, blk_device, target, fs_type, ret);
+ INFO("%s(): mount(%s,%s,%s)=%d: %s\n",
+ __func__, blk_device, target, fs_type, ret, strerror(errno));
if (!ret) {
int i;
for (i = 0; i < 5; i++) {
@@ -126,6 +128,7 @@
// Should we try rebooting if all attempts fail?
int result = umount(target);
if (result == 0) {
+ INFO("%s(): unmount(%s) succeeded\n", __func__, target);
break;
}
ERROR("%s(): umount(%s)=%d: %s\n", __func__, target, result, strerror(errno));
@@ -480,16 +483,6 @@
return FS_MGR_MNTALL_FAIL;
}
- // Link it to the normal place so ext4_crypt functions work normally
- strlcat(tmp_mnt, "/unencrypted", sizeof(tmp_mnt));
- char link_path[PATH_MAX];
- strlcpy(link_path, rec->mount_point, sizeof(link_path));
- strlcat(link_path, "/unencrypted", sizeof(link_path));
- if (symlink(tmp_mnt, link_path)) {
- ERROR("Error creating symlink to unencrypted directory\n");
- return FS_MGR_MNTALL_FAIL;
- }
-
return FS_MGR_MNTALL_DEV_NON_DEFAULT_FILE_ENCRYPTED;
}
diff --git a/include/cutils/dir_hash.h b/include/cutils/dir_hash.h
deleted file mode 100644
index fbb4d02..0000000
--- a/include/cutils/dir_hash.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-typedef enum {
- SHA_1,
-} HashAlgorithm;
-
-int get_file_hash(HashAlgorithm algorithm, const char *path,
- char *output_string, size_t max_output_string);
-
-int get_recursive_hash_manifest(HashAlgorithm algorithm,
- const char *directory_path,
- char **output_string);
diff --git a/include/cutils/partition_utils.h b/include/cutils/partition_utils.h
index 597df92..72ca80d 100644
--- a/include/cutils/partition_utils.h
+++ b/include/cutils/partition_utils.h
@@ -20,7 +20,6 @@
__BEGIN_DECLS
int partition_wiped(char *source);
-void erase_footer(const char *dev_path, long long size);
__END_DECLS
diff --git a/include/cutils/trace.h b/include/cutils/trace.h
index 9d039e6..e4ed179 100644
--- a/include/cutils/trace.h
+++ b/include/cutils/trace.h
@@ -18,6 +18,7 @@
#define _LIBS_CUTILS_TRACE_H
#include <inttypes.h>
+#include <stdatomic.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
@@ -25,7 +26,6 @@
#include <sys/types.h>
#include <unistd.h>
-#include <cutils/atomic.h>
#include <cutils/compiler.h>
__BEGIN_DECLS
@@ -113,7 +113,7 @@
* Nonzero indicates setup has completed.
* Note: This does NOT indicate whether or not setup was successful.
*/
-extern volatile int32_t atrace_is_ready;
+extern atomic_bool atrace_is_ready;
/**
* Set of ATRACE_TAG flags to trace for, initialized to ATRACE_TAG_NOT_READY.
@@ -136,7 +136,7 @@
#define ATRACE_INIT() atrace_init()
static inline void atrace_init()
{
- if (CC_UNLIKELY(!android_atomic_acquire_load(&atrace_is_ready))) {
+ if (CC_UNLIKELY(!atomic_load_explicit(&atrace_is_ready, memory_order_acquire))) {
atrace_setup();
}
}
diff --git a/include/log/log.h b/include/log/log.h
index ce253e2..f9299b0 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -492,6 +492,7 @@
EVENT_TYPE_LONG = 1,
EVENT_TYPE_STRING = 2,
EVENT_TYPE_LIST = 3,
+ EVENT_TYPE_FLOAT = 4,
} AndroidEventLogType;
#define sizeof_AndroidEventLogType sizeof(typeof_AndroidEventLogType)
#define typeof_AndroidEventLogType unsigned char
@@ -510,6 +511,13 @@
sizeof(longBuf)); \
}
#endif
+#ifndef LOG_EVENT_FLOAT
+#define LOG_EVENT_FLOAT(_tag, _value) { \
+ float floatBuf = _value; \
+ (void) android_btWriteLog(_tag, EVENT_TYPE_FLOAT, &floatBuf, \
+ sizeof(floatBuf)); \
+ }
+#endif
#ifndef LOG_EVENT_STRING
#define LOG_EVENT_STRING(_tag, _value) \
(void) __android_log_bswrite(_tag, _value);
diff --git a/include/memtrack/memtrack.h b/include/memtrack/memtrack.h
index 0f1f85e..3917300 100644
--- a/include/memtrack/memtrack.h
+++ b/include/memtrack/memtrack.h
@@ -121,7 +121,7 @@
ssize_t memtrack_proc_gl_pss(struct memtrack_proc *p);
/**
- * memtrack_proc_gl_total
+ * memtrack_proc_other_total
*
* Same as memtrack_proc_graphics_total, but counts miscellaneous memory
* not tracked by gl or graphics calls above.
@@ -131,7 +131,7 @@
ssize_t memtrack_proc_other_total(struct memtrack_proc *p);
/**
- * memtrack_proc_gl_pss
+ * memtrack_proc_other_pss
*
* Same as memtrack_proc_graphics_total, but counts miscellaneous memory
* not tracked by gl or graphics calls above.
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index fed81f8..02fe2b5 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -215,6 +215,8 @@
void fs_config(const char *path, int dir,
unsigned *uid, unsigned *gid, unsigned *mode, uint64_t *capabilities);
+ssize_t fs_config_generate(char *buffer, size_t length, const struct fs_path_config *pc);
+
__END_DECLS
#endif
diff --git a/include/utils/Timers.h b/include/utils/Timers.h
index d015421..54ec474 100644
--- a/include/utils/Timers.h
+++ b/include/utils/Timers.h
@@ -24,6 +24,8 @@
#include <sys/types.h>
#include <sys/time.h>
+#include <utils/Compat.h>
+
// ------------------------------------------------------------------
// C API
@@ -33,46 +35,46 @@
typedef int64_t nsecs_t; // nano-seconds
-static inline nsecs_t seconds_to_nanoseconds(nsecs_t secs)
+static CONSTEXPR inline nsecs_t seconds_to_nanoseconds(nsecs_t secs)
{
return secs*1000000000;
}
-static inline nsecs_t milliseconds_to_nanoseconds(nsecs_t secs)
+static CONSTEXPR inline nsecs_t milliseconds_to_nanoseconds(nsecs_t secs)
{
return secs*1000000;
}
-static inline nsecs_t microseconds_to_nanoseconds(nsecs_t secs)
+static CONSTEXPR inline nsecs_t microseconds_to_nanoseconds(nsecs_t secs)
{
return secs*1000;
}
-static inline nsecs_t nanoseconds_to_seconds(nsecs_t secs)
+static CONSTEXPR inline nsecs_t nanoseconds_to_seconds(nsecs_t secs)
{
return secs/1000000000;
}
-static inline nsecs_t nanoseconds_to_milliseconds(nsecs_t secs)
+static CONSTEXPR inline nsecs_t nanoseconds_to_milliseconds(nsecs_t secs)
{
return secs/1000000;
}
-static inline nsecs_t nanoseconds_to_microseconds(nsecs_t secs)
+static CONSTEXPR inline nsecs_t nanoseconds_to_microseconds(nsecs_t secs)
{
return secs/1000;
}
-static inline nsecs_t s2ns(nsecs_t v) {return seconds_to_nanoseconds(v);}
-static inline nsecs_t ms2ns(nsecs_t v) {return milliseconds_to_nanoseconds(v);}
-static inline nsecs_t us2ns(nsecs_t v) {return microseconds_to_nanoseconds(v);}
-static inline nsecs_t ns2s(nsecs_t v) {return nanoseconds_to_seconds(v);}
-static inline nsecs_t ns2ms(nsecs_t v) {return nanoseconds_to_milliseconds(v);}
-static inline nsecs_t ns2us(nsecs_t v) {return nanoseconds_to_microseconds(v);}
+static CONSTEXPR inline nsecs_t s2ns(nsecs_t v) {return seconds_to_nanoseconds(v);}
+static CONSTEXPR inline nsecs_t ms2ns(nsecs_t v) {return milliseconds_to_nanoseconds(v);}
+static CONSTEXPR inline nsecs_t us2ns(nsecs_t v) {return microseconds_to_nanoseconds(v);}
+static CONSTEXPR inline nsecs_t ns2s(nsecs_t v) {return nanoseconds_to_seconds(v);}
+static CONSTEXPR inline nsecs_t ns2ms(nsecs_t v) {return nanoseconds_to_milliseconds(v);}
+static CONSTEXPR inline nsecs_t ns2us(nsecs_t v) {return nanoseconds_to_microseconds(v);}
-static inline nsecs_t seconds(nsecs_t v) { return s2ns(v); }
-static inline nsecs_t milliseconds(nsecs_t v) { return ms2ns(v); }
-static inline nsecs_t microseconds(nsecs_t v) { return us2ns(v); }
+static CONSTEXPR inline nsecs_t seconds(nsecs_t v) { return s2ns(v); }
+static CONSTEXPR inline nsecs_t milliseconds(nsecs_t v) { return ms2ns(v); }
+static CONSTEXPR inline nsecs_t microseconds(nsecs_t v) { return us2ns(v); }
enum {
SYSTEM_TIME_REALTIME = 0, // system-wide realtime clock
diff --git a/init/Android.mk b/init/Android.mk
index 4bd4f3d..0dc257d 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -5,9 +5,9 @@
# --
ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
-init_options += -DALLOW_LOCAL_PROP_OVERRIDE=1 -DALLOW_DISABLE_SELINUX=1
+init_options += -DALLOW_LOCAL_PROP_OVERRIDE=1 -DALLOW_PERMISSIVE_SELINUX=1
else
-init_options += -DALLOW_LOCAL_PROP_OVERRIDE=0 -DALLOW_DISABLE_SELINUX=0
+init_options += -DALLOW_LOCAL_PROP_OVERRIDE=0 -DALLOW_PERMISSIVE_SELINUX=0
endif
init_options += -DLOG_UEVENTS=0
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 3bbaf83..d772383 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -29,7 +29,7 @@
#include <sys/wait.h>
#include <unistd.h>
#include <linux/loop.h>
-#include <ext4_crypt.h>
+#include <ext4_crypt_init_extensions.h>
#include <selinux/selinux.h>
#include <selinux/label.h>
@@ -386,18 +386,6 @@
}
/*
- * Callback to make a directory from the ext4 code
- */
-static int do_mount_alls_make_dir(const char* dir)
-{
- if (make_dir(dir, 0700) && errno != EEXIST) {
- return -1;
- }
-
- return 0;
-}
-
-/*
* This function might request a reboot, in which case it will
* not return.
*/
@@ -452,6 +440,7 @@
property_set("vold.decrypt", "trigger_encryption");
} else if (ret == FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED) {
property_set("ro.crypto.state", "encrypted");
+ property_set("ro.crypto.type", "block");
property_set("vold.decrypt", "trigger_default_encryption");
} else if (ret == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
property_set("ro.crypto.state", "unencrypted");
@@ -465,26 +454,11 @@
ret = wipe_data_via_recovery();
/* If reboot worked, there is no return. */
} else if (ret == FS_MGR_MNTALL_DEV_DEFAULT_FILE_ENCRYPTED) {
- // We have to create the key files here. Only init can call make_dir,
- // and we can't do it from fs_mgr as then fs_mgr would depend on
- // make_dir creating a circular dependency.
- fstab = fs_mgr_read_fstab(args[1]);
- for (int i = 0; i < fstab->num_entries; ++i) {
- if (fs_mgr_is_file_encrypted(&fstab->recs[i])) {
- if (e4crypt_create_device_key(fstab->recs[i].mount_point,
- do_mount_alls_make_dir)) {
- ERROR("Could not create device key on %s"
- " - continue unencrypted\n",
- fstab->recs[i].mount_point);
- }
- }
- }
- fs_mgr_free_fstab(fstab);
-
if (e4crypt_install_keyring()) {
return -1;
}
property_set("ro.crypto.state", "encrypted");
+ property_set("ro.crypto.type", "file");
// Although encrypted, we have device key, so we do not need to
// do anything different from the nonencrypted case.
@@ -494,6 +468,7 @@
return -1;
}
property_set("ro.crypto.state", "encrypted");
+ property_set("ro.crypto.type", "file");
property_set("vold.decrypt", "trigger_restart_min_framework");
} else if (ret > 0) {
ERROR("fs_mgr_mount_all returned unexpected error %d\n", ret);
@@ -515,15 +490,6 @@
return ret;
}
-int do_setcon(int nargs, char **args) {
- if (is_selinux_enabled() <= 0)
- return 0;
- if (setcon(args[1]) < 0) {
- return -errno;
- }
- return 0;
-}
-
int do_setprop(int nargs, char **args)
{
const char *name = args[1];
@@ -849,11 +815,30 @@
return -1;
}
-int do_installkey(int nargs, char **args)
+/*
+ * Callback to make a directory from the ext4 code
+ */
+static int do_installkeys_ensure_dir_exists(const char* dir)
{
- if (nargs == 2) {
- return e4crypt_install_key(args[1]);
+ if (make_dir(dir, 0700) && errno != EEXIST) {
+ return -1;
}
- return -1;
+ return 0;
+}
+
+int do_installkey(int nargs, char **args)
+{
+ if (nargs != 2) {
+ return -1;
+ }
+
+ char prop_value[PROP_VALUE_MAX] = {0};
+ property_get("ro.crypto.type", prop_value);
+ if (strcmp(prop_value, "file")) {
+ return 0;
+ }
+
+ return e4crypt_create_device_key(args[1],
+ do_installkeys_ensure_dir_exists);
}
diff --git a/init/devices.cpp b/init/devices.cpp
index 96b1696..2c7f5a9 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -266,7 +266,6 @@
static void add_platform_device(const char *path)
{
int path_len = strlen(path);
- struct listnode *node;
struct platform_node *bus;
const char *name = path;
@@ -276,15 +275,6 @@
name += 9;
}
- list_for_each_reverse(node, &platform_names) {
- bus = node_to_item(node, struct platform_node, list);
- if ((bus->path_len < path_len) &&
- (path[bus->path_len] == '/') &&
- !strncmp(path, bus->path, bus->path_len))
- /* subdevice of an existing platform, ignore it */
- return;
- }
-
INFO("adding platform device %s (%s)\n", name, path);
bus = (platform_node*) calloc(1, sizeof(struct platform_node));
diff --git a/init/init.cpp b/init/init.cpp
index b1d65db..68c8b7f 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -25,8 +25,8 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/epoll.h>
#include <sys/mount.h>
-#include <sys/poll.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -82,6 +82,17 @@
bool waiting_for_exec = false;
+static int epoll_fd = -1;
+
+void register_epoll_handler(int fd, void (*fn)()) {
+ epoll_event ev;
+ ev.events = EPOLLIN;
+ ev.data.ptr = reinterpret_cast<void*>(fn);
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {
+ ERROR("epoll_ctl failed: %s\n", strerror(errno));
+ }
+}
+
void service::NotifyStateChange(const char* new_state) {
if (!properties_initialized()) {
// If properties aren't available yet, we can't set them.
@@ -603,14 +614,16 @@
}
}
-static int wait_for_coldboot_done_action(int nargs, char **args)
-{
- int ret;
- INFO("wait for %s\n", COLDBOOT_DONE);
- ret = wait_for_file(COLDBOOT_DONE, COMMAND_RETRY_TIMEOUT);
- if (ret)
+static int wait_for_coldboot_done_action(int nargs, char **args) {
+ Timer t;
+
+ NOTICE("Waiting for %s...\n", COLDBOOT_DONE);
+ if (wait_for_file(COLDBOOT_DONE, COMMAND_RETRY_TIMEOUT)) {
ERROR("Timed out waiting for %s\n", COLDBOOT_DONE);
- return ret;
+ }
+
+ NOTICE("Waiting for %s took %.2fs.\n", COLDBOOT_DONE, t.duration());
+ return 0;
}
/*
@@ -733,7 +746,7 @@
return 0;
}
-static void import_kernel_nv(char *name, int for_emulator)
+static void import_kernel_nv(char *name, bool for_emulator)
{
char *value = strchr(name, '=');
int name_len = strlen(name);
@@ -827,35 +840,9 @@
* second pass is only necessary for qemu to export all kernel params
* as props.
*/
- import_kernel_cmdline(0, import_kernel_nv);
+ import_kernel_cmdline(false, import_kernel_nv);
if (qemu[0])
- import_kernel_cmdline(1, import_kernel_nv);
-}
-
-static int property_service_init_action(int nargs, char **args)
-{
- /* read any property files on system or data and
- * fire up the property service. This must happen
- * after the ro.foo properties are set above so
- * that /data/local.prop cannot interfere with them.
- */
- start_property_service();
- if (get_property_set_fd() < 0) {
- ERROR("start_property_service() failed\n");
- exit(1);
- }
-
- return 0;
-}
-
-static int signal_init_action(int nargs, char **args)
-{
- signal_init();
- if (get_signal_fd() < 0) {
- ERROR("signal_init() failed\n");
- exit(1);
- }
- return 0;
+ import_kernel_cmdline(true, import_kernel_nv);
}
static int queue_property_triggers_action(int nargs, char **args)
@@ -866,59 +853,43 @@
return 0;
}
-void selinux_init_all_handles(void)
+static void selinux_init_all_handles(void)
{
sehandle = selinux_android_file_context_handle();
selinux_android_set_sehandle(sehandle);
sehandle_prop = selinux_android_prop_context_handle();
}
-static bool selinux_is_disabled(void)
-{
- if (ALLOW_DISABLE_SELINUX) {
- if (access("/sys/fs/selinux", F_OK) != 0) {
- // SELinux is not compiled into the kernel, or has been disabled
- // via the kernel command line "selinux=0".
- return true;
- }
+enum selinux_enforcing_status { SELINUX_PERMISSIVE, SELINUX_ENFORCING };
- char tmp[PROP_VALUE_MAX];
- if ((property_get("ro.boot.selinux", tmp) != 0) && (strcmp(tmp, "disabled") == 0)) {
- // SELinux is compiled into the kernel, but we've been told to disable it.
- return true;
- }
- }
+static selinux_enforcing_status selinux_status_from_cmdline() {
+ selinux_enforcing_status status = SELINUX_ENFORCING;
- return false;
+ 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, fn);
+
+ return status;
}
static bool selinux_is_enforcing(void)
{
- if (ALLOW_DISABLE_SELINUX) {
- char tmp[PROP_VALUE_MAX];
- if (property_get("ro.boot.selinux", tmp) == 0) {
- // Property is not set. Assume enforcing.
- return true;
- }
-
- if (strcmp(tmp, "permissive") == 0) {
- // SELinux is in the kernel, but we've been told to go into permissive mode.
- return false;
- }
-
- if (strcmp(tmp, "enforcing") != 0) {
- ERROR("SELinux: Unknown value of ro.boot.selinux. Got: \"%s\". Assuming enforcing.\n", tmp);
- }
+ if (ALLOW_PERMISSIVE_SELINUX) {
+ return selinux_status_from_cmdline() == SELINUX_ENFORCING;
}
return true;
}
int selinux_reload_policy(void)
{
- if (selinux_is_disabled()) {
- return -1;
- }
-
INFO("SELinux: Attempting to reload policy files\n");
if (selinux_android_reload_policy() == -1) {
@@ -940,7 +911,13 @@
return 0;
}
-static void selinux_initialize() {
+static void security_failure() {
+ ERROR("Security failure; rebooting into recovery mode...\n");
+ android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
+ while (true) { pause(); } // never reached
+}
+
+static void selinux_initialize(bool in_kernel_domain) {
Timer t;
selinux_callback cb;
@@ -949,23 +926,32 @@
cb.func_audit = audit_callback;
selinux_set_callback(SELINUX_CB_AUDIT, cb);
- if (selinux_is_disabled()) {
- return;
+ if (in_kernel_domain) {
+ INFO("Loading SELinux policy...\n");
+ if (selinux_android_load_policy() < 0) {
+ ERROR("failed to load policy: %s\n", strerror(errno));
+ security_failure();
+ }
+
+ bool kernel_enforcing = (security_getenforce() == 1);
+ bool is_enforcing = selinux_is_enforcing();
+ if (kernel_enforcing != is_enforcing) {
+ if (security_setenforce(is_enforcing)) {
+ ERROR("security_setenforce(%s) failed: %s\n",
+ is_enforcing ? "true" : "false", strerror(errno));
+ security_failure();
+ }
+ }
+
+ if (write_file("/sys/fs/selinux/checkreqprot", "0") == -1) {
+ security_failure();
+ }
+
+ NOTICE("(Initializing SELinux %s took %.2fs.)\n",
+ is_enforcing ? "enforcing" : "non-enforcing", t.duration());
+ } else {
+ selinux_init_all_handles();
}
-
- INFO("Loading SELinux policy...\n");
- if (selinux_android_load_policy() < 0) {
- ERROR("SELinux: Failed to load policy; rebooting into recovery mode\n");
- android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
- while (1) { pause(); } // never reached
- }
-
- selinux_init_all_handles();
- bool is_enforcing = selinux_is_enforcing();
- INFO("SELinux: security_setenforce(%d)\n", is_enforcing);
- security_setenforce(is_enforcing);
-
- NOTICE("(Initializing SELinux took %.2fs.)\n", t.duration());
}
int main(int argc, char** argv) {
@@ -982,21 +968,18 @@
add_environment("PATH", _PATH_DEFPATH);
+ bool is_first_stage = (argc == 1) || (strcmp(argv[1], "--second-stage") != 0);
+
// Get the basic filesystem setup we need put together in the initramdisk
// on / and then we'll let the rc file figure out the rest.
- mkdir("/dev", 0755);
- mkdir("/proc", 0755);
- mkdir("/sys", 0755);
-
- mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
- mkdir("/dev/pts", 0755);
- mkdir("/dev/socket", 0755);
- mount("devpts", "/dev/pts", "devpts", 0, NULL);
- mount("proc", "/proc", "proc", 0, NULL);
- mount("sysfs", "/sys", "sysfs", 0, NULL);
-
- // Indicate that booting is in progress to background fw loaders, etc.
- close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
+ if (is_first_stage) {
+ mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
+ mkdir("/dev/pts", 0755);
+ mkdir("/dev/socket", 0755);
+ mount("devpts", "/dev/pts", "devpts", 0, NULL);
+ mount("proc", "/proc", "proc", 0, NULL);
+ mount("sysfs", "/sys", "sysfs", 0, NULL);
+ }
// We must have some place other than / to create the device nodes for
// kmsg and null, otherwise we won't be able to remount / read-only
@@ -1006,20 +989,41 @@
klog_init();
klog_set_level(KLOG_NOTICE_LEVEL);
- NOTICE("init started!\n");
+ NOTICE("init%s started!\n", is_first_stage ? "" : " second stage");
- property_init();
+ if (!is_first_stage) {
+ // Indicate that booting is in progress to background fw loaders, etc.
+ close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
- // If arguments are passed both on the command line and in DT,
- // properties set in DT always have priority over the command-line ones.
- process_kernel_dt();
- process_kernel_cmdline();
+ property_init();
- // Propogate the kernel variables to internal variables
- // used by init as well as the current required properties.
- export_kernel_boot_props();
+ // If arguments are passed both on the command line and in DT,
+ // properties set in DT always have priority over the command-line ones.
+ process_kernel_dt();
+ process_kernel_cmdline();
- selinux_initialize();
+ // Propogate the kernel variables to internal variables
+ // used by init as well as the current required properties.
+ export_kernel_boot_props();
+ }
+
+ // Set up SELinux, including loading the SELinux policy if we're in the kernel domain.
+ selinux_initialize(is_first_stage);
+
+ // If we're in the kernel domain, re-exec init to transition to the init domain now
+ // that the SELinux policy has been loaded.
+ if (is_first_stage) {
+ if (restorecon("/init") == -1) {
+ ERROR("restorecon failed: %s\n", strerror(errno));
+ security_failure();
+ }
+ char* path = argv[0];
+ char* args[] = { path, const_cast<char*>("--second-stage"), nullptr };
+ if (execv(path, args) == -1) {
+ ERROR("execv(\"%s\") failed: %s\n", path, strerror(errno));
+ security_failure();
+ }
+ }
// These directories were necessarily created before initial policy load
// and therefore need their security context restored to the proper value.
@@ -1030,13 +1034,24 @@
restorecon("/dev/__properties__");
restorecon_recursive("/sys");
+ epoll_fd = epoll_create1(EPOLL_CLOEXEC);
+ if (epoll_fd == -1) {
+ ERROR("epoll_create1 failed: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ signal_handler_init();
+
property_load_boot_defaults();
+ start_property_service();
init_parse_config_file("/init.rc");
action_for_each_trigger("early-init", action_add_queue_tail);
+ // Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");
+ // ... so that we can start queuing up actions that require stuff from /dev.
queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
queue_builtin_action(keychord_init_action, "keychord_init");
queue_builtin_action(console_init_action, "console_init");
@@ -1047,8 +1062,6 @@
// Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
// wasn't ready immediately after wait_for_coldboot_done
queue_builtin_action(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
- queue_builtin_action(property_service_init_action, "property_service_init");
- queue_builtin_action(signal_init_action, "signal_init");
// Don't mount filesystems or start core system services in charger mode.
char bootmode[PROP_VALUE_MAX];
@@ -1061,41 +1074,12 @@
// Run all property triggers based on current state of the properties.
queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");
- // TODO: why do we only initialize ufds after execute_one_command and restart_processes?
- size_t fd_count = 0;
- struct pollfd ufds[3];
- bool property_set_fd_init = false;
- bool signal_fd_init = false;
- bool keychord_fd_init = false;
-
- for (;;) {
+ while (true) {
if (!waiting_for_exec) {
execute_one_command();
restart_processes();
}
- if (!property_set_fd_init && get_property_set_fd() > 0) {
- ufds[fd_count].fd = get_property_set_fd();
- ufds[fd_count].events = POLLIN;
- ufds[fd_count].revents = 0;
- fd_count++;
- property_set_fd_init = true;
- }
- if (!signal_fd_init && get_signal_fd() > 0) {
- ufds[fd_count].fd = get_signal_fd();
- ufds[fd_count].events = POLLIN;
- ufds[fd_count].revents = 0;
- fd_count++;
- signal_fd_init = true;
- }
- if (!keychord_fd_init && get_keychord_fd() > 0) {
- ufds[fd_count].fd = get_keychord_fd();
- ufds[fd_count].events = POLLIN;
- ufds[fd_count].revents = 0;
- fd_count++;
- keychord_fd_init = true;
- }
-
int timeout = -1;
if (process_needs_restart) {
timeout = (process_needs_restart - gettime()) * 1000;
@@ -1109,21 +1093,12 @@
bootchart_sample(&timeout);
- int nr = poll(ufds, fd_count, timeout);
- if (nr <= 0) {
- continue;
- }
-
- for (size_t i = 0; i < fd_count; i++) {
- if (ufds[i].revents & POLLIN) {
- if (ufds[i].fd == get_property_set_fd()) {
- handle_property_set_fd();
- } else if (ufds[i].fd == get_keychord_fd()) {
- handle_keychord();
- } else if (ufds[i].fd == get_signal_fd()) {
- handle_signal();
- }
- }
+ epoll_event ev;
+ int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, timeout));
+ if (nr == -1) {
+ ERROR("epoll_wait failed: %s\n", strerror(errno));
+ } else if (nr == 1) {
+ ((void (*)()) ev.data.ptr)();
}
}
diff --git a/init/init.h b/init/init.h
index a104af6..1cabb14 100644
--- a/init/init.h
+++ b/init/init.h
@@ -155,4 +155,6 @@
void zap_stdio(void);
+void register_epoll_handler(int fd, void (*fn)());
+
#endif /* _INIT_INIT_H */
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index ff31093..b76b04e 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -184,7 +184,6 @@
case 's':
if (!strcmp(s, "eclabel")) return K_seclabel;
if (!strcmp(s, "ervice")) return K_service;
- if (!strcmp(s, "etcon")) return K_setcon;
if (!strcmp(s, "etenv")) return K_setenv;
if (!strcmp(s, "etprop")) return K_setprop;
if (!strcmp(s, "etrlimit")) return K_setrlimit;
diff --git a/init/keychords.cpp b/init/keychords.cpp
index 27894a2..10d9573 100644
--- a/init/keychords.cpp
+++ b/init/keychords.cpp
@@ -62,37 +62,7 @@
}
}
-void keychord_init()
-{
- int fd, ret;
-
- service_for_each(add_service_keycodes);
-
- /* nothing to do if no services require keychords */
- if (!keychords)
- return;
-
- fd = open("/dev/keychord", O_RDWR | O_CLOEXEC);
- if (fd < 0) {
- ERROR("could not open /dev/keychord\n");
- return;
- }
-
- ret = write(fd, keychords, keychords_length);
- if (ret != keychords_length) {
- ERROR("could not configure /dev/keychord %d: %s\n", ret, strerror(errno));
- close(fd);
- fd = -1;
- }
-
- free(keychords);
- keychords = 0;
-
- keychord_fd = fd;
-}
-
-void handle_keychord()
-{
+static void handle_keychord() {
struct service *svc;
char adb_enabled[PROP_VALUE_MAX];
int ret;
@@ -117,7 +87,28 @@
}
}
-int get_keychord_fd()
-{
- return keychord_fd;
+void keychord_init() {
+ service_for_each(add_service_keycodes);
+
+ // Nothing to do if no services require keychords.
+ if (!keychords) {
+ return;
+ }
+
+ keychord_fd = TEMP_FAILURE_RETRY(open("/dev/keychord", O_RDWR | O_CLOEXEC));
+ if (keychord_fd == -1) {
+ ERROR("could not open /dev/keychord: %s\n", strerror(errno));
+ return;
+ }
+
+ int ret = write(keychord_fd, keychords, keychords_length);
+ if (ret != keychords_length) {
+ ERROR("could not configure /dev/keychord %d: %s\n", ret, strerror(errno));
+ close(keychord_fd);
+ }
+
+ free(keychords);
+ keychords = nullptr;
+
+ register_epoll_handler(keychord_fd, handle_keychord);
}
diff --git a/init/keychords.h b/init/keychords.h
index 070b858..d2723b7 100644
--- a/init/keychords.h
+++ b/init/keychords.h
@@ -19,9 +19,7 @@
struct service;
-void add_service_keycodes(struct service *svc);
-void keychord_init(void);
-void handle_keychord(void);
-int get_keychord_fd(void);
+void add_service_keycodes(service*);
+void keychord_init();
#endif
diff --git a/init/keywords.h b/init/keywords.h
index 059dde1..37f01b8 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -20,7 +20,6 @@
int do_restorecon_recursive(int nargs, char **args);
int do_rm(int nargs, char **args);
int do_rmdir(int nargs, char **args);
-int do_setcon(int nargs, char **args);
int do_setprop(int nargs, char **args);
int do_setrlimit(int nargs, char **args);
int do_start(int nargs, char **args);
@@ -76,7 +75,6 @@
KEYWORD(rmdir, COMMAND, 1, do_rmdir)
KEYWORD(seclabel, OPTION, 0, 0)
KEYWORD(service, SECTION, 0, 0)
- KEYWORD(setcon, COMMAND, 1, do_setcon)
KEYWORD(setenv, OPTION, 2, 0)
KEYWORD(setprop, COMMAND, 2, do_setprop)
KEYWORD(setrlimit, COMMAND, 3, do_setrlimit)
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 2fa81d4..930ef82 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -246,7 +246,7 @@
return rc;
}
-void handle_property_set_fd()
+static void handle_property_set_fd()
{
prop_msg msg;
int s;
@@ -508,7 +508,6 @@
void load_all_props() {
load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL);
- load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT, 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.*");
@@ -520,16 +519,14 @@
}
void start_property_service() {
- int fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0, NULL);
- if (fd == -1) return;
+ property_set_fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
+ 0666, 0, 0, NULL);
+ if (property_set_fd == -1) {
+ ERROR("start_property_service socket creation failed: %s\n", strerror(errno));
+ exit(1);
+ }
- fcntl(fd, F_SETFD, FD_CLOEXEC);
- fcntl(fd, F_SETFL, O_NONBLOCK);
+ listen(property_set_fd, 8);
- listen(fd, 8);
- property_set_fd = fd;
-}
-
-int get_property_set_fd() {
- return property_set_fd;
+ register_epoll_handler(property_set_fd, handle_property_set_fd);
}
diff --git a/init/property_service.h b/init/property_service.h
index 825a7dd..a27053d 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -20,7 +20,6 @@
#include <stddef.h>
#include <sys/system_properties.h>
-extern void handle_property_set_fd(void);
extern void property_init(void);
extern void property_load_boot_defaults(void);
extern void load_persist_props(void);
@@ -30,7 +29,6 @@
extern int __property_get(const char *name, char *value);
extern int property_set(const char *name, const char *value);
extern bool properties_initialized();
-int get_property_set_fd(void);
#ifndef __clang__
extern void __property_get_size_error()
diff --git a/init/readme.txt b/init/readme.txt
index 84afd11..6b9c42d 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -252,11 +252,6 @@
rmdir <path>
Calls rmdir(2) on the given path.
-setcon <seclabel>
- Set the current process security context to the specified string.
- This is typically only used from early-init to set the init context
- before any other process is started.
-
setprop <name> <value>
Set system property <name> to <value>. Properties are expanded
within <value>.
diff --git a/init/signal_handler.cpp b/init/signal_handler.cpp
index 8be4af5..39a466d 100644
--- a/init/signal_handler.cpp
+++ b/init/signal_handler.cpp
@@ -35,14 +35,10 @@
#define CRITICAL_CRASH_THRESHOLD 4 /* if we crash >4 times ... */
#define CRITICAL_CRASH_WINDOW (4*60) /* ... in 4 minutes, goto recovery */
-static int signal_fd = -1;
-static int signal_recv_fd = -1;
+static int signal_write_fd = -1;
+static int signal_read_fd = -1;
-static void sigchld_handler(int s) {
- write(signal_fd, &s, 1);
-}
-
-std::string DescribeStatus(int status) {
+static std::string DescribeStatus(int status) {
if (WIFEXITED(status)) {
return android::base::StringPrintf("exited with status %d", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
@@ -54,11 +50,14 @@
}
}
-static int wait_for_one_process() {
+static bool wait_for_one_process() {
int status;
pid_t pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG));
- if (pid <= 0) {
- return -1;
+ if (pid == 0) {
+ return false;
+ } else if (pid == -1) {
+ ERROR("waitpid failed: %s\n", strerror(errno));
+ return false;
}
service* svc = service_find_by_pid(pid);
@@ -73,7 +72,7 @@
NOTICE("%s %s\n", name.c_str(), DescribeStatus(status).c_str());
if (!svc) {
- return 0;
+ return true;
}
// TODO: all the code from here down should be a member function on service.
@@ -96,7 +95,7 @@
list_remove(&svc->slist);
free(svc->name);
free(svc);
- return 0;
+ return true;
}
svc->pid = 0;
@@ -111,7 +110,7 @@
// Disabled and reset processes do not get restarted automatically.
if (svc->flags & (SVC_DISABLED | SVC_RESET)) {
svc->NotifyStateChange("stopped");
- return 0;
+ return true;
}
time_t now = gettime();
@@ -122,7 +121,7 @@
"rebooting into recovery mode\n", svc->name,
CRITICAL_CRASH_THRESHOLD, CRITICAL_CRASH_WINDOW / 60);
android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
- return 0;
+ return true;
}
} else {
svc->time_crashed = now;
@@ -140,34 +139,47 @@
cmd->func(cmd->nargs, cmd->args);
}
svc->NotifyStateChange("restarting");
- return 0;
+ return true;
}
-void handle_signal() {
- // We got a SIGCHLD - reap and restart as needed.
- char tmp[32];
- read(signal_recv_fd, tmp, sizeof(tmp));
- while (!wait_for_one_process()) {
+static void reap_any_outstanding_children() {
+ while (wait_for_one_process()) {
}
}
-void signal_init() {
+static void handle_signal() {
+ // Clear outstanding requests.
+ char buf[32];
+ read(signal_read_fd, buf, sizeof(buf));
+
+ reap_any_outstanding_children();
+}
+
+static void SIGCHLD_handler(int) {
+ if (TEMP_FAILURE_RETRY(write(signal_write_fd, "1", 1)) == -1) {
+ ERROR("write(signal_write_fd) failed: %s\n", strerror(errno));
+ }
+}
+
+void signal_handler_init() {
+ // Create a signalling mechanism for SIGCHLD.
+ int s[2];
+ if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == -1) {
+ ERROR("socketpair failed: %s\n", strerror(errno));
+ exit(1);
+ }
+
+ signal_write_fd = s[0];
+ signal_read_fd = s[1];
+
+ // Write to signal_write_fd if we catch SIGCHLD.
struct sigaction act;
memset(&act, 0, sizeof(act));
- act.sa_handler = sigchld_handler;
+ act.sa_handler = SIGCHLD_handler;
act.sa_flags = SA_NOCLDSTOP;
sigaction(SIGCHLD, &act, 0);
- // Create a signalling mechanism for the sigchld handler.
- int s[2];
- if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == 0) {
- signal_fd = s[0];
- signal_recv_fd = s[1];
- }
+ reap_any_outstanding_children();
- handle_signal();
-}
-
-int get_signal_fd() {
- return signal_recv_fd;
+ register_epoll_handler(signal_read_fd, handle_signal);
}
diff --git a/init/signal_handler.h b/init/signal_handler.h
index b092ccb..449b4af 100644
--- a/init/signal_handler.h
+++ b/init/signal_handler.h
@@ -17,8 +17,6 @@
#ifndef _INIT_SIGNAL_HANDLER_H_
#define _INIT_SIGNAL_HANDLER_H_
-void signal_init(void);
-void handle_signal(void);
-int get_signal_fd(void);
+void signal_handler_init(void);
#endif
diff --git a/init/util.cpp b/init/util.cpp
index 3b49b30..9343145 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -179,9 +179,13 @@
int write_file(const char* path, const char* content) {
int fd = TEMP_FAILURE_RETRY(open(path, O_WRONLY|O_CREAT|O_NOFOLLOW|O_CLOEXEC, 0600));
if (fd == -1) {
- return -errno;
+ NOTICE("write_file: Unable to open '%s': %s\n", path, strerror(errno));
+ return -1;
}
- int result = android::base::WriteStringToFd(content, fd) ? 0 : -errno;
+ int result = android::base::WriteStringToFd(content, fd) ? 0 : -1;
+ if (result == -1) {
+ NOTICE("write_file: Unable to write to '%s': %s\n", path, strerror(errno));
+ }
TEMP_FAILURE_RETRY(close(fd));
return result;
}
@@ -375,27 +379,31 @@
void open_devnull_stdio(void)
{
- int fd;
- static const char *name = "/dev/__null__";
- if (mknod(name, S_IFCHR | 0600, (1 << 8) | 3) == 0) {
- fd = open(name, O_RDWR);
- unlink(name);
- if (fd >= 0) {
- dup2(fd, 0);
- dup2(fd, 1);
- dup2(fd, 2);
- if (fd > 2) {
- close(fd);
- }
- return;
+ // Try to avoid the mknod() call if we can. Since SELinux makes
+ // a /dev/null replacement available for free, let's use it.
+ int fd = open("/sys/fs/selinux/null", O_RDWR);
+ if (fd == -1) {
+ // OOPS, /sys/fs/selinux/null isn't available, likely because
+ // /sys/fs/selinux isn't mounted. Fall back to mknod.
+ static const char *name = "/dev/__null__";
+ if (mknod(name, S_IFCHR | 0600, (1 << 8) | 3) == 0) {
+ fd = open(name, O_RDWR);
+ unlink(name);
+ }
+ if (fd == -1) {
+ exit(1);
}
}
- exit(1);
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fd, 2);
+ if (fd > 2) {
+ close(fd);
+ }
}
-void import_kernel_cmdline(int in_qemu,
- void (*import_kernel_nv)(char *name, int in_qemu))
+void import_kernel_cmdline(bool in_qemu, std::function<void(char*,bool)> import_kernel_nv)
{
char cmdline[2048];
char *ptr;
diff --git a/init/util.h b/init/util.h
index 8fec7a8..6864acf 100644
--- a/init/util.h
+++ b/init/util.h
@@ -21,6 +21,7 @@
#include <sys/types.h>
#include <string>
+#include <functional>
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
@@ -57,7 +58,7 @@
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(int in_qemu, void (*import_kernel_nv)(char *name, int in_qemu));
+void import_kernel_cmdline(bool in_qemu, std::function<void(char*,bool)>);
int make_dir(const char *path, mode_t mode);
int restorecon(const char *pathname);
int restorecon_recursive(const char *pathname);
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk
index b875efd..54cace9 100644
--- a/libbacktrace/Android.mk
+++ b/libbacktrace/Android.mk
@@ -57,7 +57,6 @@
libbacktrace_shared_libraries := \
libbase \
libunwind \
- libunwind-ptrace \
libbacktrace_shared_libraries_host := \
liblog \
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index c636196..9dc15d1 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -111,8 +111,9 @@
LOCAL_SRC_FILES_arm += arch-arm/memset32.S
LOCAL_SRC_FILES_arm64 += arch-arm64/android_memset.S
-LOCAL_SRC_FILES_mips += arch-mips/android_memset.S
-LOCAL_SRC_FILES_mips64 += arch-mips/android_memset.S
+
+LOCAL_SRC_FILES_mips += arch-mips/android_memset.c
+LOCAL_SRC_FILES_mips64 += arch-mips/android_memset.c
LOCAL_SRC_FILES_x86 += \
arch-x86/android_memset16.S \
diff --git a/libcutils/arch-mips/android_memset.S b/libcutils/arch-mips/android_memset.S
deleted file mode 100644
index 6811de0..0000000
--- a/libcutils/arch-mips/android_memset.S
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * Copyright (c) 2009
- * MIPS Technologies, Inc., California.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the MIPS Technologies, Inc., nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/************************************************************************
- *
- * memset.S, version "64h" with 1 cache line horizon for "pref 30" and 14 nops
- * Version: "043009"
- *
- ************************************************************************/
-
-
-/************************************************************************
- * Include files
- ************************************************************************/
-
-#include <machine/asm.h>
-#define END(f) .cfi_endproc; .size f, .-f; .end f
-
-/*
- * This routine could be optimized for MIPS64. The current code only
- * uses MIPS32 instructions.
- */
-
-#if defined(__MIPSEB__)
-# define SWHI swl /* high part is left in big-endian */
-# define SWLO swr /* low part is right in big-endian */
-#endif
-
-#if defined(__MIPSEL__)
-# define SWHI swr /* high part is right in little-endian */
-# define SWLO swl /* low part is left in little-endian */
-#endif
-
-#if !(defined(XGPROF) || defined(XPROF))
-#undef SETUP_GP
-#define SETUP_GP
-#endif
-
-#ifdef NDEBUG
-#define DBG #
-#else
-#define DBG
-#endif
-
-/*
- * void android_memset16(uint16_t* dst, uint16_t value, size_t size);
- */
-
-LEAF(android_memset16,0)
- .set noreorder
-DBG /* Check parameters */
-DBG andi t0,a0,1 # a0 must be halfword aligned
-DBG tne t0,zero
-DBG andi t2,a2,1 # a2 must be even
-DBG tne t2,zero
-
-#ifdef FIXARGS
- # ensure count is even
-#if (__mips==32) && (__mips_isa_rev>=2)
- ins a2,zero,0,1
-#else
- ori a2,1
- xori a2,1
-#endif
-#endif
-
-#if (__mips==32) && (__mips_isa_rev>=2)
- ins a1,a1,16,16
-#else
- andi a1,0xffff
- sll t3,a1,16
- or a1,t3
-#endif
-
- beqz a2,.Ldone
- andi t1,a0,2
- beqz t1,.Lalignok
- addu t0,a0,a2 # t0 is the "past the end" address
- sh a1,0(a0) # store one halfword to get aligned
- addu a0,2
- subu a2,2
-.Lalignok:
- slti t1,a2,4 # .Laligned for 4 or more bytes
- beqz t1,.Laligned
- sne t1,a2,2 # one more halfword?
- bnez t1,.Ldone
- nop
- sh a1,0(a0)
-.Ldone:
- j ra
- nop
- .set reorder
-END(android_memset16)
-
-/*
- * void android_memset32(uint32_t* dst, uint32_t value, size_t size);
- */
-
-LEAF(android_memset32,0)
- .set noreorder
-DBG /* Check parameters */
-DBG andi t0,a0,3 # a0 must be word aligned
-DBG tne t0,zero
-DBG andi t2,a2,3 # a2 must be a multiple of 4 bytes
-DBG tne t2,zero
-
-#ifdef FIXARGS
- # ensure count is a multiple of 4
-#if (__mips==32) && (__mips_isa_rev>=2)
- ins $a2,$0,0,2
-#else
- ori a2,3
- xori a2,3
-#endif
-#endif
-
- bnez a2,.Laligned # any work to do?
- addu t0,a0,a2 # t0 is the "past the end" address
-
- j ra
- nop
- .set reorder
-END(android_memset32)
-
-LEAF(memset,0)
-
- .set noreorder
- .set noat
-
- addu t0,a0,a2 # t0 is the "past the end" address
- slti AT,a2,4 # is a2 less than 4?
- bne AT,zero,.Llast4 # if yes, go to last4
- move v0,a0 # memset returns the dst pointer
-
- beq a1,zero,.Lset0
- subu v1,zero,a0
-
- # smear byte into 32 bit word
-#if (__mips==32) && (__mips_isa_rev>=2)
- ins a1, a1, 8, 8 # Replicate fill byte into half-word.
- ins a1, a1, 16, 16 # Replicate fill byte into word.
-#else
- and a1,0xff
- sll AT,a1,8
- or a1,AT
- sll AT,a1,16
- or a1,AT
-#endif
-
-.Lset0:
- andi v1,v1,0x3 # word-unaligned address?
- beq v1,zero,.Laligned # v1 is the unalignment count
- subu a2,a2,v1
- SWHI a1,0(a0)
- addu a0,a0,v1
-
-# Here we have the "word-aligned" a0 (until the "last4")
-.Laligned:
- andi t8,a2,0x3f # any 64-byte chunks?
- # t8 is the byte count past 64-byte chunks
- beq a2,t8,.Lchk8w # when a2==t8, no 64-byte chunks
- # There will be at most 1 32-byte chunk then
- subu a3,a2,t8 # subtract from a2 the reminder
- # Here a3 counts bytes in 16w chunks
- addu a3,a0,a3 # Now a3 is the final dst after 64-byte chunks
-
-# Find out, if there are any 64-byte chunks after which will be still at least
-# 96 bytes left. The value "96" is calculated as needed buffer for
-# "pref 30,64(a0)" prefetch, which can be used as "pref 30,0(a0)" after
-# incrementing "a0" by 64.
-# For "a2" below 160 there will be no such "pref 30 safe" 64-byte chunk.
-#
- sltiu v1,a2,160
- bgtz v1,.Lloop16w_nopref30 # skip "pref 30,0(a0)"
- subu t7,a2,96 # subtract "pref 30 unsafe" region
- # below we have at least 1 64-byte chunk which is "pref 30 safe"
- andi t6,t7,0x3f # t6 is past "64-byte safe chunks" reminder
- subu t5,t7,t6 # subtract from t7 the reminder
- # Here t5 counts bytes in 16w "safe" chunks
- addu t4,a0,t5 # Now t4 is the dst after 64-byte "safe" chunks
-
-# Don't use "pref 30,0(a0)" for a0 in a "middle" of a cache line
-# pref 30,0(a0)
-# Here we are in the region, where it is safe to use "pref 30,64(a0)"
-.Lloop16w:
- addiu a0,a0,64
- pref 30,-32(a0) # continue setting up the dest, addr 64-32
- sw a1,-64(a0)
- sw a1,-60(a0)
- sw a1,-56(a0)
- sw a1,-52(a0)
- sw a1,-48(a0)
- sw a1,-44(a0)
- sw a1,-40(a0)
- sw a1,-36(a0)
- nop
- nop # the extra nop instructions help to balance
- nop # cycles needed for "store" + "fill" + "evict"
- nop # For 64byte store there are needed 8 fill
- nop # and 8 evict cycles, i.e. at least 32 instr.
- nop
- nop
- pref 30,0(a0) # continue setting up the dest, addr 64-0
- sw a1,-32(a0)
- sw a1,-28(a0)
- sw a1,-24(a0)
- sw a1,-20(a0)
- sw a1,-16(a0)
- sw a1,-12(a0)
- sw a1,-8(a0)
- sw a1,-4(a0)
- nop
- nop
- nop
- nop # NOTE: adding 14 nop-s instead of 12 nop-s
- nop # gives better results for "fast" memory
- nop
- bne a0,t4,.Lloop16w
- nop
-
- beq a0,a3,.Lchk8w # maybe no more 64-byte chunks?
- nop # this "delayed slot" is useless ...
-
-.Lloop16w_nopref30: # there could be up to 3 "64-byte nopref30" chunks
- addiu a0,a0,64
- sw a1,-64(a0)
- sw a1,-60(a0)
- sw a1,-56(a0)
- sw a1,-52(a0)
- sw a1,-48(a0)
- sw a1,-44(a0)
- sw a1,-40(a0)
- sw a1,-36(a0)
- sw a1,-32(a0)
- sw a1,-28(a0)
- sw a1,-24(a0)
- sw a1,-20(a0)
- sw a1,-16(a0)
- sw a1,-12(a0)
- sw a1,-8(a0)
- bne a0,a3,.Lloop16w_nopref30
- sw a1,-4(a0)
-
-.Lchk8w: # t8 here is the byte count past 64-byte chunks
-
- andi t7,t8,0x1f # is there a 32-byte chunk?
- # the t7 is the reminder count past 32-bytes
- beq t8,t7,.Lchk1w # when t8==t7, no 32-byte chunk
- move a2,t7
-
- sw a1,0(a0)
- sw a1,4(a0)
- sw a1,8(a0)
- sw a1,12(a0)
- sw a1,16(a0)
- sw a1,20(a0)
- sw a1,24(a0)
- sw a1,28(a0)
- addiu a0,a0,32
-
-.Lchk1w:
- andi t8,a2,0x3 # now t8 is the reminder past 1w chunks
- beq a2,t8,.Llast4aligned
- subu a3,a2,t8 # a3 is the count of bytes in 1w chunks
- addu a3,a0,a3 # now a3 is the dst address past the 1w chunks
-
-# copying in words (4-byte chunks)
-.LwordCopy_loop:
- addiu a0,a0,4
- bne a0,a3,.LwordCopy_loop
- sw a1,-4(a0)
-
-# store last 0-3 bytes
-# this will repeat the last store if the memset finishes on a word boundary
-.Llast4aligned:
- j ra
- SWLO a1,-1(t0)
-
-.Llast4:
- beq a0,t0,.Llast4e
-.Llast4l:
- addiu a0,a0,1
- bne a0,t0,.Llast4l
- sb a1,-1(a0)
-.Llast4e:
- j ra
- nop
-
- .set at
- .set reorder
-
-END(memset)
-
-
-/************************************************************************
- * Implementation : Static functions
- ************************************************************************/
diff --git a/libcutils/arch-mips/android_memset.c b/libcutils/arch-mips/android_memset.c
new file mode 100644
index 0000000..a6b7496
--- /dev/null
+++ b/libcutils/arch-mips/android_memset.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* generic C version for any machine */
+
+#include <cutils/memory.h>
+
+void android_memset16(uint16_t* dst, uint16_t value, size_t size)
+{
+ /* optimized version of
+ size >>= 1;
+ while (size--)
+ *dst++ = value;
+ */
+
+ size >>= 1;
+ if (((uintptr_t)dst & 2) && size) {
+ /* fill unpaired first elem separately */
+ *dst++ = value;
+ size--;
+ }
+ /* dst is now 32-bit-aligned */
+ /* fill body with 32-bit pairs */
+ uint32_t value32 = (value << 16) | value;
+ android_memset32((uint32_t*) dst, value32, size<<1);
+ if (size & 1) {
+ dst[size-1] = value; /* fill unpaired last elem */
+ }
+}
+
+
+void android_memset32(uint32_t* dst, uint32_t value, size_t size)
+{
+ /* optimized version of
+ size >>= 2;
+ while (size--)
+ *dst++ = value;
+ */
+
+ size >>= 2;
+ if (((uintptr_t)dst & 4) && size) {
+ /* fill unpaired first 32-bit elem separately */
+ *dst++ = value;
+ size--;
+ }
+ /* dst is now 64-bit aligned */
+ /* fill body with 64-bit pairs */
+ uint64_t value64 = (((uint64_t)value)<<32) | value;
+ uint64_t* dst64 = (uint64_t*)dst;
+
+ while (size >= 12) {
+ dst64[0] = value64;
+ dst64[1] = value64;
+ dst64[2] = value64;
+ dst64[3] = value64;
+ dst64[4] = value64;
+ dst64[5] = value64;
+ size -= 12;
+ dst64 += 6;
+ }
+
+ /* fill remainder with original 32-bit single-elem loop */
+ dst = (uint32_t*) dst64;
+ while (size--) {
+ *dst++ = value;
+ }
+
+}
diff --git a/libcutils/dir_hash.c b/libcutils/dir_hash.c
deleted file mode 100644
index 098b5db..0000000
--- a/libcutils/dir_hash.c
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <dirent.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sha1.h>
-#include <unistd.h>
-#include <limits.h>
-
-#include <sys/stat.h>
-
-#include <netinet/in.h>
-#include <resolv.h>
-
-#include <cutils/dir_hash.h>
-
-/**
- * Copies, if it fits within max_output_string bytes, into output_string
- * a hash of the contents, size, permissions, uid, and gid of the file
- * specified by path, using the specified algorithm. Returns the length
- * of the output string, or a negative number if the buffer is too short.
- */
-int get_file_hash(HashAlgorithm algorithm, const char *path,
- char *output_string, size_t max_output_string) {
- SHA1_CTX context;
- struct stat sb;
- unsigned char md[SHA1_DIGEST_LENGTH];
- int used;
- size_t n;
-
- if (algorithm != SHA_1) {
- errno = EINVAL;
- return -1;
- }
-
- if (stat(path, &sb) != 0) {
- return -1;
- }
-
- if (S_ISLNK(sb.st_mode)) {
- char buf[PATH_MAX];
- int len;
-
- len = readlink(path, buf, sizeof(buf));
- if (len < 0) {
- return -1;
- }
-
- SHA1Init(&context);
- SHA1Update(&context, (unsigned char *) buf, len);
- SHA1Final(md, &context);
- } else if (S_ISREG(sb.st_mode)) {
- char buf[10000];
- FILE *f = fopen(path, "rb");
- int len;
-
- if (f == NULL) {
- return -1;
- }
-
- SHA1Init(&context);
-
- while ((len = fread(buf, 1, sizeof(buf), f)) > 0) {
- SHA1Update(&context, (unsigned char *) buf, len);
- }
-
- if (ferror(f)) {
- fclose(f);
- return -1;
- }
-
- fclose(f);
- SHA1Final(md, &context);
- }
-
- if (S_ISLNK(sb.st_mode) || S_ISREG(sb.st_mode)) {
- used = b64_ntop(md, SHA1_DIGEST_LENGTH,
- output_string, max_output_string);
- if (used < 0) {
- errno = ENOSPC;
- return -1;
- }
-
- n = snprintf(output_string + used, max_output_string - used,
- " %d 0%o %d %d", (int) sb.st_size, sb.st_mode,
- (int) sb.st_uid, (int) sb.st_gid);
- } else {
- n = snprintf(output_string, max_output_string,
- "- - 0%o %d %d", sb.st_mode,
- (int) sb.st_uid, (int) sb.st_gid);
- }
-
- if (n >= max_output_string - used) {
- errno = ENOSPC;
- return -(used + n);
- }
-
- return used + n;
-}
-
-struct list {
- char *name;
- struct list *next;
-};
-
-static int cmp(const void *a, const void *b) {
- struct list *const *ra = a;
- struct list *const *rb = b;
-
- return strcmp((*ra)->name, (*rb)->name);
-}
-
-static int recurse(HashAlgorithm algorithm, const char *directory_path,
- struct list **out) {
- struct list *list = NULL;
- struct list *f;
-
- struct dirent *de;
- DIR *d = opendir(directory_path);
-
- if (d == NULL) {
- return -1;
- }
-
- while ((de = readdir(d)) != NULL) {
- if (strcmp(de->d_name, ".") == 0) {
- continue;
- }
- if (strcmp(de->d_name, "..") == 0) {
- continue;
- }
-
- char *name = malloc(strlen(de->d_name) + 1);
- struct list *node = malloc(sizeof(struct list));
-
- if (name == NULL || node == NULL) {
- struct list *next;
- for (f = list; f != NULL; f = next) {
- next = f->next;
- free(f->name);
- free(f);
- }
-
- free(name);
- free(node);
- closedir(d);
- return -1;
- }
-
- strcpy(name, de->d_name);
-
- node->name = name;
- node->next = list;
- list = node;
- }
-
- closedir(d);
-
- for (f = list; f != NULL; f = f->next) {
- struct stat sb;
- char *name;
- char outstr[NAME_MAX + 100];
- char *keep;
- struct list *res;
-
- name = malloc(strlen(f->name) + strlen(directory_path) + 2);
- if (name == NULL) {
- struct list *next;
- for (f = list; f != NULL; f = f->next) {
- next = f->next;
- free(f->name);
- free(f);
- }
- for (f = *out; f != NULL; f = f->next) {
- next = f->next;
- free(f->name);
- free(f);
- }
- *out = NULL;
- return -1;
- }
-
- sprintf(name, "%s/%s", directory_path, f->name);
-
- int len = get_file_hash(algorithm, name,
- outstr, sizeof(outstr));
- if (len < 0) {
- // should not happen
- return -1;
- }
-
- keep = malloc(len + strlen(name) + 3);
- res = malloc(sizeof(struct list));
-
- if (keep == NULL || res == NULL) {
- struct list *next;
- for (f = list; f != NULL; f = f->next) {
- next = f->next;
- free(f->name);
- free(f);
- }
- for (f = *out; f != NULL; f = f->next) {
- next = f->next;
- free(f->name);
- free(f);
- }
- *out = NULL;
-
- free(keep);
- free(res);
- return -1;
- }
-
- sprintf(keep, "%s %s\n", name, outstr);
-
- res->name = keep;
- res->next = *out;
- *out = res;
-
- if ((stat(name, &sb) == 0) && S_ISDIR(sb.st_mode)) {
- if (recurse(algorithm, name, out) < 0) {
- struct list *next;
- for (f = list; f != NULL; f = next) {
- next = f->next;
- free(f->name);
- free(f);
- }
-
- return -1;
- }
- }
- }
-
- struct list *next;
- for (f = list; f != NULL; f = next) {
- next = f->next;
-
- free(f->name);
- free(f);
- }
-}
-
-/**
- * Allocates a string containing the names and hashes of all files recursively
- * reached under the specified directory_path, using the specified algorithm.
- * The string is returned as *output_string; the return value is the length
- * of the string, or a negative number if there was a failure.
- */
-int get_recursive_hash_manifest(HashAlgorithm algorithm,
- const char *directory_path,
- char **output_string) {
- struct list *out = NULL;
- struct list *r;
- struct list **list;
- int count = 0;
- int len = 0;
- int retlen = 0;
- int i;
- char *buf;
-
- if (recurse(algorithm, directory_path, &out) < 0) {
- return -1;
- }
-
- for (r = out; r != NULL; r = r->next) {
- count++;
- len += strlen(r->name);
- }
-
- list = malloc(count * sizeof(struct list *));
- if (list == NULL) {
- struct list *next;
- for (r = out; r != NULL; r = next) {
- next = r->next;
- free(r->name);
- free(r);
- }
- return -1;
- }
-
- count = 0;
- for (r = out; r != NULL; r = r->next) {
- list[count++] = r;
- }
-
- qsort(list, count, sizeof(struct list *), cmp);
-
- buf = malloc(len + 1);
- if (buf == NULL) {
- struct list *next;
- for (r = out; r != NULL; r = next) {
- next = r->next;
- free(r->name);
- free(r);
- }
- free(list);
- return -1;
- }
-
- for (i = 0; i < count; i++) {
- int n = strlen(list[i]->name);
-
- strcpy(buf + retlen, list[i]->name);
- retlen += n;
- }
-
- free(list);
-
- struct list *next;
- for (r = out; r != NULL; r = next) {
- next = r->next;
-
- free(r->name);
- free(r);
- }
-
- *output_string = buf;
- return retlen;
-}
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index 659f614..9f8023e 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -19,11 +19,54 @@
** by the device side of adb.
*/
+#define LOG_TAG "fs_config"
+
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
+#include <sys/types.h>
+#include <log/log.h>
#include <private/android_filesystem_config.h>
+#include <utils/Compat.h>
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+/* The following structure is stored little endian */
+struct fs_path_config_from_file {
+ uint16_t len;
+ uint16_t mode;
+ uint16_t uid;
+ uint16_t gid;
+ uint64_t capabilities;
+ char prefix[];
+} __attribute__((__aligned__(sizeof(uint64_t))));
+
+/* My kingdom for <endian.h> */
+static inline uint16_t get2LE(const uint8_t* src)
+{
+ return src[0] | (src[1] << 8);
+}
+
+static inline uint64_t get8LE(const uint8_t* src)
+{
+ uint32_t low, high;
+
+ low = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
+ high = src[4] | (src[5] << 8) | (src[6] << 16) | (src[7] << 24);
+ return ((uint64_t) high << 32) | (uint64_t) low;
+}
+
+#define ALIGN(x, alignment) ( ((x) + ((alignment) - 1)) & ~((alignment) - 1) )
/* Rules for directories.
** These rules are applied based on "first match", so they
@@ -61,6 +104,9 @@
** way up to the root. Prefixes ending in * denotes wildcard
** and will allow partial matches.
*/
+static const char conf_dir[] = "/system/etc/fs_config_dirs";
+static const char conf_file[] = "/system/etc/fs_config_files";
+
static const struct fs_path_config android_files[] = {
{ 00440, AID_ROOT, AID_SHELL, 0, "system/etc/init.goldfish.rc" },
{ 00550, AID_ROOT, AID_SHELL, 0, "system/etc/init.goldfish.sh" },
@@ -68,6 +114,8 @@
{ 00550, AID_DHCP, AID_SHELL, 0, "system/etc/dhcpcd/dhcpcd-run-hooks" },
{ 00555, AID_ROOT, AID_ROOT, 0, "system/etc/ppp/*" },
{ 00555, AID_ROOT, AID_ROOT, 0, "system/etc/rc.*" },
+ { 00444, AID_ROOT, AID_ROOT, 0, conf_dir + 1 },
+ { 00444, AID_ROOT, AID_ROOT, 0, conf_file + 1 },
{ 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app/*" },
{ 00644, AID_MEDIA_RW, AID_MEDIA_RW, 0, "data/media/*" },
{ 00644, AID_SYSTEM, AID_SYSTEM, 0, "data/app-private/*" },
@@ -101,30 +149,102 @@
{ 00644, AID_ROOT, AID_ROOT, 0, 0 },
};
+static int fs_config_open(int dir)
+{
+ int fd = -1;
+
+ const char *out = getenv("OUT");
+ if (out && *out) {
+ char *name = NULL;
+ asprintf(&name, "%s%s", out, dir ? conf_dir : conf_file);
+ if (name) {
+ fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_BINARY));
+ free(name);
+ }
+ }
+ if (fd < 0) {
+ fd = TEMP_FAILURE_RETRY(open(dir ? conf_dir : conf_file, O_RDONLY | O_BINARY));
+ }
+ return fd;
+}
+
+static bool fs_config_cmp(bool dir, const char *prefix, size_t len,
+ const char *path, size_t plen)
+{
+ if (dir) {
+ if (plen < len) {
+ return false;
+ }
+ } else {
+ /* If name ends in * then allow partial matches. */
+ if (prefix[len - 1] == '*') {
+ return !strncmp(prefix, path, len - 1);
+ }
+ if (plen != len) {
+ return false;
+ }
+ }
+ return !strncmp(prefix, path, len);
+}
+
void fs_config(const char *path, int dir,
unsigned *uid, unsigned *gid, unsigned *mode, uint64_t *capabilities)
{
const struct fs_path_config *pc;
- int plen;
+ int fd, plen;
if (path[0] == '/') {
path++;
}
- pc = dir ? android_dirs : android_files;
plen = strlen(path);
- for(; pc->prefix; pc++){
- int len = strlen(pc->prefix);
- if (dir) {
- if(plen < len) continue;
- if(!strncmp(pc->prefix, path, len)) break;
- continue;
+
+ fd = fs_config_open(dir);
+ if (fd >= 0) {
+ struct fs_path_config_from_file header;
+
+ while (TEMP_FAILURE_RETRY(read(fd, &header, sizeof(header))) == sizeof(header)) {
+ char *prefix;
+ uint16_t host_len = get2LE((const uint8_t *)&header.len);
+ ssize_t len, remainder = host_len - sizeof(header);
+ if (remainder <= 0) {
+ ALOGE("%s len is corrupted", dir ? conf_dir : conf_file);
+ break;
+ }
+ prefix = calloc(1, remainder);
+ if (!prefix) {
+ ALOGE("%s out of memory", dir ? conf_dir : conf_file);
+ break;
+ }
+ if (TEMP_FAILURE_RETRY(read(fd, prefix, remainder)) != remainder) {
+ free(prefix);
+ ALOGE("%s prefix is truncated", dir ? conf_dir : conf_file);
+ break;
+ }
+ len = strnlen(prefix, remainder);
+ if (len >= remainder) { /* missing a terminating null */
+ free(prefix);
+ ALOGE("%s is corrupted", dir ? conf_dir : conf_file);
+ break;
+ }
+ if (fs_config_cmp(dir, prefix, len, path, plen)) {
+ free(prefix);
+ close(fd);
+ *uid = get2LE((const uint8_t *)&(header.uid));
+ *gid = get2LE((const uint8_t *)&(header.gid));
+ *mode = (*mode & (~07777)) | get2LE((const uint8_t *)&(header.mode));
+ *capabilities = get8LE((const uint8_t *)&(header.capabilities));
+ return;
+ }
+ free(prefix);
}
- /* If name ends in * then allow partial matches. */
- if (pc->prefix[len -1] == '*') {
- if(!strncmp(pc->prefix, path, len - 1)) break;
- } else if (plen == len){
- if(!strncmp(pc->prefix, path, len)) break;
+ close(fd);
+ }
+
+ pc = dir ? android_dirs : android_files;
+ for(; pc->prefix; pc++){
+ if (fs_config_cmp(dir, pc->prefix, strlen(pc->prefix), path, plen)) {
+ break;
}
}
*uid = pc->uid;
@@ -132,3 +252,22 @@
*mode = (*mode & (~07777)) | pc->mode;
*capabilities = pc->capabilities;
}
+
+ssize_t fs_config_generate(char *buffer, size_t length, const struct fs_path_config *pc)
+{
+ struct fs_path_config_from_file *p = (struct fs_path_config_from_file *)buffer;
+ size_t len = ALIGN(sizeof(*p) + strlen(pc->prefix) + 1, sizeof(uint64_t));
+
+ if ((length < len) || (len > UINT16_MAX)) {
+ return -ENOSPC;
+ }
+ memset(p, 0, len);
+ uint16_t host_len = len;
+ p->len = get2LE((const uint8_t *)&host_len);
+ p->mode = get2LE((const uint8_t *)&(pc->mode));
+ p->uid = get2LE((const uint8_t *)&(pc->uid));
+ p->gid = get2LE((const uint8_t *)&(pc->gid));
+ p->capabilities = get8LE((const uint8_t *)&(pc->capabilities));
+ strcpy(p->prefix, pc->prefix);
+ return len;
+}
diff --git a/libcutils/trace-dev.c b/libcutils/trace-dev.c
index 4396625..a06987e 100644
--- a/libcutils/trace-dev.c
+++ b/libcutils/trace-dev.c
@@ -18,11 +18,11 @@
#include <fcntl.h>
#include <limits.h>
#include <pthread.h>
+#include <stdatomic.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
-#include <cutils/atomic.h>
#include <cutils/compiler.h>
#include <cutils/properties.h>
#include <cutils/trace.h>
@@ -37,11 +37,11 @@
*/
#define ATRACE_MESSAGE_LENGTH 1024
-volatile int32_t atrace_is_ready = 0;
+atomic_bool atrace_is_ready = ATOMIC_VAR_INIT(false);
int atrace_marker_fd = -1;
uint64_t atrace_enabled_tags = ATRACE_TAG_NOT_READY;
static bool atrace_is_debuggable = false;
-static volatile int32_t atrace_is_enabled = 1;
+static atomic_bool atrace_is_enabled = ATOMIC_VAR_INIT(true);
static pthread_once_t atrace_once_control = PTHREAD_ONCE_INIT;
static pthread_mutex_t atrace_tags_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -58,7 +58,7 @@
// the Zygote process from tracing.
void atrace_set_tracing_enabled(bool enabled)
{
- android_atomic_release_store(enabled ? 1 : 0, &atrace_is_enabled);
+ atomic_store_explicit(&atrace_is_enabled, enabled, memory_order_release);
atrace_update_tags();
}
@@ -155,8 +155,8 @@
void atrace_update_tags()
{
uint64_t tags;
- if (CC_UNLIKELY(android_atomic_acquire_load(&atrace_is_ready))) {
- if (android_atomic_acquire_load(&atrace_is_enabled)) {
+ if (CC_UNLIKELY(atomic_load_explicit(&atrace_is_ready, memory_order_acquire))) {
+ if (atomic_load_explicit(&atrace_is_enabled, memory_order_acquire)) {
tags = atrace_get_property();
pthread_mutex_lock(&atrace_tags_mutex);
atrace_enabled_tags = tags;
@@ -183,7 +183,7 @@
atrace_enabled_tags = atrace_get_property();
done:
- android_atomic_release_store(1, &atrace_is_ready);
+ atomic_store_explicit(&atrace_is_ready, true, memory_order_release);
}
void atrace_setup()
diff --git a/libcutils/trace-host.c b/libcutils/trace-host.c
index b87e543..6478e3e 100644
--- a/libcutils/trace-host.c
+++ b/libcutils/trace-host.c
@@ -20,7 +20,7 @@
#define __unused __attribute__((__unused__))
#endif
-volatile int32_t atrace_is_ready = 1;
+atomic_bool atrace_is_ready = ATOMIC_VAR_INIT(true);
int atrace_marker_fd = -1;
uint64_t atrace_enabled_tags = 0;
diff --git a/liblog/log_is_loggable.c b/liblog/log_is_loggable.c
index df67123..2e09192 100644
--- a/liblog/log_is_loggable.c
+++ b/liblog/log_is_loggable.c
@@ -28,7 +28,7 @@
return def;
}
{
- static const char log_namespace[] = "log.tag.";
+ static const char log_namespace[] = "persist.log.tag.";
char key[sizeof(log_namespace) + strlen(tag)];
strcpy(key, log_namespace);
@@ -37,6 +37,9 @@
if (__system_property_get(key + 8, buf) <= 0) {
buf[0] = '\0';
}
+ if (!buf[0] && __system_property_get(key, buf) <= 0) {
+ buf[0] = '\0';
+ }
}
switch (toupper(buf[0])) {
case 'V': return ANDROID_LOG_VERBOSE;
@@ -53,17 +56,6 @@
int __android_log_is_loggable(int prio, const char *tag, int def)
{
- static char user;
- int logLevel;
-
- if (user == 0) {
- char buf[PROP_VALUE_MAX];
- if (__system_property_get("ro.build.type", buf) <= 0) {
- buf[0] = '\0';
- }
- user = strcmp(buf, "user") ? -1 : 1;
- }
-
- logLevel = (user == 1) ? def : __android_log_level(tag, def);
+ int logLevel = __android_log_level(tag, def);
return logLevel >= 0 && prio >= logLevel;
}
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 7ba4c8e..0f01542 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -26,6 +26,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <inttypes.h>
#include <sys/param.h>
#include <log/logd.h>
@@ -432,7 +433,7 @@
low = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
high = src[4] | (src[5] << 8) | (src[6] << 16) | (src[7] << 24);
- return ((long long) high << 32) | (long long) low;
+ return ((uint64_t) high << 32) | (uint64_t) low;
}
@@ -490,7 +491,7 @@
case EVENT_TYPE_LONG:
/* 64-bit signed long */
{
- long long lval;
+ uint64_t lval;
if (eventDataLen < 8)
return -1;
@@ -498,7 +499,30 @@
eventData += 8;
eventDataLen -= 8;
- outCount = snprintf(outBuf, outBufLen, "%lld", lval);
+ outCount = snprintf(outBuf, outBufLen, "%" PRId64, lval);
+ if (outCount < outBufLen) {
+ outBuf += outCount;
+ outBufLen -= outCount;
+ } else {
+ /* halt output */
+ goto no_room;
+ }
+ }
+ break;
+ case EVENT_TYPE_FLOAT:
+ /* float */
+ {
+ uint32_t ival;
+ float fval;
+
+ if (eventDataLen < 4)
+ return -1;
+ ival = get4LE(eventData);
+ fval = *(float*)&ival;
+ eventData += 4;
+ eventDataLen -= 4;
+
+ outCount = snprintf(outBuf, outBufLen, "%f", fval);
if (outCount < outBufLen) {
outBuf += outCount;
outBufLen -= outCount;
diff --git a/liblog/tests/liblog_benchmark.cpp b/liblog/tests/liblog_benchmark.cpp
index 979aded..b594634 100644
--- a/liblog/tests/liblog_benchmark.cpp
+++ b/liblog/tests/liblog_benchmark.cpp
@@ -266,3 +266,17 @@
android_logger_list_free(logger_list);
}
BENCHMARK(BM_log_delay);
+
+/*
+ * Measure the time it takes for __android_log_is_loggable.
+ */
+static void BM_is_loggable(int iters) {
+ StartBenchmarkTiming();
+
+ for (int i = 0; i < iters; ++i) {
+ __android_log_is_loggable(ANDROID_LOG_WARN, "logd", ANDROID_LOG_VERBOSE);
+ }
+
+ StopBenchmarkTiming();
+}
+BENCHMARK(BM_is_loggable);
diff --git a/libnetutils/Android.mk b/libnetutils/Android.mk
index 1f61511..2060df4 100644
--- a/libnetutils/Android.mk
+++ b/libnetutils/Android.mk
@@ -17,3 +17,10 @@
LOCAL_CFLAGS := -Werror
include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := dhcptool.c
+LOCAL_SHARED_LIBRARIES := libnetutils
+LOCAL_MODULE := dhcptool
+LOCAL_MODULE_TAGS := debug
+include $(BUILD_EXECUTABLE)
diff --git a/libnetutils/dhcptool.c b/libnetutils/dhcptool.c
new file mode 100644
index 0000000..352ac5e
--- /dev/null
+++ b/libnetutils/dhcptool.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright 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 <errno.h>
+#include <error.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <netutils/dhcp.h>
+#include <netutils/ifc.h>
+
+int main(int argc, char* argv[]) {
+ if (argc != 2) {
+ error(EXIT_FAILURE, 0, "usage: %s INTERFACE", argv[0]);
+ }
+
+ char* interface = argv[1];
+ if (ifc_init()) {
+ error(EXIT_FAILURE, errno, "dhcptool %s: ifc_init failed", interface);
+ }
+
+ int rc = do_dhcp(interface);
+ if (rc) {
+ error(0, errno, "dhcptool %s: do_dhcp failed", interface);
+ }
+
+ ifc_close();
+
+ return rc ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/libsparse/sparse.c b/libsparse/sparse.c
index 65c09e0..311678a 100644
--- a/libsparse/sparse.c
+++ b/libsparse/sparse.c
@@ -238,14 +238,15 @@
struct backed_block *last_bb = NULL;
struct backed_block *bb;
struct backed_block *start;
+ unsigned int last_block = 0;
int64_t file_len = 0;
int ret;
/*
- * overhead is sparse file header, initial skip chunk, split chunk, end
- * skip chunk, and crc chunk.
+ * overhead is sparse file header, the potential end skip
+ * chunk and crc chunk.
*/
- int overhead = sizeof(sparse_header_t) + 4 * sizeof(chunk_header_t) +
+ int overhead = sizeof(sparse_header_t) + 2 * sizeof(chunk_header_t) +
sizeof(uint32_t);
len -= overhead;
@@ -258,6 +259,11 @@
for (bb = start; bb; bb = backed_block_iter_next(bb)) {
count = 0;
+ if (backed_block_block(bb) > last_block)
+ count += sizeof(chunk_header_t);
+ last_block = backed_block_block(bb) +
+ DIV_ROUND_UP(backed_block_len(bb), to->block_size);
+
/* will call out_counter_write to update count */
ret = sparse_file_write_block(out_counter, bb);
if (ret) {
@@ -270,6 +276,7 @@
* requested size, split the chunk. Results in sparse files that
* are at least 7/8ths of the requested size
*/
+ file_len += sizeof(chunk_header_t);
if (!last_bb || (len - file_len > (len / 8))) {
backed_block_split(from->backed_block_list, bb, len - file_len);
last_bb = bb;
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 57c46a3..79c4c53 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -30,6 +30,7 @@
#include <memory>
#include <vector>
+#include "base/file.h"
#include "base/macros.h" // TEMP_FAILURE_RETRY may or may not be in unistd
#include "base/memory.h"
#include "log/log.h"
@@ -85,7 +86,8 @@
// Length of the central directory comment.
uint16_t comment_length;
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(EocdRecord);
+ EocdRecord() = default;
+ DISALLOW_COPY_AND_ASSIGN(EocdRecord);
} __attribute__((packed));
// A structure representing the fixed length fields for a single
@@ -138,7 +140,8 @@
// beginning of this archive.
uint32_t local_file_header_offset;
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(CentralDirectoryRecord);
+ CentralDirectoryRecord() = default;
+ DISALLOW_COPY_AND_ASSIGN(CentralDirectoryRecord);
} __attribute__((packed));
// The local file header for a given entry. This duplicates information
@@ -175,7 +178,8 @@
// will appear immediately after the entry file name.
uint16_t extra_field_length;
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(LocalFileHeader);
+ LocalFileHeader() = default;
+ DISALLOW_COPY_AND_ASSIGN(LocalFileHeader);
} __attribute__((packed));
struct DataDescriptor {
@@ -189,10 +193,10 @@
// Uncompressed size of the entry.
uint32_t uncompressed_size;
private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(DataDescriptor);
+ DataDescriptor() = default;
+ DISALLOW_COPY_AND_ASSIGN(DataDescriptor);
} __attribute__((packed));
-#undef DISALLOW_IMPLICIT_CONSTRUCTORS
static const uint32_t kGPBDDFlagMask = 0x0008; // mask value that signifies that the entry has a DD
@@ -265,8 +269,6 @@
static const int32_t kErrorMessageLowerBound = -13;
-static const char kTempMappingFileName[] = "zip: ExtractFileToFile";
-
/*
* A Read-only Zip archive.
*
@@ -324,35 +326,6 @@
}
};
-static int32_t CopyFileToFile(int fd, uint8_t* begin, const uint32_t length, uint64_t *crc_out) {
- static const uint32_t kBufSize = 32768;
- uint8_t buf[kBufSize];
-
- uint32_t count = 0;
- uint64_t crc = 0;
- while (count < length) {
- uint32_t remaining = length - count;
-
- // Safe conversion because kBufSize is narrow enough for a 32 bit signed
- // value.
- ssize_t get_size = (remaining > kBufSize) ? kBufSize : remaining;
- ssize_t actual = TEMP_FAILURE_RETRY(read(fd, buf, get_size));
-
- if (actual != get_size) {
- ALOGW("CopyFileToFile: copy read failed (" ZD " vs " ZD ")", actual, get_size);
- return kIoError;
- }
-
- memcpy(begin + count, buf, get_size);
- crc = crc32(crc, buf, get_size);
- count += get_size;
- }
-
- *crc_out = crc;
-
- return 0;
-}
-
/*
* Round up to the next highest power of 2.
*
@@ -972,6 +945,117 @@
return kIterationEnd;
}
+class Writer {
+ public:
+ virtual bool Append(uint8_t* buf, size_t buf_size) = 0;
+ virtual ~Writer() {}
+ protected:
+ Writer() = default;
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Writer);
+};
+
+// A Writer that writes data to a fixed size memory region.
+// The size of the memory region must be equal to the total size of
+// the data appended to it.
+class MemoryWriter : public Writer {
+ public:
+ MemoryWriter(uint8_t* buf, size_t size) : Writer(),
+ buf_(buf), size_(size), bytes_written_(0) {
+ }
+
+ virtual bool Append(uint8_t* buf, size_t buf_size) override {
+ if (bytes_written_ + buf_size > size_) {
+ ALOGW("Zip: Unexpected size " ZD " (declared) vs " ZD " (actual)",
+ size_, bytes_written_ + buf_size);
+ return false;
+ }
+
+ memcpy(buf_ + bytes_written_, buf, buf_size);
+ bytes_written_ += buf_size;
+ return true;
+ }
+
+ private:
+ uint8_t* const buf_;
+ const size_t size_;
+ size_t bytes_written_;
+};
+
+// A Writer that appends data to a file |fd| at its current position.
+// The file will be truncated to the end of the written data.
+class FileWriter : public Writer {
+ public:
+
+ // Creates a FileWriter for |fd| and prepare to write |entry| to it,
+ // guaranteeing that the file descriptor is valid and that there's enough
+ // space on the volume to write out the entry completely and that the file
+ // is truncated to the correct length.
+ //
+ // Returns a valid FileWriter on success, |nullptr| if an error occurred.
+ static std::unique_ptr<FileWriter> Create(int fd, const ZipEntry* entry) {
+ const uint32_t declared_length = entry->uncompressed_length;
+ const off64_t current_offset = lseek64(fd, 0, SEEK_CUR);
+ if (current_offset == -1) {
+ ALOGW("Zip: unable to seek to current location on fd %d: %s", fd, strerror(errno));
+ return nullptr;
+ }
+
+ int result = 0;
+#if defined(__linux__)
+ if (declared_length > 0) {
+ // Make sure we have enough space on the volume to extract the compressed
+ // entry. Note that the call to ftruncate below will change the file size but
+ // will not allocate space on disk and this call to fallocate will not
+ // change the file size.
+ result = TEMP_FAILURE_RETRY(fallocate(fd, 0, current_offset, declared_length));
+ if (result == -1) {
+ ALOGW("Zip: unable to allocate space for file to %" PRId64 ": %s",
+ static_cast<int64_t>(declared_length + current_offset), strerror(errno));
+ return std::unique_ptr<FileWriter>(nullptr);
+ }
+ }
+#endif // __linux__
+
+ result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
+ if (result == -1) {
+ ALOGW("Zip: unable to truncate file to %" PRId64 ": %s",
+ static_cast<int64_t>(declared_length + current_offset), strerror(errno));
+ return std::unique_ptr<FileWriter>(nullptr);
+ }
+
+ return std::unique_ptr<FileWriter>(new FileWriter(fd, declared_length));
+ }
+
+ virtual bool Append(uint8_t* buf, size_t buf_size) override {
+ if (total_bytes_written_ + buf_size > declared_length_) {
+ ALOGW("Zip: Unexpected size " ZD " (declared) vs " ZD " (actual)",
+ declared_length_, total_bytes_written_ + buf_size);
+ return false;
+ }
+
+ const bool result = android::base::WriteFully(fd_, buf, buf_size);
+ if (result) {
+ total_bytes_written_ += buf_size;
+ } else {
+ ALOGW("Zip: unable to write " ZD " bytes to file; %s", buf_size, strerror(errno));
+ }
+
+ return result;
+ }
+ private:
+ FileWriter(const int fd, const size_t declared_length) :
+ Writer(),
+ fd_(fd),
+ declared_length_(declared_length),
+ total_bytes_written_(0) {
+ }
+
+ const int fd_;
+ const size_t declared_length_;
+ size_t total_bytes_written_;
+};
+
// This method is using libz macros with old-style-casts
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"
@@ -980,9 +1064,8 @@
}
#pragma GCC diagnostic pop
-static int32_t InflateToFile(int fd, const ZipEntry* entry,
- uint8_t* begin, uint32_t length,
- uint64_t* crc_out) {
+static int32_t InflateEntryToWriter(int fd, const ZipEntry* entry,
+ Writer* writer, uint64_t* crc_out) {
const size_t kBufSize = 32768;
std::vector<uint8_t> read_buf(kBufSize);
std::vector<uint8_t> write_buf(kBufSize);
@@ -1027,7 +1110,6 @@
const uint32_t uncompressed_length = entry->uncompressed_length;
uint32_t compressed_length = entry->compressed_length;
- uint32_t write_count = 0;
do {
/* read as much as we can */
if (zstream.avail_in == 0) {
@@ -1057,12 +1139,10 @@
if (zstream.avail_out == 0 ||
(zerr == Z_STREAM_END && zstream.avail_out != kBufSize)) {
const size_t write_size = zstream.next_out - &write_buf[0];
- // The file might have declared a bogus length.
- if (write_size + write_count > length) {
- return -1;
+ if (!writer->Append(&write_buf[0], write_size)) {
+ // The file might have declared a bogus length.
+ return kInconsistentInformation;
}
- memcpy(begin + write_count, &write_buf[0], write_size);
- write_count += write_size;
zstream.next_out = &write_buf[0];
zstream.avail_out = kBufSize;
@@ -1083,8 +1163,41 @@
return 0;
}
-int32_t ExtractToMemory(ZipArchiveHandle handle,
- ZipEntry* entry, uint8_t* begin, uint32_t size) {
+static int32_t CopyEntryToWriter(int fd, const ZipEntry* entry, Writer* writer,
+ uint64_t *crc_out) {
+ static const uint32_t kBufSize = 32768;
+ std::vector<uint8_t> buf(kBufSize);
+
+ const uint32_t length = entry->uncompressed_length;
+ uint32_t count = 0;
+ uint64_t crc = 0;
+ while (count < length) {
+ uint32_t remaining = length - count;
+
+ // Safe conversion because kBufSize is narrow enough for a 32 bit signed
+ // value.
+ const ssize_t block_size = (remaining > kBufSize) ? kBufSize : remaining;
+ const ssize_t actual = TEMP_FAILURE_RETRY(read(fd, &buf[0], block_size));
+
+ if (actual != block_size) {
+ ALOGW("CopyFileToFile: copy read failed (" ZD " vs " ZD ")", actual, block_size);
+ return kIoError;
+ }
+
+ if (!writer->Append(&buf[0], block_size)) {
+ return kIoError;
+ }
+ crc = crc32(crc, &buf[0], block_size);
+ count += block_size;
+ }
+
+ *crc_out = crc;
+
+ return 0;
+}
+
+int32_t ExtractToWriter(ZipArchiveHandle handle,
+ ZipEntry* entry, Writer* writer) {
ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
const uint16_t method = entry->method;
off64_t data_offset = entry->offset;
@@ -1098,9 +1211,9 @@
int32_t return_value = -1;
uint64_t crc = 0;
if (method == kCompressStored) {
- return_value = CopyFileToFile(archive->fd, begin, size, &crc);
+ return_value = CopyEntryToWriter(archive->fd, entry, writer, &crc);
} else if (method == kCompressDeflated) {
- return_value = InflateToFile(archive->fd, entry, begin, size, &crc);
+ return_value = InflateEntryToWriter(archive->fd, entry, writer, &crc);
}
if (!return_value && entry->has_data_descriptor) {
@@ -1120,40 +1233,20 @@
return return_value;
}
+int32_t ExtractToMemory(ZipArchiveHandle handle, ZipEntry* entry,
+ uint8_t* begin, uint32_t size) {
+ std::unique_ptr<Writer> writer(new MemoryWriter(begin, size));
+ return ExtractToWriter(handle, entry, writer.get());
+}
+
int32_t ExtractEntryToFile(ZipArchiveHandle handle,
ZipEntry* entry, int fd) {
- const uint32_t declared_length = entry->uncompressed_length;
-
- const off64_t current_offset = lseek64(fd, 0, SEEK_CUR);
- if (current_offset == -1) {
- ALOGW("Zip: unable to seek to current location on fd %d: %s", fd,
- strerror(errno));
+ std::unique_ptr<Writer> writer(FileWriter::Create(fd, entry));
+ if (writer.get() == nullptr) {
return kIoError;
}
- int result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
- if (result == -1) {
- ALOGW("Zip: unable to truncate file to %" PRId64 ": %s",
- static_cast<int64_t>(declared_length + current_offset), strerror(errno));
- return kIoError;
- }
-
- // Don't attempt to map a region of length 0. We still need the
- // ftruncate() though, since the API guarantees that we will truncate
- // the file to the end of the uncompressed output.
- if (declared_length == 0) {
- return 0;
- }
-
- android::FileMap map;
- if (!map.create(kTempMappingFileName, fd, current_offset, declared_length, false)) {
- return kMmapFailed;
- }
-
- const int32_t error = ExtractToMemory(handle, entry,
- reinterpret_cast<uint8_t*>(map.getDataPtr()),
- map.getDataLength());
- return error;
+ return ExtractToWriter(handle, entry, writer.get());
}
const char* ErrorCodeString(int32_t error_code) {
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index 64faa6d..f8952ce 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -23,6 +23,7 @@
#include <unistd.h>
#include <vector>
+#include <base/file.h>
#include <gtest/gtest.h>
static std::string test_data_dir;
@@ -228,6 +229,44 @@
0x54557478, 0x13030005, 0x7552e25c, 0x01000b78, 0x00428904, 0x13880400,
0x4b500000, 0x00000605, 0x00010000, 0x004f0001, 0x00430000, 0x00000000 };
+// This is a zip file containing a single entry (ab.txt) that contains
+// 90072 repetitions of the string "ab\n" and has an uncompressed length
+// of 270216 bytes.
+static const uint16_t kAbZip[] = {
+ 0x4b50, 0x0403, 0x0014, 0x0000, 0x0008, 0x51d2, 0x4698, 0xc4b0,
+ 0x2cda, 0x011b, 0x0000, 0x1f88, 0x0004, 0x0006, 0x001c, 0x6261,
+ 0x742e, 0x7478, 0x5455, 0x0009, 0x7c03, 0x3a09, 0x7c55, 0x3a09,
+ 0x7555, 0x0b78, 0x0100, 0x8904, 0x0042, 0x0400, 0x1388, 0x0000,
+ 0xc2ed, 0x0d31, 0x0000, 0x030c, 0x7fa0, 0x3b2e, 0x22ff, 0xa2aa,
+ 0x841f, 0x45fc, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555, 0x5555,
+ 0x5555, 0x5555, 0x5555, 0x5555, 0xdd55, 0x502c, 0x014b, 0x1e02,
+ 0x1403, 0x0000, 0x0800, 0xd200, 0x9851, 0xb046, 0xdac4, 0x1b2c,
+ 0x0001, 0x8800, 0x041f, 0x0600, 0x1800, 0x0000, 0x0000, 0x0100,
+ 0x0000, 0xa000, 0x0081, 0x0000, 0x6100, 0x2e62, 0x7874, 0x5574,
+ 0x0554, 0x0300, 0x097c, 0x553a, 0x7875, 0x000b, 0x0401, 0x4289,
+ 0x0000, 0x8804, 0x0013, 0x5000, 0x054b, 0x0006, 0x0000, 0x0100,
+ 0x0100, 0x4c00, 0x0000, 0x5b00, 0x0001, 0x0000, 0x0000
+};
+
+static const uint8_t kAbTxtName[] = { 'a', 'b', '.', 't', 'x', 't' };
+static const uint16_t kAbTxtNameLength = sizeof(kAbTxtName);
+static const size_t kAbUncompressedSize = 270216;
+
static int make_temporary_file(const char* file_name_pattern) {
char full_path[1024];
// Account for differences between the host and the target.
@@ -275,6 +314,55 @@
close(output_fd);
}
+TEST(ziparchive, EntryLargerThan32K) {
+ char temp_file_pattern[] = "entry_larger_than_32k_test_XXXXXX";
+ int fd = make_temporary_file(temp_file_pattern);
+ ASSERT_NE(-1, fd);
+ ASSERT_TRUE(android::base::WriteFully(fd, reinterpret_cast<const uint8_t*>(kAbZip),
+ sizeof(kAbZip) - 1));
+ ZipArchiveHandle handle;
+ ASSERT_EQ(0, OpenArchiveFd(fd, "EntryLargerThan32KTest", &handle));
+
+ ZipEntry entry;
+ ZipEntryName ab_name;
+ ab_name.name = kAbTxtName;
+ ab_name.name_length = kAbTxtNameLength;
+ ASSERT_EQ(0, FindEntry(handle, ab_name, &entry));
+ ASSERT_EQ(kAbUncompressedSize, entry.uncompressed_length);
+
+ // Extract the entry to memory.
+ std::vector<uint8_t> buffer(kAbUncompressedSize);
+ ASSERT_EQ(0, ExtractToMemory(handle, &entry, &buffer[0], buffer.size()));
+
+ // Extract the entry to a file.
+ char output_file_pattern[] = "entry_larger_than_32k_test_output_XXXXXX";
+ int output_fd = make_temporary_file(output_file_pattern);
+ ASSERT_NE(-1, output_fd);
+ ASSERT_EQ(0, ExtractEntryToFile(handle, &entry, output_fd));
+
+ // Make sure the extracted file size is as expected.
+ struct stat stat_buf;
+ ASSERT_EQ(0, fstat(output_fd, &stat_buf));
+ ASSERT_EQ(kAbUncompressedSize, static_cast<size_t>(stat_buf.st_size));
+
+ // Read the file back to a buffer and make sure the contents are
+ // the same as the memory buffer we extracted directly to.
+ std::vector<uint8_t> file_contents(kAbUncompressedSize);
+ ASSERT_EQ(0, lseek64(output_fd, 0, SEEK_SET));
+ ASSERT_TRUE(android::base::ReadFully(output_fd, &file_contents[0], file_contents.size()));
+ ASSERT_EQ(file_contents, buffer);
+
+ for (int i = 0; i < 90072; ++i) {
+ const uint8_t* line = &file_contents[0] + (3 * i);
+ ASSERT_EQ('a', line[0]);
+ ASSERT_EQ('b', line[1]);
+ ASSERT_EQ('\n', line[2]);
+ }
+
+ close(fd);
+ close(output_fd);
+}
+
TEST(ziparchive, TrailerAfterEOCD) {
char temp_file_pattern[] = "trailer_after_eocd_test_XXXXXX";
int fd = make_temporary_file(temp_file_pattern);
diff --git a/logcat/event.logtags b/logcat/event.logtags
index 1b5c6f4..909f8e2 100644
--- a/logcat/event.logtags
+++ b/logcat/event.logtags
@@ -21,6 +21,7 @@
# 2: long
# 3: string
# 4: list
+# 5: float
#
# The data unit is a number taken from the following list:
# 1: Number of objects
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 90370e9..caae54b 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -155,12 +155,14 @@
event->length = htole32(l);
memcpy(event->data, str, l);
- logbuf->log(LOG_ID_EVENTS, now, uid, pid, tid,
- reinterpret_cast<char *>(event),
- (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
+ rc = logbuf->log(LOG_ID_EVENTS, now, uid, pid, tid,
+ reinterpret_cast<char *>(event),
+ (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
free(event);
- notify = true;
+ if (rc >= 0) {
+ notify = true;
+ }
}
// log to main
@@ -197,17 +199,22 @@
strncpy(newstr + 1 + l, str, estr - str);
strcpy(newstr + 1 + l + (estr - str), ecomm);
- logbuf->log(LOG_ID_MAIN, now, uid, pid, tid, newstr,
- (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
+ rc = logbuf->log(LOG_ID_MAIN, now, uid, pid, tid, newstr,
+ (n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
free(newstr);
- notify = true;
+ if (rc >= 0) {
+ notify = true;
+ }
}
free(str);
if (notify) {
reader->notifyNewLog();
+ if (rc < 0) {
+ rc = n;
+ }
}
return rc;
@@ -216,7 +223,7 @@
int LogAudit::log(char *buf) {
char *audit = strstr(buf, " audit(");
if (!audit) {
- return 0;
+ return -EXDEV;
}
*audit = '\0';
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 260e237..1dced11 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -15,6 +15,7 @@
*/
#include <ctype.h>
+#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/user.h>
@@ -132,11 +133,11 @@
init();
}
-void LogBuffer::log(log_id_t log_id, log_time realtime,
- uid_t uid, pid_t pid, pid_t tid,
- const char *msg, unsigned short len) {
+int LogBuffer::log(log_id_t log_id, log_time realtime,
+ uid_t uid, pid_t pid, pid_t tid,
+ const char *msg, unsigned short len) {
if ((log_id >= LOG_ID_MAX) || (log_id < 0)) {
- return;
+ return -EINVAL;
}
LogBufferElement *elem = new LogBufferElement(log_id, realtime,
uid, pid, tid, msg, len);
@@ -193,6 +194,8 @@
stats.add(elem);
maybePrune(log_id);
pthread_mutex_unlock(&mLogElementsLock);
+
+ return len;
}
// If we're using more than 256K of memory for log entries, prune
@@ -223,6 +226,84 @@
return it;
}
+// Define a temporary mechanism to report the last LogBufferElement pointer
+// for the specified uid, pid and tid. Used below to help merge-sort when
+// pruning for worst UID.
+class LogBufferElementKey {
+ const union {
+ struct {
+ uint16_t uid;
+ uint16_t pid;
+ uint16_t tid;
+ uint16_t padding;
+ } __packed;
+ uint64_t value;
+ } __packed;
+
+public:
+ LogBufferElementKey(uid_t u, pid_t p, pid_t t):uid(u),pid(p),tid(t),padding(0) { }
+ LogBufferElementKey(uint64_t k):value(k) { }
+
+ uint64_t getKey() { return value; }
+};
+
+class LogBufferElementEntry {
+ const uint64_t key;
+ LogBufferElement *last;
+
+public:
+ LogBufferElementEntry(const uint64_t &k, LogBufferElement *e):key(k),last(e) { }
+
+ const uint64_t&getKey() const { return key; }
+
+ LogBufferElement *getLast() { return last; }
+};
+
+class LogBufferElementLast : public android::BasicHashtable<uint64_t, LogBufferElementEntry> {
+
+public:
+ bool merge(LogBufferElement *e, unsigned short dropped) {
+ LogBufferElementKey key(e->getUid(), e->getPid(), e->getTid());
+ android::hash_t hash = android::hash_type(key.getKey());
+ ssize_t index = find(-1, hash, key.getKey());
+ if (index != -1) {
+ LogBufferElementEntry &entry = editEntryAt(index);
+ LogBufferElement *l = entry.getLast();
+ unsigned short d = l->getDropped();
+ if ((dropped + d) > USHRT_MAX) {
+ removeAt(index);
+ } else {
+ l->setDropped(dropped + d);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ size_t add(LogBufferElement *e) {
+ LogBufferElementKey key(e->getUid(), e->getPid(), e->getTid());
+ android::hash_t hash = android::hash_type(key.getKey());
+ return android::BasicHashtable<uint64_t, LogBufferElementEntry>::
+ add(hash, LogBufferElementEntry(key.getKey(), e));
+ }
+
+ inline void clear() {
+ android::BasicHashtable<uint64_t, LogBufferElementEntry>::clear();
+ }
+
+ void clear(LogBufferElement *e) {
+ 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()) {
+ removeAt(index);
+ index = -1;
+ }
+ }
+ }
+
+};
+
// prune "pruneRows" of type "id" from the buffer.
//
// mLogElementsLock must be held when this function is called.
@@ -284,9 +365,16 @@
if (sorted.get()) {
if (sorted[0] && sorted[1]) {
- worst = sorted[0]->getKey();
worst_sizes = sorted[0]->getSizes();
- second_worst_sizes = sorted[1]->getSizes();
+ // Calculate threshold as 12.5% of available storage
+ size_t threshold = log_buffer_size(id) / 8;
+ if (worst_sizes > threshold) {
+ worst = sorted[0]->getKey();
+ second_worst_sizes = sorted[1]->getSizes();
+ if (second_worst_sizes < threshold) {
+ second_worst_sizes = threshold;
+ }
+ }
}
}
}
@@ -298,7 +386,7 @@
bool kick = false;
bool leading = true;
- LogBufferElement *last = NULL;
+ LogBufferElementLast last;
for(it = mLogElements.begin(); it != mLogElements.end();) {
LogBufferElement *e = *it;
@@ -319,24 +407,18 @@
continue;
}
- pid_t pid = e->getPid();
-
// merge any drops
- if (last && dropped
- && ((dropped + last->getDropped()) < USHRT_MAX)
- && (last->getPid() == pid)
- && (last->getTid() == e->getTid())) {
+ if (dropped && last.merge(e, dropped)) {
it = mLogElements.erase(it);
stats.erase(e);
delete e;
- last->setDropped(dropped + last->getDropped());
continue;
}
leading = false;
if (hasBlacklist && mPrune.naughty(e)) {
- last = NULL;
+ last.clear(e);
it = erase(it);
if (dropped) {
continue;
@@ -358,13 +440,13 @@
}
if (dropped) {
- last = e;
+ last.add(e);
++it;
continue;
}
if (e->getUid() != worst) {
- last = NULL;
+ last.clear(e);
++it;
continue;
}
@@ -379,17 +461,12 @@
unsigned short len = e->getMsgLen();
stats.drop(e);
e->setDropped(1);
- // merge any drops
- if (last
- && (last->getDropped() < (USHRT_MAX - 1))
- && (last->getPid() == pid)
- && (last->getTid() == e->getTid())) {
+ if (last.merge(e, 1)) {
it = mLogElements.erase(it);
stats.erase(e);
delete e;
- last->setDropped(last->getDropped() + 1);
} else {
- last = e;
+ last.add(e);
++it;
}
if (worst_sizes < second_worst_sizes) {
@@ -397,6 +474,7 @@
}
worst_sizes -= len;
}
+ last.clear();
if (!kick || !mPrune.worstUidEnabled()) {
break; // the following loop will ask bad clients to skip/drop
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index a29e015..9ee243d 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -48,9 +48,9 @@
LogBuffer(LastLogTimes *times);
void init();
- void log(log_id_t log_id, log_time realtime,
- uid_t uid, pid_t pid, pid_t tid,
- const char *msg, unsigned short len);
+ int log(log_id_t log_id, log_time realtime,
+ uid_t uid, pid_t pid, pid_t tid,
+ const char *msg, unsigned short len);
uint64_t flushTo(SocketClient *writer, const uint64_t start,
bool privileged,
int (*filter)(const LogBufferElement *element, void *arg) = NULL,
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
index 3b4ef88..05ced06 100644
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -98,10 +98,11 @@
// NB: hdr.msg_flags & MSG_TRUNC is not tested, silently passing a
// truncated message to the logs.
- logbuf->log((log_id_t)header->id, header->realtime,
- cred->uid, cred->pid, header->tid, msg,
- ((size_t) n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX);
- reader->notifyNewLog();
+ if (logbuf->log((log_id_t)header->id, header->realtime,
+ cred->uid, cred->pid, header->tid, msg,
+ ((size_t) n <= USHRT_MAX) ? (unsigned short) n : USHRT_MAX) >= 0) {
+ reader->notifyNewLog();
+ }
return true;
}
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 0801fe8..eadc4dd 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -328,22 +328,32 @@
}
if (!headerPrinted) {
+ output.appendFormat("\n\n");
+ android::String8 name("");
if (uid == AID_ROOT) {
- output.appendFormat(
- "\n\nChattiest UIDs in %s:\n",
+ name.appendFormat(
+ "Chattiest UIDs in %s log buffer:",
android_log_id_to_name(id));
} else {
- output.appendFormat(
- "\n\nLogging for your UID in %s:\n",
+ name.appendFormat(
+ "Logging for your UID in %s log buffer:",
android_log_id_to_name(id));
}
- android::String8 name("UID");
android::String8 size("Size");
android::String8 pruned("Pruned");
if (!worstUidEnabledForLogid(id)) {
pruned.setTo("");
}
format_line(output, name, size, pruned);
+
+ name.setTo("UID PACKAGE");
+ size.setTo("BYTES");
+ pruned.setTo("LINES");
+ if (!worstUidEnabledForLogid(id)) {
+ pruned.setTo("");
+ }
+ format_line(output, name, size, pruned);
+
headerPrinted = true;
}
@@ -380,15 +390,22 @@
}
if (!headerPrinted) {
+ output.appendFormat("\n\n");
+ android::String8 name("");
if (uid == AID_ROOT) {
- output.appendFormat("\n\nChattiest PIDs:\n");
+ name.appendFormat("Chattiest PIDs:");
} else {
- output.appendFormat("\n\nLogging for this PID:\n");
+ name.appendFormat("Logging for this PID:");
}
- android::String8 name(" PID/UID");
android::String8 size("Size");
android::String8 pruned("Pruned");
format_line(output, name, size, pruned);
+
+ name.setTo(" PID/UID COMMAND LINE");
+ size.setTo("BYTES");
+ pruned.setTo("LINES");
+ format_line(output, name, size, pruned);
+
headerPrinted = true;
}
diff --git a/logd/main.cpp b/logd/main.cpp
index 4aa38b3..eb29596 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -367,12 +367,12 @@
int rc = klogctl(KLOG_READ_ALL, buf, len);
- buf[len - 1] = '\0';
+ if (rc >= 0) {
+ buf[len - 1] = '\0';
- for(char *ptr, *tok = buf;
- (rc >= 0) && ((tok = strtok_r(tok, "\r\n", &ptr)));
- tok = NULL) {
- rc = al->log(tok);
+ for (char *ptr, *tok = buf; (tok = strtok_r(tok, "\r\n", &ptr)); tok = NULL) {
+ al->log(tok);
+ }
}
}
diff --git a/rootdir/etc/mountd.conf b/rootdir/etc/mountd.conf
deleted file mode 100644
index 094a2c7..0000000
--- a/rootdir/etc/mountd.conf
+++ /dev/null
@@ -1,19 +0,0 @@
-## mountd configuration file
-
-## add a mount entry for each mount point to be managed by mountd
-mount {
- ## root block device with partition map or raw FAT file system
- block_device /dev/block/mmcblk0
-
- ## mount point for block device
- mount_point /sdcard
-
- ## true if this mount point can be shared via USB mass storage
- enable_ums true
-
- ## path to the UMS driver file for specifying the block device path
- ## use this for the mass_storage function driver
- driver_store_path /sys/devices/platform/usb_mass_storage/lun0/file
- ## use this for android_usb composite gadget driver
- ##driver_store_path /sys/devices/platform/msm_hsusb/gadget/lun0/file
-}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index a2b8f59..3709b82 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -14,13 +14,6 @@
# Set init and its forked children's oom_adj.
write /proc/1/oom_score_adj -1000
- # Apply strict SELinux checking of PROT_EXEC on mmap/mprotect calls.
- write /sys/fs/selinux/checkreqprot 0
-
- # Set the security context for the init process.
- # This should occur before anything else (e.g. ueventd) is started.
- setcon u:r:init:s0
-
# Set the security context of /adb_keys if present.
restorecon /adb_keys
@@ -162,6 +155,7 @@
# Load properties from /system/ + /factory after fs mount.
on load_all_props_action
load_all_props
+ start logd
start logd-reinit
# Indicate to fw loaders that the relevant mounts are up.
@@ -226,14 +220,17 @@
mkdir /cache/lost+found 0770 root root
on post-fs-data
- installkey /data
-
# We chown/chmod /data again so because mount is run as root + defaults
chown system system /data
chmod 0771 /data
# We restorecon /data in case the userdata partition has been reset.
restorecon /data
+ # Make sure we have the device encryption key
+ start logd
+ start vold
+ installkey /data
+
# Start bootcharting as soon as possible after the data partition is
# mounted to collect more data.
mkdir /data/bootchart 0755 shell shell
@@ -248,6 +245,7 @@
mkdir /data/misc/bluedroid 0770 bluetooth net_bt_stack
mkdir /data/misc/bluetooth 0770 system system
mkdir /data/misc/keystore 0700 keystore keystore
+ mkdir /data/misc/gatekeeper 0700 system system
mkdir /data/misc/keychain 0771 system system
mkdir /data/misc/net 0750 root shell
mkdir /data/misc/radio 0770 system radio
@@ -444,6 +442,7 @@
on property:vold.decrypt=trigger_load_persist_props
load_persist_props
+ start logd
start logd-reinit
on property:vold.decrypt=trigger_post_fs_data
@@ -453,7 +452,6 @@
class_start main
on property:vold.decrypt=trigger_restart_framework
- installkey /data
class_start main
class_start late_start
@@ -489,7 +487,6 @@
socket logdw dgram 0222 logd logd
service logd-reinit /system/bin/logd --reinit
- start logd
oneshot
disabled
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index 041c37a..893c0dc 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -1875,7 +1875,7 @@
struct fuse fuse;
/* cleanup from previous instance, if necessary */
- umount2(dest_path, 2);
+ umount2(dest_path, MNT_DETACH);
fd = open("/dev/fuse", O_RDWR);
if (fd < 0){
diff --git a/toolbox/toolbox.c b/toolbox/toolbox.c
index 0eac390..915da44 100644
--- a/toolbox/toolbox.c
+++ b/toolbox/toolbox.c
@@ -1,6 +1,8 @@
+#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
int main(int, char **);
@@ -31,11 +33,24 @@
{ 0, 0 },
};
+static void SIGPIPE_handler(int signal) {
+ // Those desktop Linux tools that catch SIGPIPE seem to agree that it's
+ // a successful way to exit, not a failure. (Which makes sense --- we were
+ // told to stop by a reader, rather than failing to continue ourselves.)
+ _exit(0);
+}
+
int main(int argc, char **argv)
{
int i;
char *name = argv[0];
+ // Let's assume that none of this code handles broken pipes. At least ls,
+ // ps, and top were broken (though I'd previously added this fix locally
+ // to top). We exit rather than use SIG_IGN because tools like top will
+ // just keep on writing to nowhere forever if we don't stop them.
+ signal(SIGPIPE, SIGPIPE_handler);
+
if((argc > 1) && (argv[1][0] == '@')) {
name = argv[1] + 1;
argc--;
diff --git a/toolbox/top.c b/toolbox/top.c
index b1a275c..1e99d4c 100644
--- a/toolbox/top.c
+++ b/toolbox/top.c
@@ -109,15 +109,9 @@
static int numcmp(long long a, long long b);
static void usage(char *cmd);
-static void exit_top(int signal) {
- exit(EXIT_FAILURE);
-}
-
int top_main(int argc, char *argv[]) {
num_used_procs = num_free_procs = 0;
- signal(SIGPIPE, exit_top);
-
max_procs = 0;
delay = 3;
iterations = -1;