Merge "Add -f to insmod"
diff --git a/adb/Android.mk b/adb/Android.mk
index 6188184..0babf1d 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -319,6 +319,7 @@
LOCAL_C_INCLUDES += system/extras/ext4_utils
LOCAL_SANITIZE := $(adb_target_sanitize)
+LOCAL_STRIP_MODULE := keep_symbols
LOCAL_STATIC_LIBRARIES := \
libadbd \
libbase \
@@ -333,6 +334,7 @@
libbase \
libcrypto_utils_static \
libcrypto_static \
- libminijail
+ libminijail \
+ libdebuggerd_client \
include $(BUILD_EXECUTABLE)
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 3f14f1a..c3f1a96 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -329,8 +329,6 @@
void handle_packet(apacket *p, atransport *t)
{
- asocket *s;
-
D("handle_packet() %c%c%c%c", ((char*) (&(p->msg.command)))[0],
((char*) (&(p->msg.command)))[1],
((char*) (&(p->msg.command)))[2],
@@ -339,7 +337,7 @@
switch(p->msg.command){
case A_SYNC:
- if(p->msg.arg0){
+ if (p->msg.arg0){
send_packet(p, t);
#if ADB_HOST
send_connect(t);
@@ -384,8 +382,8 @@
if (t->online && p->msg.arg0 != 0 && p->msg.arg1 == 0) {
char *name = (char*) p->data;
name[p->msg.data_length > 0 ? p->msg.data_length - 1 : 0] = 0;
- s = create_local_service_socket(name, t);
- if(s == 0) {
+ asocket* s = create_local_service_socket(name, t);
+ if (s == nullptr) {
send_close(0, p->msg.arg0, t);
} else {
s->peer = create_remote_socket(p->msg.arg0, t);
@@ -398,7 +396,8 @@
case A_OKAY: /* READY(local-id, remote-id, "") */
if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
- if((s = find_local_socket(p->msg.arg1, 0))) {
+ asocket* s = find_local_socket(p->msg.arg1, 0);
+ if (s) {
if(s->peer == 0) {
/* On first READY message, create the connection. */
s->peer = create_remote_socket(p->msg.arg0, t);
@@ -422,7 +421,8 @@
case A_CLSE: /* CLOSE(local-id, remote-id, "") or CLOSE(0, remote-id, "") */
if (t->online && p->msg.arg1 != 0) {
- if((s = find_local_socket(p->msg.arg1, p->msg.arg0))) {
+ asocket* s = find_local_socket(p->msg.arg1, p->msg.arg0);
+ if (s) {
/* According to protocol.txt, p->msg.arg0 might be 0 to indicate
* a failed OPEN only. However, due to a bug in previous ADB
* versions, CLOSE(0, remote-id, "") was also used for normal
@@ -445,11 +445,12 @@
case A_WRTE: /* WRITE(local-id, remote-id, <data>) */
if (t->online && p->msg.arg0 != 0 && p->msg.arg1 != 0) {
- if((s = find_local_socket(p->msg.arg1, p->msg.arg0))) {
+ asocket* s = find_local_socket(p->msg.arg1, p->msg.arg0);
+ if (s) {
unsigned rid = p->msg.arg0;
p->len = p->msg.data_length;
- if(s->enqueue(s, p) == 0) {
+ if (s->enqueue(s, p) == 0) {
D("Enqueue the socket");
send_ready(s->id, rid, t);
}
diff --git a/adb/adb_auth_host.cpp b/adb/adb_auth_host.cpp
index 03cebe9..dff874f 100644
--- a/adb/adb_auth_host.cpp
+++ b/adb/adb_auth_host.cpp
@@ -33,16 +33,13 @@
#include <crypto_utils/android_pubkey.h>
#include <cutils/list.h>
+#include <openssl/base64.h>
#include <openssl/evp.h>
#include <openssl/objects.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/sha.h>
-#if defined(OPENSSL_IS_BORINGSSL)
-#include <openssl/base64.h>
-#endif
-
#define ANDROID_PATH ".android"
#define ADB_KEY_FILE "adbkey"
@@ -54,108 +51,52 @@
static struct listnode key_list;
-static void get_user_info(char *buf, size_t len)
-{
- char hostname[1024], username[1024];
- int ret = -1;
-
- if (getenv("HOSTNAME") != NULL) {
- strncpy(hostname, getenv("HOSTNAME"), sizeof(hostname));
- hostname[sizeof(hostname)-1] = '\0';
- ret = 0;
- }
-
-#ifndef _WIN32
- if (ret < 0)
- ret = gethostname(hostname, sizeof(hostname));
+static std::string get_user_info() {
+ std::string hostname;
+ if (getenv("HOSTNAME")) hostname = getenv("HOSTNAME");
+#if !defined(_WIN32)
+ char buf[64];
+ if (hostname.empty() && gethostname(buf, sizeof(buf)) != -1) hostname = buf;
#endif
- if (ret < 0)
- strcpy(hostname, "unknown");
+ if (hostname.empty()) hostname = "unknown";
- ret = -1;
-
- if (getenv("LOGNAME") != NULL) {
- strncpy(username, getenv("LOGNAME"), sizeof(username));
- username[sizeof(username)-1] = '\0';
- ret = 0;
- }
-
+ std::string username;
+ if (getenv("LOGNAME")) username = getenv("LOGNAME");
#if !defined _WIN32 && !defined ADB_HOST_ON_TARGET
- if (ret < 0)
- ret = getlogin_r(username, sizeof(username));
+ if (username.empty() && getlogin()) username = getlogin();
#endif
- if (ret < 0)
- strcpy(username, "unknown");
+ if (username.empty()) hostname = "unknown";
- ret = snprintf(buf, len, " %s@%s", username, hostname);
- if (ret >= (signed)len)
- buf[len - 1] = '\0';
+ return " " + username + "@" + hostname;
}
-static int write_public_keyfile(RSA *private_key, const char *private_key_path)
-{
+static bool write_public_keyfile(RSA* private_key, const std::string& private_key_path) {
uint8_t binary_key_data[ANDROID_PUBKEY_ENCODED_SIZE];
- uint8_t* base64_key_data = nullptr;
- size_t base64_key_length = 0;
- FILE *outfile = NULL;
- char path[PATH_MAX], info[MAX_PAYLOAD_V1];
- int ret = 0;
-
- if (!android_pubkey_encode(private_key, binary_key_data,
- sizeof(binary_key_data))) {
- D("Failed to convert to publickey");
- goto out;
+ if (!android_pubkey_encode(private_key, binary_key_data, sizeof(binary_key_data))) {
+ LOG(ERROR) << "Failed to convert to public key";
+ return false;
}
- D("Writing public key to '%s'", path);
-
-#if defined(OPENSSL_IS_BORINGSSL)
+ size_t base64_key_length;
if (!EVP_EncodedLength(&base64_key_length, sizeof(binary_key_data))) {
- D("Public key too large to base64 encode");
- goto out;
- }
-#else
- /* While we switch from OpenSSL to BoringSSL we have to implement
- * |EVP_EncodedLength| here. */
- base64_key_length = 1 + ((sizeof(binary_key_data) + 2) / 3 * 4);
-#endif
-
- base64_key_data = new uint8_t[base64_key_length];
- if (base64_key_data == nullptr) {
- D("Allocation failure");
- goto out;
+ LOG(ERROR) << "Public key too large to base64 encode";
+ return false;
}
- base64_key_length = EVP_EncodeBlock(base64_key_data, binary_key_data,
+ std::string content;
+ content.resize(base64_key_length);
+ base64_key_length = EVP_EncodeBlock(reinterpret_cast<uint8_t*>(&content[0]), binary_key_data,
sizeof(binary_key_data));
- get_user_info(info, sizeof(info));
- if (snprintf(path, sizeof(path), "%s.pub", private_key_path) >=
- (int)sizeof(path)) {
- D("Path too long while writing public key");
- goto out;
+ content += get_user_info();
+
+ std::string path(private_key_path + ".pub");
+ if (!android::base::WriteStringToFile(content, path)) {
+ PLOG(ERROR) << "Failed to write public key to '" << path << "'";
+ return false;
}
- outfile = fopen(path, "w");
- if (!outfile) {
- D("Failed to open '%s'", path);
- goto out;
- }
-
- if (fwrite(base64_key_data, base64_key_length, 1, outfile) != 1 ||
- fwrite(info, strlen(info), 1, outfile) != 1) {
- D("Write error while writing public key");
- goto out;
- }
-
- ret = 1;
-
- out:
- if (outfile != NULL) {
- fclose(outfile);
- }
- delete[] base64_key_data;
- return ret;
+ return true;
}
static int generate_key(const char *file)
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index 65640ad..d2ca44e 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -23,11 +23,6 @@
#include <stdlib.h>
#include <unistd.h>
-// We only build the affinity WAR code for Linux.
-#if defined(__linux__)
-#include <sched.h>
-#endif
-
#include <android-base/errors.h>
#include <android-base/file.h>
#include <android-base/logging.h>
@@ -39,21 +34,14 @@
#include "adb_utils.h"
#include "transport.h"
-#if defined(_WIN32)
-static BOOL WINAPI ctrlc_handler(DWORD type) {
- // TODO: Consider trying to kill a starting up adb server (if we're in
- // launch_server) by calling GenerateConsoleCtrlEvent().
- exit(STATUS_CONTROL_C_EXIT);
- return TRUE;
-}
-
static std::string GetLogFilePath() {
+#if defined(_WIN32)
const char log_name[] = "adb.log";
WCHAR temp_path[MAX_PATH];
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa364992%28v=vs.85%29.aspx
DWORD nchars = GetTempPathW(arraysize(temp_path), temp_path);
- if ((nchars >= arraysize(temp_path)) || (nchars == 0)) {
+ if (nchars >= arraysize(temp_path) || nchars == 0) {
// If string truncation or some other error.
fatal("cannot retrieve temporary file path: %s\n",
android::base::SystemErrorCodeToString(GetLastError()).c_str());
@@ -65,12 +53,12 @@
}
return temp_path_utf8 + log_name;
-}
#else
-static std::string GetLogFilePath() {
- return std::string("/tmp/adb.log");
-}
+ const char* tmp_dir = getenv("TMPDIR");
+ if (tmp_dir == nullptr) tmp_dir = "/tmp";
+ return android::base::StringPrintf("%s/adb.%u.log", tmp_dir, getuid());
#endif
+}
static void setup_daemon_logging(void) {
const std::string log_file_path(GetLogFilePath());
@@ -90,6 +78,15 @@
LOG(INFO) << adb_version();
}
+#if defined(_WIN32)
+static BOOL WINAPI ctrlc_handler(DWORD type) {
+ // TODO: Consider trying to kill a starting up adb server (if we're in
+ // launch_server) by calling GenerateConsoleCtrlEvent().
+ exit(STATUS_CONTROL_C_EXIT);
+ return TRUE;
+}
+#endif
+
int adb_server_main(int is_daemon, int server_port, int ack_reply_fd) {
#if defined(_WIN32)
// adb start-server starts us up with stdout and stderr hooked up to
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 82fa19a..477edc1 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -872,27 +872,26 @@
* we hang up.
*/
static int adb_sideload_host(const char* fn) {
- printf("loading: '%s'", fn);
- fflush(stdout);
+ fprintf(stderr, "loading: '%s'...\n", fn);
std::string content;
if (!android::base::ReadFileToString(fn, &content)) {
- printf("\n");
- fprintf(stderr, "* cannot read '%s' *\n", fn);
+ fprintf(stderr, "failed: %s\n", strerror(errno));
return -1;
}
const uint8_t* data = reinterpret_cast<const uint8_t*>(content.data());
unsigned sz = content.size();
+ fprintf(stderr, "connecting...\n");
std::string service =
android::base::StringPrintf("sideload-host:%d:%d", sz, SIDELOAD_HOST_BLOCK_SIZE);
std::string error;
unique_fd fd(adb_connect(service, &error));
- if (fd >= 0) {
+ if (fd < 0) {
// Try falling back to the older sideload method. Maybe this
// is an older device that doesn't support sideload-host.
- printf("\n");
+ fprintf(stderr, "falling back to older sideload method...\n");
return adb_download_buffer("sideload", fn, data, sz, true);
}
@@ -1093,12 +1092,10 @@
return true;
}
- // Give adbd 500ms to kill itself, then wait-for-device for it to come back up.
- adb_sleep_ms(500);
- TransportType type;
- const char* serial;
- adb_get_transport(&type, &serial);
- return wait_for_device("wait-for-any", type, serial);
+ // Give adbd some time to kill itself and come back up.
+ // We can't use wait-for-device because devices (e.g. adb over network) might not come back.
+ adb_sleep_ms(3000);
+ return true;
}
// Connects to the device "shell" service with |command| and prints the
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index 916bedf..b0a0162 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -32,6 +32,7 @@
#include <libminijail.h>
#include "cutils/properties.h"
+#include "debuggerd/client.h"
#include "private/android_filesystem_config.h"
#include "selinux/android.h"
@@ -247,6 +248,7 @@
close_stdin();
+ debuggerd_init(nullptr);
adb_trace_init(argv);
D("Handling main()");
diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp
index 926dbcf..14c26cb 100644
--- a/adb/file_sync_service.cpp
+++ b/adb/file_sync_service.cpp
@@ -21,13 +21,13 @@
#include <dirent.h>
#include <errno.h>
-#include <log/log.h>
-#include <selinux/android.h>
+#include <linux/xattr.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <sys/xattr.h>
#include <unistd.h>
#include <utime.h>
@@ -39,6 +39,8 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <log/log.h>
+#include <selinux/android.h>
static bool should_use_fs_config(const std::string& path) {
// TODO: use fs_config to configure permissions on /data.
@@ -47,11 +49,27 @@
android::base::StartsWith(path, "/oem/");
}
+static bool update_capabilities(const char* path, uint64_t capabilities) {
+ if (capabilities == 0) {
+ // Ensure we clean up in case the capabilities weren't 0 in the past.
+ removexattr(path, XATTR_NAME_CAPS);
+ return true;
+ }
+
+ vfs_cap_data cap_data = {};
+ cap_data.magic_etc = VFS_CAP_REVISION | VFS_CAP_FLAGS_EFFECTIVE;
+ cap_data.data[0].permitted = (capabilities & 0xffffffff);
+ cap_data.data[0].inheritable = 0;
+ cap_data.data[1].permitted = (capabilities >> 32);
+ cap_data.data[1].inheritable = 0;
+ return setxattr(path, XATTR_NAME_CAPS, &cap_data, sizeof(cap_data), 0) != -1;
+}
+
static bool secure_mkdirs(const std::string& path) {
uid_t uid = -1;
gid_t gid = -1;
unsigned int mode = 0775;
- uint64_t cap = 0;
+ uint64_t capabilities = 0;
if (path[0] != '/') return false;
@@ -62,18 +80,19 @@
partial_path += path_component;
if (should_use_fs_config(partial_path)) {
- fs_config(partial_path.c_str(), 1, nullptr, &uid, &gid, &mode, &cap);
+ fs_config(partial_path.c_str(), 1, nullptr, &uid, &gid, &mode, &capabilities);
}
if (adb_mkdir(partial_path.c_str(), mode) == -1) {
if (errno != EEXIST) {
return false;
}
} else {
- if (chown(partial_path.c_str(), uid, gid) == -1) {
- return false;
- }
+ if (chown(partial_path.c_str(), uid, gid) == -1) return false;
+
// Not all filesystems support setting SELinux labels. http://b/23530370.
selinux_android_restorecon(partial_path.c_str(), 0);
+
+ if (!update_capabilities(partial_path.c_str(), capabilities)) return false;
}
}
return true;
@@ -83,8 +102,7 @@
syncmsg msg;
msg.stat.id = ID_STAT;
- struct stat st;
- memset(&st, 0, sizeof(st));
+ struct stat st = {};
// TODO: add a way to report that the stat failed!
lstat(path, &st);
msg.stat.mode = st.st_mode;
@@ -146,8 +164,8 @@
return SendSyncFail(fd, android::base::StringPrintf("%s: %s", reason.c_str(), strerror(errno)));
}
-static bool handle_send_file(int s, const char* path, uid_t uid,
- gid_t gid, mode_t mode, std::vector<char>& buffer, bool do_unlink) {
+static bool handle_send_file(int s, const char* path, uid_t uid, gid_t gid, uint64_t capabilities,
+ mode_t mode, std::vector<char>& buffer, bool do_unlink) {
syncmsg msg;
unsigned int timestamp = 0;
@@ -178,8 +196,13 @@
// fchown clears the setuid bit - restore it if present.
// Ignore the result of calling fchmod. It's not supported
- // by all filesystems. b/12441485
+ // by all filesystems, so we don't check for success. b/12441485
fchmod(fd, mode);
+
+ if (!update_capabilities(path, capabilities)) {
+ SendSyncFailErrno(s, "update_capabilities failed");
+ goto fail;
+ }
}
while (true) {
@@ -338,13 +361,13 @@
uid_t uid = -1;
gid_t gid = -1;
- uint64_t cap = 0;
+ uint64_t capabilities = 0;
if (should_use_fs_config(path)) {
unsigned int broken_api_hack = mode;
- fs_config(path.c_str(), 0, nullptr, &uid, &gid, &broken_api_hack, &cap);
+ fs_config(path.c_str(), 0, nullptr, &uid, &gid, &broken_api_hack, &capabilities);
mode = broken_api_hack;
}
- return handle_send_file(s, path.c_str(), uid, gid, mode, buffer, do_unlink);
+ return handle_send_file(s, path.c_str(), uid, gid, capabilities, mode, buffer, do_unlink);
}
static bool do_recv(int s, const char* path, std::vector<char>& buffer) {
diff --git a/adb/jdwp_service.cpp b/adb/jdwp_service.cpp
index 3c812cc..7a44801 100644
--- a/adb/jdwp_service.cpp
+++ b/adb/jdwp_service.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-/* implement the "debug-ports" and "track-debug-ports" device services */
+#if !ADB_HOST
#define TRACE_TAG JDWP
@@ -24,22 +24,29 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/socket.h>
+#include <sys/un.h>
#include <unistd.h>
+#include <list>
+#include <memory>
+#include <vector>
+
#include "adb.h"
+#include "adb_io.h"
#include "adb_utils.h"
/* here's how these things work.
when adbd starts, it creates a unix server socket
- named @vm-debug-control (@ is a shortcut for "first byte is zero"
+ named @jdwp-control (@ is a shortcut for "first byte is zero"
to use the private namespace instead of the file system)
when a new JDWP daemon thread starts in a new VM process, it creates
- a connection to @vm-debug-control to announce its availability.
+ a connection to @jdwp-control to announce its availability.
- JDWP thread @vm-debug-control
+ JDWP thread @jdwp-control
| |
|-------------------------------> |
| hello I'm in process <pid> |
@@ -72,7 +79,7 @@
to the JDWP process with the help of sendmsg()
- JDWP thread @vm-debug-control
+ JDWP thread @jdwp-control
| |
| <----------------------|
| OK, try this file descriptor |
@@ -116,249 +123,191 @@
** for each JDWP process, we record its pid and its connected socket
**/
-#define MAX_OUT_FDS 4
+// PIDs are transmitted as 4 hex digits in ascii.
+static constexpr size_t PID_LEN = 4;
-#if !ADB_HOST
+static void jdwp_process_event(int socket, unsigned events, void* _proc);
+static void jdwp_process_list_updated(void);
-#include <sys/socket.h>
-#include <sys/un.h>
+struct JdwpProcess;
+static std::list<std::unique_ptr<JdwpProcess>> _jdwp_list;
struct JdwpProcess {
- JdwpProcess* next;
- JdwpProcess* prev;
- int pid;
- int socket;
- fdevent* fde;
+ explicit JdwpProcess(int socket) {
+ this->socket = socket;
+ this->fde = fdevent_create(socket, jdwp_process_event, this);
- char in_buff[4]; /* input character to read PID */
- int in_len; /* number from JDWP process */
+ if (!this->fde) {
+ fatal("could not create fdevent for new JDWP process");
+ }
- int out_fds[MAX_OUT_FDS]; /* output array of file descriptors */
- int out_count; /* to send to the JDWP process */
+ this->fde->state |= FDE_DONT_CLOSE;
+
+ /* start by waiting for the PID */
+ fdevent_add(this->fde, FDE_READ);
+ }
+
+ ~JdwpProcess() {
+ if (this->socket >= 0) {
+ adb_shutdown(this->socket);
+ adb_close(this->socket);
+ this->socket = -1;
+ }
+
+ if (this->fde) {
+ fdevent_destroy(this->fde);
+ this->fde = nullptr;
+ }
+
+ out_fds.clear();
+ }
+
+ void RemoveFromList() {
+ if (this->pid >= 0) {
+ D("removing pid %d from jdwp process list", this->pid);
+ } else {
+ D("removing transient JdwpProcess from list");
+ }
+
+ auto pred = [this](const auto& proc) { return proc.get() == this; };
+ _jdwp_list.remove_if(pred);
+ }
+
+ int pid = -1;
+ int socket = -1;
+ fdevent* fde = nullptr;
+
+ std::vector<unique_fd> out_fds;
+ char in_buf[PID_LEN + 1];
+ ssize_t in_len = 0;
};
-static JdwpProcess _jdwp_list;
+static size_t jdwp_process_list(char* buffer, size_t bufferlen) {
+ std::string temp;
-static int
-jdwp_process_list( char* buffer, int bufferlen )
-{
- char* end = buffer + bufferlen;
- char* p = buffer;
- JdwpProcess* proc = _jdwp_list.next;
-
- for ( ; proc != &_jdwp_list; proc = proc->next ) {
- int len;
-
+ for (auto& proc : _jdwp_list) {
/* skip transient connections */
- if (proc->pid < 0)
+ if (proc->pid < 0) {
continue;
+ }
- len = snprintf(p, end-p, "%d\n", proc->pid);
- if (p + len >= end)
+ std::string next = std::to_string(proc->pid) + "\n";
+ if (temp.length() + next.length() > bufferlen) {
+ D("truncating JDWP process list (max len = %zu)", bufferlen);
break;
- p += len;
- }
- p[0] = 0;
- return (p - buffer);
-}
-
-
-static int
-jdwp_process_list_msg( char* buffer, int bufferlen )
-{
- char head[5];
- int len = jdwp_process_list( buffer+4, bufferlen-4 );
- snprintf(head, sizeof head, "%04x", len);
- memcpy(buffer, head, 4);
- return len + 4;
-}
-
-
-static void jdwp_process_list_updated(void);
-
-static void
-jdwp_process_free( JdwpProcess* proc )
-{
- if (proc) {
- int n;
-
- proc->prev->next = proc->next;
- proc->next->prev = proc->prev;
-
- if (proc->socket >= 0) {
- adb_shutdown(proc->socket);
- adb_close(proc->socket);
- proc->socket = -1;
}
-
- if (proc->fde != NULL) {
- fdevent_destroy(proc->fde);
- proc->fde = NULL;
- }
- proc->pid = -1;
-
- for (n = 0; n < proc->out_count; n++) {
- adb_close(proc->out_fds[n]);
- }
- proc->out_count = 0;
-
- free(proc);
-
- jdwp_process_list_updated();
+ temp.append(next);
}
+
+ memcpy(buffer, temp.data(), temp.length());
+ return temp.length();
}
-
-static void jdwp_process_event(int, unsigned, void*); /* forward */
-
-
-static JdwpProcess*
-jdwp_process_alloc( int socket )
-{
- JdwpProcess* proc = reinterpret_cast<JdwpProcess*>(
- calloc(1, sizeof(*proc)));
-
- if (proc == NULL) {
- D("not enough memory to create new JDWP process");
- return NULL;
+static size_t jdwp_process_list_msg(char* buffer, size_t bufferlen) {
+ // Message is length-prefixed with 4 hex digits in ASCII.
+ static constexpr size_t header_len = 4;
+ if (bufferlen < header_len) {
+ fatal("invalid JDWP process list buffer size: %zu", bufferlen);
}
- proc->socket = socket;
- proc->pid = -1;
- proc->next = proc;
- proc->prev = proc;
-
- proc->fde = fdevent_create( socket, jdwp_process_event, proc );
- if (proc->fde == NULL) {
- D("could not create fdevent for new JDWP process" );
- free(proc);
- return NULL;
- }
-
- proc->fde->state |= FDE_DONT_CLOSE;
- proc->in_len = 0;
- proc->out_count = 0;
-
- /* append to list */
- proc->next = &_jdwp_list;
- proc->prev = proc->next->prev;
-
- proc->prev->next = proc;
- proc->next->prev = proc;
-
- /* start by waiting for the PID */
- fdevent_add(proc->fde, FDE_READ);
-
- return proc;
+ char head[header_len + 1];
+ size_t len = jdwp_process_list(buffer + header_len, bufferlen - header_len);
+ snprintf(head, sizeof head, "%04zx", len);
+ memcpy(buffer, head, header_len);
+ return len + header_len;
}
-
-static void
-jdwp_process_event( int socket, unsigned events, void* _proc )
-{
- JdwpProcess* proc = reinterpret_cast<JdwpProcess*>(_proc);
+static void jdwp_process_event(int socket, unsigned events, void* _proc) {
+ JdwpProcess* proc = reinterpret_cast<JdwpProcess*>(_proc);
if (events & FDE_READ) {
if (proc->pid < 0) {
/* read the PID as a 4-hexchar string */
- char* p = proc->in_buff + proc->in_len;
- int size = 4 - proc->in_len;
- char temp[5];
- while (size > 0) {
- int len = recv( socket, p, size, 0 );
- if (len < 0) {
- if (errno == EINTR)
- continue;
- if (errno == EAGAIN)
- return;
- /* this can fail here if the JDWP process crashes very fast */
- D("weird unknown JDWP process failure: %s",
- strerror(errno));
-
- goto CloseProcess;
- }
- if (len == 0) { /* end of stream ? */
- D("weird end-of-stream from unknown JDWP process");
- goto CloseProcess;
- }
- p += len;
- proc->in_len += len;
- size -= len;
+ if (proc->in_len < 0) {
+ fatal("attempting to read JDWP pid again?");
}
- /* we have read 4 characters, now decode the pid */
- memcpy(temp, proc->in_buff, 4);
- temp[4] = 0;
- if (sscanf( temp, "%04x", &proc->pid ) != 1) {
- D("could not decode JDWP %p PID number: '%s'", proc, temp);
+ char* p = proc->in_buf + proc->in_len;
+ size_t size = PID_LEN - proc->in_len;
+
+ ssize_t rc = TEMP_FAILURE_RETRY(recv(socket, p, size, 0));
+ if (rc < 0) {
+ if (errno == EAGAIN) {
+ return;
+ }
+
+ D("failed to read jdwp pid: %s", strerror(errno));
+ goto CloseProcess;
+ }
+
+ proc->in_len += rc;
+ if (proc->in_len != PID_LEN) {
+ return;
+ }
+
+ proc->in_buf[PID_LEN] = '\0';
+ proc->in_len = -1;
+
+ if (sscanf(proc->in_buf, "%04x", &proc->pid) != 1) {
+ D("could not decode JDWP %p PID number: '%s'", proc, p);
goto CloseProcess;
}
/* all is well, keep reading to detect connection closure */
D("Adding pid %d to jdwp process list", proc->pid);
jdwp_process_list_updated();
- }
- else
- {
+ } else {
/* the pid was read, if we get there it's probably because the connection
* was closed (e.g. the JDWP process exited or crashed) */
- char buf[32];
+ char buf[32];
- for (;;) {
- int len = recv(socket, buf, sizeof(buf), 0);
+ while (true) {
+ int len = TEMP_FAILURE_RETRY(recv(socket, buf, sizeof(buf), 0));
- if (len <= 0) {
- if (len < 0 && errno == EINTR)
- continue;
- if (len < 0 && errno == EAGAIN)
+ if (len == 0) {
+ D("terminating JDWP %d connection: EOF", proc->pid);
+ break;
+ } else if (len < 0) {
+ if (len < 0 && errno == EAGAIN) {
return;
- else {
- D("terminating JDWP %d connection: %s", proc->pid,
- strerror(errno));
- break;
}
- }
- else {
- D( "ignoring unexpected JDWP %d control socket activity (%d bytes)",
- proc->pid, len );
+
+ D("terminating JDWP %d connection: EOF", proc->pid);
+ break;
+ } else {
+ D("ignoring unexpected JDWP %d control socket activity (%d bytes)", proc->pid,
+ len);
}
}
- CloseProcess:
- if (proc->pid >= 0) {
- D( "remove pid %d to jdwp process list", proc->pid );
- }
- jdwp_process_free(proc);
- return;
+ goto CloseProcess;
}
}
if (events & FDE_WRITE) {
- D("trying to write to JDWP pid controli (count=%d first=%d) %d",
- proc->pid, proc->out_count, proc->out_fds[0]);
- if (proc->out_count > 0) {
- int fd = proc->out_fds[0];
- int n, ret;
- struct cmsghdr* cmsg;
- struct msghdr msg;
- struct iovec iov;
- char dummy = '!';
- char buffer[sizeof(struct cmsghdr) + sizeof(int)];
+ D("trying to send fd to JDWP process (count = %zu)", proc->out_fds.size());
+ if (!proc->out_fds.empty()) {
+ int fd = proc->out_fds.back().get();
+ struct cmsghdr* cmsg;
+ struct msghdr msg;
+ struct iovec iov;
+ char dummy = '!';
+ char buffer[sizeof(struct cmsghdr) + sizeof(int)];
- iov.iov_base = &dummy;
- iov.iov_len = 1;
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_flags = 0;
- msg.msg_control = buffer;
+ iov.iov_base = &dummy;
+ iov.iov_len = 1;
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_flags = 0;
+ msg.msg_control = buffer;
msg.msg_controllen = sizeof(buffer);
cmsg = CMSG_FIRSTHDR(&msg);
- cmsg->cmsg_len = msg.msg_controllen;
+ cmsg->cmsg_len = msg.msg_controllen;
cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_type = SCM_RIGHTS;
((int*)CMSG_DATA(cmsg))[0] = fd;
if (!set_file_block_mode(proc->socket, true)) {
@@ -366,74 +315,59 @@
goto CloseProcess;
}
- for (;;) {
- ret = sendmsg(proc->socket, &msg, 0);
- if (ret >= 0) {
- adb_close(fd);
- break;
- }
- if (errno == EINTR)
- continue;
- D("sending new file descriptor to JDWP %d failed: %s",
- proc->pid, strerror(errno));
+ int ret = TEMP_FAILURE_RETRY(sendmsg(proc->socket, &msg, 0));
+ if (ret < 0) {
+ D("sending new file descriptor to JDWP %d failed: %s", proc->pid, strerror(errno));
goto CloseProcess;
}
- D("sent file descriptor %d to JDWP process %d",
- fd, proc->pid);
+ adb_close(fd);
- for (n = 1; n < proc->out_count; n++)
- proc->out_fds[n-1] = proc->out_fds[n];
+ D("sent file descriptor %d to JDWP process %d", fd, proc->pid);
+
+ proc->out_fds.pop_back();
if (!set_file_block_mode(proc->socket, false)) {
VLOG(JDWP) << "failed to set non-blocking mode for fd " << proc->socket;
goto CloseProcess;
}
- if (--proc->out_count == 0)
- fdevent_del( proc->fde, FDE_WRITE );
+ if (proc->out_fds.empty()) {
+ fdevent_del(proc->fde, FDE_WRITE);
+ }
}
}
+
+ return;
+
+CloseProcess:
+ proc->RemoveFromList();
+ jdwp_process_list_updated();
}
-
-int
-create_jdwp_connection_fd(int pid)
-{
- JdwpProcess* proc = _jdwp_list.next;
-
+int create_jdwp_connection_fd(int pid) {
D("looking for pid %d in JDWP process list", pid);
- for ( ; proc != &_jdwp_list; proc = proc->next ) {
+
+ for (auto& proc : _jdwp_list) {
if (proc->pid == pid) {
- goto FoundIt;
+ int fds[2];
+
+ if (adb_socketpair(fds) < 0) {
+ D("%s: socket pair creation failed: %s", __FUNCTION__, strerror(errno));
+ return -1;
+ }
+ D("socketpair: (%d,%d)", fds[0], fds[1]);
+
+ proc->out_fds.emplace_back(fds[1]);
+ if (proc->out_fds.size() == 1) {
+ fdevent_add(proc->fde, FDE_WRITE);
+ }
+
+ return fds[0];
}
}
D("search failed !!");
return -1;
-
-FoundIt:
- {
- int fds[2];
-
- if (proc->out_count >= MAX_OUT_FDS) {
- D("%s: too many pending JDWP connection for pid %d",
- __FUNCTION__, pid);
- return -1;
- }
-
- if (adb_socketpair(fds) < 0) {
- D("%s: socket pair creation failed: %s",
- __FUNCTION__, strerror(errno));
- return -1;
- }
- D("socketpair: (%d,%d)", fds[0], fds[1]);
-
- proc->out_fds[ proc->out_count ] = fds[1];
- if (++proc->out_count == 1)
- fdevent_add( proc->fde, FDE_WRITE );
-
- return fds[0];
- }
}
/** VM DEBUG CONTROL SOCKET
@@ -442,33 +376,27 @@
**/
/* name of the debug control Unix socket */
-#define JDWP_CONTROL_NAME "\0jdwp-control"
-#define JDWP_CONTROL_NAME_LEN (sizeof(JDWP_CONTROL_NAME)-1)
+#define JDWP_CONTROL_NAME "\0jdwp-control"
+#define JDWP_CONTROL_NAME_LEN (sizeof(JDWP_CONTROL_NAME) - 1)
struct JdwpControl {
- int listen_socket;
- fdevent* fde;
+ int listen_socket;
+ fdevent* fde;
};
+static JdwpControl _jdwp_control;
-static void
-jdwp_control_event(int s, unsigned events, void* user);
+static void jdwp_control_event(int s, unsigned events, void* user);
-
-static int
-jdwp_control_init( JdwpControl* control,
- const char* sockname,
- int socknamelen )
-{
- sockaddr_un addr;
- socklen_t addrlen;
- int s;
- int maxpath = sizeof(addr.sun_path);
- int pathlen = socknamelen;
+static int jdwp_control_init(JdwpControl* control, const char* sockname, int socknamelen) {
+ sockaddr_un addr;
+ socklen_t addrlen;
+ int s;
+ int maxpath = sizeof(addr.sun_path);
+ int pathlen = socknamelen;
if (pathlen >= maxpath) {
- D( "vm debug control socket name too long (%d extra chars)",
- pathlen+1-maxpath );
+ D("vm debug control socket name too long (%d extra chars)", pathlen + 1 - maxpath);
return -1;
}
@@ -476,25 +404,22 @@
addr.sun_family = AF_UNIX;
memcpy(addr.sun_path, sockname, socknamelen);
- s = socket( AF_UNIX, SOCK_STREAM, 0 );
+ s = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (s < 0) {
- D( "could not create vm debug control socket. %d: %s",
- errno, strerror(errno));
+ D("could not create vm debug control socket. %d: %s", errno, strerror(errno));
return -1;
}
- addrlen = (pathlen + sizeof(addr.sun_family));
+ addrlen = pathlen + sizeof(addr.sun_family);
if (bind(s, reinterpret_cast<sockaddr*>(&addr), addrlen) < 0) {
- D( "could not bind vm debug control socket: %d: %s",
- errno, strerror(errno) );
+ D("could not bind vm debug control socket: %d: %s", errno, strerror(errno));
adb_close(s);
return -1;
}
- if ( listen(s, 4) < 0 ) {
- D("listen failed in jdwp control socket: %d: %s",
- errno, strerror(errno));
+ if (listen(s, 4) < 0) {
+ D("listen failed in jdwp control socket: %d: %s", errno, strerror(errno));
adb_close(s);
return -1;
}
@@ -503,128 +428,109 @@
control->fde = fdevent_create(s, jdwp_control_event, control);
if (control->fde == NULL) {
- D( "could not create fdevent for jdwp control socket" );
+ D("could not create fdevent for jdwp control socket");
adb_close(s);
return -1;
}
/* only wait for incoming connections */
fdevent_add(control->fde, FDE_READ);
- close_on_exec(s);
D("jdwp control socket started (%d)", control->listen_socket);
return 0;
}
-
-static void
-jdwp_control_event( int s, unsigned events, void* _control )
-{
- JdwpControl* control = (JdwpControl*) _control;
+static void jdwp_control_event(int s, unsigned events, void* _control) {
+ JdwpControl* control = (JdwpControl*)_control;
if (events & FDE_READ) {
- sockaddr_storage ss;
- sockaddr* addrp = reinterpret_cast<sockaddr*>(&ss);
- socklen_t addrlen = sizeof(ss);
- int s = -1;
- JdwpProcess* proc;
-
- do {
- s = adb_socket_accept(control->listen_socket, addrp, &addrlen);
- if (s < 0) {
- if (errno == EINTR)
- continue;
- if (errno == ECONNABORTED) {
- /* oops, the JDWP process died really quick */
- D("oops, the JDWP process died really quick");
- return;
- }
+ sockaddr_storage ss;
+ sockaddr* addrp = reinterpret_cast<sockaddr*>(&ss);
+ socklen_t addrlen = sizeof(ss);
+ int s = adb_socket_accept(control->listen_socket, addrp, &addrlen);
+ if (s < 0) {
+ if (errno == ECONNABORTED) {
+ /* oops, the JDWP process died really quick */
+ D("oops, the JDWP process died really quick");
+ return;
+ } else {
/* the socket is probably closed ? */
- D( "weird accept() failed on jdwp control socket: %s",
- strerror(errno) );
+ D("weird accept() failed on jdwp control socket: %s", strerror(errno));
return;
}
}
- while (s < 0);
- proc = jdwp_process_alloc( s );
- if (proc == NULL)
- return;
+ auto proc = std::make_unique<JdwpProcess>(s);
+ if (!proc) {
+ fatal("failed to allocate JdwpProcess");
+ }
+
+ _jdwp_list.emplace_back(std::move(proc));
}
}
-
-static JdwpControl _jdwp_control;
-
/** "jdwp" local service implementation
** this simply returns the list of known JDWP process pids
**/
-struct JdwpSocket {
- asocket socket;
- int pass;
+struct JdwpSocket : public asocket {
+ bool pass;
};
-static void
-jdwp_socket_close( asocket* s )
-{
- asocket* peer = s->peer;
+static void jdwp_socket_close(asocket* s) {
+ D("LS(%d): closing jdwp socket", s->id);
+
+ if (s->peer) {
+ D("LS(%d) peer->close()ing peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd);
+ s->peer->peer = nullptr;
+ s->peer->close(s->peer);
+ s->peer = nullptr;
+ }
remove_socket(s);
-
- if (peer) {
- peer->peer = NULL;
- peer->close(peer);
- }
free(s);
}
-static int
-jdwp_socket_enqueue( asocket* s, apacket* p )
-{
+static int jdwp_socket_enqueue(asocket* s, apacket* p) {
/* you can't write to this asocket */
+ D("LS(%d): JDWP socket received data?", s->id);
put_apacket(p);
s->peer->close(s->peer);
return -1;
}
+static void jdwp_socket_ready(asocket* s) {
+ JdwpSocket* jdwp = (JdwpSocket*)s;
+ asocket* peer = jdwp->peer;
-static void
-jdwp_socket_ready( asocket* s )
-{
- JdwpSocket* jdwp = (JdwpSocket*)s;
- asocket* peer = jdwp->socket.peer;
-
- /* on the first call, send the list of pids,
- * on the second one, close the connection
- */
- if (jdwp->pass == 0) {
- apacket* p = get_apacket();
+ /* on the first call, send the list of pids,
+ * on the second one, close the connection
+ */
+ if (!jdwp->pass) {
+ apacket* p = get_apacket();
p->len = jdwp_process_list((char*)p->data, s->get_max_payload());
peer->enqueue(peer, p);
- jdwp->pass = 1;
- }
- else {
+ jdwp->pass = true;
+ } else {
peer->close(peer);
}
}
-asocket*
-create_jdwp_service_socket( void )
-{
+asocket* create_jdwp_service_socket(void) {
JdwpSocket* s = reinterpret_cast<JdwpSocket*>(calloc(sizeof(*s), 1));
- if (s == NULL)
- return NULL;
+ if (!s) {
+ fatal("failed to allocate JdwpSocket");
+ }
- install_local_socket(&s->socket);
+ install_local_socket(s);
- s->socket.ready = jdwp_socket_ready;
- s->socket.enqueue = jdwp_socket_enqueue;
- s->socket.close = jdwp_socket_close;
- s->pass = 0;
+ s->ready = jdwp_socket_ready;
+ s->enqueue = jdwp_socket_enqueue;
+ s->close = jdwp_socket_close;
+ s->pass = false;
- return &s->socket;
+ return s;
}
/** "track-jdwp" local service implementation
@@ -632,113 +538,88 @@
** to the client...
**/
-struct JdwpTracker {
- asocket socket;
- JdwpTracker* next;
- JdwpTracker* prev;
- int need_update;
+struct JdwpTracker : public asocket {
+ bool need_initial;
};
-static JdwpTracker _jdwp_trackers_list;
+static std::vector<std::unique_ptr<JdwpTracker>> _jdwp_trackers;
+static void jdwp_process_list_updated(void) {
+ char buffer[1024];
+ int len = jdwp_process_list_msg(buffer, sizeof(buffer));
-static void
-jdwp_process_list_updated(void)
-{
- char buffer[1024];
- int len;
- JdwpTracker* t = _jdwp_trackers_list.next;
-
- len = jdwp_process_list_msg(buffer, sizeof(buffer));
-
- for ( ; t != &_jdwp_trackers_list; t = t->next ) {
- apacket* p = get_apacket();
- asocket* peer = t->socket.peer;
+ for (auto& t : _jdwp_trackers) {
+ apacket* p = get_apacket();
memcpy(p->data, buffer, len);
p->len = len;
- peer->enqueue( peer, p );
+
+ if (t->peer) {
+ // The tracker might not have been connected yet.
+ t->peer->enqueue(t->peer, p);
+ }
}
}
-static void
-jdwp_tracker_close( asocket* s )
-{
- JdwpTracker* tracker = (JdwpTracker*) s;
- asocket* peer = s->peer;
+static void jdwp_tracker_close(asocket* s) {
+ D("LS(%d): destroying jdwp tracker service", s->id);
- if (peer) {
- peer->peer = NULL;
- peer->close(peer);
+ if (s->peer) {
+ D("LS(%d) peer->close()ing peer->id=%d peer->fd=%d", s->id, s->peer->id, s->peer->fd);
+ s->peer->peer = nullptr;
+ s->peer->close(s->peer);
+ s->peer = nullptr;
}
remove_socket(s);
- tracker->prev->next = tracker->next;
- tracker->next->prev = tracker->prev;
-
- free(s);
+ auto pred = [s](const auto& tracker) { return tracker.get() == s; };
+ std::remove_if(_jdwp_trackers.begin(), _jdwp_trackers.end(), pred);
}
-static void
-jdwp_tracker_ready( asocket* s )
-{
- JdwpTracker* t = (JdwpTracker*) s;
+static void jdwp_tracker_ready(asocket* s) {
+ JdwpTracker* t = (JdwpTracker*)s;
- if (t->need_update) {
- apacket* p = get_apacket();
- t->need_update = 0;
+ if (t->need_initial) {
+ apacket* p = get_apacket();
+ t->need_initial = false;
p->len = jdwp_process_list_msg((char*)p->data, s->get_max_payload());
s->peer->enqueue(s->peer, p);
}
}
-static int
-jdwp_tracker_enqueue( asocket* s, apacket* p )
-{
+static int jdwp_tracker_enqueue(asocket* s, apacket* p) {
/* you can't write to this socket */
+ D("LS(%d): JDWP tracker received data?", s->id);
put_apacket(p);
s->peer->close(s->peer);
return -1;
}
+asocket* create_jdwp_tracker_service_socket(void) {
+ auto t = std::make_unique<JdwpTracker>();
+ if (!t) {
+ fatal("failed to allocate JdwpTracker");
+ }
-asocket*
-create_jdwp_tracker_service_socket( void )
-{
- JdwpTracker* t = reinterpret_cast<JdwpTracker*>(calloc(sizeof(*t), 1));
+ memset(t.get(), 0, sizeof(asocket));
- if (t == NULL)
- return NULL;
+ install_local_socket(t.get());
+ D("LS(%d): created new jdwp tracker service", t->id);
- t->next = &_jdwp_trackers_list;
- t->prev = t->next->prev;
+ t->ready = jdwp_tracker_ready;
+ t->enqueue = jdwp_tracker_enqueue;
+ t->close = jdwp_tracker_close;
+ t->need_initial = true;
- t->next->prev = t;
- t->prev->next = t;
+ asocket* result = t.get();
- install_local_socket(&t->socket);
+ _jdwp_trackers.emplace_back(std::move(t));
- t->socket.ready = jdwp_tracker_ready;
- t->socket.enqueue = jdwp_tracker_enqueue;
- t->socket.close = jdwp_tracker_close;
- t->need_update = 1;
-
- return &t->socket;
+ return result;
}
-
-int
-init_jdwp(void)
-{
- _jdwp_list.next = &_jdwp_list;
- _jdwp_list.prev = &_jdwp_list;
-
- _jdwp_trackers_list.next = &_jdwp_trackers_list;
- _jdwp_trackers_list.prev = &_jdwp_trackers_list;
-
- return jdwp_control_init( &_jdwp_control,
- JDWP_CONTROL_NAME,
- JDWP_CONTROL_NAME_LEN );
+int init_jdwp(void) {
+ return jdwp_control_init(&_jdwp_control, JDWP_CONTROL_NAME, JDWP_CONTROL_NAME_LEN);
}
#endif /* !ADB_HOST */
diff --git a/adb/shell_service.cpp b/adb/shell_service.cpp
index e8dad58..d83622c 100644
--- a/adb/shell_service.cpp
+++ b/adb/shell_service.cpp
@@ -155,14 +155,19 @@
const std::string& command() const { return command_; }
- int local_socket_fd() const { return local_socket_sfd_; }
+ int ReleaseLocalSocket() { return local_socket_sfd_.release(); }
pid_t pid() const { return pid_; }
// Sets up FDs, forks a subprocess, starts the subprocess manager thread,
- // and exec's the child. Returns false on failure.
+ // and exec's the child. Returns false and sets error on failure.
bool ForkAndExec(std::string* _Nonnull error);
+ // Start the subprocess manager thread. Consumes the subprocess, regardless of success.
+ // Returns false and sets error on failure.
+ static bool StartThread(std::unique_ptr<Subprocess> subprocess,
+ std::string* _Nonnull error);
+
private:
// Opens the file at |pts_name|.
int OpenPtyChildFd(const char* pts_name, unique_fd* error_sfd);
@@ -390,14 +395,19 @@
}
}
- if (!adb_thread_create(ThreadHandler, this)) {
+ D("subprocess parent: completed");
+ return true;
+}
+
+bool Subprocess::StartThread(std::unique_ptr<Subprocess> subprocess, std::string* error) {
+ Subprocess* raw = subprocess.release();
+ if (!adb_thread_create(ThreadHandler, raw)) {
*error =
android::base::StringPrintf("failed to create subprocess thread: %s", strerror(errno));
- kill(pid_, SIGKILL);
+ kill(raw->pid_, SIGKILL);
return false;
}
- D("subprocess parent: completed");
return true;
}
@@ -439,8 +449,9 @@
Subprocess* subprocess = reinterpret_cast<Subprocess*>(userdata);
adb_thread_setname(android::base::StringPrintf(
- "shell srvc %d", subprocess->local_socket_fd()));
+ "shell srvc %d", subprocess->pid()));
+ D("passing data streams for PID %d", subprocess->pid());
subprocess->PassDataStreams();
D("deleting Subprocess for PID %d", subprocess->pid());
@@ -477,8 +488,14 @@
// and only fall back on this for unexpected closures.
D("protocol FD died, sending SIGHUP to pid %d", pid_);
kill(pid_, SIGHUP);
+
+ // We also need to close the pipes connected to the child process
+ // so that if it ignores SIGHUP and continues to write data it
+ // won't fill up the pipe and block.
+ stdinout_sfd_.clear();
+ stderr_sfd_.clear();
}
- dead_sfd->reset(-1);
+ dead_sfd->clear();
}
}
}
@@ -727,7 +744,7 @@
protocol == SubprocessProtocol::kNone ? "none" : "shell",
terminal_type, name);
- Subprocess* subprocess = new Subprocess(name, terminal_type, type, protocol);
+ auto subprocess = std::make_unique<Subprocess>(name, terminal_type, type, protocol);
if (!subprocess) {
LOG(ERROR) << "failed to allocate new subprocess";
return ReportError(protocol, "failed to allocate new subprocess");
@@ -736,11 +753,17 @@
std::string error;
if (!subprocess->ForkAndExec(&error)) {
LOG(ERROR) << "failed to start subprocess: " << error;
- delete subprocess;
return ReportError(protocol, error);
}
- D("subprocess creation successful: local_socket_fd=%d, pid=%d",
- subprocess->local_socket_fd(), subprocess->pid());
- return subprocess->local_socket_fd();
+ unique_fd local_socket(subprocess->ReleaseLocalSocket());
+ D("subprocess creation successful: local_socket_fd=%d, pid=%d", local_socket.get(),
+ subprocess->pid());
+
+ if (!Subprocess::StartThread(std::move(subprocess), &error)) {
+ LOG(ERROR) << "failed to start subprocess management thread: " << error;
+ return ReportError(protocol, error);
+ }
+
+ return local_socket.release();
}
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index b2555d0..4ed1c45 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -410,7 +410,7 @@
#endif
int fd = service_to_fd(name, transport);
if (fd < 0) {
- return 0;
+ return nullptr;
}
asocket* s = create_local_socket(fd);
diff --git a/adb/test_device.py b/adb/test_device.py
index cdc57c6..2efac9d 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -31,6 +31,7 @@
import subprocess
import sys
import tempfile
+import time
import unittest
import mock
@@ -495,6 +496,36 @@
self.assertEqual(input.splitlines(), stdout.splitlines())
self.assertEqual('', stderr)
+ def test_sighup(self):
+ """Ensure that SIGHUP gets sent upon non-interactive ctrl-c"""
+ log_path = "/data/local/tmp/adb_signal_test.log"
+
+ # Clear the output file.
+ self.device.shell_nocheck(["echo", ">", log_path])
+
+ script = """
+ trap "echo SIGINT > {path}; exit 0" SIGINT
+ trap "echo SIGHUP > {path}; exit 0" SIGHUP
+ echo Waiting
+ while true; do sleep 100; done
+ """.format(path=log_path)
+
+ script = ";".join([x.strip() for x in script.strip().splitlines()])
+
+ process = self.device.shell_popen(
+ ["sh", "-c", "'{}'".format(script)], kill_atexit=False, stdout=subprocess.PIPE)
+
+ self.assertEqual("Waiting\n", process.stdout.readline())
+ process.send_signal(signal.SIGINT)
+ process.wait()
+
+ # Waiting for the local adb to finish is insufficient, since it hangs
+ # up immediately.
+ time.sleep(0.25)
+
+ stdout, _ = self.device.shell(["cat", log_path])
+ self.assertEqual(stdout.strip(), "SIGHUP")
+
class ArgumentEscapingTest(DeviceTest):
def test_shell_escaping(self):
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index 31b5ad6..d918cc7 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -235,16 +235,20 @@
/* This is relevant only for ADB daemon running inside the emulator. */
/*
* Redefine open and write for qemu_pipe.h that contains inlined references
- * to those routines. We will redifine them back after qemu_pipe.h inclusion.
+ * to those routines. We will redefine them back after qemu_pipe.h inclusion.
*/
#undef open
+#undef read
#undef write
#define open adb_open
+#define read adb_read
#define write adb_write
-#include <hardware/qemu_pipe.h>
+#include <system/qemu_pipe.h>
#undef open
+#undef read
#undef write
#define open ___xxx_open
+#define read ___xxx_read
#define write ___xxx_write
/* A worker thread that monitors host connections, and registers a transport for
@@ -292,7 +296,7 @@
D("transport: qemu_socket_thread() starting");
/* adb QEMUD service connection request. */
- snprintf(con_name, sizeof(con_name), "qemud:adb:%d", port);
+ snprintf(con_name, sizeof(con_name), "pipe:qemud:adb:%d", port);
/* Connect to the adb QEMUD service. */
fd = qemu_pipe_open(con_name);
diff --git a/base/logging.cpp b/base/logging.cpp
index 1741871..769c266 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -21,6 +21,7 @@
#include "android-base/logging.h"
#include <libgen.h>
+#include <time.h>
// For getprogname(3) or program_invocation_short_name.
#if defined(__ANDROID__) || defined(__APPLE__)
@@ -186,12 +187,24 @@
void StderrLogger(LogId, LogSeverity severity, const char*, const char* file,
unsigned int line, const char* message) {
+ struct tm now;
+ time_t t = time(nullptr);
+
+#if defined(_WIN32)
+ localtime_s(&now, &t);
+#else
+ localtime_r(&t, &now);
+#endif
+
+ char timestamp[32];
+ strftime(timestamp, sizeof(timestamp), "%m-%d %H:%M:%S", &now);
+
static const char log_characters[] = "VDIWEF";
static_assert(arraysize(log_characters) - 1 == FATAL + 1,
"Mismatch in size of log_characters and values in LogSeverity");
char severity_char = log_characters[severity];
- fprintf(stderr, "%s %c %5d %5d %s:%u] %s\n", ProgramInvocationName(),
- severity_char, getpid(), GetThreadId(), file, line, message);
+ fprintf(stderr, "%s %c %s %5d %5d %s:%u] %s\n", ProgramInvocationName(),
+ severity_char, timestamp, getpid(), GetThreadId(), file, line, message);
}
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
new file mode 100644
index 0000000..8a63f3f
--- /dev/null
+++ b/debuggerd/Android.bp
@@ -0,0 +1,19 @@
+cc_library_static {
+ name: "libdebuggerd_client",
+ srcs: ["client/debuggerd_client.cpp"],
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Os",
+ ],
+
+ local_include_dirs: ["include"],
+ export_include_dirs: ["include"],
+
+ // libdebuggerd_client gets async signal safe logging via libc_logging,
+ // which defines its interface in bionic private headers.
+ include_dirs: ["bionic/libc"],
+ static_libs: ["libc_logging"],
+}
diff --git a/debuggerd/Android.mk b/debuggerd/Android.soong.mk
similarity index 73%
rename from debuggerd/Android.mk
rename to debuggerd/Android.soong.mk
index 9ce94c5..19c7298 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.soong.mk
@@ -8,6 +8,10 @@
-Wunused \
-Werror \
+ifeq ($(TARGET_IS_64_BIT),true)
+common_cppflags += -DTARGET_IS_64_BIT
+endif
+
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
@@ -26,15 +30,12 @@
LOCAL_SRC_FILES_x86 := x86/machine.cpp
LOCAL_SRC_FILES_x86_64 := x86_64/machine.cpp
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_CPPFLAGS := $(common_cppflags)
LOCAL_INIT_RC_32 := debuggerd.rc
LOCAL_INIT_RC_64 := debuggerd64.rc
-ifeq ($(TARGET_IS_64_BIT),true)
-LOCAL_CPPFLAGS += -DTARGET_IS_64_BIT
-endif
-
LOCAL_SHARED_LIBRARIES := \
libbacktrace \
libbase \
@@ -51,7 +52,7 @@
include $(BUILD_EXECUTABLE)
-
+crasher_cppflags := $(common_cppflags) -fstack-protector-all -Wno-free-nonheap-object -Wno-date-time
include $(CLEAR_VARS)
LOCAL_SRC_FILES := crasher.cpp
@@ -63,8 +64,7 @@
LOCAL_SRC_FILES_x86_64 := x86_64/crashglue.S
LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
LOCAL_MODULE_TAGS := optional
-LOCAL_CPPFLAGS := $(common_cppflags) -fstack-protector-all -Wno-free-nonheap-object -Wno-date-time
-#LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_CPPFLAGS := $(crasher_cppflags)
LOCAL_SHARED_LIBRARIES := libcutils liblog
# The arm emulator has VFP but not VFPv3-D32.
@@ -79,6 +79,34 @@
include $(BUILD_EXECUTABLE)
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := crasher.cpp
+LOCAL_SRC_FILES_arm := arm/crashglue.S
+LOCAL_SRC_FILES_arm64 := arm64/crashglue.S
+LOCAL_SRC_FILES_mips := mips/crashglue.S
+LOCAL_SRC_FILES_mips64 := mips64/crashglue.S
+LOCAL_SRC_FILES_x86 := x86/crashglue.S
+LOCAL_SRC_FILES_x86_64 := x86_64/crashglue.S
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+LOCAL_MODULE_TAGS := optional
+LOCAL_CPPFLAGS := $(crasher_cppflags) -DSTATIC_CRASHER
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_SHARED_LIBRARIES := libcutils liblog
+
+# The arm emulator has VFP but not VFPv3-D32.
+ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
+LOCAL_ASFLAGS_arm += -DHAS_VFP_D32
+endif
+
+LOCAL_MODULE := static_crasher
+LOCAL_MODULE_STEM_32 := static_crasher
+LOCAL_MODULE_STEM_64 := static_crasher64
+LOCAL_MULTILIB := both
+
+LOCAL_STATIC_LIBRARIES := libdebuggerd_client libcutils liblog
+
+include $(BUILD_EXECUTABLE)
+
debuggerd_test_src_files := \
utility.cpp \
test/dump_memory_test.cpp \
diff --git a/debuggerd/client/debuggerd_client.cpp b/debuggerd/client/debuggerd_client.cpp
new file mode 100644
index 0000000..44e92fe
--- /dev/null
+++ b/debuggerd/client/debuggerd_client.cpp
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+#include "debuggerd/client.h"
+
+#include <errno.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/prctl.h>
+#include <sys/socket.h>
+#include <sys/syscall.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "private/libc_logging.h"
+
+#if defined(TARGET_IS_64_BIT) && !defined(__LP64__)
+#define SOCKET_NAME "android:debuggerd32"
+#else
+#define SOCKET_NAME "android:debuggerd"
+#endif
+
+// see man(2) prctl, specifically the section about PR_GET_NAME
+#define MAX_TASK_NAME_LEN (16)
+
+static debuggerd_callbacks_t g_callbacks;
+
+static int socket_abstract_client(const char* name, int type) {
+ sockaddr_un addr;
+
+ // Test with length +1 for the *initial* '\0'.
+ size_t namelen = strlen(name);
+ if ((namelen + 1) > sizeof(addr.sun_path)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ // This is used for abstract socket namespace, we need
+ // an initial '\0' at the start of the Unix socket path.
+ //
+ // Note: The path in this case is *not* supposed to be
+ // '\0'-terminated. ("man 7 unix" for the gory details.)
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_LOCAL;
+ addr.sun_path[0] = 0;
+ memcpy(addr.sun_path + 1, name, namelen);
+
+ socklen_t alen = namelen + offsetof(sockaddr_un, sun_path) + 1;
+
+ int s = socket(AF_LOCAL, type, 0);
+ if (s == -1) {
+ return -1;
+ }
+
+ int rc = TEMP_FAILURE_RETRY(connect(s, reinterpret_cast<sockaddr*>(&addr), alen));
+ if (rc == -1) {
+ close(s);
+ return -1;
+ }
+
+ return s;
+}
+
+/*
+ * Writes a summary of the signal to the log file. We do this so that, if
+ * for some reason we're not able to contact debuggerd, there is still some
+ * indication of the failure in the log.
+ *
+ * We could be here as a result of native heap corruption, or while a
+ * mutex is being held, so we don't want to use any libc functions that
+ * could allocate memory or hold a lock.
+ */
+static void log_signal_summary(int signum, const siginfo_t* info) {
+ const char* signal_name = "???";
+ bool has_address = false;
+ switch (signum) {
+ case SIGABRT:
+ signal_name = "SIGABRT";
+ break;
+ case SIGBUS:
+ signal_name = "SIGBUS";
+ has_address = true;
+ break;
+ case SIGFPE:
+ signal_name = "SIGFPE";
+ has_address = true;
+ break;
+ case SIGILL:
+ signal_name = "SIGILL";
+ has_address = true;
+ break;
+ case SIGSEGV:
+ signal_name = "SIGSEGV";
+ has_address = true;
+ break;
+#if defined(SIGSTKFLT)
+ case SIGSTKFLT:
+ signal_name = "SIGSTKFLT";
+ break;
+#endif
+ case SIGTRAP:
+ signal_name = "SIGTRAP";
+ break;
+ }
+
+ char thread_name[MAX_TASK_NAME_LEN + 1]; // one more for termination
+ if (prctl(PR_GET_NAME, reinterpret_cast<unsigned long>(thread_name), 0, 0, 0) != 0) {
+ strcpy(thread_name, "<name unknown>");
+ } else {
+ // short names are null terminated by prctl, but the man page
+ // implies that 16 byte names are not.
+ thread_name[MAX_TASK_NAME_LEN] = 0;
+ }
+
+ // "info" will be null if the siginfo_t information was not available.
+ // Many signals don't have an address or a code.
+ char code_desc[32]; // ", code -6"
+ char addr_desc[32]; // ", fault addr 0x1234"
+ addr_desc[0] = code_desc[0] = 0;
+ if (info != nullptr) {
+ // For a rethrown signal, this si_code will be right and the one debuggerd shows will
+ // always be SI_TKILL.
+ __libc_format_buffer(code_desc, sizeof(code_desc), ", code %d", info->si_code);
+ if (has_address) {
+ __libc_format_buffer(addr_desc, sizeof(addr_desc), ", fault addr %p", info->si_addr);
+ }
+ }
+ __libc_format_log(ANDROID_LOG_FATAL, "libc", "Fatal signal %d (%s)%s%s in tid %d (%s)", signum,
+ signal_name, code_desc, addr_desc, gettid(), thread_name);
+}
+
+/*
+ * Returns true if the handler for signal "signum" has SA_SIGINFO set.
+ */
+static bool have_siginfo(int signum) {
+ struct sigaction old_action, new_action;
+
+ memset(&new_action, 0, sizeof(new_action));
+ new_action.sa_handler = SIG_DFL;
+ new_action.sa_flags = SA_RESTART;
+ sigemptyset(&new_action.sa_mask);
+
+ if (sigaction(signum, &new_action, &old_action) < 0) {
+ __libc_format_log(ANDROID_LOG_WARN, "libc", "Failed testing for SA_SIGINFO: %s",
+ strerror(errno));
+ return false;
+ }
+ bool result = (old_action.sa_flags & SA_SIGINFO) != 0;
+
+ if (sigaction(signum, &old_action, nullptr) == -1) {
+ __libc_format_log(ANDROID_LOG_WARN, "libc", "Restore failed in test for SA_SIGINFO: %s",
+ strerror(errno));
+ }
+ return result;
+}
+
+static void send_debuggerd_packet(siginfo_t* info) {
+ // Mutex to prevent multiple crashing threads from trying to talk
+ // to debuggerd at the same time.
+ static pthread_mutex_t crash_mutex = PTHREAD_MUTEX_INITIALIZER;
+ int ret = pthread_mutex_trylock(&crash_mutex);
+ if (ret != 0) {
+ if (ret == EBUSY) {
+ __libc_format_log(ANDROID_LOG_INFO, "libc",
+ "Another thread contacted debuggerd first; not contacting debuggerd.");
+ // This will never complete since the lock is never released.
+ pthread_mutex_lock(&crash_mutex);
+ } else {
+ __libc_format_log(ANDROID_LOG_INFO, "libc", "pthread_mutex_trylock failed: %s", strerror(ret));
+ }
+ return;
+ }
+
+ int s = socket_abstract_client(SOCKET_NAME, SOCK_STREAM | SOCK_CLOEXEC);
+ if (s == -1) {
+ __libc_format_log(ANDROID_LOG_FATAL, "libc", "Unable to open connection to debuggerd: %s",
+ strerror(errno));
+ return;
+ }
+
+ // debuggerd knows our pid from the credentials on the
+ // local socket but we need to tell it the tid of the crashing thread.
+ // debuggerd will be paranoid and verify that we sent a tid
+ // that's actually in our process.
+ debugger_msg_t msg;
+ msg.action = DEBUGGER_ACTION_CRASH;
+ msg.tid = gettid();
+ msg.abort_msg_address = 0;
+
+ if (g_callbacks.get_abort_message) {
+ msg.abort_msg_address = reinterpret_cast<uintptr_t>(g_callbacks.get_abort_message());
+ }
+
+ msg.original_si_code = (info != nullptr) ? info->si_code : 0;
+ ret = TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg)));
+ if (ret == sizeof(msg)) {
+ char debuggerd_ack;
+ ret = TEMP_FAILURE_RETRY(read(s, &debuggerd_ack, 1));
+ int saved_errno = errno;
+ if (g_callbacks.post_dump) {
+ g_callbacks.post_dump();
+ }
+ errno = saved_errno;
+ } else {
+ // read or write failed -- broken connection?
+ __libc_format_log(ANDROID_LOG_FATAL, "libc", "Failed while talking to debuggerd: %s",
+ strerror(errno));
+ }
+
+ close(s);
+}
+
+/*
+ * Catches fatal signals so we can ask debuggerd to ptrace us before
+ * we crash.
+ */
+static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void*) {
+ // It's possible somebody cleared the SA_SIGINFO flag, which would mean
+ // our "info" arg holds an undefined value.
+ if (!have_siginfo(signal_number)) {
+ info = nullptr;
+ }
+
+ log_signal_summary(signal_number, info);
+
+ send_debuggerd_packet(info);
+
+ // We need to return from the signal handler so that debuggerd can dump the
+ // thread that crashed, but returning here does not guarantee that the signal
+ // will be thrown again, even for SIGSEGV and friends, since the signal could
+ // have been sent manually. Resend the signal with rt_tgsigqueueinfo(2) to
+ // preserve the SA_SIGINFO contents.
+ signal(signal_number, SIG_DFL);
+
+ struct siginfo si;
+ if (!info) {
+ memset(&si, 0, sizeof(si));
+ si.si_code = SI_USER;
+ si.si_pid = getpid();
+ si.si_uid = getuid();
+ info = &si;
+ } else if (info->si_code >= 0 || info->si_code == SI_TKILL) {
+ // rt_tgsigqueueinfo(2)'s documentation appears to be incorrect on kernels
+ // that contain commit 66dd34a (3.9+). The manpage claims to only allow
+ // negative si_code values that are not SI_TKILL, but 66dd34a changed the
+ // check to allow all si_code values in calls coming from inside the house.
+ }
+
+ int rc = syscall(SYS_rt_tgsigqueueinfo, getpid(), gettid(), signal_number, info);
+ if (rc != 0) {
+ __libc_format_log(ANDROID_LOG_FATAL, "libc", "failed to resend signal during crash: %s",
+ strerror(errno));
+ _exit(0);
+ }
+}
+
+void debuggerd_init(debuggerd_callbacks_t* callbacks) {
+ if (callbacks) {
+ g_callbacks = *callbacks;
+ }
+
+ struct sigaction action;
+ memset(&action, 0, sizeof(action));
+ sigemptyset(&action.sa_mask);
+ action.sa_sigaction = debuggerd_signal_handler;
+ action.sa_flags = SA_RESTART | SA_SIGINFO;
+
+ // Use the alternate signal stack if available so we can catch stack overflows.
+ action.sa_flags |= SA_ONSTACK;
+
+ sigaction(SIGABRT, &action, nullptr);
+ sigaction(SIGBUS, &action, nullptr);
+ sigaction(SIGFPE, &action, nullptr);
+ sigaction(SIGILL, &action, nullptr);
+ sigaction(SIGSEGV, &action, nullptr);
+#if defined(SIGSTKFLT)
+ sigaction(SIGSTKFLT, &action, nullptr);
+#endif
+ sigaction(SIGTRAP, &action, nullptr);
+}
diff --git a/debuggerd/crasher.cpp b/debuggerd/crasher.cpp
index bdeaf0b..a37df33 100644
--- a/debuggerd/crasher.cpp
+++ b/debuggerd/crasher.cpp
@@ -16,6 +16,10 @@
#include <cutils/sockets.h>
#include <log/log.h>
+#if defined(STATIC_CRASHER)
+#include "debuggerd/client.h"
+#endif
+
#ifndef __unused
#define __unused __attribute__((__unused__))
#endif
@@ -43,7 +47,7 @@
// Assign local array address to global variable to force stack guards.
// Use another noinline function to corrupt the stack.
__attribute__ ((noinline)) static int smash_stack(volatile int* plen) {
- printf("crasher: deliberately corrupting stack...\n");
+ printf("%s: deliberately corrupting stack...\n", __progname);
char buf[128];
smash_stack_dummy_buf = buf;
@@ -135,7 +139,7 @@
static int do_action(const char* arg)
{
- fprintf(stderr,"crasher: init pid=%d tid=%d\n", getpid(), gettid());
+ fprintf(stderr, "%s: init pid=%d tid=%d\n", __progname, getpid(), gettid());
if (!strncmp(arg, "thread-", strlen("thread-"))) {
return do_action_on_thread(arg + strlen("thread-"));
@@ -209,9 +213,26 @@
int main(int argc, char **argv)
{
- fprintf(stderr,"crasher: built at " __TIME__ "!@\n");
+ fprintf(stderr, "%s: built at " __TIME__ "!@\n", __progname);
- if(argc > 1) {
+#if defined(STATIC_CRASHER)
+ debuggerd_callbacks_t callbacks = {
+ .get_abort_message = []() {
+ static struct {
+ size_t size;
+ char msg[32];
+ } msg;
+
+ msg.size = strlen("dummy abort message");
+ memcpy(msg.msg, "dummy abort message", strlen("dummy abort message"));
+ return reinterpret_cast<abort_msg_t*>(&msg);
+ },
+ .post_dump = nullptr
+ };
+ debuggerd_init(&callbacks);
+#endif
+
+ if (argc > 1) {
return do_action(argv[1]);
} else {
crash1();
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp
index d87594c..a82fd07 100644
--- a/debuggerd/debuggerd.cpp
+++ b/debuggerd/debuggerd.cpp
@@ -562,7 +562,7 @@
// won't necessarily have stopped by the time ptrace() returns. (We
// currently assume it does.) We write to the file descriptor to
// ensure that it can run as soon as we call PTRACE_CONT below.
- // See details in bionic/libc/linker/debugger.c, in function
+ // See details in client/debuggerd_client.cpp, in function
// debugger_signal_handler().
// Attach to the target process.
diff --git a/debuggerd/include/debuggerd/client.h b/debuggerd/include/debuggerd/client.h
new file mode 100644
index 0000000..41b7b3a
--- /dev/null
+++ b/debuggerd/include/debuggerd/client.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2016 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.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+// On 32-bit devices, DEBUGGER_SOCKET_NAME is a 32-bit debuggerd.
+// On 64-bit devices, DEBUGGER_SOCKET_NAME is a 64-bit debuggerd.
+#define DEBUGGER_SOCKET_NAME "android:debuggerd"
+
+// Used only on 64-bit devices for debuggerd32.
+#define DEBUGGER32_SOCKET_NAME "android:debuggerd32"
+
+__BEGIN_DECLS
+
+typedef enum {
+ // dump a crash
+ DEBUGGER_ACTION_CRASH,
+ // dump a tombstone file
+ DEBUGGER_ACTION_DUMP_TOMBSTONE,
+ // dump a backtrace only back to the socket
+ DEBUGGER_ACTION_DUMP_BACKTRACE,
+} debugger_action_t;
+
+// Make sure that all values have a fixed size so that this structure
+// is the same for 32 bit and 64 bit processes.
+typedef struct __attribute__((packed)) {
+ int32_t action;
+ pid_t tid;
+ uint64_t abort_msg_address;
+ int32_t original_si_code;
+} debugger_msg_t;
+
+// These callbacks are called in a signal handler, and thus must be async signal safe.
+// If null, the callbacks will not be called.
+typedef struct {
+ struct abort_msg_t* (*get_abort_message)();
+ void (*post_dump)();
+} debuggerd_callbacks_t;
+
+void debuggerd_init(debuggerd_callbacks_t* callbacks);
+
+__END_DECLS
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp
index fa983fa..dfdf29c 100644
--- a/debuggerd/tombstone.cpp
+++ b/debuggerd/tombstone.cpp
@@ -368,6 +368,7 @@
ALOGE("Cannot get siginfo for %d: %s\n", tid, strerror(errno));
}
+ ScopedBacktraceMapIteratorLock lock(map);
_LOG(log, logtype::MAPS, "\n");
if (!print_fault_address_marker) {
_LOG(log, logtype::MAPS, "memory map:\n");
diff --git a/fastboot/engine.cpp b/fastboot/engine.cpp
index db5d0e0..a245e49 100644
--- a/fastboot/engine.cpp
+++ b/fastboot/engine.cpp
@@ -38,7 +38,7 @@
#include <sys/types.h>
#include <unistd.h>
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
#define OP_DOWNLOAD 1
#define OP_COMMAND 2
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index b3e65cb..1b3893f 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -586,6 +586,7 @@
/* mount(2) returned an error, handle the encryptable/formattable case */
bool wiped = partition_wiped(fstab->recs[top_idx].blk_device);
+ bool crypt_footer = false;
if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
fs_mgr_is_formattable(&fstab->recs[top_idx]) && wiped) {
/* top_idx and attempted_idx point at the same partition, but sometimes
@@ -606,8 +607,11 @@
ERROR("%s(): %s wouldn't open (%s)\n", __func__,
fstab->recs[top_idx].key_loc, strerror(errno));
}
+ } else if (fs_mgr_is_encryptable(&fstab->recs[top_idx]) &&
+ !strcmp(fstab->recs[top_idx].key_loc, KEY_IN_FOOTER)) {
+ crypt_footer = true;
}
- if (fs_mgr_do_format(&fstab->recs[top_idx]) == 0) {
+ if (fs_mgr_do_format(&fstab->recs[top_idx], crypt_footer) == 0) {
/* Let's replay the mount actions. */
i = top_idx - 1;
continue;
diff --git a/fs_mgr/fs_mgr_format.c b/fs_mgr/fs_mgr_format.c
index 6c5b1eb..5011b08 100644
--- a/fs_mgr/fs_mgr_format.c
+++ b/fs_mgr/fs_mgr_format.c
@@ -32,11 +32,12 @@
#include "ext4.h"
#include "make_ext4fs.h"
#include "fs_mgr_priv.h"
+#include "cryptfs.h"
extern struct fs_info info; /* magic global from ext4_utils */
extern void reset_ext4fs_info();
-static int format_ext4(char *fs_blkdev, char *fs_mnt_point)
+static int format_ext4(char *fs_blkdev, char *fs_mnt_point, bool crypt_footer)
{
uint64_t dev_sz;
int fd, rc = 0;
@@ -63,6 +64,9 @@
/* Format the partition using the calculated length */
reset_ext4fs_info();
info.len = (off64_t)dev_sz;
+ if (crypt_footer) {
+ info.len -= CRYPT_FOOTER_OFFSET;
+ }
/* Use make_ext4fs_internal to avoid wiping an already-wiped partition. */
rc = make_ext4fs_internal(fd, NULL, NULL, fs_mnt_point, 0, 0, 0, 0, 0, 0, sehandle, 0, 0, NULL);
@@ -118,7 +122,7 @@
return rc;
}
-int fs_mgr_do_format(struct fstab_rec *fstab)
+int fs_mgr_do_format(struct fstab_rec *fstab, bool crypt_footer)
{
int rc = -EINVAL;
@@ -127,7 +131,7 @@
if (!strncmp(fstab->fs_type, "f2fs", 4)) {
rc = format_f2fs(fstab->blk_device);
} else if (!strncmp(fstab->fs_type, "ext4", 4)) {
- rc = format_ext4(fstab->blk_device, fstab->mount_point);
+ rc = format_ext4(fstab->blk_device, fstab->mount_point, crypt_footer);
} else {
ERROR("File system type '%s' is not supported\n", fstab->fs_type);
}
diff --git a/fs_mgr/fs_mgr_slotselect.c b/fs_mgr/fs_mgr_slotselect.c
index ca07b18..0f59115 100644
--- a/fs_mgr/fs_mgr_slotselect.c
+++ b/fs_mgr/fs_mgr_slotselect.c
@@ -41,7 +41,7 @@
int n;
int misc_fd;
ssize_t num_read;
- struct bootloader_message msg;
+ struct bootloader_message_ab msg;
misc_fd = -1;
for (n = 0; n < fstab->num_entries; n++) {
diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp
index 72554a8..25b023e 100644
--- a/fs_mgr/fs_mgr_verity.cpp
+++ b/fs_mgr/fs_mgr_verity.cpp
@@ -91,14 +91,12 @@
FILE* f = fopen(path, "r");
if (!f) {
ERROR("Can't open '%s'\n", path);
- free(key_data);
return NULL;
}
if (!fread(key_data, sizeof(key_data), 1, f)) {
ERROR("Could not read key!\n");
fclose(f);
- free(key_data);
return NULL;
}
@@ -107,7 +105,6 @@
RSA* key = NULL;
if (!android_pubkey_decode(key_data, sizeof(key_data), &key)) {
ERROR("Could not parse key!\n");
- free(key_data);
return NULL;
}
@@ -145,6 +142,18 @@
return retval;
}
+static int verify_verity_signature(const struct fec_verity_metadata& verity)
+{
+ if (verify_table(verity.signature, sizeof(verity.signature),
+ verity.table, verity.table_length) == 0 ||
+ verify_table(verity.ecc_signature, sizeof(verity.ecc_signature),
+ verity.table, verity.table_length) == 0) {
+ return 0;
+ }
+
+ return -1;
+}
+
static int invalidate_table(char *table, size_t table_length)
{
size_t n = 0;
@@ -950,8 +959,7 @@
}
// verify the signature on the table
- if (verify_table(verity.signature, sizeof(verity.signature), params.table,
- verity.table_length) < 0) {
+ if (verify_verity_signature(verity) < 0) {
if (params.mode == VERITY_MODE_LOGGING) {
// the user has been warned, allow mounting without dm-verity
retval = FS_MGR_SETUP_VERITY_SUCCESS;
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index b498618..3c27ede 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -18,6 +18,7 @@
#define __CORE_FS_MGR_H
#include <stdint.h>
+#include <stdbool.h>
#include <linux/dm-ioctl.h>
// Magic number at start of verity metadata
@@ -108,7 +109,7 @@
int fs_mgr_is_nofail(struct fstab_rec *fstab);
int fs_mgr_swapon_all(struct fstab *fstab);
-int fs_mgr_do_format(struct fstab_rec *fstab);
+int fs_mgr_do_format(struct fstab_rec *fstab, bool reserve_footer);
#ifdef __cplusplus
}
diff --git a/healthd/Android.mk b/healthd/Android.mk
index 127f39e..deebed5 100644
--- a/healthd/Android.mk
+++ b/healthd/Android.mk
@@ -17,7 +17,7 @@
LOCAL_MODULE := libbatterymonitor
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_STATIC_LIBRARIES := libutils libbinder
+LOCAL_STATIC_LIBRARIES := libutils libbase libbinder
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
@@ -60,7 +60,7 @@
LOCAL_C_INCLUDES := bootable/recovery $(LOCAL_PATH)/include
-LOCAL_STATIC_LIBRARIES := libbatterymonitor libbatteryservice libbinder
+LOCAL_STATIC_LIBRARIES := libbatterymonitor libbatteryservice libbinder libbase
ifneq ($(strip $(LOCAL_CHARGER_NO_UI)),true)
LOCAL_STATIC_LIBRARIES += libminui libpng libz
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 69647de..d1c547d 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -28,6 +28,8 @@
#include <unistd.h>
#include <memory>
+#include <android-base/file.h>
+#include <android-base/strings.h>
#include <batteryservice/BatteryService.h>
#include <cutils/klog.h>
#include <cutils/properties.h>
@@ -121,34 +123,15 @@
return ret;
}
-int BatteryMonitor::readFromFile(const String8& path, char* buf, size_t size) {
- char *cp = NULL;
-
- if (path.isEmpty())
- return -1;
- int fd = open(path.string(), O_RDONLY, 0);
- if (fd == -1) {
- KLOG_ERROR(LOG_TAG, "Could not open '%s'\n", path.string());
- return -1;
+int BatteryMonitor::readFromFile(const String8& path, std::string* buf) {
+ if (android::base::ReadFileToString(String8::std_string(path), buf)) {
+ *buf = android::base::Trim(*buf);
}
-
- ssize_t count = TEMP_FAILURE_RETRY(read(fd, buf, size));
- if (count > 0)
- cp = (char *)memrchr(buf, '\n', count);
-
- if (cp)
- *cp = '\0';
- else
- buf[0] = '\0';
-
- close(fd);
- return count;
+ return buf->length();
}
BatteryMonitor::PowerSupplyType BatteryMonitor::readPowerSupplyType(const String8& path) {
- const int SIZE = 128;
- char buf[SIZE];
- int length = readFromFile(path, buf, SIZE);
+ std::string buf;
BatteryMonitor::PowerSupplyType ret;
struct sysfsStringEnumMap supplyTypeMap[] = {
{ "Unknown", ANDROID_POWER_SUPPLY_TYPE_UNKNOWN },
@@ -167,12 +150,12 @@
{ NULL, 0 },
};
- if (length <= 0)
+ if (readFromFile(path, &buf) <= 0)
return ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
- ret = (BatteryMonitor::PowerSupplyType)mapSysfsString(buf, supplyTypeMap);
+ ret = (BatteryMonitor::PowerSupplyType)mapSysfsString(buf.c_str(), supplyTypeMap);
if (ret < 0) {
- KLOG_WARNING(LOG_TAG, "Unknown power supply type '%s'\n", buf);
+ KLOG_WARNING(LOG_TAG, "Unknown power supply type '%s'\n", buf.c_str());
ret = ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
}
@@ -180,27 +163,23 @@
}
bool BatteryMonitor::getBooleanField(const String8& path) {
- const int SIZE = 16;
- char buf[SIZE];
-
+ std::string buf;
bool value = false;
- if (readFromFile(path, buf, SIZE) > 0) {
- if (buf[0] != '0') {
+
+ if (readFromFile(path, &buf) > 0)
+ if (buf[0] != '0')
value = true;
- }
- }
return value;
}
int BatteryMonitor::getIntField(const String8& path) {
- const int SIZE = 128;
- char buf[SIZE];
-
+ std::string buf;
int value = 0;
- if (readFromFile(path, buf, SIZE) > 0) {
- value = strtol(buf, NULL, 0);
- }
+
+ if (readFromFile(path, &buf) > 0)
+ value = std::stoi(buf.c_str(), NULL, 0);
+
return value;
}
@@ -241,18 +220,16 @@
props.batteryHealth = BATTERY_HEALTH_GOOD;
}
- const int SIZE = 128;
- char buf[SIZE];
- String8 btech;
+ std::string buf;
- if (readFromFile(mHealthdConfig->batteryStatusPath, buf, SIZE) > 0)
- props.batteryStatus = getBatteryStatus(buf);
+ if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0)
+ props.batteryStatus = getBatteryStatus(buf.c_str());
- if (readFromFile(mHealthdConfig->batteryHealthPath, buf, SIZE) > 0)
- props.batteryHealth = getBatteryHealth(buf);
+ if (readFromFile(mHealthdConfig->batteryHealthPath, &buf) > 0)
+ props.batteryHealth = getBatteryHealth(buf.c_str());
- if (readFromFile(mHealthdConfig->batteryTechnologyPath, buf, SIZE) > 0)
- props.batteryTechnology = String8(buf);
+ if (readFromFile(mHealthdConfig->batteryTechnologyPath, &buf) > 0)
+ props.batteryTechnology = String8(buf.c_str());
unsigned int i;
@@ -261,33 +238,31 @@
path.appendFormat("%s/%s/online", POWER_SUPPLY_SYSFS_PATH,
mChargerNames[i].string());
- if (readFromFile(path, buf, SIZE) > 0) {
- if (buf[0] != '0') {
- path.clear();
- path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH,
- mChargerNames[i].string());
- switch(readPowerSupplyType(path)) {
- case ANDROID_POWER_SUPPLY_TYPE_AC:
- props.chargerAcOnline = true;
- break;
- case ANDROID_POWER_SUPPLY_TYPE_USB:
- props.chargerUsbOnline = true;
- break;
- case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
- props.chargerWirelessOnline = true;
- break;
- default:
- KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n",
- mChargerNames[i].string());
- }
- path.clear();
- path.appendFormat("%s/%s/current_max", POWER_SUPPLY_SYSFS_PATH,
- mChargerNames[i].string());
- if (access(path.string(), R_OK) == 0) {
- int maxChargingCurrent = getIntField(path);
- if (props.maxChargingCurrent < maxChargingCurrent) {
- props.maxChargingCurrent = maxChargingCurrent;
- }
+ if (getIntField(path)) {
+ path.clear();
+ path.appendFormat("%s/%s/type", POWER_SUPPLY_SYSFS_PATH,
+ mChargerNames[i].string());
+ switch(readPowerSupplyType(path)) {
+ case ANDROID_POWER_SUPPLY_TYPE_AC:
+ props.chargerAcOnline = true;
+ break;
+ case ANDROID_POWER_SUPPLY_TYPE_USB:
+ props.chargerUsbOnline = true;
+ break;
+ case ANDROID_POWER_SUPPLY_TYPE_WIRELESS:
+ props.chargerWirelessOnline = true;
+ break;
+ default:
+ KLOG_WARNING(LOG_TAG, "%s: Unknown power supply type\n",
+ mChargerNames[i].string());
+ }
+ path.clear();
+ path.appendFormat("%s/%s/current_max", POWER_SUPPLY_SYSFS_PATH,
+ mChargerNames[i].string());
+ if (access(path.string(), R_OK) == 0) {
+ int maxChargingCurrent = getIntField(path);
+ if (props.maxChargingCurrent < maxChargingCurrent) {
+ props.maxChargingCurrent = maxChargingCurrent;
}
}
}
@@ -343,10 +318,9 @@
int BatteryMonitor::getChargeStatus() {
int result = BATTERY_STATUS_UNKNOWN;
if (!mHealthdConfig->batteryStatusPath.isEmpty()) {
- char buf[128];
- if (readFromFile(mHealthdConfig->batteryStatusPath, buf, sizeof(buf)) > 0) {
- result = getBatteryStatus(buf);
- }
+ std::string buf;
+ if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0)
+ result = getBatteryStatus(buf.c_str());
}
return result;
}
diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp
index 5846626..612885b 100644
--- a/healthd/healthd_mode_charger.cpp
+++ b/healthd/healthd_mode_charger.cpp
@@ -58,7 +58,7 @@
#define min(a,b) ((a) < (b) ? (a) : (b))
#endif
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
#define MSEC_PER_SEC (1000LL)
#define NSEC_PER_MSEC (1000000LL)
diff --git a/healthd/include/healthd/BatteryMonitor.h b/healthd/include/healthd/BatteryMonitor.h
index 440f2e4..8865a7d 100644
--- a/healthd/include/healthd/BatteryMonitor.h
+++ b/healthd/include/healthd/BatteryMonitor.h
@@ -55,7 +55,7 @@
int getBatteryStatus(const char* status);
int getBatteryHealth(const char* status);
- int readFromFile(const String8& path, char* buf, size_t size);
+ int readFromFile(const String8& path, std::string* buf);
PowerSupplyType readPowerSupplyType(const String8& path);
bool getBooleanField(const String8& path);
int getIntField(const String8& path);
diff --git a/include/android/log.h b/include/android/log.h
index 1c171b7..2956e6e 100644
--- a/include/android/log.h
+++ b/include/android/log.h
@@ -124,7 +124,7 @@
void __android_log_assert(const char *cond, const char *tag,
const char *fmt, ...)
#if defined(__GNUC__)
- __attribute__ ((noreturn))
+ __attribute__ ((__noreturn__))
#ifdef __USE_MINGW_ANSI_STDIO
#if __USE_MINGW_ANSI_STDIO
__attribute__ ((format(gnu_printf, 3, 4)))
diff --git a/include/backtrace/BacktraceMap.h b/include/backtrace/BacktraceMap.h
index 2373c45..b80045f 100644
--- a/include/backtrace/BacktraceMap.h
+++ b/include/backtrace/BacktraceMap.h
@@ -71,6 +71,12 @@
bool IsWritable(uintptr_t pc) { return GetFlags(pc) & PROT_WRITE; }
bool IsExecutable(uintptr_t pc) { return GetFlags(pc) & PROT_EXEC; }
+ // In order to use the iterators on this object, a caller must
+ // call the LockIterator and UnlockIterator function to guarantee
+ // that the data does not change while it's being used.
+ virtual void LockIterator() {}
+ virtual void UnlockIterator() {}
+
typedef std::deque<backtrace_map_t>::iterator iterator;
iterator begin() { return maps_.begin(); }
iterator end() { return maps_.end(); }
@@ -102,4 +108,18 @@
pid_t pid_;
};
+class ScopedBacktraceMapIteratorLock {
+public:
+ explicit ScopedBacktraceMapIteratorLock(BacktraceMap* map) : map_(map) {
+ map->LockIterator();
+ }
+
+ ~ScopedBacktraceMapIteratorLock() {
+ map_->UnlockIterator();
+ }
+
+private:
+ BacktraceMap* map_;
+};
+
#endif // _BACKTRACE_BACKTRACE_MAP_H
diff --git a/include/cutils/debugger.h b/include/cutils/debugger.h
index 285e1af..20e8796 100644
--- a/include/cutils/debugger.h
+++ b/include/cutils/debugger.h
@@ -20,32 +20,10 @@
#include <sys/cdefs.h>
#include <sys/types.h>
+#include "debuggerd/client.h"
+
__BEGIN_DECLS
-#define DEBUGGER_SOCKET_NAME "android:debuggerd"
-#define DEBUGGER32_SOCKET_NAME "android:debuggerd32"
-#define DEBUGGER64_SOCKET_NAME DEBUGGER_SOCKET_NAME
-
-typedef enum {
- // dump a crash
- DEBUGGER_ACTION_CRASH,
- // dump a tombstone file
- DEBUGGER_ACTION_DUMP_TOMBSTONE,
- // dump a backtrace only back to the socket
- DEBUGGER_ACTION_DUMP_BACKTRACE,
-} debugger_action_t;
-
-// Make sure that all values have a fixed size so that this structure
-// is the same for 32 bit and 64 bit processes.
-// NOTE: Any changes to this structure must also be reflected in
-// bionic/linker/debugger.cpp.
-typedef struct __attribute__((packed)) {
- int32_t action;
- pid_t tid;
- uint64_t abort_msg_address;
- int32_t original_si_code;
-} debugger_msg_t;
-
/* Dumps a process backtrace, registers, and stack to a tombstone file (requires root).
* Stores the tombstone path in the provided buffer.
* Returns 0 on success, -1 on error.
diff --git a/include/cutils/properties.h b/include/cutils/properties.h
index 24aa224..adf670b 100644
--- a/include/cutils/properties.h
+++ b/include/cutils/properties.h
@@ -109,7 +109,7 @@
int property_list(void (*propfn)(const char *key, const char *value, void *cookie), void *cookie);
-#if defined(__BIONIC_FORTIFY)
+#if defined(__BIONIC_FORTIFY) && !defined(__clang__)
extern int __property_get_real(const char *, char *, const char *)
__asm__(__USER_LABEL_PREFIX__ "property_get");
diff --git a/include/system/qemu_pipe.h b/include/system/qemu_pipe.h
new file mode 100644
index 0000000..d403f8d
--- /dev/null
+++ b/include/system/qemu_pipe.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_INCLUDE_SYSTEM_QEMU_PIPE_H
+#define ANDROID_INCLUDE_SYSTEM_QEMU_PIPE_H
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+
+// Define QEMU_PIPE_DEBUG if you want to print error messages when an error
+// occurs during pipe operations. The macro should simply take a printf-style
+// formatting string followed by optional arguments.
+#ifndef QEMU_PIPE_DEBUG
+# define QEMU_PIPE_DEBUG(...) (void)0
+#endif
+
+// Try to open a new Qemu fast-pipe. This function returns a file descriptor
+// that can be used to communicate with a named service managed by the
+// emulator.
+//
+// This file descriptor can be used as a standard pipe/socket descriptor.
+//
+// 'pipeName' is the name of the emulator service you want to connect to,
+// and must begin with 'pipe:' (e.g. 'pipe:camera' or 'pipe:opengles').
+//
+// On success, return a valid file descriptor, or -1/errno on failure. E.g.:
+//
+// EINVAL -> unknown/unsupported pipeName
+// ENOSYS -> fast pipes not available in this system.
+//
+// ENOSYS should never happen, except if you're trying to run within a
+// misconfigured emulator.
+//
+// You should be able to open several pipes to the same pipe service,
+// except for a few special cases (e.g. GSM modem), where EBUSY will be
+// returned if more than one client tries to connect to it.
+static __inline__ int qemu_pipe_open(const char* pipeName) {
+ // Sanity check.
+ if (!pipeName || memcmp(pipeName, "pipe:", 5) != 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ int fd = TEMP_FAILURE_RETRY(open("/dev/qemu_pipe", O_RDWR));
+ if (fd < 0) {
+ QEMU_PIPE_DEBUG("%s: Could not open /dev/qemu_pipe: %s", __FUNCTION__,
+ strerror(errno));
+ return -1;
+ }
+
+ // Write the pipe name, *including* the trailing zero which is necessary.
+ size_t pipeNameLen = strlen(pipeName);
+ ssize_t ret = TEMP_FAILURE_RETRY(write(fd, pipeName, pipeNameLen + 1U));
+ if (ret != (ssize_t)pipeNameLen + 1) {
+ QEMU_PIPE_DEBUG("%s: Could not connect to %s pipe service: %s",
+ __FUNCTION__, pipeName, strerror(errno));
+ if (ret == 0) {
+ errno = ECONNRESET;
+ } else if (ret > 0) {
+ errno = EINVAL;
+ }
+ return -1;
+ }
+ return fd;
+}
+
+// Send a framed message |buff| of |len| bytes through the |fd| descriptor.
+// This really adds a 4-hexchar prefix describing the payload size.
+// Returns 0 on success, and -1 on error.
+static int __inline__ qemu_pipe_frame_send(int fd,
+ const void* buff,
+ size_t len) {
+ char header[5];
+ snprintf(header, sizeof(header), "%04x", len);
+ ssize_t ret = TEMP_FAILURE_RETRY(write(fd, header, 4));
+ if (ret != 4) {
+ QEMU_PIPE_DEBUG("Can't write qemud frame header: %s", strerror(errno));
+ return -1;
+ }
+ ret = TEMP_FAILURE_RETRY(write(fd, buff, len));
+ if (ret != (ssize_t)len) {
+ QEMU_PIPE_DEBUG("Can't write qemud frame payload: %s", strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+// Read a frame message from |fd|, and store it into |buff| of |len| bytes.
+// If the framed message is larger than |len|, then this returns -1 and the
+// content is lost. Otherwise, this returns the size of the message. NOTE:
+// empty messages are possible in a framed wire protocol and do not mean
+// end-of-stream.
+static int __inline__ qemu_pipe_frame_recv(int fd, void* buff, size_t len) {
+ char header[5];
+ ssize_t ret = TEMP_FAILURE_RETRY(read(fd, header, 4));
+ if (ret != 4) {
+ QEMU_PIPE_DEBUG("Can't read qemud frame header: %s", strerror(errno));
+ return -1;
+ }
+ header[4] = '\0';
+ size_t size;
+ if (sscanf(header, "%04zx", &size) != 1) {
+ QEMU_PIPE_DEBUG("Malformed qemud frame header: [%.*s]", 4, header);
+ return -1;
+ }
+ if (size > len) {
+ QEMU_PIPE_DEBUG("Oversized qemud frame (% bytes, expected <= %)", size,
+ len);
+ return -1;
+ }
+ ret = TEMP_FAILURE_RETRY(read(fd, buff, size));
+ if (ret != size) {
+ QEMU_PIPE_DEBUG("Could not read qemud frame payload: %s",
+ strerror(errno));
+ return -1;
+ }
+ return size;
+}
+
+#endif /* ANDROID_INCLUDE_HARDWARE_QEMUD_PIPE_H */
diff --git a/init/Android.mk b/init/Android.mk
index e1a3638..7aa3c3f 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -52,7 +52,7 @@
service.cpp \
util.cpp \
-LOCAL_STATIC_LIBRARIES := libbase libselinux
+LOCAL_STATIC_LIBRARIES := libbase libselinux liblog libprocessgroup
LOCAL_MODULE := libinit
LOCAL_SANITIZE := integer
LOCAL_CLANG := true
@@ -91,7 +91,6 @@
libcutils \
libbase \
libext4_utils_static \
- libutils \
libc \
libselinux \
liblog \
@@ -100,7 +99,8 @@
libc++_static \
libdl \
libsparse_static \
- libz
+ libz \
+ libprocessgroup
# Create symlinks
LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT)/sbin; \
diff --git a/init/devices.cpp b/init/devices.cpp
index 1410e3b..32fec52 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -257,11 +257,25 @@
/* If the node already exists update its SELinux label to handle cases when
* it was created with the wrong context during coldboot procedure. */
if (mknod(path, mode, dev) && (errno == EEXIST)) {
- if (lsetfilecon(path, secontext)) {
+
+ char* fcon = nullptr;
+ int rc = lgetfilecon(path, &fcon);
+ if (rc < 0) {
+ ERROR("Cannot get SELinux label on '%s' device (%s)\n",
+ path, strerror(errno));
+ goto out;
+ }
+
+ bool different = strcmp(fcon, secontext) != 0;
+ freecon(fcon);
+
+ if (different && lsetfilecon(path, secontext)) {
ERROR("Cannot set '%s' SELinux label on '%s' device (%s)\n",
secontext, path, strerror(errno));
}
}
+
+out:
chown(path, uid, -1);
setegid(AID_ROOT);
diff --git a/init/readme.txt b/init/readme.txt
index c25a59a..e75b4b2 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -184,6 +184,9 @@
Write the child's pid to the given files when it forks. Meant for
cgroup/cpuset usage.
+priority <priority>
+ Scheduling priority of the service process. This value has to be in range
+ -20 to 19. Default priority is 0. Priority is set via setpriority().
Triggers
--------
diff --git a/init/service.cpp b/init/service.cpp
index f5b8b00..d917b30 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -17,7 +17,9 @@
#include "service.h"
#include <fcntl.h>
+#include <sys/resource.h>
#include <sys/stat.h>
+#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <termios.h>
@@ -29,6 +31,9 @@
#include <android-base/stringprintf.h>
#include <cutils/android_reboot.h>
#include <cutils/sockets.h>
+#include <system/thread_defs.h>
+
+#include <processgroup/processgroup.h>
#include "action.h"
#include "init.h"
@@ -63,7 +68,7 @@
const std::vector<std::string>& args)
: name_(name), classname_(classname), flags_(0), pid_(0), time_started_(0),
time_crashed_(0), nr_crashed_(0), uid_(0), gid_(0), seclabel_(""),
- ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0), args_(args) {
+ ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0), priority_(0), args_(args) {
onrestart_.InitSingleTrigger("onrestart");
}
@@ -72,7 +77,8 @@
const std::string& seclabel, const std::vector<std::string>& args)
: name_(name), classname_(classname), flags_(flags), pid_(0), time_started_(0),
time_crashed_(0), nr_crashed_(0), uid_(uid), gid_(gid), supp_gids_(supp_gids),
- seclabel_(seclabel), ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0), args_(args) {
+ seclabel_(seclabel), ioprio_class_(IoSchedClass_NONE), ioprio_pri_(0), priority_(0),
+ args_(args) {
onrestart_.InitSingleTrigger("onrestart");
}
@@ -93,11 +99,16 @@
property_set(prop_name.c_str(), new_state.c_str());
}
+void Service::KillProcessGroup(int signal) {
+ NOTICE("Sending signal %d to service '%s' (pid %d) process group...\n",
+ signal, name_.c_str(), pid_);
+ kill(pid_, signal);
+ killProcessGroup(uid_, pid_, signal);
+}
+
bool Service::Reap() {
if (!(flags_ & SVC_ONESHOT) || (flags_ & SVC_RESTART)) {
- NOTICE("Service '%s' (pid %d) killing any children in process group\n",
- name_.c_str(), pid_);
- kill(-pid_, SIGKILL);
+ KillProcessGroup(SIGKILL);
}
// Remove any sockets we may have created.
@@ -195,6 +206,19 @@
return true;
}
+bool Service::HandlePriority(const std::vector<std::string>& args, std::string* err) {
+ priority_ = std::stoi(args[1]);
+
+ if (priority_ < ANDROID_PRIORITY_HIGHEST || priority_ > ANDROID_PRIORITY_LOWEST) {
+ priority_ = 0;
+ *err = StringPrintf("process priority value must be range %d - %d",
+ ANDROID_PRIORITY_HIGHEST, ANDROID_PRIORITY_LOWEST);
+ return false;
+ }
+
+ return true;
+}
+
bool Service::HandleIoprio(const std::vector<std::string>& args, std::string* err) {
ioprio_pri_ = std::stoul(args[2], 0, 8);
@@ -288,6 +312,7 @@
{"disabled", {0, 0, &Service::HandleDisabled}},
{"group", {1, NR_SVC_SUPP_GIDS + 1, &Service::HandleGroup}},
{"ioprio", {2, 2, &Service::HandleIoprio}},
+ {"priority", {1, 1, &Service::HandlePriority}},
{"keycodes", {1, kMax, &Service::HandleKeycodes}},
{"oneshot", {0, 0, &Service::HandleOneshot}},
{"onrestart", {1, kMax, &Service::HandleOnrestart}},
@@ -468,14 +493,28 @@
_exit(127);
}
}
+ if (priority_ != 0) {
+ if (setpriority(PRIO_PROCESS, 0, priority_) != 0) {
+ ERROR("setpriority failed: %s\n", strerror(errno));
+ _exit(127);
+ }
+ }
+ std::vector<std::string> expanded_args;
std::vector<char*> strs;
- for (const auto& s : args_) {
- strs.push_back(const_cast<char*>(s.c_str()));
+ expanded_args.resize(args_.size());
+ strs.push_back(const_cast<char*>(args_[0].c_str()));
+ for (std::size_t i = 1; i < args_.size(); ++i) {
+ if (!expand_props(args_[i], &expanded_args[i])) {
+ ERROR("%s: cannot expand '%s'\n", args_[0].c_str(), args_[i].c_str());
+ _exit(127);
+ }
+ strs.push_back(const_cast<char*>(expanded_args[i].c_str()));
}
strs.push_back(nullptr);
- if (execve(args_[0].c_str(), (char**) &strs[0], (char**) ENV) < 0) {
- ERROR("cannot execve('%s'): %s\n", args_[0].c_str(), strerror(errno));
+
+ if (execve(strs[0], (char**) &strs[0], (char**) ENV) < 0) {
+ ERROR("cannot execve('%s'): %s\n", strs[0], strerror(errno));
}
_exit(127);
@@ -491,6 +530,12 @@
pid_ = pid;
flags_ |= SVC_RUNNING;
+ errno = -createProcessGroup(uid_, pid_);
+ if (errno != 0) {
+ ERROR("createProcessGroup(%d, %d) failed for service '%s': %s\n",
+ uid_, pid_, name_.c_str(), strerror(errno));
+ }
+
if ((flags_ & SVC_EXEC) != 0) {
INFO("SVC_EXEC pid %d (uid %d gid %d+%zu context %s) started; waiting...\n",
pid_, uid_, gid_, supp_gids_.size(),
@@ -530,9 +575,7 @@
flags_ &= ~(SVC_RESTARTING | SVC_DISABLED_START);
flags_ |= SVC_DISABLED;
if (pid_) {
- NOTICE("Sending SIGTERM to service '%s' (pid %d)...\n", name_.c_str(),
- pid_);
- kill(-pid_, SIGTERM);
+ KillProcessGroup(SIGTERM);
NotifyStateChange("stopping");
}
}
@@ -562,19 +605,18 @@
}
}
-/* The how field should be either SVC_DISABLED, SVC_RESET, or SVC_RESTART */
+// The how field should be either SVC_DISABLED, SVC_RESET, or SVC_RESTART.
void Service::StopOrReset(int how) {
- /* The service is still SVC_RUNNING until its process exits, but if it has
- * already exited it shoudn't attempt a restart yet. */
+ // The service is still SVC_RUNNING until its process exits, but if it has
+ // already exited it shoudn't attempt a restart yet.
flags_ &= ~(SVC_RESTARTING | SVC_DISABLED_START);
if ((how != SVC_DISABLED) && (how != SVC_RESET) && (how != SVC_RESTART)) {
- /* Hrm, an illegal flag. Default to SVC_DISABLED */
+ // An illegal flag: default to SVC_DISABLED.
how = SVC_DISABLED;
}
- /* if the service has not yet started, prevent
- * it from auto-starting with its class
- */
+
+ // If the service has not yet started, prevent it from auto-starting with its class.
if (how == SVC_RESET) {
flags_ |= (flags_ & SVC_RC_DISABLED) ? SVC_DISABLED : SVC_RESET;
} else {
@@ -582,8 +624,7 @@
}
if (pid_) {
- NOTICE("Service '%s' is being killed...\n", name_.c_str());
- kill(-pid_, SIGKILL);
+ KillProcessGroup(SIGKILL);
NotifyStateChange("stopping");
} else {
NotifyStateChange("stopped");
diff --git a/init/service.h b/init/service.h
index d6ce664..8b3a0ad 100644
--- a/init/service.h
+++ b/init/service.h
@@ -93,6 +93,7 @@
pid_t pid() const { return pid_; }
uid_t uid() const { return uid_; }
gid_t gid() const { return gid_; }
+ int priority() const { return priority_; }
const std::vector<gid_t>& supp_gids() const { return supp_gids_; }
const std::string& seclabel() const { return seclabel_; }
const std::vector<int>& keycodes() const { return keycodes_; }
@@ -110,12 +111,14 @@
void ZapStdio() const;
void OpenConsole() const;
void PublishSocket(const std::string& name, int fd) const;
+ void KillProcessGroup(int signal);
bool HandleClass(const std::vector<std::string>& args, std::string* err);
bool HandleConsole(const std::vector<std::string>& args, std::string* err);
bool HandleCritical(const std::vector<std::string>& args, std::string* err);
bool HandleDisabled(const std::vector<std::string>& args, std::string* err);
bool HandleGroup(const std::vector<std::string>& args, std::string* err);
+ bool HandlePriority(const std::vector<std::string>& args, std::string* err);
bool HandleIoprio(const std::vector<std::string>& args, std::string* err);
bool HandleKeycodes(const std::vector<std::string>& args, std::string* err);
bool HandleOneshot(const std::vector<std::string>& args, std::string* err);
@@ -155,6 +158,7 @@
IoSchedClass ioprio_class_;
int ioprio_pri_;
+ int priority_;
std::vector<std::string> args_;
};
diff --git a/init/util.cpp b/init/util.cpp
index 750e040..69f6566 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -489,6 +489,7 @@
* - will accept $$ as a literal $.
* - no nested property expansion, i.e. ${foo.${bar}} is not supported,
* bad things will happen
+ * - ${x.y:-default} will return default value if property empty.
*/
while (*src_ptr) {
const char* c;
@@ -511,6 +512,7 @@
}
std::string prop_name;
+ std::string def_val;
if (*c == '{') {
c++;
const char* end = strchr(c, '}');
@@ -521,6 +523,11 @@
}
prop_name = std::string(c, end);
c = end + 1;
+ size_t def = prop_name.find(":-");
+ if (def < prop_name.size()) {
+ def_val = prop_name.substr(def + 2);
+ prop_name = prop_name.substr(0, def);
+ }
} else {
prop_name = c;
ERROR("using deprecated syntax for specifying property '%s', use ${name} instead\n",
@@ -535,9 +542,12 @@
std::string prop_val = property_get(prop_name.c_str());
if (prop_val.empty()) {
- ERROR("property '%s' doesn't exist while expanding '%s'\n",
- prop_name.c_str(), src.c_str());
- return false;
+ if (def_val.empty()) {
+ ERROR("property '%s' doesn't exist while expanding '%s'\n",
+ prop_name.c_str(), src.c_str());
+ return false;
+ }
+ prop_val = def_val;
}
dst->append(prop_val);
diff --git a/init/util.h b/init/util.h
index c2efb01..b9496a9 100644
--- a/init/util.h
+++ b/init/util.h
@@ -23,7 +23,7 @@
#include <string>
#include <functional>
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
#define COLDBOOT_DONE "/dev/.coldboot_done"
diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
index 19551dc..00c35b1 100644
--- a/libbacktrace/BacktraceMap.cpp
+++ b/libbacktrace/BacktraceMap.cpp
@@ -36,8 +36,8 @@
}
void BacktraceMap::FillIn(uintptr_t addr, backtrace_map_t* map) {
- for (BacktraceMap::const_iterator it = begin();
- it != end(); ++it) {
+ ScopedBacktraceMapIteratorLock lock(this);
+ for (BacktraceMap::const_iterator it = begin(); it != end(); ++it) {
if (addr >= it->start && addr < it->end) {
*map = *it;
return;
diff --git a/libbacktrace/UnwindMap.cpp b/libbacktrace/UnwindMap.cpp
index 34d79f9..af79562 100644
--- a/libbacktrace/UnwindMap.cpp
+++ b/libbacktrace/UnwindMap.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <pthread.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
@@ -72,6 +73,7 @@
}
UnwindMapLocal::UnwindMapLocal() : UnwindMap(getpid()), map_created_(false) {
+ pthread_rwlock_init(&map_lock_, nullptr);
}
UnwindMapLocal::~UnwindMapLocal() {
@@ -82,9 +84,14 @@
}
bool UnwindMapLocal::GenerateMap() {
+ // Lock so that multiple threads cannot modify the maps data at the
+ // same time.
+ pthread_rwlock_wrlock(&map_lock_);
+
// It's possible for the map to be regenerated while this loop is occurring.
// If that happens, get the map again, but only try at most three times
// before giving up.
+ bool generated = false;
for (int i = 0; i < 3; i++) {
maps_.clear();
@@ -110,12 +117,17 @@
}
// Check to see if the map changed while getting the data.
if (ret != -UNW_EINVAL) {
- return true;
+ generated = true;
+ break;
}
}
- BACK_LOGW("Unable to generate the map.");
- return false;
+ pthread_rwlock_unlock(&map_lock_);
+
+ if (!generated) {
+ BACK_LOGW("Unable to generate the map.");
+ }
+ return generated;
}
bool UnwindMapLocal::Build() {
diff --git a/libbacktrace/UnwindMap.h b/libbacktrace/UnwindMap.h
index 111401f..f85b54a 100644
--- a/libbacktrace/UnwindMap.h
+++ b/libbacktrace/UnwindMap.h
@@ -17,6 +17,7 @@
#ifndef _LIBBACKTRACE_UNWIND_MAP_H
#define _LIBBACKTRACE_UNWIND_MAP_H
+#include <pthread.h>
#include <stdint.h>
#include <sys/types.h>
@@ -56,10 +57,15 @@
void FillIn(uintptr_t addr, backtrace_map_t* map) override;
+ void LockIterator() override { pthread_rwlock_rdlock(&map_lock_); }
+ void UnlockIterator() override { pthread_rwlock_unlock(&map_lock_); }
+
private:
bool GenerateMap();
bool map_created_;
+
+ pthread_rwlock_t map_lock_;
};
#endif // _LIBBACKTRACE_UNWIND_MAP_H
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index 7066c79..e25c8e9 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -895,6 +895,7 @@
std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(pid));
// Basic test that verifies that the map is in the expected order.
+ ScopedBacktraceMapIteratorLock lock(map.get());
std::vector<map_test_t>::const_iterator test_it = test_maps.begin();
for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) {
ASSERT_TRUE(test_it != test_maps.end());
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 822a7d3..e29c9ad 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -117,7 +117,8 @@
arch-x86_64/android_memset32.S \
LOCAL_C_INCLUDES := $(libcutils_c_includes)
-LOCAL_STATIC_LIBRARIES := liblog
+LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := libdebuggerd_client
+LOCAL_STATIC_LIBRARIES := liblog libdebuggerd_client
ifneq ($(ENABLE_CPUSETS),)
LOCAL_CFLAGS += -DUSE_CPUSETS
endif
@@ -134,6 +135,8 @@
# TODO: remove liblog as whole static library, once we don't have prebuilt that requires
# liblog symbols present in libcutils.
LOCAL_WHOLE_STATIC_LIBRARIES := libcutils liblog
+LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := libdebuggerd_client
+LOCAL_STATIC_LIBRARIES := libdebuggerd_client
LOCAL_SHARED_LIBRARIES := liblog
ifneq ($(ENABLE_CPUSETS),)
LOCAL_CFLAGS += -DUSE_CPUSETS
diff --git a/liblog/Android.mk b/liblog/Android.mk
deleted file mode 100644
index b24b489..0000000
--- a/liblog/Android.mk
+++ /dev/null
@@ -1,85 +0,0 @@
-#
-# Copyright (C) 2008-2014 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# 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.
-#
-LOCAL_PATH := $(my-dir)
-include $(CLEAR_VARS)
-
-# This is what we want to do:
-# liblog_cflags := $(shell \
-# sed -n \
-# 's/^\([0-9]*\)[ \t]*liblog[ \t].*/-DLIBLOG_LOG_TAG=\1/p' \
-# $(LOCAL_PATH)/event.logtags)
-# so make sure we do not regret hard-coding it as follows:
-liblog_cflags := -DLIBLOG_LOG_TAG=1005
-liblog_cflags += -DSNET_EVENT_LOG_TAG=1397638484
-
-liblog_sources := log_event_list.c log_event_write.c logger_write.c
-liblog_sources += config_write.c logger_name.c logger_lock.c
-liblog_host_sources := $(liblog_sources) fake_log_device.c event.logtags
-liblog_host_sources += fake_writer.c
-liblog_target_sources := $(liblog_sources) event_tag_map.c
-liblog_target_sources += config_read.c log_time.cpp log_is_loggable.c logprint.c
-liblog_target_sources += pmsg_reader.c pmsg_writer.c
-liblog_target_sources += logd_reader.c logd_writer.c logger_read.c
-
-# Shared and static library for host
-# ========================================================
-LOCAL_MODULE := liblog
-LOCAL_SRC_FILES := $(liblog_host_sources)
-# some files must not be compiled when building against Mingw
-# they correspond to features not used by our host development tools
-# which are also hard or even impossible to port to native Win32
-LOCAL_SRC_FILES_darwin := event_tag_map.c
-LOCAL_SRC_FILES_linux := event_tag_map.c
-LOCAL_SRC_FILES_windows := uio.c
-LOCAL_CFLAGS := -DFAKE_LOG_DEVICE=1 -Werror -fvisibility=hidden $(liblog_cflags)
-LOCAL_MULTILIB := both
-LOCAL_MODULE_HOST_OS := darwin linux windows
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := liblog
-LOCAL_WHOLE_STATIC_LIBRARIES := liblog
-LOCAL_LDLIBS_linux := -lrt
-LOCAL_MULTILIB := both
-LOCAL_CXX_STL := none
-LOCAL_MODULE_HOST_OS := darwin linux windows
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-
-# Shared and static library for target
-# ========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := liblog
-LOCAL_SRC_FILES := $(liblog_target_sources)
-LOCAL_CFLAGS := -Werror -fvisibility=hidden $(liblog_cflags)
-# AddressSanitizer runtime library depends on liblog.
-LOCAL_SANITIZE := never
-include $(BUILD_STATIC_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := liblog
-LOCAL_WHOLE_STATIC_LIBRARIES := liblog
-LOCAL_CFLAGS := -Werror -fvisibility=hidden $(liblog_cflags)
-
-# TODO: This is to work around b/24465209. Remove after root cause is fixed
-LOCAL_LDFLAGS_arm := -Wl,--hash-style=both
-
-LOCAL_SANITIZE := never
-LOCAL_CXX_STL := none
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/liblog/Android.soong.mk b/liblog/Android.soong.mk
new file mode 100644
index 0000000..6c4dff5
--- /dev/null
+++ b/liblog/Android.soong.mk
@@ -0,0 +1,3 @@
+LOCAL_PATH := $(my-dir)
+
+include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/liblog/tests/liblog_benchmark.cpp b/liblog/tests/liblog_benchmark.cpp
index 01fb50f..1b66a56 100644
--- a/liblog/tests/liblog_benchmark.cpp
+++ b/liblog/tests/liblog_benchmark.cpp
@@ -205,7 +205,7 @@
android_log_header_t header;
android_log_event_int_t payload;
};
- char buf[sizeof(struct packet) + 8] __aligned(8);
+ alignas(8) char buf[sizeof(struct packet) + 8];
memset(buf, 0, sizeof(buf));
struct packet *buffer = (struct packet*)(((uintptr_t)buf + 7) & ~7);
if (((uintptr_t)&buffer->pmsg_header) & 7) {
@@ -281,7 +281,7 @@
android_log_header_t header;
android_log_event_int_t payload;
};
- char buf[sizeof(struct packet) + 8] __aligned(8);
+ alignas(8) char buf[sizeof(struct packet) + 8];
memset(buf, 0, sizeof(buf));
struct packet *buffer = (struct packet*)((((uintptr_t)buf + 7) & ~7) + 1);
if ((((uintptr_t)&buffer->pmsg_header) & 7) != 1) {
@@ -357,7 +357,7 @@
android_log_header_t header;
android_log_event_int_t payload;
};
- char buf[sizeof(struct packet) + 8 + LOGGER_ENTRY_MAX_PAYLOAD] __aligned(8);
+ alignas(8) char buf[sizeof(struct packet) + 8 + LOGGER_ENTRY_MAX_PAYLOAD];
memset(buf, 0, sizeof(buf));
struct packet *buffer = (struct packet*)(((uintptr_t)buf + 7) & ~7);
if (((uintptr_t)&buffer->pmsg_header) & 7) {
@@ -430,7 +430,7 @@
android_log_header_t header;
android_log_event_int_t payload;
};
- char buf[sizeof(struct packet) + 8 + LOGGER_ENTRY_MAX_PAYLOAD] __aligned(8);
+ alignas(8) char buf[sizeof(struct packet) + 8 + LOGGER_ENTRY_MAX_PAYLOAD];
memset(buf, 0, sizeof(buf));
struct packet *buffer = (struct packet*)((((uintptr_t)buf + 7) & ~7) + 1);
if ((((uintptr_t)&buffer->pmsg_header) & 7) != 1) {
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 713a59d..d0e07dd 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -133,9 +133,10 @@
std::string public_native_libraries_system_config =
root_dir + kPublicNativeLibrariesSystemConfigPathFromRoot;
- LOG_ALWAYS_FATAL_IF(!ReadConfig(public_native_libraries_system_config, &sonames),
+ std::string error_msg;
+ LOG_ALWAYS_FATAL_IF(!ReadConfig(public_native_libraries_system_config, &sonames, &error_msg),
"Error reading public native library list from \"%s\": %s",
- public_native_libraries_system_config.c_str(), strerror(errno));
+ public_native_libraries_system_config.c_str(), error_msg.c_str());
// For debuggable platform builds use ANDROID_ADDITIONAL_PUBLIC_LIBRARIES environment
// variable to add libraries to the list. This is intended for platform tests only.
@@ -172,20 +173,42 @@
}
private:
- bool ReadConfig(const std::string& configFile, std::vector<std::string>* sonames) {
+ bool ReadConfig(const std::string& configFile, std::vector<std::string>* sonames,
+ std::string* error_msg = nullptr) {
// Read list of public native libraries from the config file.
std::string file_content;
if(!base::ReadFileToString(configFile, &file_content)) {
+ if (error_msg) *error_msg = strerror(errno);
return false;
}
std::vector<std::string> lines = base::Split(file_content, "\n");
- for (const auto& line : lines) {
+ for (auto& line : lines) {
auto trimmed_line = base::Trim(line);
if (trimmed_line[0] == '#' || trimmed_line.empty()) {
continue;
}
+ size_t space_pos = trimmed_line.rfind(' ');
+ if (space_pos != std::string::npos) {
+ std::string type = trimmed_line.substr(space_pos + 1);
+ if (type != "32" && type != "64") {
+ if (error_msg) *error_msg = "Malformed line: " + line;
+ return false;
+ }
+#if defined(__LP64__)
+ // Skip 32 bit public library.
+ if (type == "32") {
+ continue;
+ }
+#else
+ // Skip 64 bit public library.
+ if (type == "64") {
+ continue;
+ }
+#endif
+ trimmed_line.resize(space_pos);
+ }
sonames->push_back(trimmed_line);
}
diff --git a/libnetutils/dhcptool.c b/libnetutils/dhcptool.c
index 352ac5e..a2d3869 100644
--- a/libnetutils/dhcptool.c
+++ b/libnetutils/dhcptool.c
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <err.h>
#include <errno.h>
#include <error.h>
#include <stdbool.h>
@@ -29,12 +30,14 @@
char* interface = argv[1];
if (ifc_init()) {
- error(EXIT_FAILURE, errno, "dhcptool %s: ifc_init failed", interface);
+ err(errno, "dhcptool %s: ifc_init failed", interface);
+ ifc_close();
+ return EXIT_FAILURE;
}
int rc = do_dhcp(interface);
if (rc) {
- error(0, errno, "dhcptool %s: do_dhcp failed", interface);
+ err(errno, "dhcptool %s: do_dhcp failed", interface);
}
ifc_close();
diff --git a/libnetutils/ifc_utils.c b/libnetutils/ifc_utils.c
index f9f62f8..eae32ce 100644
--- a/libnetutils/ifc_utils.c
+++ b/libnetutils/ifc_utils.c
@@ -19,6 +19,7 @@
#include <unistd.h>
#include <string.h>
#include <errno.h>
+#include <pthread.h>
#include <sys/socket.h>
#include <sys/select.h>
@@ -57,6 +58,8 @@
static int ifc_ctl_sock = -1;
static int ifc_ctl_sock6 = -1;
+static pthread_mutex_t ifc_sock_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+static pthread_mutex_t ifc_sock6_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
void printerr(char *fmt, ...);
#define DBG 0
@@ -122,6 +125,8 @@
int ifc_init(void)
{
int ret;
+
+ pthread_mutex_lock(&ifc_sock_mutex);
if (ifc_ctl_sock == -1) {
ifc_ctl_sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (ifc_ctl_sock < 0) {
@@ -136,6 +141,7 @@
int ifc_init6(void)
{
+ pthread_mutex_lock(&ifc_sock6_mutex);
if (ifc_ctl_sock6 == -1) {
ifc_ctl_sock6 = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (ifc_ctl_sock6 < 0) {
@@ -152,6 +158,7 @@
(void)close(ifc_ctl_sock);
ifc_ctl_sock = -1;
}
+ pthread_mutex_unlock(&ifc_sock_mutex);
}
void ifc_close6(void)
@@ -160,6 +167,7 @@
(void)close(ifc_ctl_sock6);
ifc_ctl_sock6 = -1;
}
+ pthread_mutex_unlock(&ifc_sock6_mutex);
}
static void ifc_init_ifr(const char *name, struct ifreq *ifr)
@@ -553,6 +561,7 @@
ifc_init();
if (ifc_ctl_sock < 0) {
+ ifc_close();
return -errno;
}
diff --git a/libpixelflinger/Android.mk b/libpixelflinger/Android.mk
index 9a937f8..55891db 100644
--- a/libpixelflinger/Android.mk
+++ b/libpixelflinger/Android.mk
@@ -74,10 +74,6 @@
external/safe-iop/include
LOCAL_SHARED_LIBRARIES := libcutils liblog libutils
-# Really this should go away entirely or at least not depend on
-# libhardware, but this at least gets us built.
-LOCAL_SHARED_LIBRARIES += libhardware_legacy
-LOCAL_CFLAGS += -DWITH_LIB_HARDWARE
include $(BUILD_SHARED_LIBRARY)
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libpixelflinger/codeflinger/ARMAssembler.cpp b/libpixelflinger/codeflinger/ARMAssembler.cpp
index 92243da..849512a 100644
--- a/libpixelflinger/codeflinger/ARMAssembler.cpp
+++ b/libpixelflinger/codeflinger/ARMAssembler.cpp
@@ -22,10 +22,6 @@
#include <cutils/log.h>
#include <cutils/properties.h>
-#if defined(WITH_LIB_HARDWARE)
-#include <hardware_legacy/qemu_tracing.h>
-#endif
-
#include <private/pixelflinger/ggl_context.h>
#include "ARMAssembler.h"
@@ -48,9 +44,6 @@
{
mBase = mPC = (uint32_t *)assembly->base();
mDuration = ggl_system_time();
-#if defined(WITH_LIB_HARDWARE)
- mQemuTracing = true;
-#endif
}
ARMAssembler::~ARMAssembler()
@@ -184,13 +177,6 @@
const char * const format = "generated %s (%d ins) at [%p:%p] in %lld ns\n";
ALOGI(format, name, int(pc()-base()), base(), pc(), duration);
-#if defined(WITH_LIB_HARDWARE)
- if (__builtin_expect(mQemuTracing, 0)) {
- int err = qemu_add_mapping(uintptr_t(base()), name);
- mQemuTracing = (err >= 0);
- }
-#endif
-
char value[PROPERTY_VALUE_MAX];
property_get("debug.pf.disasm", value, "0");
if (atoi(value) != 0) {
diff --git a/libpixelflinger/codeflinger/ARMAssembler.h b/libpixelflinger/codeflinger/ARMAssembler.h
index e0c7646..7178c65 100644
--- a/libpixelflinger/codeflinger/ARMAssembler.h
+++ b/libpixelflinger/codeflinger/ARMAssembler.h
@@ -167,9 +167,6 @@
uint32_t* mPC;
uint32_t* mPrologPC;
int64_t mDuration;
-#if defined(WITH_LIB_HARDWARE)
- bool mQemuTracing;
-#endif
struct branch_target_t {
inline branch_target_t() : label(0), pc(0) { }
diff --git a/libpixelflinger/codeflinger/MIPS64Assembler.cpp b/libpixelflinger/codeflinger/MIPS64Assembler.cpp
index 672040b..b9f31ff 100644
--- a/libpixelflinger/codeflinger/MIPS64Assembler.cpp
+++ b/libpixelflinger/codeflinger/MIPS64Assembler.cpp
@@ -33,10 +33,6 @@
#include <cutils/log.h>
#include <cutils/properties.h>
-#if defined(WITH_LIB_HARDWARE)
-#include <hardware_legacy/qemu_tracing.h>
-#endif
-
#include <private/pixelflinger/ggl_context.h>
#include "MIPS64Assembler.h"
diff --git a/libpixelflinger/codeflinger/MIPSAssembler.cpp b/libpixelflinger/codeflinger/MIPSAssembler.cpp
index 5497fae..ae06a13 100644
--- a/libpixelflinger/codeflinger/MIPSAssembler.cpp
+++ b/libpixelflinger/codeflinger/MIPSAssembler.cpp
@@ -55,10 +55,6 @@
#include <cutils/log.h>
#include <cutils/properties.h>
-#if defined(WITH_LIB_HARDWARE)
-#include <hardware_legacy/qemu_tracing.h>
-#endif
-
#include <private/pixelflinger/ggl_context.h>
#include "MIPSAssembler.h"
@@ -1411,13 +1407,6 @@
const char * const format = "generated %s (%d ins) at [%p:%p] in %lld ns\n";
ALOGI(format, name, int(pc()-base()), base(), pc(), duration);
-#if defined(WITH_LIB_HARDWARE)
- if (__builtin_expect(mQemuTracing, 0)) {
- int err = qemu_add_mapping(uintptr_t(base()), name);
- mQemuTracing = (err >= 0);
- }
-#endif
-
char value[PROPERTY_VALUE_MAX];
value[0] = '\0';
diff --git a/libpixelflinger/codeflinger/MIPSAssembler.h b/libpixelflinger/codeflinger/MIPSAssembler.h
index b53fefb..c1178b6 100644
--- a/libpixelflinger/codeflinger/MIPSAssembler.h
+++ b/libpixelflinger/codeflinger/MIPSAssembler.h
@@ -410,9 +410,6 @@
uint32_t* mPC;
uint32_t* mPrologPC;
int64_t mDuration;
-#if defined(WITH_LIB_HARDWARE)
- bool mQemuTracing;
-#endif
struct branch_target_t {
inline branch_target_t() : label(0), pc(0) { }
diff --git a/libprocessgroup/Android.mk b/libprocessgroup/Android.mk
index ee6ba58..87985d4 100644
--- a/libprocessgroup/Android.mk
+++ b/libprocessgroup/Android.mk
@@ -3,7 +3,16 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := processgroup.cpp
LOCAL_MODULE := libprocessgroup
-LOCAL_SHARED_LIBRARIES := liblog libutils
+LOCAL_STATIC_LIBRARIES := liblog
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_CFLAGS := -Wall -Werror
+include $(BUILD_STATIC_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := processgroup.cpp
+LOCAL_MODULE := libprocessgroup
+LOCAL_SHARED_LIBRARIES := liblog
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_CFLAGS := -Wall -Werror
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 00a0357..da4bb71 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -22,19 +22,18 @@
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
-#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
+
+#include <chrono>
#include <memory>
#include <log/log.h>
#include <private/android_filesystem_config.h>
-#include <utils/SystemClock.h>
-
#include <processgroup/processgroup.h>
#include "processgroup_priv.h"
@@ -250,25 +249,26 @@
int killProcessGroup(uid_t uid, int initialPid, int signal)
{
- int processes;
- const int sleep_us = 5 * 1000; // 5ms
- int64_t startTime = android::uptimeMillis();
- int retry = 40;
+ std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
+ int retry = 40;
+ int processes;
while ((processes = killProcessGroupOnce(uid, initialPid, signal)) > 0) {
SLOGV("killed %d processes for processgroup %d\n", processes, initialPid);
if (retry > 0) {
- usleep(sleep_us);
+ usleep(5 * 1000); // 5ms
--retry;
} else {
- SLOGE("failed to kill %d processes for processgroup %d\n",
- processes, initialPid);
+ SLOGE("failed to kill %d processes for processgroup %d\n", processes, initialPid);
break;
}
}
- SLOGV("Killed process group uid %d pid %d in %" PRId64 "ms, %d procs remain", uid, initialPid,
- android::uptimeMillis()-startTime, processes);
+ std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
+
+ SLOGV("Killed process group uid %d pid %d in %dms, %d procs remain", uid, initialPid,
+ static_cast<int>(std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()),
+ processes);
if (processes == 0) {
return removeProcessGroup(uid, initialPid);
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 52f49cc..ea698c8 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -27,7 +27,6 @@
#include <android-base/file.h>
#include <android-base/strings.h>
-#include <cutils/properties.h>
#include <cutils/sched_policy.h>
#include <cutils/sockets.h>
#include <log/event_tag_map.h>
@@ -281,16 +280,17 @@
fprintf(stderr, "options include:\n"
" -s Set default filter to silent. Equivalent to filterspec '*:S'\n"
" -f <file>, --file=<file> Log to file. Default is stdout\n"
- " -r <kbytes>, --rotate-kbytes=<kbytes> Rotate log every kbytes. Requires -f\n"
- " option. Permits property expansion.\n"
- " -n <count>, --rotate-count=<count> Sets max number of rotated logs to\n"
- " <count>, default 4. Permits property expansion.\n"
+ " -r <kbytes>, --rotate-kbytes=<kbytes>\n"
+ " Rotate log every kbytes. Requires -f option\n"
+ " -n <count>, --rotate-count=<count>\n"
+ " Sets max number of rotated logs to <count>, default 4\n"
" -v <format>, --format=<format>\n"
" Sets the log print format, where <format> is:\n"
" brief color epoch long monotonic printable process raw\n"
" tag thread threadtime time uid usec UTC year zone\n"
" -D, --dividers Print dividers between each log buffer\n"
" -c, --clear Clear (flush) the entire log and exit\n"
+ " if Log to File specified, clear fileset instead\n"
" -d Dump the log and then exit (don't block)\n"
" -e <expr>, --regex=<expr>\n"
" Only print lines where the log message matches <expr>\n"
@@ -318,7 +318,6 @@
" 'system', 'radio', 'events', 'crash', 'default' or 'all'.\n"
" Multiple -b parameters or comma separated list of buffers are\n"
" allowed. Buffers interleaved. Default -b main,system,crash.\n"
- " Permits property expansion.\n"
" -B, --binary Output the log in binary.\n"
" -S, --statistics Output statistics.\n"
" -p, --prune Print prune white and ~black list. Service is specified as\n"
@@ -336,11 +335,7 @@
" comes first. Improves efficiency of polling by providing\n"
" an about-to-wrap wakeup.\n");
- fprintf(stderr,"\nProperty expansion where available, may need to be single quoted to prevent\n"
- "shell expansion:\n"
- " ${key} - Expand string with property value associated with key\n"
- " ${key:-default} - Expand, if property key value clear, use default\n"
- "\nfilterspecs are a series of \n"
+ fprintf(stderr,"\nfilterspecs are a series of \n"
" <tag>[:priority]\n\n"
"where <tag> is a log component tag (or * for all) and priority is:\n"
" V Verbose (default for <tag>)\n"
@@ -538,49 +533,6 @@
return retval;
}
-// Expand multiple flat property references ${<tag>:-default} or ${tag}.
-//
-// ToDo: Do we permit nesting?
-// ${persist.logcat.something:-${ro.logcat.something:-maybesomething}}
-// For now this will result in a syntax error for caller and is acceptable.
-//
-std::string expand(const char *str)
-{
- std::string retval(str);
-
- // Caller has no use for ${, } or :- as literals so no use for escape
- // character. Result expectations are a number or a string, with validity
- // checking for both in caller. Recursive expansion or other syntax errors
- // will result in content caller can not obviously tolerate, error must
- // report substring if applicable, expanded and original content (if
- // different) so that it will be clear to user what they did wrong.
- for (size_t pos; (pos = retval.find("${")) != std::string::npos; ) {
- size_t epos = retval.find("}", pos + 2);
- if (epos == std::string::npos) {
- break; // Caller will error out, showing this unexpanded.
- }
- size_t def = retval.find(":-", pos + 2);
- if (def >= epos) {
- def = std::string::npos;
- }
- std::string default_value("");
- std::string key;
- if (def == std::string::npos) {
- key = retval.substr(pos + 2, epos - (pos + 2));
- } else {
- key = retval.substr(pos + 2, def - (pos + 2));
- default_value = retval.substr(def + 2, epos - (def + 2));
- }
- char value[PROPERTY_VALUE_MAX];
- property_get(key.c_str(), value, default_value.c_str());
- // Caller will error out, syntactically empty content at this point
- // will not be tolerated as expected.
- retval.replace(pos, epos - pos + 1, value);
- }
-
- return retval;
-}
-
} /* namespace android */
@@ -812,35 +764,23 @@
case 'b': {
unsigned idMask = 0;
- std::string expanded = expand(optarg);
- std::istringstream copy(expanded);
- std::string token;
- // wish for strtok and ",:; \t\n\r\f" for hidden flexibility
- while (std::getline(copy, token, ',')) { // settle for ","
- if (token.compare("default") == 0) {
+ while ((optarg = strtok(optarg, ",:; \t\n\r\f")) != NULL) {
+ if (strcmp(optarg, "default") == 0) {
idMask |= (1 << LOG_ID_MAIN) |
(1 << LOG_ID_SYSTEM) |
(1 << LOG_ID_CRASH);
- } else if (token.compare("all") == 0) {
+ } else if (strcmp(optarg, "all") == 0) {
idMask = (unsigned)-1;
} else {
- log_id_t log_id = android_name_to_log_id(token.c_str());
+ log_id_t log_id = android_name_to_log_id(optarg);
const char *name = android_log_id_to_name(log_id);
- if (token.compare(name) != 0) {
- bool strDifferent = expanded.compare(token);
- if (expanded.compare(optarg)) {
- expanded += " expanded from ";
- expanded += optarg;
- }
- if (strDifferent) {
- expanded = token + " within " + expanded;
- }
- logcat_panic(true, "unknown buffer -b %s\n",
- expanded.c_str());
+ if (strcmp(name, optarg) != 0) {
+ logcat_panic(true, "unknown buffer %s\n", optarg);
}
idMask |= (1 << log_id);
}
+ optarg = NULL;
}
for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
@@ -895,36 +835,22 @@
g_outputFileName = optarg;
break;
- case 'r': {
- std::string expanded = expand(optarg);
- if (!getSizeTArg(expanded.c_str(), &g_logRotateSizeKBytes, 1)) {
- if (expanded.compare(optarg)) {
- expanded += " expanded from ";
- expanded += optarg;
- }
- logcat_panic(true, "Invalid parameter -r %s\n",
- expanded.c_str());
+ case 'r':
+ if (!getSizeTArg(optarg, &g_logRotateSizeKBytes, 1)) {
+ logcat_panic(true, "Invalid parameter %s to -r\n", optarg);
}
- }
break;
- case 'n': {
- std::string expanded = expand(optarg);
- if (!getSizeTArg(expanded.c_str(), &g_maxRotatedLogs, 1)) {
- if (expanded.compare(optarg)) {
- expanded += " expanded from ";
- expanded += optarg;
- }
- logcat_panic(true, "Invalid parameter -n %s\n",
- expanded.c_str());
+ case 'n':
+ if (!getSizeTArg(optarg, &g_maxRotatedLogs, 1)) {
+ logcat_panic(true, "Invalid parameter %s to -n\n", optarg);
}
- }
break;
case 'v':
err = setLogFormat (optarg);
if (err < 0) {
- logcat_panic(true, "Invalid parameter -v %s\n", optarg);
+ logcat_panic(true, "Invalid parameter %s to -v\n", optarg);
}
hasSetLogFormat |= err;
break;
@@ -1108,7 +1034,35 @@
}
if (clearLog) {
- if (android_logger_clear(dev->logger)) {
+ if (g_outputFileName) {
+ int maxRotationCountDigits =
+ (g_maxRotatedLogs > 0) ? (int) (floor(log10(g_maxRotatedLogs) + 1)) : 0;
+
+ for (int i = g_maxRotatedLogs ; i >= 0 ; --i) {
+ char *file;
+
+ if (i == 0) {
+ asprintf(&file, "%s", g_outputFileName);
+ } else {
+ asprintf(&file, "%s.%.*d", g_outputFileName, maxRotationCountDigits, i);
+ }
+
+ if (!file) {
+ perror("while clearing log files");
+ clearFail = clearFail ?: dev->device;
+ break;
+ }
+
+ err = unlink(file);
+
+ if (err < 0 && errno != ENOENT && clearFail == NULL) {
+ perror("while clearing log files");
+ clearFail = dev->device;
+ }
+
+ free(file);
+ }
+ } else if (android_logger_clear(dev->logger)) {
clearFail = clearFail ?: dev->device;
}
}
diff --git a/logcat/logcatd.rc b/logcat/logcatd.rc
index 70d1dd4..7d70dd9 100644
--- a/logcat/logcatd.rc
+++ b/logcat/logcatd.rc
@@ -5,6 +5,16 @@
exec - logd log -- /system/bin/logcat -L -b ${persist.logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${persist.logd.logpersistd.size:-256}
start logcatd
+on property:persist.logd.logpersistd=clear
+ stop logcatd
+ # logd for clear of only our files in /data/misc/logd
+ exec - logd log -- /system/bin/logcat -c -f /data/misc/logd/logcat -n ${persist.logd.logpersistd.size:-256}
+ setprop persist.logd.logpersistd ""
+
+on property:persist.logd.logpersistd=stop
+ stop logcatd
+ setprop persist.logd.logpersistd ""
+
service logcatd /system/bin/logcat -b ${persist.logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 1024 -n ${persist.logd.logpersistd.size:-256}
class late_start
disabled
diff --git a/logcat/logpersist b/logcat/logpersist
index e448456..d1eda37 100755
--- a/logcat/logpersist
+++ b/logcat/logpersist
@@ -28,7 +28,7 @@
-b|--buffer) buffer="${2}" ; shift ;;
-h|--help|*)
LEAD_SPACE_="`echo ${progname%.*} | tr '[ -~]' ' '`"
- echo "${progname%.*}.cat - dump current ${service%d} logs"
+ echo "${progname%.*}.cat - dump current ${service} logs"
echo "${progname%.*}.start [--size=<size_in_kb>] [--buffer=<buffers>] [--clear]"
echo "${LEAD_SPACE_} - start ${service} service"
echo "${progname%.*}.stop [--clear] - stop ${service} service"
@@ -73,10 +73,7 @@
current_size="`getprop ${property}.size`"
if [ "${service}" = "`getprop ${property}`" ]; then
if [ "true" = "${clear}" ]; then
- su root stop ${service}
- su root setprop ${property} ""
- # 20ms done, guarantees content stop before rm
- sleep 1
+ setprop ${property} "clear"
elif [ "${buffer}|${size}" != "${current_buffer}|${current_size}" ]; then
echo "ERROR: Changing existing collection parameters from" >&2
if [ "${buffer}" != "${current_buffer}" ]; then
@@ -98,41 +95,44 @@
echo " To blindly override and retain data, ${progname%.*}.stop first." >&2
exit 1
fi
- fi
- if [ "true" = "${clear}" ]; then
- su logd,misc rm -rf "${data}"
+ elif [ "true" = "${clear}" ]; then
+ setprop ${property} "clear"
fi
if [ -n "${buffer}${current_buffer}" ]; then
- su root setprop ${property}.buffer "${buffer}"
+ setprop ${property}.buffer "${buffer}"
fi
if [ -n "${size}${current_size}" ]; then
- su root setprop ${property}.size "${size}"
+ setprop ${property}.size "${size}"
fi
+ while [ "clear" = "`getprop ${property}`" ]; do
+ continue
+ done
# ${service}.rc does the heavy lifting with the following trigger
- su root setprop ${property} ${service}
+ setprop ${property} ${service}
getprop ${property}
# 20ms done, to permit process feedback check
sleep 1
- # also generate an error return code if not found running, bonus
- ps -t | grep "${data##*/}.*${service%d}"
+ # also generate an error return code if not found running
+ pgrep -u ${data##*/} ${service%d}
;;
*.stop)
if [ -n "${size}${buffer}" ]; then
echo "WARNING: Can not use --size or --buffer with ${progname%.*}.stop" >&2
fi
- su root stop ${service}
- su root setprop ${property} ""
+ if [ "true" = "${clear}" ]; then
+ setprop ${property} "clear"
+ else
+ setprop ${property} "stop"
+ fi
if [ -n "`getprop ${property}.buffer`" ]; then
- su root setprop ${property}.buffer ""
+ setprop ${property}.buffer ""
fi
if [ -n "`getprop ${property}.size`" ]; then
- su root setprop ${property}.size ""
+ setprop ${property}.size ""
fi
- if [ "true" = "${clear}" ]; then
- # 20ms done, guarantees content stop before rm
- sleep 1
- su logd,misc rm -rf "${data}"
- fi
+ while [ "clear" = "`getprop ${property}`" ]; do
+ continue
+ done
;;
*)
echo "ERROR: Unexpected command ${0##*/} ${args}" >&2
diff --git a/logcat/tests/Android.mk b/logcat/tests/Android.mk
index 3bf8a0b..a28664e 100644
--- a/logcat/tests/Android.mk
+++ b/logcat/tests/Android.mk
@@ -56,6 +56,6 @@
LOCAL_MODULE := $(test_module_prefix)unit-tests
LOCAL_MODULE_TAGS := $(test_tags)
LOCAL_CFLAGS += $(test_c_flags)
-LOCAL_SHARED_LIBRARIES := liblog libcutils
+LOCAL_SHARED_LIBRARIES := liblog
LOCAL_SRC_FILES := $(test_src_files)
include $(BUILD_NATIVE_TEST)
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index 920d504..0043d1b 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -25,7 +25,6 @@
#include <memory>
-#include <cutils/properties.h>
#include <gtest/gtest.h>
#include <log/log.h>
#include <log/logger.h>
@@ -426,14 +425,6 @@
"logcat -v brief -b radio,events,system,main -g 2>/dev/null"));
}
-// duplicate test for get_size, but use test.logcat.buffer property
-TEST(logcat, property_expand) {
- property_set("test.logcat.buffer", "radio,events");
- EXPECT_EQ(4, get_groups(
- "logcat -v brief -b 'system,${test.logcat.buffer:-bogo},main' -g 2>/dev/null"));
- property_set("test.logcat.buffer", "");
-}
-
TEST(logcat, bad_buffer) {
ASSERT_EQ(0, get_groups(
"logcat -v brief -b radio,events,bogo,system,main -g 2>/dev/null"));
@@ -781,6 +772,82 @@
EXPECT_FALSE(system(command));
}
+TEST(logcat, logrotate_clear) {
+ static const char tmp_out_dir_form[] = "/data/local/tmp/logcat.logrotate.XXXXXX";
+ char tmp_out_dir[sizeof(tmp_out_dir_form)];
+ ASSERT_TRUE(NULL != mkdtemp(strcpy(tmp_out_dir, tmp_out_dir_form)));
+
+ static const char log_filename[] = "log.txt";
+ static const unsigned num_val = 32;
+ static const char logcat_cmd[] = "logcat -b all -d -f %s/%s -n %d -r 1";
+ static const char clear_cmd[] = " -c";
+ static const char cleanup_cmd[] = "rm -rf %s";
+ char command[sizeof(tmp_out_dir) + sizeof(logcat_cmd) + sizeof(log_filename) + sizeof(clear_cmd) + 32];
+
+ // Run command with all data
+ {
+ snprintf(command, sizeof(command) - sizeof(clear_cmd),
+ logcat_cmd, tmp_out_dir, log_filename, num_val);
+
+ int ret;
+ EXPECT_FALSE((ret = system(command)));
+ if (ret) {
+ snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
+ EXPECT_FALSE(system(command));
+ return;
+ }
+ std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir), closedir);
+ EXPECT_NE(nullptr, dir);
+ if (!dir) {
+ snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
+ EXPECT_FALSE(system(command));
+ return;
+ }
+ struct dirent *entry;
+ unsigned count = 0;
+ while ((entry = readdir(dir.get()))) {
+ if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) {
+ continue;
+ }
+ ++count;
+ }
+ EXPECT_EQ(count, num_val + 1);
+ }
+
+ {
+ // Now with -c option tacked onto the end
+ strcat(command, clear_cmd);
+
+ int ret;
+ EXPECT_FALSE((ret = system(command)));
+ if (ret) {
+ snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
+ EXPECT_FALSE(system(command));
+ return;
+ }
+ std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir), closedir);
+ EXPECT_NE(nullptr, dir);
+ if (!dir) {
+ snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
+ EXPECT_FALSE(system(command));
+ return;
+ }
+ struct dirent *entry;
+ unsigned count = 0;
+ while ((entry = readdir(dir.get()))) {
+ if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) {
+ continue;
+ }
+ fprintf(stderr, "Found %s/%s!!!\n", tmp_out_dir, entry->d_name);
+ ++count;
+ }
+ EXPECT_EQ(count, 0U);
+ }
+
+ snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
+ EXPECT_FALSE(system(command));
+}
+
TEST(logcat, logrotate_nodir) {
// expect logcat to error out on writing content and exit(1) for nodir
EXPECT_EQ(W_EXITCODE(1, 0),
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
index 39dd227..61b7fd8 100644
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -48,7 +48,7 @@
+ LOGGER_ENTRY_MAX_PAYLOAD];
struct iovec iov = { buffer, sizeof(buffer) };
- char control[CMSG_SPACE(sizeof(struct ucred))] __aligned(4);
+ alignas(4) char control[CMSG_SPACE(sizeof(struct ucred))];
struct msghdr hdr = {
NULL,
0,
diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc
index 0ca38b9..4b76383 100644
--- a/rootdir/init.zygote32.rc
+++ b/rootdir/init.zygote32.rc
@@ -1,5 +1,6 @@
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
+ priority -20
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc
index 1646c0f..2efd8e2 100644
--- a/rootdir/init.zygote32_64.rc
+++ b/rootdir/init.zygote32_64.rc
@@ -1,5 +1,6 @@
service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
class main
+ priority -20
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
@@ -9,6 +10,7 @@
service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
class main
+ priority -20
socket zygote_secondary stream 660 root system
onrestart restart zygote
writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc
index b477c8e..342a561 100644
--- a/rootdir/init.zygote64.rc
+++ b/rootdir/init.zygote64.rc
@@ -1,5 +1,6 @@
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
class main
+ priority -20
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index 633a981..b3ac7b0 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -1,5 +1,6 @@
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
class main
+ priority -20
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
@@ -9,6 +10,7 @@
service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
class main
+ priority -20
socket zygote_secondary stream 660 root system
onrestart restart zygote
writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index ba04364..73e19de 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -32,14 +32,11 @@
OUR_TOOLS := \
getevent \
- ioctl \
- log \
nandread \
newfs_msdos \
sendevent \
start \
stop \
- top \
ALL_TOOLS = $(BSD_TOOLS) $(OUR_TOOLS)
@@ -53,9 +50,7 @@
LOCAL_CONLYFLAGS += -std=gnu99
LOCAL_SHARED_LIBRARIES := \
- liblog \
libcutils \
- libselinux \
LOCAL_WHOLE_STATIC_LIBRARIES := $(patsubst %,libtoolbox_%,$(BSD_TOOLS))
diff --git a/toolbox/ioctl.c b/toolbox/ioctl.c
deleted file mode 100644
index 093e467..0000000
--- a/toolbox/ioctl.c
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (c) 2008, 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.
- * * Neither the name of Google, 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 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.
- */
-
-#include <errno.h>
-#include <error.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-
-static void usage() {
- fprintf(stderr, "%s [-l <length>] [-a <argsize>] [-rdh] <device> <ioctlnr>\n"
- " -l <length> Length of io buffer\n"
- " -a <argsize> Size of each argument (1-8)\n"
- " -r Open device in read only mode\n"
- " -d Direct argument (no iobuffer)\n"
- " -h Print help\n", getprogname());
- exit(1);
-}
-
-static int xstrtoi(const char* s, const char* what) {
- char* endp;
- errno = 0;
- long result = strtol(s, &endp, 0);
- if (errno != 0 || *endp != '\0') {
- error(1, errno, "couldn't parse %s '%s'", what, s);
- }
- if (result > INT_MAX || result < INT_MIN) {
- error(1, errno, "%s '%s' out of range", what, s);
- }
- return result;
-}
-
-int ioctl_main(int argc, char* argv[]) {
- int read_only = 0;
- int length = -1;
- int arg_size = 4;
- int direct_arg = 0;
-
- void *ioctl_args = NULL;
- uint8_t *ioctl_argp;
- uint8_t *ioctl_argp_save = NULL;
- int rem;
-
- int c;
- while ((c = getopt(argc, argv, "rdl:a:h")) != -1) {
- switch (c) {
- case 'r':
- read_only = 1;
- break;
- case 'd':
- direct_arg = 1;
- break;
- case 'l':
- length = xstrtoi(optarg, "length");
- break;
- case 'a':
- arg_size = xstrtoi(optarg, "argument size");
- break;
- case 'h':
- usage();
- break;
- default:
- error(1, 0, "invalid option -%c", optopt);
- }
- }
-
- if (optind + 2 > argc) {
- usage();
- }
-
- const char* device = argv[optind];
- int fd;
- if (strcmp(device, "-") == 0) {
- fd = STDIN_FILENO;
- } else {
- fd = open(device, read_only ? O_RDONLY : (O_RDWR | O_SYNC));
- if (fd == -1) {
- error(1, errno, "cannot open %s", argv[optind]);
- }
- }
- optind++;
-
- // IOCTL(2) wants second parameter as a signed int.
- // Let's let the user specify either negative numbers or large positive
- // numbers, for the case where ioctl number is larger than INT_MAX.
- errno = 0;
- char* endp;
- int ioctl_nr = UINT_MAX & strtoll(argv[optind], &endp, 0);
- if (errno != 0 || *endp != '\0') {
- error(1, errno, "couldn't parse ioctl number '%s'", argv[optind]);
- }
- optind++;
-
- if(direct_arg) {
- arg_size = 4;
- length = 4;
- }
-
- if(length < 0) {
- length = (argc - optind) * arg_size;
- }
- if(length) {
- ioctl_args = calloc(1, length);
-
- ioctl_argp_save = ioctl_argp = ioctl_args;
- rem = length;
- while (optind < argc) {
- uint64_t tmp = strtoull(argv[optind], NULL, 0);
- if (rem < arg_size) {
- error(1, 0, "too many arguments");
- }
- memcpy(ioctl_argp, &tmp, arg_size);
- ioctl_argp += arg_size;
- rem -= arg_size;
- optind++;
- }
- }
- printf("sending ioctl 0x%x", ioctl_nr);
- rem = length;
- while(rem--) {
- printf(" 0x%02x", *ioctl_argp_save++);
- }
- printf(" to %s\n", device);
-
- int res;
- if(direct_arg)
- res = ioctl(fd, ioctl_nr, *(uint32_t*)ioctl_args);
- else if(length)
- res = ioctl(fd, ioctl_nr, ioctl_args);
- else
- res = ioctl(fd, ioctl_nr, 0);
- if (res < 0) {
- free(ioctl_args);
- error(1, errno, "ioctl 0x%x failed (returned %d)", ioctl_nr, res);
- }
-
- if (length) {
- printf("return buf:");
- ioctl_argp = ioctl_args;
- rem = length;
- while(rem--) {
- printf(" %02x", *ioctl_argp++);
- }
- printf("\n");
- }
- free(ioctl_args);
- close(fd);
- return 0;
-}
diff --git a/toolbox/log.c b/toolbox/log.c
deleted file mode 100644
index 2f020a8..0000000
--- a/toolbox/log.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (c) 2008, 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.
- * * Neither the name of Google, 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 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.
- */
-
-#include <stdio.h>
-#include <log/logd.h>
-#include <ctype.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <stdlib.h>
-#include <cutils/sockets.h>
-#include <unistd.h>
-
-/*
- * Note: also accepts 0-9 priorities
- * returns ANDROID_LOG_UNKNOWN if the character is unrecognized
- */
-static android_LogPriority filterCharToPri (char c)
-{
- android_LogPriority pri;
-
- c = tolower(c);
-
- if (c >= '0' && c <= '9') {
- if (c >= ('0'+ANDROID_LOG_SILENT)) {
- pri = ANDROID_LOG_VERBOSE;
- } else {
- pri = (android_LogPriority)(c - '0');
- }
- } else if (c == 'v') {
- pri = ANDROID_LOG_VERBOSE;
- } else if (c == 'd') {
- pri = ANDROID_LOG_DEBUG;
- } else if (c == 'i') {
- pri = ANDROID_LOG_INFO;
- } else if (c == 'w') {
- pri = ANDROID_LOG_WARN;
- } else if (c == 'e') {
- pri = ANDROID_LOG_ERROR;
- } else if (c == 'f') {
- pri = ANDROID_LOG_FATAL;
- } else if (c == 's') {
- pri = ANDROID_LOG_SILENT;
- } else if (c == '*') {
- pri = ANDROID_LOG_DEFAULT;
- } else {
- pri = ANDROID_LOG_UNKNOWN;
- }
-
- return pri;
-}
-
-static int usage(const char *s)
-{
- fprintf(stderr, "USAGE: %s [-p priorityChar] [-t tag] message\n", s);
-
- fprintf(stderr, "\tpriorityChar should be one of:\n"
- "\t\tv,d,i,w,e\n");
- exit(-1);
-}
-
-
-int log_main(int argc, char *argv[])
-{
- android_LogPriority priority;
- const char *tag = "log";
- char buffer[4096];
- int i;
-
- priority = ANDROID_LOG_INFO;
-
- for (;;) {
- int ret;
-
- ret = getopt(argc, argv, "t:p:h");
-
- if (ret < 0) {
- break;
- }
-
- switch(ret) {
- case 't':
- tag = optarg;
- break;
-
- case 'p':
- priority = filterCharToPri(optarg[0]);
- if (priority == ANDROID_LOG_UNKNOWN) {
- usage(argv[0]);
- }
- break;
-
- case 'h':
- usage(argv[0]);
- break;
- }
- }
-
- if (optind == argc) {
- usage(argv[0]);
- }
-
- buffer[0] = '\0';
-
- for (i = optind ; i < argc ; i++) {
- strlcat(buffer, argv[i], sizeof(buffer)-1);
- strlcat(buffer, " ", sizeof(buffer)-1);
- }
-
- if(buffer[0] == 0) {
- usage(argv[0]);
- }
-
- __android_log_print(priority, tag, "%s", buffer);
-
- return 0;
-}
-
diff --git a/toolbox/top.c b/toolbox/top.c
deleted file mode 100644
index 003f4c9..0000000
--- a/toolbox/top.c
+++ /dev/null
@@ -1,589 +0,0 @@
-/*
- * Copyright (c) 2008, 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.
- * * Neither the name of Google, 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 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.
- */
-
-#include <ctype.h>
-#include <dirent.h>
-#include <grp.h>
-#include <inttypes.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <cutils/sched_policy.h>
-
-struct cpu_info {
- long unsigned utime, ntime, stime, itime;
- long unsigned iowtime, irqtime, sirqtime;
-};
-
-#define PROC_NAME_LEN 64
-#define THREAD_NAME_LEN 32
-#define POLICY_NAME_LEN 4
-
-struct proc_info {
- struct proc_info *next;
- pid_t pid;
- pid_t tid;
- uid_t uid;
- gid_t gid;
- char name[PROC_NAME_LEN];
- char tname[THREAD_NAME_LEN];
- char state;
- uint64_t utime;
- uint64_t stime;
- char pr[3];
- long ni;
- uint64_t delta_utime;
- uint64_t delta_stime;
- uint64_t delta_time;
- uint64_t vss;
- uint64_t rss;
- int num_threads;
- char policy[POLICY_NAME_LEN];
-};
-
-struct proc_list {
- struct proc_info **array;
- int size;
-};
-
-#define die(...) { fprintf(stderr, __VA_ARGS__); exit(EXIT_FAILURE); }
-
-#define INIT_PROCS 50
-#define THREAD_MULT 8
-static struct proc_info **old_procs, **new_procs;
-static int num_old_procs, num_new_procs;
-static struct proc_info *free_procs;
-static int num_used_procs, num_free_procs;
-
-static int max_procs, delay, iterations, threads;
-
-static struct cpu_info old_cpu, new_cpu;
-
-static struct proc_info *alloc_proc(void);
-static void free_proc(struct proc_info *proc);
-static void read_procs(void);
-static int read_stat(char *filename, struct proc_info *proc);
-static void read_policy(int pid, struct proc_info *proc);
-static void add_proc(int proc_num, struct proc_info *proc);
-static int read_cmdline(char *filename, struct proc_info *proc);
-static int read_status(char *filename, struct proc_info *proc);
-static void print_procs(void);
-static struct proc_info *find_old_proc(pid_t pid, pid_t tid);
-static void free_old_procs(void);
-static int (*proc_cmp)(const void *a, const void *b);
-static int proc_cpu_cmp(const void *a, const void *b);
-static int proc_vss_cmp(const void *a, const void *b);
-static int proc_rss_cmp(const void *a, const void *b);
-static int proc_thr_cmp(const void *a, const void *b);
-static int numcmp(long long a, long long b);
-static void usage(char *cmd);
-
-int top_main(int argc, char *argv[]) {
- num_used_procs = num_free_procs = 0;
-
- max_procs = 0;
- delay = 3;
- iterations = -1;
- proc_cmp = &proc_cpu_cmp;
- for (int i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "-m")) {
- if (i + 1 >= argc) {
- fprintf(stderr, "Option -m expects an argument.\n");
- usage(argv[0]);
- exit(EXIT_FAILURE);
- }
- max_procs = atoi(argv[++i]);
- continue;
- }
- if (!strcmp(argv[i], "-n")) {
- if (i + 1 >= argc) {
- fprintf(stderr, "Option -n expects an argument.\n");
- usage(argv[0]);
- exit(EXIT_FAILURE);
- }
- iterations = atoi(argv[++i]);
- continue;
- }
- if (!strcmp(argv[i], "-d")) {
- if (i + 1 >= argc) {
- fprintf(stderr, "Option -d expects an argument.\n");
- usage(argv[0]);
- exit(EXIT_FAILURE);
- }
- delay = atoi(argv[++i]);
- continue;
- }
- if (!strcmp(argv[i], "-s")) {
- if (i + 1 >= argc) {
- fprintf(stderr, "Option -s expects an argument.\n");
- usage(argv[0]);
- exit(EXIT_FAILURE);
- }
- ++i;
- if (!strcmp(argv[i], "cpu")) { proc_cmp = &proc_cpu_cmp; continue; }
- if (!strcmp(argv[i], "vss")) { proc_cmp = &proc_vss_cmp; continue; }
- if (!strcmp(argv[i], "rss")) { proc_cmp = &proc_rss_cmp; continue; }
- if (!strcmp(argv[i], "thr")) { proc_cmp = &proc_thr_cmp; continue; }
- fprintf(stderr, "Invalid argument \"%s\" for option -s.\n", argv[i]);
- exit(EXIT_FAILURE);
- }
- if (!strcmp(argv[i], "-H") || !strcmp(argv[i], "-t")) { threads = 1; continue; }
- if (!strcmp(argv[i], "-h")) {
- usage(argv[0]);
- exit(EXIT_SUCCESS);
- }
- fprintf(stderr, "Invalid argument \"%s\".\n", argv[i]);
- usage(argv[0]);
- exit(EXIT_FAILURE);
- }
-
- if (threads && proc_cmp == &proc_thr_cmp) {
- fprintf(stderr, "Sorting by threads per thread makes no sense!\n");
- exit(EXIT_FAILURE);
- }
-
- free_procs = NULL;
-
- num_new_procs = num_old_procs = 0;
- new_procs = old_procs = NULL;
-
- read_procs();
- while ((iterations == -1) || (iterations-- > 0)) {
- old_procs = new_procs;
- num_old_procs = num_new_procs;
- memcpy(&old_cpu, &new_cpu, sizeof(old_cpu));
- read_procs();
- print_procs();
- free_old_procs();
- fflush(stdout);
- if (iterations != 0) sleep(delay);
- }
-
- return 0;
-}
-
-static struct proc_info *alloc_proc(void) {
- struct proc_info *proc;
-
- if (free_procs) {
- proc = free_procs;
- free_procs = free_procs->next;
- num_free_procs--;
- } else {
- proc = malloc(sizeof(*proc));
- if (!proc) die("Could not allocate struct process_info.\n");
- }
-
- num_used_procs++;
-
- return proc;
-}
-
-static void free_proc(struct proc_info *proc) {
- proc->next = free_procs;
- free_procs = proc;
-
- num_used_procs--;
- num_free_procs++;
-}
-
-#define MAX_LINE 256
-
-static void read_procs(void) {
- DIR *proc_dir, *task_dir;
- struct dirent *pid_dir, *tid_dir;
- char filename[64];
- FILE *file;
- int proc_num;
- struct proc_info *proc;
- pid_t pid, tid;
-
- int i;
-
- proc_dir = opendir("/proc");
- if (!proc_dir) die("Could not open /proc.\n");
-
- new_procs = calloc(INIT_PROCS * (threads ? THREAD_MULT : 1), sizeof(struct proc_info *));
- num_new_procs = INIT_PROCS * (threads ? THREAD_MULT : 1);
-
- file = fopen("/proc/stat", "r");
- if (!file) die("Could not open /proc/stat.\n");
- fscanf(file, "cpu %lu %lu %lu %lu %lu %lu %lu", &new_cpu.utime, &new_cpu.ntime, &new_cpu.stime,
- &new_cpu.itime, &new_cpu.iowtime, &new_cpu.irqtime, &new_cpu.sirqtime);
- fclose(file);
-
- proc_num = 0;
- while ((pid_dir = readdir(proc_dir))) {
- if (!isdigit(pid_dir->d_name[0]))
- continue;
-
- pid = atoi(pid_dir->d_name);
-
- struct proc_info cur_proc;
-
- if (!threads) {
- proc = alloc_proc();
-
- proc->pid = proc->tid = pid;
-
- snprintf(filename, sizeof(filename), "/proc/%d/stat", pid);
- read_stat(filename, proc);
-
- snprintf(filename, sizeof(filename), "/proc/%d/cmdline", pid);
- read_cmdline(filename, proc);
-
- snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
- read_status(filename, proc);
-
- read_policy(pid, proc);
-
- proc->num_threads = 0;
- } else {
- snprintf(filename, sizeof(filename), "/proc/%d/cmdline", pid);
- read_cmdline(filename, &cur_proc);
-
- snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
- read_status(filename, &cur_proc);
-
- proc = NULL;
- }
-
- snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
- task_dir = opendir(filename);
- if (!task_dir) continue;
-
- while ((tid_dir = readdir(task_dir))) {
- if (!isdigit(tid_dir->d_name[0]))
- continue;
-
- if (threads) {
- tid = atoi(tid_dir->d_name);
-
- proc = alloc_proc();
-
- proc->pid = pid; proc->tid = tid;
-
- snprintf(filename, sizeof(filename), "/proc/%d/task/%d/stat", pid, tid);
- read_stat(filename, proc);
-
- read_policy(tid, proc);
-
- strcpy(proc->name, cur_proc.name);
- proc->uid = cur_proc.uid;
- proc->gid = cur_proc.gid;
-
- add_proc(proc_num++, proc);
- } else {
- proc->num_threads++;
- }
- }
-
- closedir(task_dir);
-
- if (!threads)
- add_proc(proc_num++, proc);
- }
-
- for (i = proc_num; i < num_new_procs; i++)
- new_procs[i] = NULL;
-
- closedir(proc_dir);
-}
-
-static int read_stat(char *filename, struct proc_info *proc) {
- FILE *file;
- char buf[MAX_LINE], *open_paren, *close_paren;
-
- file = fopen(filename, "r");
- if (!file) return 1;
- fgets(buf, MAX_LINE, file);
- fclose(file);
-
- /* Split at first '(' and last ')' to get process name. */
- open_paren = strchr(buf, '(');
- close_paren = strrchr(buf, ')');
- if (!open_paren || !close_paren) return 1;
-
- *open_paren = *close_paren = '\0';
- strncpy(proc->tname, open_paren + 1, THREAD_NAME_LEN);
- proc->tname[THREAD_NAME_LEN-1] = 0;
-
- // Scan rest of string.
- long pr;
- sscanf(close_paren + 1,
- " %c "
- "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
- "%" SCNu64 // utime %lu (14)
- "%" SCNu64 // stime %lu (15)
- "%*d %*d "
- "%ld " // priority %ld (18)
- "%ld " // nice %ld (19)
- "%*d %*d %*d "
- "%" SCNu64 // vsize %lu (23)
- "%" SCNu64, // rss %ld (24)
- &proc->state,
- &proc->utime,
- &proc->stime,
- &pr,
- &proc->ni,
- &proc->vss,
- &proc->rss);
-
- // Translate the PR field.
- if (pr < -9) strcpy(proc->pr, "RT");
- else snprintf(proc->pr, sizeof(proc->pr), "%ld", pr);
-
- return 0;
-}
-
-static void add_proc(int proc_num, struct proc_info *proc) {
- int i;
-
- if (proc_num >= num_new_procs) {
- new_procs = realloc(new_procs, 2 * num_new_procs * sizeof(struct proc_info *));
- if (!new_procs) die("Could not expand procs array.\n");
- for (i = num_new_procs; i < 2 * num_new_procs; i++)
- new_procs[i] = NULL;
- num_new_procs = 2 * num_new_procs;
- }
- new_procs[proc_num] = proc;
-}
-
-static int read_cmdline(char *filename, struct proc_info *proc) {
- FILE *file;
- char line[MAX_LINE];
-
- line[0] = '\0';
- file = fopen(filename, "r");
- if (!file) return 1;
- fgets(line, MAX_LINE, file);
- fclose(file);
- if (strlen(line) > 0) {
- strncpy(proc->name, line, PROC_NAME_LEN);
- proc->name[PROC_NAME_LEN-1] = 0;
- } else
- proc->name[0] = 0;
- return 0;
-}
-
-static void read_policy(int pid, struct proc_info *proc) {
- SchedPolicy p;
- if (get_sched_policy(pid, &p) < 0)
- strlcpy(proc->policy, "unk", POLICY_NAME_LEN);
- else {
- strlcpy(proc->policy, get_sched_policy_name(p), POLICY_NAME_LEN);
- proc->policy[2] = '\0';
- }
-}
-
-static int read_status(char *filename, struct proc_info *proc) {
- FILE *file;
- char line[MAX_LINE];
- unsigned int uid, gid;
-
- file = fopen(filename, "r");
- if (!file) return 1;
- while (fgets(line, MAX_LINE, file)) {
- sscanf(line, "Uid: %u", &uid);
- sscanf(line, "Gid: %u", &gid);
- }
- fclose(file);
- proc->uid = uid; proc->gid = gid;
- return 0;
-}
-
-static void print_procs(void) {
- static int call = 0;
- int i;
- struct proc_info *old_proc, *proc;
- long unsigned total_delta_time;
-
- for (i = 0; i < num_new_procs; i++) {
- if (new_procs[i]) {
- old_proc = find_old_proc(new_procs[i]->pid, new_procs[i]->tid);
- if (old_proc) {
- new_procs[i]->delta_utime = new_procs[i]->utime - old_proc->utime;
- new_procs[i]->delta_stime = new_procs[i]->stime - old_proc->stime;
- } else {
- new_procs[i]->delta_utime = 0;
- new_procs[i]->delta_stime = 0;
- }
- new_procs[i]->delta_time = new_procs[i]->delta_utime + new_procs[i]->delta_stime;
- }
- }
-
- total_delta_time = (new_cpu.utime + new_cpu.ntime + new_cpu.stime + new_cpu.itime
- + new_cpu.iowtime + new_cpu.irqtime + new_cpu.sirqtime)
- - (old_cpu.utime + old_cpu.ntime + old_cpu.stime + old_cpu.itime
- + old_cpu.iowtime + old_cpu.irqtime + old_cpu.sirqtime);
-
- qsort(new_procs, num_new_procs, sizeof(struct proc_info *), proc_cmp);
-
- if (call++ > 0) printf("\n\n\n");
- printf("User %ld%%, System %ld%%, IOW %ld%%, IRQ %ld%%\n",
- ((new_cpu.utime + new_cpu.ntime) - (old_cpu.utime + old_cpu.ntime)) * 100 / total_delta_time,
- ((new_cpu.stime ) - (old_cpu.stime)) * 100 / total_delta_time,
- ((new_cpu.iowtime) - (old_cpu.iowtime)) * 100 / total_delta_time,
- ((new_cpu.irqtime + new_cpu.sirqtime)
- - (old_cpu.irqtime + old_cpu.sirqtime)) * 100 / total_delta_time);
- printf("User %ld + Nice %ld + Sys %ld + Idle %ld + IOW %ld + IRQ %ld + SIRQ %ld = %ld\n",
- new_cpu.utime - old_cpu.utime,
- new_cpu.ntime - old_cpu.ntime,
- new_cpu.stime - old_cpu.stime,
- new_cpu.itime - old_cpu.itime,
- new_cpu.iowtime - old_cpu.iowtime,
- new_cpu.irqtime - old_cpu.irqtime,
- new_cpu.sirqtime - old_cpu.sirqtime,
- total_delta_time);
- printf("\n");
- if (!threads)
- printf("%5s %-8s %2s %3s %4s %1s %5s %7s %7s %3s %s\n", "PID", "USER", "PR", "NI", "CPU%", "S", "#THR", "VSS", "RSS", "PCY", "Name");
- else
- printf("%5s %5s %-8s %2s %3s %4s %1s %7s %7s %3s %-15s %s\n", "PID", "TID", "USER", "PR", "NI", "CPU%", "S", "VSS", "RSS", "PCY", "Thread", "Proc");
-
- for (i = 0; i < num_new_procs; i++) {
- proc = new_procs[i];
-
- if (!proc || (max_procs && (i >= max_procs)))
- break;
- struct passwd* user = getpwuid(proc->uid);
- char user_buf[20];
- char* user_str;
- if (user && user->pw_name) {
- user_str = user->pw_name;
- } else {
- snprintf(user_buf, sizeof(user_buf), "%d", proc->uid);
- user_str = user_buf;
- }
- if (!threads) {
- printf("%5d %-8.8s %2s %3ld %3" PRIu64 "%% %c %5d %6" PRIu64 "K %6" PRIu64 "K %3s %s\n",
- proc->pid, user_str, proc->pr, proc->ni,
- proc->delta_time * 100 / total_delta_time, proc->state, proc->num_threads,
- proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy,
- proc->name[0] != 0 ? proc->name : proc->tname);
- } else {
- printf("%5d %5d %-8.8s %2s %3ld %3" PRIu64 "%% %c %6" PRIu64 "K %6" PRIu64 "K %3s %-15s %s\n",
- proc->pid, proc->tid, user_str, proc->pr, proc->ni,
- proc->delta_time * 100 / total_delta_time, proc->state,
- proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy,
- proc->tname, proc->name);
- }
- }
-}
-
-static struct proc_info *find_old_proc(pid_t pid, pid_t tid) {
- int i;
-
- for (i = 0; i < num_old_procs; i++)
- if (old_procs[i] && (old_procs[i]->pid == pid) && (old_procs[i]->tid == tid))
- return old_procs[i];
-
- return NULL;
-}
-
-static void free_old_procs(void) {
- int i;
-
- for (i = 0; i < num_old_procs; i++)
- if (old_procs[i])
- free_proc(old_procs[i]);
-
- free(old_procs);
-}
-
-static int proc_cpu_cmp(const void *a, const void *b) {
- struct proc_info *pa, *pb;
-
- pa = *((struct proc_info **)a); pb = *((struct proc_info **)b);
-
- if (!pa && !pb) return 0;
- if (!pa) return 1;
- if (!pb) return -1;
-
- return -numcmp(pa->delta_time, pb->delta_time);
-}
-
-static int proc_vss_cmp(const void *a, const void *b) {
- struct proc_info *pa, *pb;
-
- pa = *((struct proc_info **)a); pb = *((struct proc_info **)b);
-
- if (!pa && !pb) return 0;
- if (!pa) return 1;
- if (!pb) return -1;
-
- return -numcmp(pa->vss, pb->vss);
-}
-
-static int proc_rss_cmp(const void *a, const void *b) {
- struct proc_info *pa, *pb;
-
- pa = *((struct proc_info **)a); pb = *((struct proc_info **)b);
-
- if (!pa && !pb) return 0;
- if (!pa) return 1;
- if (!pb) return -1;
-
- return -numcmp(pa->rss, pb->rss);
-}
-
-static int proc_thr_cmp(const void *a, const void *b) {
- struct proc_info *pa, *pb;
-
- pa = *((struct proc_info **)a); pb = *((struct proc_info **)b);
-
- if (!pa && !pb) return 0;
- if (!pa) return 1;
- if (!pb) return -1;
-
- return -numcmp(pa->num_threads, pb->num_threads);
-}
-
-static int numcmp(long long a, long long b) {
- if (a < b) return -1;
- if (a > b) return 1;
- return 0;
-}
-
-static void usage(char *cmd) {
- fprintf(stderr, "Usage: %s [ -m max_procs ] [ -n iterations ] [ -d delay ] [ -s sort_column ] [ -t ] [ -h ]\n"
- " -m num Maximum number of processes to display.\n"
- " -n num Updates to show before exiting.\n"
- " -d num Seconds to wait between updates.\n"
- " -s col Column to sort by (cpu,vss,rss,thr).\n"
- " -H Show threads instead of processes.\n"
- " -h Display this help screen.\n",
- cmd);
-}
diff --git a/trusty/storage/tests/main.cpp b/trusty/storage/tests/main.cpp
index a771b87..1fd6f8d 100644
--- a/trusty/storage/tests/main.cpp
+++ b/trusty/storage/tests/main.cpp
@@ -23,7 +23,7 @@
#define TRUSTY_DEVICE_NAME "/dev/trusty-ipc-dev0"
-#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
+#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
static inline bool is_32bit_aligned(size_t sz)
{