Merge "init: fix errno handling on KillProcessGroup"
diff --git a/adb/adb.cpp b/adb/adb.cpp
index cf6b359..39e71e5 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -253,6 +253,19 @@
send_packet(cp, t);
}
+#if ADB_HOST
+
+void SendConnectOnHost(atransport* t) {
+ // Send an empty message before A_CNXN message. This is because the data toggle of the ep_out on
+ // host and ep_in on device may not be the same.
+ apacket* p = get_apacket();
+ CHECK(p);
+ send_packet(p, t);
+ send_connect(t);
+}
+
+#endif
+
// qual_overwrite is used to overwrite a qualifier string. dst is a
// pointer to a char pointer. It is assumed that if *dst is non-NULL, it
// was malloc'ed and needs to freed. *dst will be set to a dup of src.
@@ -299,29 +312,29 @@
const std::string& type = pieces[0];
if (type == "bootloader") {
D("setting connection_state to kCsBootloader");
- t->connection_state = kCsBootloader;
+ t->SetConnectionState(kCsBootloader);
update_transports();
} else if (type == "device") {
D("setting connection_state to kCsDevice");
- t->connection_state = kCsDevice;
+ t->SetConnectionState(kCsDevice);
update_transports();
} else if (type == "recovery") {
D("setting connection_state to kCsRecovery");
- t->connection_state = kCsRecovery;
+ t->SetConnectionState(kCsRecovery);
update_transports();
} else if (type == "sideload") {
D("setting connection_state to kCsSideload");
- t->connection_state = kCsSideload;
+ t->SetConnectionState(kCsSideload);
update_transports();
} else {
D("setting connection_state to kCsHost");
- t->connection_state = kCsHost;
+ t->SetConnectionState(kCsHost);
}
}
static void handle_new_connection(atransport* t, apacket* p) {
- if (t->connection_state != kCsOffline) {
- t->connection_state = kCsOffline;
+ if (t->GetConnectionState() != kCsOffline) {
+ t->SetConnectionState(kCsOffline);
handle_offline(t);
}
@@ -355,10 +368,10 @@
if (p->msg.arg0){
send_packet(p, t);
#if ADB_HOST
- send_connect(t);
+ SendConnectOnHost(t);
#endif
} else {
- t->connection_state = kCsOffline;
+ t->SetConnectionState(kCsOffline);
handle_offline(t);
send_packet(p, t);
}
@@ -372,7 +385,9 @@
switch (p->msg.arg0) {
#if ADB_HOST
case ADB_AUTH_TOKEN:
- t->connection_state = kCsUnauthorized;
+ if (t->GetConnectionState() == kCsOffline) {
+ t->SetConnectionState(kCsUnauthorized);
+ }
send_auth_response(p->data, p->msg.data_length, t);
break;
#else
@@ -391,7 +406,7 @@
break;
#endif
default:
- t->connection_state = kCsOffline;
+ t->SetConnectionState(kCsOffline);
handle_offline(t);
break;
}
@@ -507,8 +522,8 @@
if (!_try_make_handle_noninheritable(h)) {
// Show the handle value to give us a clue in case we have problems
// with pseudo-handle values.
- fprintf(stderr, "Cannot make handle 0x%p non-inheritable: %s\n",
- h, android::base::SystemErrorCodeToString(GetLastError()).c_str());
+ fprintf(stderr, "adb: cannot make handle 0x%p non-inheritable: %s\n", h,
+ android::base::SystemErrorCodeToString(GetLastError()).c_str());
return false;
}
@@ -523,7 +538,7 @@
HANDLE pipe_read_raw = NULL;
HANDLE pipe_write_raw = NULL;
if (!CreatePipe(&pipe_read_raw, &pipe_write_raw, sa, 0)) {
- fprintf(stderr, "Cannot create pipe: %s\n",
+ fprintf(stderr, "adb: CreatePipe failed: %s\n",
android::base::SystemErrorCodeToString(GetLastError()).c_str());
return false;
}
@@ -554,7 +569,8 @@
std::unique_ptr<FILE, decltype(&fclose)> stream(nullptr, fclose);
if (original_fd == -1) {
- fprintf(stderr, "Failed to get file descriptor for %s: %s\n", output_name, strerror(errno));
+ fprintf(stderr, "adb: failed to get file descriptor for %s: %s\n", output_name,
+ strerror(errno));
return EXIT_FAILURE;
}
@@ -566,7 +582,7 @@
// call this function if subprocesses may be started concurrently.
const int fd = dup(original_fd);
if (fd == -1) {
- fprintf(stderr, "Failed to duplicate file descriptor for %s: %s\n", output_name,
+ fprintf(stderr, "adb: failed to duplicate file descriptor for %s: %s\n", output_name,
strerror(errno));
return EXIT_FAILURE;
}
@@ -574,7 +590,7 @@
// Note that although we call fdopen() below with a binary flag, it may not adhere to that
// flag, so we have to set the mode manually.
if (_setmode(fd, _O_BINARY) == -1) {
- fprintf(stderr, "Failed to set binary mode for duplicate of %s: %s\n", output_name,
+ fprintf(stderr, "adb: failed to set binary mode for duplicate of %s: %s\n", output_name,
strerror(errno));
unix_close(fd);
return EXIT_FAILURE;
@@ -582,7 +598,7 @@
stream.reset(fdopen(fd, "wb"));
if (stream.get() == nullptr) {
- fprintf(stderr, "Failed to open duplicate stream for %s: %s\n", output_name,
+ fprintf(stderr, "adb: failed to open duplicate stream for %s: %s\n", output_name,
strerror(errno));
unix_close(fd);
return EXIT_FAILURE;
@@ -591,7 +607,7 @@
// Unbuffer the stream because it will be buffered by default and we want subprocess output
// to be shown immediately.
if (setvbuf(stream.get(), NULL, _IONBF, 0) == -1) {
- fprintf(stderr, "Failed to unbuffer %s: %s\n", output_name, strerror(errno));
+ fprintf(stderr, "adb: failed to unbuffer %s: %s\n", output_name, strerror(errno));
return EXIT_FAILURE;
}
@@ -608,7 +624,7 @@
if (err == ERROR_BROKEN_PIPE) {
return EXIT_SUCCESS;
} else {
- fprintf(stderr, "Failed to read from %s: %s\n", output_name,
+ fprintf(stderr, "adb: failed to read from %s: %s\n", output_name,
android::base::SystemErrorCodeToString(err).c_str());
return EXIT_FAILURE;
}
@@ -619,8 +635,8 @@
// fwrite() actually calls adb_fwrite() which can write UTF-8 to the console.
const size_t bytes_written = fwrite(buf, 1, bytes_read, stream.get());
if (bytes_written != bytes_read) {
- fprintf(stderr, "Only wrote %zu of %lu bytes to %s\n", bytes_written, bytes_read,
- output_name);
+ fprintf(stderr, "adb: error: only wrote %zu of %lu bytes to %s\n", bytes_written,
+ bytes_read, output_name);
return EXIT_FAILURE;
}
}
@@ -663,7 +679,7 @@
FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL));
if (nul_read.get() == INVALID_HANDLE_VALUE) {
- fprintf(stderr, "Cannot open 'nul': %s\n",
+ fprintf(stderr, "adb: CreateFileW 'nul' failed: %s\n",
android::base::SystemErrorCodeToString(GetLastError()).c_str());
return -1;
}
@@ -725,8 +741,7 @@
// If this fires, either handle values are larger than 32-bits or else
// there is a bug in our casting.
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa384203%28v=vs.85%29.aspx
- fprintf(stderr, "Cannot fit pipe handle value into 32-bits: 0x%p\n",
- ack_write.get());
+ fprintf(stderr, "adb: cannot fit pipe handle value into 32-bits: 0x%p\n", ack_write.get());
return -1;
}
@@ -736,7 +751,7 @@
arraysize(program_path));
if ((module_result >= arraysize(program_path)) || (module_result == 0)) {
// String truncation or some other error.
- fprintf(stderr, "Cannot get executable path: %s\n",
+ fprintf(stderr, "adb: cannot get executable path: %s\n",
android::base::SystemErrorCodeToString(GetLastError()).c_str());
return -1;
}
@@ -761,7 +776,7 @@
NULL, /* use parent's starting directory */
&startup, /* startup info, i.e. std handles */
&pinfo )) {
- fprintf(stderr, "Cannot create process: %s\n",
+ fprintf(stderr, "adb: CreateProcessW failed: %s\n",
android::base::SystemErrorCodeToString(GetLastError()).c_str());
return -1;
}
@@ -791,7 +806,7 @@
_beginthreadex(NULL, 0, _redirect_stdout_thread, stdout_read.get(),
0, NULL)));
if (stdout_thread.get() == nullptr) {
- fprintf(stderr, "Cannot create thread: %s\n", strerror(errno));
+ fprintf(stderr, "adb: cannot create thread: %s\n", strerror(errno));
return -1;
}
stdout_read.release(); // Transfer ownership to new thread
@@ -800,7 +815,7 @@
_beginthreadex(NULL, 0, _redirect_stderr_thread, stderr_read.get(),
0, NULL)));
if (stderr_thread.get() == nullptr) {
- fprintf(stderr, "Cannot create thread: %s\n", strerror(errno));
+ fprintf(stderr, "adb: cannot create thread: %s\n", strerror(errno));
return -1;
}
stderr_read.release(); // Transfer ownership to new thread
@@ -845,22 +860,20 @@
if (wait_result == WAIT_TIMEOUT) {
// Threads did not finish after waiting a little while. Perhaps the
// server didn't close pipes, or it is hung.
- fprintf(stderr, "Timed-out waiting for threads to finish reading from "
- "ADB Server\n");
+ fprintf(stderr, "adb: timed out waiting for threads to finish reading from ADB server\n");
// Process handles are signaled when the process exits, so if we wait
// on the handle for 0 seconds and it returns 'timeout', that means that
// the process is still running.
if (WaitForSingleObject(process_handle.get(), 0) == WAIT_TIMEOUT) {
// We could TerminateProcess(), but that seems somewhat presumptive.
- fprintf(stderr, "ADB Server is running: process id %lu\n",
- pinfo.dwProcessId);
+ fprintf(stderr, "adb: server is running with process id %lu\n", pinfo.dwProcessId);
}
return -1;
}
if (wait_result != WAIT_OBJECT_0) {
- fprintf(stderr, "Unexpected result waiting for threads: %lu: %s\n",
- wait_result, android::base::SystemErrorCodeToString(GetLastError()).c_str());
+ fprintf(stderr, "adb: unexpected result waiting for threads: %lu: %s\n", wait_result,
+ android::base::SystemErrorCodeToString(GetLastError()).c_str());
return -1;
}
@@ -894,7 +907,7 @@
int result = execl(path.c_str(), "adb", "-L", socket_spec.c_str(), "fork-server", "server",
"--reply-fd", reply_fd, NULL);
// this should not return
- fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
+ fprintf(stderr, "adb: execl returned %d: %s\n", result, strerror(errno));
} else {
// parent side of the fork
@@ -1034,7 +1047,6 @@
SendProtocolString(fd, s);
return 0;
}
-#endif
int handle_host_request(const char* service, TransportType type,
const char* serial, int reply_fd, asocket* s) {
@@ -1053,7 +1065,6 @@
android::base::quick_exit(0);
}
-#if ADB_HOST
// "transport:" is used for switching transport with a specified serial number
// "transport-usb:" is used for switching transport to the only USB transport
// "transport-local:" is used for switching transport to the only local transport
@@ -1098,16 +1109,10 @@
if (!strcmp(service, "reconnect-offline")) {
std::string response;
close_usb_devices([&response](const atransport* transport) {
- switch (transport->connection_state) {
+ switch (transport->GetConnectionState()) {
case kCsOffline:
case kCsUnauthorized:
- response += "reconnecting ";
- if (transport->serial) {
- response += transport->serial;
- } else {
- response += "<unknown>";
- }
- response += "\n";
+ response += "reconnecting " + transport->serial_name() + "\n";
return true;
default:
return false;
@@ -1131,7 +1136,6 @@
return 0;
}
-#if ADB_HOST
if (!strcmp(service, "host-features")) {
FeatureSet features = supported_features();
// Abuse features to report libusb status.
@@ -1141,7 +1145,6 @@
SendOkay(reply_fd, FeatureSetToString(features));
return 0;
}
-#endif
// remove TCP transport
if (!strncmp(service, "disconnect:", 11)) {
@@ -1211,15 +1214,19 @@
}
if (!strcmp(service, "reconnect")) {
- if (s->transport != nullptr) {
- kick_transport(s->transport);
+ std::string response;
+ atransport* t = acquire_one_transport(type, serial, nullptr, &response, true);
+ if (t != nullptr) {
+ kick_transport(t);
+ response =
+ "reconnecting " + t->serial_name() + " [" + t->connection_state_name() + "]\n";
}
- return SendOkay(reply_fd, "done");
+ return SendOkay(reply_fd, response);
}
-#endif // ADB_HOST
int ret = handle_forward_request(service, type, serial, reply_fd);
if (ret >= 0)
return ret - 1;
return -1;
}
+#endif // ADB_HOST
diff --git a/adb/adb.h b/adb/adb.h
index aea5fb8..e3675d8 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -139,7 +139,7 @@
int get_available_local_transport_index();
#endif
int init_socket_transport(atransport *t, int s, int port, int local);
-void init_usb_transport(atransport *t, usb_handle *usb, ConnectionState state);
+void init_usb_transport(atransport* t, usb_handle* usb);
std::string getEmulatorSerialString(int console_port);
#if ADB_HOST
@@ -222,6 +222,9 @@
void handle_offline(atransport *t);
void send_connect(atransport *t);
+#if ADB_HOST
+void SendConnectOnHost(atransport* t);
+#endif
void parse_banner(const std::string&, atransport* t);
diff --git a/adb/adb_client.cpp b/adb/adb_client.cpp
index ef52189..b656887 100644
--- a/adb/adb_client.cpp
+++ b/adb/adb_client.cpp
@@ -136,8 +136,7 @@
return -2;
}
- if ((memcmp(&service[0],"host",4) != 0 || service == "host:reconnect") &&
- switch_socket_transport(fd, error)) {
+ if (memcmp(&service[0], "host", 4) != 0 && switch_socket_transport(fd, error)) {
return -1;
}
@@ -147,11 +146,9 @@
return -1;
}
- if (service != "reconnect") {
- if (!adb_status(fd, error)) {
- adb_close(fd);
- return -1;
- }
+ if (!adb_status(fd, error)) {
+ adb_close(fd);
+ return -1;
}
D("_adb_connect: return fd %d", fd);
@@ -164,21 +161,21 @@
D("adb_connect: service %s", service.c_str());
if (fd == -2 && !is_local_socket_spec(__adb_server_socket_spec)) {
- fprintf(stderr,"** Cannot start server on remote host\n");
+ fprintf(stderr, "* cannot start server on remote host\n");
// error is the original network connection error
return fd;
} else if (fd == -2) {
- fprintf(stdout, "* daemon not running. starting it now at %s *\n", __adb_server_socket_spec);
+ fprintf(stderr, "* daemon not running; starting now at %s\n", __adb_server_socket_spec);
start_server:
if (launch_server(__adb_server_socket_spec)) {
- fprintf(stderr,"* failed to start daemon *\n");
+ fprintf(stderr, "* failed to start daemon\n");
// launch_server() has already printed detailed error info, so just
// return a generic error string about the overall adb_connect()
// that the caller requested.
*error = "cannot connect to daemon";
return -1;
} else {
- fprintf(stdout,"* daemon started successfully *\n");
+ fprintf(stderr, "* daemon started successfully\n");
}
// Give the server some time to start properly and detect devices.
std::this_thread::sleep_for(3s);
@@ -213,8 +210,8 @@
}
if (version != ADB_SERVER_VERSION) {
- printf("adb server version (%d) doesn't match this client (%d); killing...\n",
- version, ADB_SERVER_VERSION);
+ fprintf(stderr, "adb server version (%d) doesn't match this client (%d); killing...\n",
+ version, ADB_SERVER_VERSION);
fd = _adb_connect("host:kill", error);
if (fd >= 0) {
ReadOrderlyShutdown(fd);
@@ -240,7 +237,7 @@
if (fd == -1) {
D("_adb_connect error: %s", error->c_str());
} else if(fd == -2) {
- fprintf(stderr,"** daemon still not running\n");
+ fprintf(stderr, "* daemon still not running\n");
}
D("adb_connect: return fd %d", fd);
diff --git a/adb/adb_trace.cpp b/adb/adb_trace.cpp
index c369d60..eac923d 100644
--- a/adb/adb_trace.cpp
+++ b/adb/adb_trace.cpp
@@ -155,7 +155,7 @@
}
#endif
-#if !defined(_WIN32)
+#if ADB_HOST && !defined(_WIN32)
// adb historically ignored $ANDROID_LOG_TAGS but passed it through to logcat.
// If set, move it out of the way so that libbase logging doesn't try to parse it.
std::string log_tags;
@@ -168,7 +168,7 @@
android::base::InitLogging(argv, &AdbLogger);
-#if !defined(_WIN32)
+#if ADB_HOST && !defined(_WIN32)
// Put $ANDROID_LOG_TAGS back so we can pass it to logcat.
if (!log_tags.empty()) setenv("ANDROID_LOG_TAGS", log_tags.c_str(), 1);
#endif
diff --git a/adb/adb_trace.h b/adb/adb_trace.h
index aaffa29..fc6560c 100644
--- a/adb/adb_trace.h
+++ b/adb/adb_trace.h
@@ -58,6 +58,9 @@
void adb_trace_init(char**);
void adb_trace_enable(AdbTrace trace_tag);
+// Include <atomic> before stdatomic.h (introduced in cutils/trace.h) to avoid compile error.
+#include <atomic>
+
#define ATRACE_TAG ATRACE_TAG_ADB
#include <cutils/trace.h>
#include <utils/Trace.h>
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index 31d3dc6..6f2403d 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -267,8 +267,8 @@
adb_close(fd);
}
-int usage(const char* fmt, ...) {
- fprintf(stderr, "adb: ");
+int syntax_error(const char* fmt, ...) {
+ fprintf(stderr, "adb: usage: ");
va_list ap;
va_start(ap, fmt);
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index e0ad103..c1d5549 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -21,7 +21,7 @@
#include <android-base/macros.h>
-int usage(const char*, ...);
+int syntax_error(const char*, ...);
void close_stdin();
diff --git a/adb/bugreport.cpp b/adb/bugreport.cpp
index 9dc9811..da2cfa2 100644
--- a/adb/bugreport.cpp
+++ b/adb/bugreport.cpp
@@ -137,7 +137,7 @@
SetSrcFile(&line[strlen(BUGZ_OK_PREFIX)]);
} else if (android::base::StartsWith(line, BUGZ_FAIL_PREFIX)) {
const char* error_message = &line[strlen(BUGZ_FAIL_PREFIX)];
- fprintf(stderr, "Device failed to take a zipped bugreport: %s\n", error_message);
+ fprintf(stderr, "adb: device failed to take a zipped bugreport: %s\n", error_message);
status_ = -1;
} else if (show_progress_ && android::base::StartsWith(line, BUGZ_PROGRESS_PREFIX)) {
// progress_line should have the following format:
@@ -195,7 +195,7 @@
};
int Bugreport::DoIt(TransportType transport_type, const char* serial, int argc, const char** argv) {
- if (argc > 2) return usage("usage: adb bugreport [PATH]");
+ if (argc > 2) return syntax_error("adb bugreport [PATH]");
// Gets bugreportz version.
std::string bugz_stdout, bugz_stderr;
diff --git a/adb/client/usb_libusb.cpp b/adb/client/usb_libusb.cpp
index c48a251..fec4742 100644
--- a/adb/client/usb_libusb.cpp
+++ b/adb/client/usb_libusb.cpp
@@ -62,12 +62,11 @@
using unique_device_handle = std::unique_ptr<libusb_device_handle, DeviceHandleDeleter>;
struct transfer_info {
- transfer_info(const char* name, uint16_t zero_mask) :
- name(name),
- transfer(libusb_alloc_transfer(0)),
- zero_mask(zero_mask)
- {
- }
+ transfer_info(const char* name, uint16_t zero_mask, bool is_bulk_out)
+ : name(name),
+ transfer(libusb_alloc_transfer(0)),
+ is_bulk_out(is_bulk_out),
+ zero_mask(zero_mask) {}
~transfer_info() {
libusb_free_transfer(transfer);
@@ -75,6 +74,7 @@
const char* name;
libusb_transfer* transfer;
+ bool is_bulk_out;
bool transfer_complete;
std::condition_variable cv;
std::mutex mutex;
@@ -96,12 +96,11 @@
serial(serial),
closing(false),
device_handle(device_handle.release()),
- read("read", zero_mask),
- write("write", zero_mask),
+ read("read", zero_mask, false),
+ write("write", zero_mask, true),
interface(interface),
bulk_in(bulk_in),
- bulk_out(bulk_out) {
- }
+ bulk_out(bulk_out) {}
~usb_handle() {
Close();
@@ -365,11 +364,6 @@
device_poll_thread = new std::thread(poll_for_devices);
android::base::at_quick_exit([]() {
terminate_device_poll_thread = true;
- std::unique_lock<std::mutex> lock(usb_handles_mutex);
- for (auto& it : usb_handles) {
- it.second->Close();
- }
- lock.unlock();
device_poll_thread->join();
});
}
@@ -397,7 +391,8 @@
return;
}
- if (transfer->actual_length != transfer->length) {
+ // usb_read() can return when receiving some data.
+ if (info->is_bulk_out && transfer->actual_length != transfer->length) {
LOG(DEBUG) << info->name << " transfer incomplete, resubmitting";
transfer->length -= transfer->actual_length;
transfer->buffer += transfer->actual_length;
@@ -491,8 +486,12 @@
info->transfer->num_iso_packets = 0;
int rc = perform_usb_transfer(h, info, std::move(lock));
- LOG(DEBUG) << "usb_read(" << len << ") = " << rc;
- return rc;
+ LOG(DEBUG) << "usb_read(" << len << ") = " << rc << ", actual_length "
+ << info->transfer->actual_length;
+ if (rc < 0) {
+ return rc;
+ }
+ return info->transfer->actual_length;
}
int usb_close(usb_handle* h) {
diff --git a/adb/client/usb_linux.cpp b/adb/client/usb_linux.cpp
index 3a45dbd..6efed27 100644
--- a/adb/client/usb_linux.cpp
+++ b/adb/client/usb_linux.cpp
@@ -401,7 +401,6 @@
}
}
-
int usb_write(usb_handle *h, const void *_data, int len)
{
D("++ usb_write ++");
@@ -429,19 +428,16 @@
int n;
D("++ usb_read ++");
- while(len > 0) {
+ int orig_len = len;
+ while (len == orig_len) {
int xfer = len;
D("[ usb read %d fd = %d], path=%s", xfer, h->fd, h->path.c_str());
n = usb_bulk_read(h, data, xfer);
D("[ usb read %d ] = %d, path=%s", xfer, n, h->path.c_str());
- if(n != xfer) {
+ if (n <= 0) {
if((errno == ETIMEDOUT) && (h->fd != -1)) {
D("[ timeout ]");
- if(n > 0){
- data += n;
- len -= n;
- }
continue;
}
D("ERROR: n = %d, errno = %d (%s)",
@@ -449,12 +445,12 @@
return -1;
}
- len -= xfer;
- data += xfer;
+ len -= n;
+ data += n;
}
D("-- usb_read --");
- return 0;
+ return orig_len - len;
}
void usb_kick(usb_handle* h) {
diff --git a/adb/client/usb_osx.cpp b/adb/client/usb_osx.cpp
index 8713b2c..fcd0bc0 100644
--- a/adb/client/usb_osx.cpp
+++ b/adb/client/usb_osx.cpp
@@ -518,7 +518,7 @@
}
if (kIOReturnSuccess == result)
- return 0;
+ return numBytes;
else {
LOG(ERROR) << "usb_read failed with status: " << std::hex << result;
}
diff --git a/adb/client/usb_windows.cpp b/adb/client/usb_windows.cpp
index 9e00a5d..ee7f802 100644
--- a/adb/client/usb_windows.cpp
+++ b/adb/client/usb_windows.cpp
@@ -415,6 +415,7 @@
unsigned long time_out = 0;
unsigned long read = 0;
int err = 0;
+ int orig_len = len;
D("usb_read %d", len);
if (NULL == handle) {
@@ -423,9 +424,8 @@
goto fail;
}
- while (len > 0) {
- if (!AdbReadEndpointSync(handle->adb_read_pipe, data, len, &read,
- time_out)) {
+ while (len == orig_len) {
+ if (!AdbReadEndpointSync(handle->adb_read_pipe, data, len, &read, time_out)) {
D("AdbReadEndpointSync failed: %s",
android::base::SystemErrorCodeToString(GetLastError()).c_str());
err = EIO;
@@ -433,11 +433,11 @@
}
D("usb_read got: %ld, expected: %d", read, len);
- data = (char *)data + read;
+ data = (char*)data + read;
len -= read;
}
- return 0;
+ return orig_len - len;
fail:
// Any failure should cause us to kick the device instead of leaving it a
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 7702b0e..5f55ab9 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -212,6 +212,7 @@
" kill-server kill the server if it is running\n"
" reconnect kick connection from host side to force reconnect\n"
" reconnect device kick connection from device side to force reconnect\n"
+ " reconnect offline reset offline/unauthorized devices to force reconnect\n"
"\n"
"environment variables:\n"
" $ADB_TRACE\n"
@@ -690,8 +691,7 @@
switch (opt) {
case 'e':
if (!(strlen(optarg) == 1 || strcmp(optarg, "none") == 0)) {
- fprintf(stderr, "error: -e requires a single-character argument or 'none'\n");
- return 1;
+ return syntax_error("-e requires a single-character argument or 'none'");
}
escape_char = (strcmp(optarg, "none") == 0) ? 0 : optarg[0];
break;
@@ -843,7 +843,10 @@
* we hang up.
*/
static int adb_sideload_host(const char* filename) {
- fprintf(stderr, "opening '%s'...\n", filename);
+ // TODO: use a LinePrinter instead...
+ fprintf(stdout, "opening '%s'...\n", filename);
+ fflush(stdout);
+
struct stat sb;
if (stat(filename, &sb) == -1) {
fprintf(stderr, "failed to stat file %s: %s\n", filename, strerror(errno));
@@ -855,7 +858,8 @@
return -1;
}
- fprintf(stderr, "connecting...\n");
+ fprintf(stdout, "connecting...\n");
+ fflush(stdout);
std::string service = android::base::StringPrintf(
"sideload-host:%d:%d", static_cast<int>(sb.st_size), SIDELOAD_HOST_BLOCK_SIZE);
std::string error;
@@ -944,19 +948,13 @@
fprintf(stderr, "error: adb %s not implemented on Win32\n", argv[0]);
return -1;
#else
- if (argc < 2) {
- fprintf(stderr, "usage: adb %s <adb service name> [ppp opts]\n",
- argv[0]);
-
- return 1;
- }
+ if (argc < 2) return syntax_error("adb %s <adb service name> [ppp opts]", argv[0]);
const char* adb_service_name = argv[1];
std::string error;
int fd = adb_connect(adb_service_name, &error);
if (fd < 0) {
- fprintf(stderr,"Error: Could not open adb service: %s. Error: %s\n",
- adb_service_name, error.c_str());
+ fprintf(stderr, "adb: could not open adb service %s: %s\n", adb_service_name, error.c_str());
return 1;
}
@@ -1175,10 +1173,7 @@
/* find, extract, and use any -f argument */
for (int i = 1; i < argc; i++) {
if (!strcmp("-f", argv[i])) {
- if (i == argc-1) {
- fprintf(stderr, "adb: backup -f passed with no filename.\n");
- return EXIT_FAILURE;
- }
+ if (i == argc - 1) return syntax_error("backup -f passed with no filename");
filename = argv[i+1];
for (int j = i+2; j <= argc; ) {
argv[i++] = argv[j++];
@@ -1190,10 +1185,7 @@
// Bare "adb backup" or "adb backup -f filename" are not valid invocations ---
// a list of packages is required.
- if (argc < 2) {
- fprintf(stderr, "adb: backup either needs a list of packages or -all/-shared.\n");
- return EXIT_FAILURE;
- }
+ if (argc < 2) return syntax_error("backup either needs a list of packages or -all/-shared");
adb_unlink(filename);
int outFd = adb_creat(filename, 0640);
@@ -1218,7 +1210,7 @@
return EXIT_FAILURE;
}
- printf("Now unlock your device and confirm the backup operation...\n");
+ fprintf(stdout, "Now unlock your device and confirm the backup operation...\n");
fflush(stdout);
copy_to_file(fd, outFd);
@@ -1229,7 +1221,7 @@
}
static int restore(int argc, const char** argv) {
- if (argc != 2) return usage("restore requires an argument");
+ if (argc != 2) return syntax_error("restore requires an argument");
const char* filename = argv[1];
int tarFd = adb_open(filename, O_RDONLY);
@@ -1246,7 +1238,9 @@
return -1;
}
- printf("Now unlock your device and confirm the restore operation.\n");
+ fprintf(stdout, "Now unlock your device and confirm the restore operation.\n");
+ fflush(stdout);
+
copy_to_file(tarFd, fd);
// Provide an in-band EOD marker in case the archive file is malformed
@@ -1338,7 +1332,7 @@
} else if (!strcmp(*arg, "--")) {
ignore_flags = true;
} else {
- fprintf(stderr, "adb: unrecognized option '%s'\n", *arg);
+ syntax_error("unrecognized option '%s'", *arg);
exit(1);
}
}
@@ -1437,7 +1431,7 @@
/* this is a special flag used only when the ADB client launches the ADB Server */
is_daemon = 1;
} else if (!strcmp(argv[0], "--reply-fd")) {
- if (argc < 2) return usage("--reply-fd requires an argument");
+ if (argc < 2) return syntax_error("--reply-fd requires an argument");
const char* reply_fd_str = argv[1];
argc--;
argv++;
@@ -1449,7 +1443,7 @@
} else if (!strncmp(argv[0], "-p", 2)) {
const char* product = nullptr;
if (argv[0][2] == '\0') {
- if (argc < 2) return usage("-p requires an argument");
+ if (argc < 2) return syntax_error("-p requires an argument");
product = argv[1];
argc--;
argv++;
@@ -1465,7 +1459,7 @@
if (isdigit(argv[0][2])) {
serial = argv[0] + 2;
} else {
- if (argc < 2 || argv[0][2] != '\0') return usage("-s requires an argument");
+ if (argc < 2 || argv[0][2] != '\0') return syntax_error("-s requires an argument");
serial = argv[1];
argc--;
argv++;
@@ -1478,7 +1472,7 @@
gListenAll = 1;
} else if (!strncmp(argv[0], "-H", 2)) {
if (argv[0][2] == '\0') {
- if (argc < 2) return usage("-H requires an argument");
+ if (argc < 2) return syntax_error("-H requires an argument");
server_host_str = argv[1];
argc--;
argv++;
@@ -1487,7 +1481,7 @@
}
} else if (!strncmp(argv[0], "-P", 2)) {
if (argv[0][2] == '\0') {
- if (argc < 2) return usage("-P requires an argument");
+ if (argc < 2) return syntax_error("-P requires an argument");
server_port_str = argv[1];
argc--;
argv++;
@@ -1495,7 +1489,7 @@
server_port_str = argv[0] + 2;
}
} else if (!strcmp(argv[0], "-L")) {
- if (argc < 2) return usage("-L requires an argument");
+ if (argc < 2) return syntax_error("-L requires an argument");
server_socket_str = argv[1];
argc--;
argv++;
@@ -1508,8 +1502,7 @@
}
if ((server_host_str || server_port_str) && server_socket_str) {
- fprintf(stderr, "adb: -L is incompatible with -H or -P\n");
- exit(1);
+ return syntax_error("-L is incompatible with -H or -P");
}
// If -L, -H, or -P are specified, ignore environment variables.
@@ -1604,8 +1597,7 @@
} else if (argc == 2 && !strcmp(argv[1], "-l")) {
listopt = argv[1];
} else {
- fprintf(stderr, "Usage: adb devices [-l]\n");
- return 1;
+ return syntax_error("adb devices [-l]");
}
std::string query = android::base::StringPrintf("host:%s%s", argv[0], listopt);
@@ -1613,19 +1605,13 @@
return adb_query_command(query);
}
else if (!strcmp(argv[0], "connect")) {
- if (argc != 2) {
- fprintf(stderr, "Usage: adb connect <host>[:<port>]\n");
- return 1;
- }
+ if (argc != 2) return syntax_error("adb connect <host>[:<port>]");
std::string query = android::base::StringPrintf("host:connect:%s", argv[1]);
return adb_query_command(query);
}
else if (!strcmp(argv[0], "disconnect")) {
- if (argc > 2) {
- fprintf(stderr, "Usage: adb disconnect [<host>[:<port>]]\n");
- return 1;
- }
+ if (argc > 2) return syntax_error("adb disconnect [<host>[:<port>]]");
std::string query = android::base::StringPrintf("host:disconnect:%s",
(argc == 2) ? argv[1] : "");
@@ -1640,10 +1626,7 @@
else if (!strcmp(argv[0], "exec-in") || !strcmp(argv[0], "exec-out")) {
int exec_in = !strcmp(argv[0], "exec-in");
- if (argc < 2) {
- fprintf(stderr, "Usage: adb %s command\n", argv[0]);
- return 1;
- }
+ if (argc < 2) return syntax_error("adb %s command", argv[0]);
std::string cmd = "exec:";
cmd += argv[1];
@@ -1691,7 +1674,7 @@
}
}
else if (!strcmp(argv[0], "sideload")) {
- if (argc != 2) return usage("sideload requires an argument");
+ if (argc != 2) return syntax_error("sideload requires an argument");
if (adb_sideload_host(argv[1])) {
return 1;
} else {
@@ -1725,7 +1708,7 @@
bool reverse = !strcmp(argv[0], "reverse");
++argv;
--argc;
- if (argc < 1) return usage("%s requires an argument", argv[0]);
+ if (argc < 1) return syntax_error("%s requires an argument", argv[0]);
// Determine the <host-prefix> for this command.
std::string host_prefix;
@@ -1745,24 +1728,24 @@
std::string cmd, error;
if (strcmp(argv[0], "--list") == 0) {
- if (argc != 1) return usage("--list doesn't take any arguments");
+ if (argc != 1) return syntax_error("--list doesn't take any arguments");
return adb_query_command(host_prefix + ":list-forward");
} else if (strcmp(argv[0], "--remove-all") == 0) {
- if (argc != 1) return usage("--remove-all doesn't take any arguments");
+ if (argc != 1) return syntax_error("--remove-all doesn't take any arguments");
cmd = host_prefix + ":killforward-all";
} else if (strcmp(argv[0], "--remove") == 0) {
// forward --remove <local>
- if (argc != 2) return usage("--remove requires an argument");
+ if (argc != 2) return syntax_error("--remove requires an argument");
cmd = host_prefix + ":killforward:" + argv[1];
} else if (strcmp(argv[0], "--no-rebind") == 0) {
// forward --no-rebind <local> <remote>
- if (argc != 3) return usage("--no-rebind takes two arguments");
+ if (argc != 3) return syntax_error("--no-rebind takes two arguments");
if (forward_targets_are_valid(argv[1], argv[2], &error)) {
cmd = host_prefix + ":forward:norebind:" + argv[1] + ";" + argv[2];
}
} else {
// forward <local> <remote>
- if (argc != 2) return usage("forward takes two arguments");
+ if (argc != 2) return syntax_error("forward takes two arguments");
if (forward_targets_are_valid(argv[0], argv[1], &error)) {
cmd = host_prefix + ":forward:" + argv[0] + ";" + argv[1];
}
@@ -1791,7 +1774,7 @@
}
/* do_sync_*() commands */
else if (!strcmp(argv[0], "ls")) {
- if (argc != 2) return usage("ls requires an argument");
+ if (argc != 2) return syntax_error("ls requires an argument");
return do_sync_ls(argv[1]) ? 0 : 1;
}
else if (!strcmp(argv[0], "push")) {
@@ -1800,7 +1783,7 @@
const char* dst = nullptr;
parse_push_pull_args(&argv[1], argc - 1, &srcs, &dst, ©_attrs);
- if (srcs.empty() || !dst) return usage("push requires an argument");
+ if (srcs.empty() || !dst) return syntax_error("push requires an argument");
return do_sync_push(srcs, dst) ? 0 : 1;
}
else if (!strcmp(argv[0], "pull")) {
@@ -1809,22 +1792,22 @@
const char* dst = ".";
parse_push_pull_args(&argv[1], argc - 1, &srcs, &dst, ©_attrs);
- if (srcs.empty()) return usage("pull requires an argument");
+ if (srcs.empty()) return syntax_error("pull requires an argument");
return do_sync_pull(srcs, dst, copy_attrs) ? 0 : 1;
}
else if (!strcmp(argv[0], "install")) {
- if (argc < 2) return usage("install requires an argument");
+ if (argc < 2) return syntax_error("install requires an argument");
if (_use_legacy_install()) {
return install_app_legacy(transport_type, serial, argc, argv);
}
return install_app(transport_type, serial, argc, argv);
}
else if (!strcmp(argv[0], "install-multiple")) {
- if (argc < 2) return usage("install-multiple requires an argument");
+ if (argc < 2) return syntax_error("install-multiple requires an argument");
return install_multiple_app(transport_type, serial, argc, argv);
}
else if (!strcmp(argv[0], "uninstall")) {
- if (argc < 2) return usage("uninstall requires an argument");
+ if (argc < 2) return syntax_error("uninstall requires an argument");
if (_use_legacy_install()) {
return uninstall_app_legacy(transport_type, serial, argc, argv);
}
@@ -1847,12 +1830,12 @@
// A local path or "android"/"data" arg was specified.
src = argv[1];
} else {
- return usage("usage: adb sync [-l] [PARTITION]");
+ return syntax_error("adb sync [-l] [PARTITION]");
}
if (src != "" &&
src != "system" && src != "data" && src != "vendor" && src != "oem") {
- return usage("don't know how to sync %s partition", src.c_str());
+ return syntax_error("don't know how to sync %s partition", src.c_str());
}
std::string system_src_path = product_file("system");
@@ -1904,7 +1887,7 @@
return restore(argc, argv);
}
else if (!strcmp(argv[0], "keygen")) {
- if (argc != 2) return usage("keygen requires an argument");
+ if (argc != 2) return syntax_error("keygen requires an argument");
// Always print key generation information for keygen command.
adb_trace_enable(AUTH);
return adb_auth_keygen(argv[1]);
@@ -1947,7 +1930,7 @@
return adb_query_command("host:host-features");
} else if (!strcmp(argv[0], "reconnect")) {
if (argc == 1) {
- return adb_query_command("host:reconnect");
+ return adb_query_command(format_host_command(argv[0], transport_type, serial));
} else if (argc == 2) {
if (!strcmp(argv[1], "device")) {
std::string err;
@@ -1957,12 +1940,12 @@
std::string err;
return adb_query_command("host:reconnect-offline");
} else {
- return usage("usage: adb reconnect [device|offline]");
+ return syntax_error("adb reconnect [device|offline]");
}
}
}
- usage("unknown command %s", argv[0]);
+ syntax_error("unknown command %s", argv[0]);
return 1;
}
@@ -1989,19 +1972,18 @@
// The last argument must be the APK file
const char* file = argv[argc - 1];
if (!android::base::EndsWithIgnoreCase(file, ".apk")) {
- fprintf(stderr, "Filename doesn't end .apk: %s\n", file);
- return EXIT_FAILURE;
+ return syntax_error("filename doesn't end .apk: %s", file);
}
struct stat sb;
if (stat(file, &sb) == -1) {
- fprintf(stderr, "Failed to stat %s: %s\n", file, strerror(errno));
+ fprintf(stderr, "adb: failed to stat %s: %s\n", file, strerror(errno));
return 1;
}
int localFd = adb_open(file, O_RDONLY);
if (localFd < 0) {
- fprintf(stderr, "Failed to open %s: %s\n", file, strerror(errno));
+ fprintf(stderr, "adb: failed to open %s: %s\n", file, strerror(errno));
return 1;
}
@@ -2019,7 +2001,7 @@
int remoteFd = adb_connect(cmd, &error);
if (remoteFd < 0) {
- fprintf(stderr, "Connect error for write: %s\n", error.c_str());
+ fprintf(stderr, "adb: connect error for write: %s\n", error.c_str());
adb_close(localFd);
return 1;
}
@@ -2031,12 +2013,12 @@
adb_close(localFd);
adb_close(remoteFd);
- if (strncmp("Success", buf, 7)) {
- fprintf(stderr, "Failed to install %s: %s", file, buf);
- return 1;
+ if (!strncmp("Success", buf, 7)) {
+ fputs(buf, stdout);
+ return 0;
}
- fputs(buf, stderr);
- return 0;
+ fprintf(stderr, "adb: failed to install %s: %s", file, buf);
+ return 1;
}
static int install_multiple_app(TransportType transport, const char* serial, int argc,
@@ -2058,10 +2040,7 @@
}
}
- if (first_apk == -1) {
- fprintf(stderr, "No APK file on command line\n");
- return 1;
- }
+ if (first_apk == -1) return syntax_error("need APK file on command line");
std::string install_cmd;
if (_use_legacy_install()) {
@@ -2079,7 +2058,7 @@
std::string error;
int fd = adb_connect(cmd, &error);
if (fd < 0) {
- fprintf(stderr, "Connect error for create: %s\n", error.c_str());
+ fprintf(stderr, "adb: connect error for create: %s\n", error.c_str());
return EXIT_FAILURE;
}
char buf[BUFSIZ];
@@ -2096,7 +2075,7 @@
}
}
if (session_id < 0) {
- fprintf(stderr, "Failed to create session\n");
+ fprintf(stderr, "adb: failed to create session\n");
fputs(buf, stderr);
return EXIT_FAILURE;
}
@@ -2107,7 +2086,7 @@
const char* file = argv[i];
struct stat sb;
if (stat(file, &sb) == -1) {
- fprintf(stderr, "Failed to stat %s: %s\n", file, strerror(errno));
+ fprintf(stderr, "adb: failed to stat %s: %s\n", file, strerror(errno));
success = 0;
goto finalize_session;
}
@@ -2119,7 +2098,7 @@
int localFd = adb_open(file, O_RDONLY);
if (localFd < 0) {
- fprintf(stderr, "Failed to open %s: %s\n", file, strerror(errno));
+ fprintf(stderr, "adb: failed to open %s: %s\n", file, strerror(errno));
success = 0;
goto finalize_session;
}
@@ -2127,7 +2106,7 @@
std::string error;
int remoteFd = adb_connect(cmd, &error);
if (remoteFd < 0) {
- fprintf(stderr, "Connect error for write: %s\n", error.c_str());
+ fprintf(stderr, "adb: connect error for write: %s\n", error.c_str());
adb_close(localFd);
success = 0;
goto finalize_session;
@@ -2140,7 +2119,7 @@
adb_close(remoteFd);
if (strncmp("Success", buf, 7)) {
- fprintf(stderr, "Failed to write %s\n", file);
+ fprintf(stderr, "adb: failed to write %s\n", file);
fputs(buf, stderr);
success = 0;
goto finalize_session;
@@ -2154,20 +2133,19 @@
install_cmd.c_str(), success ? "commit" : "abandon", session_id);
fd = adb_connect(service, &error);
if (fd < 0) {
- fprintf(stderr, "Connect error for finalize: %s\n", error.c_str());
+ fprintf(stderr, "adb: connect error for finalize: %s\n", error.c_str());
return EXIT_FAILURE;
}
read_status_line(fd, buf, sizeof(buf));
adb_close(fd);
if (!strncmp("Success", buf, 7)) {
- fputs(buf, stderr);
+ fputs(buf, stdout);
return 0;
- } else {
- fprintf(stderr, "Failed to finalize session\n");
- fputs(buf, stderr);
- return EXIT_FAILURE;
}
+ fprintf(stderr, "adb: failed to finalize session\n");
+ fputs(buf, stderr);
+ return EXIT_FAILURE;
}
static int pm_command(TransportType transport, const char* serial, int argc, const char** argv) {
@@ -2225,10 +2203,7 @@
}
}
- if (last_apk == -1) {
- fprintf(stderr, "No APK file on command line\n");
- return EXIT_FAILURE;
- }
+ if (last_apk == -1) return syntax_error("need APK file on command line");
int result = -1;
std::vector<const char*> apk_file = {argv[last_apk]};
diff --git a/adb/commandline.h b/adb/commandline.h
index 0cf655c..9ba69a3 100644
--- a/adb/commandline.h
+++ b/adb/commandline.h
@@ -87,7 +87,6 @@
extern DefaultStandardStreamsCallback DEFAULT_STANDARD_STREAMS_CALLBACK;
int adb_commandline(int argc, const char** argv);
-int usage();
// Connects to the device "shell" service with |command| and prints the
// resulting output.
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index 04cd865..72c9eef 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -75,13 +75,13 @@
static bool main_thread_valid;
static unsigned long main_thread_id;
-static void check_main_thread() {
+void check_main_thread() {
if (main_thread_valid) {
CHECK_EQ(main_thread_id, adb_thread_id());
}
}
-static void set_main_thread() {
+void set_main_thread() {
main_thread_valid = true;
main_thread_id = adb_thread_id();
}
diff --git a/adb/fdevent.h b/adb/fdevent.h
index 207f9b7..e32845a 100644
--- a/adb/fdevent.h
+++ b/adb/fdevent.h
@@ -76,9 +76,12 @@
*/
void fdevent_loop();
+void check_main_thread();
+
// The following functions are used only for tests.
void fdevent_terminate_loop();
size_t fdevent_installed_count();
void fdevent_reset();
+void set_main_thread();
#endif
diff --git a/adb/services.cpp b/adb/services.cpp
index 4327044..9605e6e 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -347,7 +347,7 @@
std::string error = "unknown error";
const char* serial = sinfo->serial.length() ? sinfo->serial.c_str() : NULL;
atransport* t = acquire_one_transport(sinfo->transport_type, serial, &is_ambiguous, &error);
- if (t != nullptr && (sinfo->state == kCsAny || sinfo->state == t->connection_state)) {
+ if (t != nullptr && (sinfo->state == kCsAny || sinfo->state == t->GetConnectionState())) {
SendOkay(fd);
break;
} else if (!is_ambiguous) {
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index 59a48f5..14ad1ff 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -794,7 +794,7 @@
if (!s->transport) {
SendFail(s->peer->fd, "device offline (no transport)");
goto fail;
- } else if (s->transport->connection_state == kCsOffline) {
+ } else if (s->transport->GetConnectionState() == kCsOffline) {
/* if there's no remote we fail the connection
** right here and terminate it
*/
diff --git a/adb/test_device.py b/adb/test_device.py
index e76aaed..a30972e 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -1188,6 +1188,77 @@
self.device.shell(['rm', '-f', '/data/local/tmp/adb-test-*'])
+class DeviceOfflineTest(DeviceTest):
+ def _get_device_state(self, serialno):
+ output = subprocess.check_output(self.device.adb_cmd + ['devices'])
+ for line in output.split('\n'):
+ m = re.match('(\S+)\s+(\S+)', line)
+ if m and m.group(1) == serialno:
+ return m.group(2)
+ return None
+
+ def test_killed_when_pushing_a_large_file(self):
+ """
+ While running adb push with a large file, kill adb server.
+ Occasionally the device becomes offline. Because the device is still
+ reading data without realizing that the adb server has been restarted.
+ Test if we can bring the device online automatically now.
+ http://b/32952319
+ """
+ serialno = subprocess.check_output(self.device.adb_cmd + ['get-serialno']).strip()
+ # 1. Push a large file
+ file_path = 'tmp_large_file'
+ try:
+ fh = open(file_path, 'w')
+ fh.write('\0' * (100 * 1024 * 1024))
+ fh.close()
+ subproc = subprocess.Popen(self.device.adb_cmd + ['push', file_path, '/data/local/tmp'])
+ time.sleep(0.1)
+ # 2. Kill the adb server
+ subprocess.check_call(self.device.adb_cmd + ['kill-server'])
+ subproc.terminate()
+ finally:
+ try:
+ os.unlink(file_path)
+ except:
+ pass
+ # 3. See if the device still exist.
+ # Sleep to wait for the adb server exit.
+ time.sleep(0.5)
+ # 4. The device should be online
+ self.assertEqual(self._get_device_state(serialno), 'device')
+
+ def test_killed_when_pulling_a_large_file(self):
+ """
+ While running adb pull with a large file, kill adb server.
+ Occasionally the device can't be connected. Because the device is trying to
+ send a message larger than what is expected by the adb server.
+ Test if we can bring the device online automatically now.
+ """
+ serialno = subprocess.check_output(self.device.adb_cmd + ['get-serialno']).strip()
+ file_path = 'tmp_large_file'
+ try:
+ # 1. Create a large file on device.
+ self.device.shell(['dd', 'if=/dev/zero', 'of=/data/local/tmp/tmp_large_file',
+ 'bs=1000000', 'count=100'])
+ # 2. Pull the large file on host.
+ subproc = subprocess.Popen(self.device.adb_cmd +
+ ['pull','/data/local/tmp/tmp_large_file', file_path])
+ time.sleep(0.1)
+ # 3. Kill the adb server
+ subprocess.check_call(self.device.adb_cmd + ['kill-server'])
+ subproc.terminate()
+ finally:
+ try:
+ os.unlink(file_path)
+ except:
+ pass
+ # 4. See if the device still exist.
+ # Sleep to wait for the adb server exit.
+ time.sleep(0.5)
+ self.assertEqual(self._get_device_state(serialno), 'device')
+
+
def main():
random.seed(0)
if len(adb.get_devices()) > 0:
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 4686841..cc8c162 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -33,6 +33,7 @@
#include <android-base/logging.h>
#include <android-base/parsenetaddress.h>
+#include <android-base/quick_exit.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
@@ -41,6 +42,7 @@
#include "adb_trace.h"
#include "adb_utils.h"
#include "diagnose_usb.h"
+#include "fdevent.h"
static void transport_unref(atransport *t);
@@ -209,6 +211,11 @@
put_apacket(p);
break;
}
+#if ADB_HOST
+ if (p->msg.command == 0) {
+ continue;
+ }
+#endif
}
D("%s: received remote packet, sending to transport", t->serial);
@@ -271,7 +278,11 @@
if (active) {
D("%s: transport got packet, sending to remote", t->serial);
ATRACE_NAME("write_transport write_remote");
- t->write_to_remote(p, t);
+ if (t->Write(p) != 0) {
+ D("%s: remote write failed for transport", t->serial);
+ put_apacket(p);
+ break;
+ }
} else {
D("%s: transport ignoring packet while offline", t->serial);
}
@@ -493,7 +504,7 @@
}
/* don't create transport threads for inaccessible devices */
- if (t->connection_state != kCsNoPerm) {
+ if (t->GetConnectionState() != kCsNoPerm) {
/* initial references are the two threads */
t->ref_count = 2;
@@ -538,6 +549,15 @@
transport_registration_func, 0);
fdevent_set(&transport_registration_fde, FDE_READ);
+#if ADB_HOST
+ android::base::at_quick_exit([]() {
+ // To avoid only writing part of a packet to a transport after exit, kick all transports.
+ std::lock_guard<std::mutex> lock(transport_lock);
+ for (auto t : transport_list) {
+ t->Kick();
+ }
+ });
+#endif
}
/* the fdevent select pump is single threaded */
@@ -600,7 +620,7 @@
}
atransport* acquire_one_transport(TransportType type, const char* serial, bool* is_ambiguous,
- std::string* error_out) {
+ std::string* error_out, bool accept_any_state) {
atransport* result = nullptr;
if (serial) {
@@ -615,7 +635,7 @@
std::unique_lock<std::mutex> lock(transport_lock);
for (const auto& t : transport_list) {
- if (t->connection_state == kCsNoPerm) {
+ if (t->GetConnectionState() == kCsNoPerm) {
#if ADB_HOST
*error_out = UsbNoPermissionsLongHelpText();
#endif
@@ -664,7 +684,7 @@
lock.unlock();
// Don't return unauthorized devices; the caller can't do anything with them.
- if (result && result->connection_state == kCsUnauthorized) {
+ if (result && result->GetConnectionState() == kCsUnauthorized && !accept_any_state) {
*error_out = "device unauthorized.\n";
char* ADB_VENDOR_KEYS = getenv("ADB_VENDOR_KEYS");
*error_out += "This adb server's $ADB_VENDOR_KEYS is ";
@@ -676,7 +696,7 @@
}
// Don't return offline devices; the caller can't do anything with them.
- if (result && result->connection_state == kCsOffline) {
+ if (result && result->GetConnectionState() == kCsOffline && !accept_any_state) {
*error_out = "device offline";
result = nullptr;
}
@@ -688,16 +708,38 @@
return result;
}
+int atransport::Write(apacket* p) {
+#if ADB_HOST
+ std::lock_guard<std::mutex> lock(write_msg_lock_);
+#endif
+ return write_func_(p, this);
+}
+
void atransport::Kick() {
if (!kicked_) {
kicked_ = true;
CHECK(kick_func_ != nullptr);
+#if ADB_HOST
+ // On host, adb server should avoid writing part of a packet, so don't
+ // kick a transport whiling writing a packet.
+ std::lock_guard<std::mutex> lock(write_msg_lock_);
+#endif
kick_func_(this);
}
}
+ConnectionState atransport::GetConnectionState() const {
+ return connection_state_;
+}
+
+void atransport::SetConnectionState(ConnectionState state) {
+ check_main_thread();
+ connection_state_ = state;
+}
+
const std::string atransport::connection_state_name() const {
- switch (connection_state) {
+ ConnectionState state = GetConnectionState();
+ switch (state) {
case kCsOffline:
return "offline";
case kCsBootloader:
@@ -963,10 +1005,10 @@
void register_usb_transport(usb_handle* usb, const char* serial, const char* devpath,
unsigned writeable) {
- atransport* t = new atransport();
+ atransport* t = new atransport((writeable ? kCsOffline : kCsNoPerm));
D("transport: %p init'ing for usb_handle %p (sn='%s')", t, usb, serial ? serial : "");
- init_usb_transport(t, usb, (writeable ? kCsOffline : kCsNoPerm));
+ init_usb_transport(t, usb);
if (serial) {
t->serial = strdup(serial);
}
@@ -987,12 +1029,13 @@
void unregister_usb_transport(usb_handle* usb) {
std::lock_guard<std::mutex> lock(transport_lock);
transport_list.remove_if(
- [usb](atransport* t) { return t->usb == usb && t->connection_state == kCsNoPerm; });
+ [usb](atransport* t) { return t->usb == usb && t->GetConnectionState() == kCsNoPerm; });
}
int check_header(apacket* p, atransport* t) {
if (p->msg.magic != (p->msg.command ^ 0xffffffff)) {
- VLOG(RWX) << "check_header(): invalid magic";
+ VLOG(RWX) << "check_header(): invalid magic command = " << std::hex << p->msg.command
+ << ", magic = " << p->msg.magic;
return -1;
}
@@ -1020,4 +1063,11 @@
keys_.pop_front();
return result;
}
+bool atransport::SetSendConnectOnError() {
+ if (has_send_connect_on_error_) {
+ return false;
+ }
+ has_send_connect_on_error_ = true;
+ return true;
+}
#endif
diff --git a/adb/transport.h b/adb/transport.h
index 4d97fc7..8c15d66 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -19,10 +19,12 @@
#include <sys/types.h>
+#include <atomic>
#include <deque>
#include <functional>
#include <list>
#include <memory>
+#include <mutex>
#include <string>
#include <unordered_set>
@@ -57,31 +59,35 @@
// class in one go is a very large change. Given how bad our testing is,
// it's better to do this piece by piece.
- atransport() {
+ atransport(ConnectionState state = kCsOffline) : connection_state_(state) {
transport_fde = {};
protocol_version = A_VERSION;
max_payload = MAX_PAYLOAD;
}
-
virtual ~atransport() {}
int (*read_from_remote)(apacket* p, atransport* t) = nullptr;
- int (*write_to_remote)(apacket* p, atransport* t) = nullptr;
void (*close)(atransport* t) = nullptr;
+
+ void SetWriteFunction(int (*write_func)(apacket*, atransport*)) { write_func_ = write_func; }
void SetKickFunction(void (*kick_func)(atransport*)) {
kick_func_ = kick_func;
}
bool IsKicked() {
return kicked_;
}
+ int Write(apacket* p);
void Kick();
+ // ConnectionState can be read by all threads, but can only be written in the main thread.
+ ConnectionState GetConnectionState() const;
+ void SetConnectionState(ConnectionState state);
+
int fd = -1;
int transport_socket = -1;
fdevent transport_fde;
size_t ref_count = 0;
uint32_t sync_token = 0;
- ConnectionState connection_state = kCsOffline;
bool online = false;
TransportType type = kTransportAny;
@@ -114,11 +120,13 @@
#if ADB_HOST
std::shared_ptr<RSA> NextKey();
+ bool SetSendConnectOnError();
#endif
char token[TOKEN_SIZE] = {};
size_t failed_auth_attempts = 0;
+ const std::string serial_name() const { return serial ? serial : "<unknown>"; }
const std::string connection_state_name() const;
void update_version(int version, size_t payload);
@@ -157,6 +165,7 @@
int local_port_for_emulator_ = -1;
bool kicked_ = false;
void (*kick_func_)(atransport*) = nullptr;
+ int (*write_func_)(apacket*, atransport*) = nullptr;
// A set of features transmitted in the banner with the initial connection.
// This is stored in the banner as 'features=feature0,feature1,etc'.
@@ -167,8 +176,11 @@
// A list of adisconnect callbacks called when the transport is kicked.
std::list<adisconnect*> disconnects_;
+ std::atomic<ConnectionState> connection_state_;
#if ADB_HOST
std::deque<std::shared_ptr<RSA>> keys_;
+ std::mutex write_msg_lock_;
+ bool has_send_connect_on_error_ = false;
#endif
DISALLOW_COPY_AND_ASSIGN(atransport);
@@ -181,8 +193,8 @@
* is set to true and nullptr returned.
* If no suitable transport is found, error is set and nullptr returned.
*/
-atransport* acquire_one_transport(TransportType type, const char* serial,
- bool* is_ambiguous, std::string* error_out);
+atransport* acquire_one_transport(TransportType type, const char* serial, bool* is_ambiguous,
+ std::string* error_out, bool accept_any_state = false);
void kick_transport(atransport* t);
void update_transports(void);
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index 408f51f..3ee286a 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -515,12 +515,11 @@
int fail = 0;
t->SetKickFunction(remote_kick);
+ t->SetWriteFunction(remote_write);
t->close = remote_close;
t->read_from_remote = remote_read;
- t->write_to_remote = remote_write;
t->sfd = s;
t->sync_token = 1;
- t->connection_state = kCsOffline;
t->type = kTransportLocal;
#if ADB_HOST
diff --git a/adb/transport_test.cpp b/adb/transport_test.cpp
index 8b38e03..68689d4 100644
--- a/adb/transport_test.cpp
+++ b/adb/transport_test.cpp
@@ -94,12 +94,13 @@
}
TEST(transport, parse_banner_no_features) {
+ set_main_thread();
atransport t;
parse_banner("host::", &t);
ASSERT_EQ(0U, t.features().size());
- ASSERT_EQ(kCsHost, t.connection_state);
+ ASSERT_EQ(kCsHost, t.GetConnectionState());
ASSERT_EQ(nullptr, t.product);
ASSERT_EQ(nullptr, t.model);
@@ -113,7 +114,7 @@
"host::ro.product.name=foo;ro.product.model=bar;ro.product.device=baz;";
parse_banner(banner, &t);
- ASSERT_EQ(kCsHost, t.connection_state);
+ ASSERT_EQ(kCsHost, t.GetConnectionState());
ASSERT_EQ(0U, t.features().size());
@@ -130,7 +131,7 @@
"features=woodly,doodly";
parse_banner(banner, &t);
- ASSERT_EQ(kCsHost, t.connection_state);
+ ASSERT_EQ(kCsHost, t.GetConnectionState());
ASSERT_EQ(2U, t.features().size());
ASSERT_TRUE(t.has_feature("woodly"));
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index 516b4f2..ce419b8 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -25,9 +25,115 @@
#include "adb.h"
+#if ADB_HOST
+
+static constexpr size_t MAX_USB_BULK_PACKET_SIZE = 1024u;
+
+// Call usb_read using a buffer having a multiple of MAX_USB_BULK_PACKET_SIZE bytes
+// to avoid overflow. See http://libusb.sourceforge.net/api-1.0/packetoverflow.html.
+static int UsbReadMessage(usb_handle* h, amessage* msg) {
+ D("UsbReadMessage");
+ char buffer[MAX_USB_BULK_PACKET_SIZE];
+ int n = usb_read(h, buffer, sizeof(buffer));
+ if (n == sizeof(*msg)) {
+ memcpy(msg, buffer, sizeof(*msg));
+ }
+ return n;
+}
+
+// Call usb_read using a buffer having a multiple of MAX_USB_BULK_PACKET_SIZE bytes
+// to avoid overflow. See http://libusb.sourceforge.net/api-1.0/packetoverflow.html.
+static int UsbReadPayload(usb_handle* h, apacket* p) {
+ D("UsbReadPayload");
+ size_t need_size = p->msg.data_length;
+ size_t data_pos = 0u;
+ while (need_size > 0u) {
+ int n = 0;
+ if (data_pos + MAX_USB_BULK_PACKET_SIZE <= sizeof(p->data)) {
+ // Read directly to p->data.
+ size_t rem_size = need_size % MAX_USB_BULK_PACKET_SIZE;
+ size_t direct_read_size = need_size - rem_size;
+ if (rem_size &&
+ data_pos + direct_read_size + MAX_USB_BULK_PACKET_SIZE <= sizeof(p->data)) {
+ direct_read_size += MAX_USB_BULK_PACKET_SIZE;
+ }
+ n = usb_read(h, &p->data[data_pos], direct_read_size);
+ if (n < 0) {
+ D("usb_read(size %zu) failed", direct_read_size);
+ return n;
+ }
+ } else {
+ // Read indirectly using a buffer.
+ char buffer[MAX_USB_BULK_PACKET_SIZE];
+ n = usb_read(h, buffer, sizeof(buffer));
+ if (n < 0) {
+ D("usb_read(size %zu) failed", sizeof(buffer));
+ return -1;
+ }
+ size_t copy_size = std::min(static_cast<size_t>(n), need_size);
+ D("usb read %d bytes, need %zu bytes, copy %zu bytes", n, need_size, copy_size);
+ memcpy(&p->data[data_pos], buffer, copy_size);
+ }
+ data_pos += n;
+ need_size -= std::min(static_cast<size_t>(n), need_size);
+ }
+ return static_cast<int>(data_pos);
+}
+
+static int remote_read(apacket* p, atransport* t) {
+ int n = UsbReadMessage(t->usb, &p->msg);
+ if (n < 0) {
+ D("remote usb: read terminated (message)");
+ return -1;
+ }
+ if (static_cast<size_t>(n) != sizeof(p->msg) || check_header(p, t)) {
+ D("remote usb: check_header failed, skip it");
+ goto err_msg;
+ }
+ if (t->GetConnectionState() == kCsOffline) {
+ // If we read a wrong msg header declaring a large message payload, don't read its payload.
+ // Otherwise we may miss true messages from the device.
+ if (p->msg.command != A_CNXN && p->msg.command != A_AUTH) {
+ goto err_msg;
+ }
+ }
+ if (p->msg.data_length) {
+ n = UsbReadPayload(t->usb, p);
+ if (n < 0) {
+ D("remote usb: terminated (data)");
+ return -1;
+ }
+ if (static_cast<uint32_t>(n) != p->msg.data_length) {
+ D("remote usb: read payload failed (need %u bytes, give %d bytes), skip it",
+ p->msg.data_length, n);
+ goto err_msg;
+ }
+ }
+ if (check_data(p)) {
+ D("remote usb: check_data failed, skip it");
+ goto err_msg;
+ }
+ return 0;
+
+err_msg:
+ p->msg.command = 0;
+ if (t->GetConnectionState() == kCsOffline) {
+ // If the data toggle of ep_out on device and ep_in on host are not the same, we may receive
+ // an error message. In this case, resend one A_CNXN message to connect the device.
+ if (t->SetSendConnectOnError()) {
+ SendConnectOnHost(t);
+ }
+ }
+ return 0;
+}
+
+#else
+
+// On Android devices, we rely on the kernel to provide buffered read.
+// So we can recover automatically from EOVERFLOW.
static int remote_read(apacket *p, atransport *t)
{
- if(usb_read(t->usb, &p->msg, sizeof(amessage))){
+ if (usb_read(t->usb, &p->msg, sizeof(amessage))) {
D("remote usb: read terminated (message)");
return -1;
}
@@ -38,7 +144,7 @@
}
if(p->msg.data_length) {
- if(usb_read(t->usb, p->data, p->msg.data_length)){
+ if (usb_read(t->usb, p->data, p->msg.data_length)) {
D("remote usb: terminated (data)");
return -1;
}
@@ -51,17 +157,18 @@
return 0;
}
+#endif
static int remote_write(apacket *p, atransport *t)
{
unsigned size = p->msg.data_length;
- if(usb_write(t->usb, &p->msg, sizeof(amessage))) {
+ if (usb_write(t->usb, &p->msg, sizeof(amessage))) {
D("remote usb: 1 - write terminated");
return -1;
}
if(p->msg.data_length == 0) return 0;
- if(usb_write(t->usb, &p->data, size)) {
+ if (usb_write(t->usb, &p->data, size)) {
D("remote usb: 2 - write terminated");
return -1;
}
@@ -75,20 +182,17 @@
t->usb = 0;
}
-static void remote_kick(atransport *t)
-{
+static void remote_kick(atransport* t) {
usb_kick(t->usb);
}
-void init_usb_transport(atransport *t, usb_handle *h, ConnectionState state)
-{
+void init_usb_transport(atransport* t, usb_handle* h) {
D("transport: usb");
t->close = remote_close;
t->SetKickFunction(remote_kick);
+ t->SetWriteFunction(remote_write);
t->read_from_remote = remote_read;
- t->write_to_remote = remote_write;
t->sync_token = 1;
- t->connection_state = state;
t->type = kTransportUsb;
t->usb = h;
}
diff --git a/base/Android.bp b/base/Android.bp
index 3af7686..afb7dd3 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -20,8 +20,28 @@
"-Werror",
]
+cc_library_headers {
+ name: "libbase_headers",
+ vendor_available: true,
+ host_supported: true,
+ export_include_dirs: ["include"],
+
+ header_libs: ["libutils_headers"],
+ export_header_lib_headers: ["libutils_headers"],
+
+ target: {
+ linux_bionic: {
+ enabled: true,
+ },
+ windows: {
+ enabled: true,
+ },
+ },
+}
+
cc_library {
name: "libbase",
+ vendor_available: true,
clang: true,
host_supported: true,
srcs: [
@@ -33,9 +53,11 @@
"strings.cpp",
"test_utils.cpp",
],
- local_include_dirs: ["include"],
+
+ header_libs: ["libbase_headers"],
+ export_header_lib_headers: ["libbase_headers"],
+
cppflags: libbase_cppflags,
- export_include_dirs: ["include"],
shared_libs: ["liblog"],
target: {
android: {
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 7de72a8..4a525be 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -62,6 +62,7 @@
cc_library {
name: "libbacktrace",
+ vendor_available: true,
defaults: ["libbacktrace_common"],
host_supported: true,
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 0a3bab7..58170ec 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -30,16 +30,14 @@
]
cc_library_headers {
- name: "libcutils_vndk_headers",
- host_supported: true,
- export_include_dirs: ["include_vndk"],
-}
-
-cc_library_headers {
name: "libcutils_headers",
+ vendor_available: true,
host_supported: true,
export_include_dirs: ["include"],
target: {
+ vendor: {
+ export_include_dirs: ["include_vndk"],
+ },
linux_bionic: {
enabled: true,
},
@@ -51,6 +49,7 @@
cc_library {
name: "libcutils",
+ vendor_available: true,
host_supported: true,
srcs: [
"config_utils.c",
diff --git a/libcutils/include_vndk/cutils/log.h b/libcutils/include_vndk/cutils/log.h
index ae74024..21dc11e 100644
--- a/libcutils/include_vndk/cutils/log.h
+++ b/libcutils/include_vndk/cutils/log.h
@@ -16,6 +16,32 @@
*/
#ifndef _LIBS_CUTIL_LOG_H
#define _LIBS_CUTIL_LOG_H
-#warning "Deprecated: don't include cutils/log.h, use either android/log.h or log/log.h"
+
+/* We do not know if developer wanted log/log.h or subset android/log.h */
#include <log/log.h>
+
+#if defined(__GNUC__)
+#if defined( __clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic warning "-W#warnings"
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpedantic"
+#elif (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR > 9))
+#pragma GCC diagnostic push
+#pragma GCC diagnostic warning "-W#warnings"
+#else
+#pragma GCC diagnostic push
+#pragma GCC diagnostic warning "-Wcpp"
+#endif
+#endif
+
+#warning "Deprecated: don't include cutils/log.h, use either android/log.h or log/log.h"
+
+#if defined(__GNUC__)
+#if defined( __clang__)
+#pragma clang diagnostic pop
+#endif
+#pragma GCC diagnostic pop
+#endif
+
#endif /* _LIBS_CUTIL_LOG_H */
diff --git a/libsync/Android.bp b/libsync/Android.bp
index a4e5599..4bafb08 100644
--- a/libsync/Android.bp
+++ b/libsync/Android.bp
@@ -8,6 +8,7 @@
cc_library_shared {
name: "libsync",
+ vendor_available: true,
defaults: ["libsync_defaults"],
}
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index e35593f..05d0353 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -54,6 +54,7 @@
"ElfInterfaceArm.cpp",
"Log.cpp",
"Regs.cpp",
+ "MapInfo.cpp",
"Maps.cpp",
"Memory.cpp",
"Symbols.cpp",
@@ -98,6 +99,7 @@
"tests/ElfInterfaceTest.cpp",
"tests/ElfTest.cpp",
"tests/LogFake.cpp",
+ "tests/MapInfoTest.cpp",
"tests/MapsTest.cpp",
"tests/MemoryFake.cpp",
"tests/MemoryFileTest.cpp",
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
new file mode 100644
index 0000000..051f700
--- /dev/null
+++ b/libunwindstack/MapInfo.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <memory>
+#include <string>
+
+#include "Elf.h"
+#include "MapInfo.h"
+#include "Maps.h"
+#include "Memory.h"
+
+Memory* MapInfo::CreateMemory(pid_t pid) {
+ if (end <= start) {
+ return nullptr;
+ }
+
+ elf_offset = 0;
+
+ // First try and use the file associated with the info.
+ if (!name.empty()) {
+ // Fail on device maps.
+ if (flags & MAPS_FLAGS_DEVICE_MAP) {
+ return nullptr;
+ }
+
+ std::unique_ptr<MemoryFileAtOffset> file_memory(new MemoryFileAtOffset);
+ uint64_t map_size;
+ if (offset != 0) {
+ // Only map in a piece of the file.
+ map_size = end - start;
+ } else {
+ map_size = UINT64_MAX;
+ }
+ if (file_memory->Init(name, offset, map_size)) {
+ // It's possible that a non-zero offset might not be pointing to
+ // valid elf data. Check if this is a valid elf, and if not assume
+ // that this was meant to incorporate the entire file.
+ if (offset != 0 && !Elf::IsValidElf(file_memory.get())) {
+ // Don't bother checking the validity that will happen on the elf init.
+ if (file_memory->Init(name, 0)) {
+ elf_offset = offset;
+ return file_memory.release();
+ }
+ // Fall through if the init fails.
+ } else {
+ return file_memory.release();
+ }
+ }
+ }
+
+ Memory* memory = nullptr;
+ if (pid == getpid()) {
+ memory = new MemoryLocal();
+ } else {
+ memory = new MemoryRemote(pid);
+ }
+ return new MemoryRange(memory, start, end);
+}
+
+Elf* MapInfo::GetElf(pid_t pid, bool) {
+ if (elf) {
+ return elf;
+ }
+
+ elf = new Elf(CreateMemory(pid));
+ elf->Init();
+ // If the init fails, keep the elf around as an invalid object so we
+ // don't try to reinit the object.
+ return elf;
+}
diff --git a/libunwindstack/MapInfo.h b/libunwindstack/MapInfo.h
index 8342904..79a2ada 100644
--- a/libunwindstack/MapInfo.h
+++ b/libunwindstack/MapInfo.h
@@ -39,6 +39,7 @@
uint64_t elf_offset;
Memory* CreateMemory(pid_t pid);
+ Elf* GetElf(pid_t pid, bool init_gnu_debugdata = false);
};
#endif // _LIBUNWINDSTACK_MAP_INFO_H
diff --git a/libunwindstack/tests/MapInfoTest.cpp b/libunwindstack/tests/MapInfoTest.cpp
new file mode 100644
index 0000000..c846ad7
--- /dev/null
+++ b/libunwindstack/tests/MapInfoTest.cpp
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include <elf.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <memory>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/test_utils.h>
+#include <gtest/gtest.h>
+
+#include "Elf.h"
+#include "MapInfo.h"
+#include "Memory.h"
+
+class MapInfoTest : public ::testing::Test {
+ protected:
+ static void SetUpTestCase() {
+ std::vector<uint8_t> buffer(1024);
+ memcpy(buffer.data(), ELFMAG, SELFMAG);
+ for (size_t i = SELFMAG; i < buffer.size(); i++) {
+ buffer[i] = i / 256 + 1;
+ }
+ ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
+
+ for (size_t i = 0; i < 0x100; i++) {
+ buffer[i] = i / 256 + 1;
+ }
+ memcpy(&buffer[0x100], ELFMAG, SELFMAG);
+ for (size_t i = 0x100 + SELFMAG; i < buffer.size(); i++) {
+ buffer[i] = i / 256 + 1;
+ }
+ ASSERT_TRUE(android::base::WriteFully(elf_at_100_.fd, buffer.data(), buffer.size()));
+ }
+
+ static TemporaryFile elf_;
+
+ static TemporaryFile elf_at_100_;
+};
+TemporaryFile MapInfoTest::elf_;
+TemporaryFile MapInfoTest::elf_at_100_;
+
+TEST_F(MapInfoTest, end_le_start) {
+ MapInfo info{.start = 0x100, .end = 0x100, .offset = 0, .name = elf_.path};
+
+ std::unique_ptr<Memory> memory;
+ memory.reset(info.CreateMemory(getpid()));
+ ASSERT_TRUE(memory.get() == nullptr);
+
+ info.end = 0xff;
+ memory.reset(info.CreateMemory(getpid()));
+ ASSERT_TRUE(memory.get() == nullptr);
+
+ // Make sure this test is valid.
+ info.end = 0x101;
+ memory.reset(info.CreateMemory(getpid()));
+ ASSERT_FALSE(info.CreateMemory(getpid()) == nullptr);
+}
+
+// Verify that if the offset is non-zero but there is no elf at the offset,
+// that the full file is used.
+TEST_F(MapInfoTest, create_memory_file_backed_non_zero_offset_full_file) {
+ MapInfo info{.start = 0x100, .end = 0x200, .offset = 0x100, .name = elf_.path};
+
+ std::unique_ptr<Memory> memory(info.CreateMemory(getpid()));
+ ASSERT_TRUE(memory.get() != nullptr);
+ ASSERT_EQ(0x100U, info.elf_offset);
+
+ // Read the entire file.
+ std::vector<uint8_t> buffer(1024);
+ ASSERT_TRUE(memory->Read(0, buffer.data(), 1024));
+ ASSERT_TRUE(memcmp(buffer.data(), ELFMAG, SELFMAG) == 0);
+ for (size_t i = SELFMAG; i < buffer.size(); i++) {
+ ASSERT_EQ(i / 256 + 1, buffer[i]) << "Failed at byte " << i;
+ }
+
+ ASSERT_FALSE(memory->Read(1024, buffer.data(), 1));
+}
+
+// Verify that if the offset is non-zero and there is an elf at that
+// offset, that only part of the file is used.
+TEST_F(MapInfoTest, create_memory_file_backed_non_zero_offset_partial_file) {
+ MapInfo info{.start = 0x100, .end = 0x200, .offset = 0x100, .name = elf_at_100_.path};
+
+ std::unique_ptr<Memory> memory(info.CreateMemory(getpid()));
+ ASSERT_TRUE(memory.get() != nullptr);
+ ASSERT_EQ(0U, info.elf_offset);
+
+ // Read the valid part of the file.
+ std::vector<uint8_t> buffer(0x100);
+ ASSERT_TRUE(memory->Read(0, buffer.data(), 0x100));
+ ASSERT_TRUE(memcmp(buffer.data(), ELFMAG, SELFMAG) == 0);
+ for (size_t i = SELFMAG; i < buffer.size(); i++) {
+ ASSERT_EQ(2, buffer[i]) << "Failed at byte " << i;
+ }
+
+ ASSERT_FALSE(memory->Read(0x100, buffer.data(), 1));
+}
+
+// Verify that device file names will never result in Memory object creation.
+TEST_F(MapInfoTest, create_memory_check_device_maps) {
+ // Set up some memory so that a valid local memory object would
+ // be returned if the file mapping fails, but the device check is incorrect.
+ std::vector<uint8_t> buffer(1024);
+ MapInfo info;
+ info.start = reinterpret_cast<uint64_t>(buffer.data());
+ info.end = info.start + buffer.size();
+ info.offset = 0;
+ std::unique_ptr<Memory> memory;
+
+ info.flags = 0x8000;
+ info.name = "/dev/something";
+ memory.reset(info.CreateMemory(getpid()));
+ ASSERT_TRUE(memory.get() == nullptr);
+}
+
+TEST_F(MapInfoTest, create_memory_local_memory) {
+ // Set up some memory for a valid local memory object.
+ std::vector<uint8_t> buffer(1024);
+ for (size_t i = 0; i < buffer.size(); i++) {
+ buffer[i] = i % 256;
+ }
+
+ MapInfo info;
+ info.start = reinterpret_cast<uint64_t>(buffer.data());
+ info.end = info.start + buffer.size();
+ info.offset = 0;
+
+ std::unique_ptr<Memory> memory;
+ memory.reset(info.CreateMemory(getpid()));
+ ASSERT_TRUE(memory.get() != nullptr);
+
+ std::vector<uint8_t> read_buffer(1024);
+ ASSERT_TRUE(memory->Read(0, read_buffer.data(), read_buffer.size()));
+ for (size_t i = 0; i < read_buffer.size(); i++) {
+ ASSERT_EQ(i % 256, read_buffer[i]) << "Failed at byte " << i;
+ }
+
+ ASSERT_FALSE(memory->Read(read_buffer.size(), read_buffer.data(), 1));
+}
+
+TEST_F(MapInfoTest, create_memory_remote_memory) {
+ std::vector<uint8_t> buffer(1024);
+ memset(buffer.data(), 0xa, buffer.size());
+
+ pid_t pid;
+ if ((pid = fork()) == 0) {
+ while (true)
+ ;
+ exit(1);
+ }
+ ASSERT_LT(0, pid);
+
+ ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) != -1);
+ uint64_t iterations = 0;
+ siginfo_t si;
+ while (TEMP_FAILURE_RETRY(ptrace(PTRACE_GETSIGINFO, pid, 0, &si)) < 0 && errno == ESRCH) {
+ usleep(30);
+ iterations++;
+ ASSERT_LT(iterations, 500000000ULL);
+ }
+
+ MapInfo info;
+ info.start = reinterpret_cast<uint64_t>(buffer.data());
+ info.end = info.start + buffer.size();
+ info.offset = 0;
+
+ std::unique_ptr<Memory> memory;
+ memory.reset(info.CreateMemory(pid));
+ ASSERT_TRUE(memory.get() != nullptr);
+ // Set the local memory to a different value to guarantee we are reading
+ // from the remote process.
+ memset(buffer.data(), 0x1, buffer.size());
+ std::vector<uint8_t> read_buffer(1024);
+ ASSERT_TRUE(memory->Read(0, read_buffer.data(), read_buffer.size()));
+ for (size_t i = 0; i < read_buffer.size(); i++) {
+ ASSERT_EQ(0xaU, read_buffer[i]) << "Failed at byte " << i;
+ }
+
+ ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
+
+ kill(pid, SIGKILL);
+}
+
+TEST_F(MapInfoTest, get_elf) {
+ // Create a map to use as initialization data.
+ void* map = mmap(nullptr, 1024, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ ASSERT_NE(MAP_FAILED, map);
+
+ uint64_t start = reinterpret_cast<uint64_t>(map);
+ MapInfo info{.start = start, .end = start + 1024, .offset = 0, .name = ""};
+
+ // The map contains garbage, but this should still produce an elf object.
+ Elf* elf = info.GetElf(getpid(), false);
+ ASSERT_TRUE(elf != nullptr);
+ ASSERT_FALSE(elf->valid());
+
+ ASSERT_EQ(0, munmap(map, 1024));
+}
diff --git a/libusbhost/Android.bp b/libusbhost/Android.bp
new file mode 100644
index 0000000..a0d6b9b
--- /dev/null
+++ b/libusbhost/Android.bp
@@ -0,0 +1,35 @@
+//
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library {
+ name: "libusbhost",
+ host_supported: true,
+ srcs: ["usbhost.c"],
+ cflags: ["-Werror"],
+ export_include_dirs: ["include"],
+ target: {
+ android: {
+ cflags: [
+ "-g",
+ "-DUSE_LIBLOG",
+ ],
+ shared_libs: ["liblog"],
+ },
+ darwin: {
+ enabled: false,
+ },
+ },
+}
diff --git a/libusbhost/Android.mk b/libusbhost/Android.mk
deleted file mode 100644
index 9439846..0000000
--- a/libusbhost/Android.mk
+++ /dev/null
@@ -1,56 +0,0 @@
-#
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-# Static library for Linux host
-# ========================================================
-
-ifeq ($(HOST_OS),linux)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libusbhost
-LOCAL_SRC_FILES := usbhost.c
-LOCAL_CFLAGS := -Werror
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-endif
-
-# Shared library for target
-# ========================================================
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libusbhost
-LOCAL_SRC_FILES := usbhost.c
-LOCAL_CFLAGS := -g -DUSE_LIBLOG -Werror
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-# needed for logcat
-LOCAL_SHARED_LIBRARIES := libcutils
-include $(BUILD_SHARED_LIBRARY)
-
-# Static library for target
-# ========================================================
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libusbhost
-LOCAL_SRC_FILES := usbhost.c
-LOCAL_CFLAGS := -Werror
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-include $(BUILD_STATIC_LIBRARY)
diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c
index 68aca17..050fc2f 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -19,7 +19,7 @@
#ifdef USE_LIBLOG
#define LOG_TAG "usbhost"
-#include "utils/Log.h"
+#include "log/log.h"
#define D ALOGD
#else
#define D printf
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index e487a97..9c07472 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -1216,7 +1216,12 @@
signal(SIGALRM, caught_blocking_clear);
alarm(2);
while (fgets(buffer, sizeof(buffer), fp)) {
- if (!strncmp(buffer, "clearLog: ", 10)) {
+ if (!strncmp(buffer, "clearLog: ", strlen("clearLog: "))) {
+ fprintf(stderr, "WARNING: Test lacks permission to run :-(\n");
+ count = signals = 1;
+ break;
+ }
+ if (!strncmp(buffer, "failed to clear", strlen("failed to clear"))) {
fprintf(stderr, "WARNING: Test lacks permission to run :-(\n");
count = signals = 1;
break;
diff --git a/logd/FlushCommand.cpp b/logd/FlushCommand.cpp
index c67d2bf..a9edc3e 100644
--- a/logd/FlushCommand.cpp
+++ b/logd/FlushCommand.cpp
@@ -44,14 +44,14 @@
// LogTimeEntrys, and spawn a transitory per-client thread to
// work at filing data to the socket.
//
-// global LogTimeEntry::lock() is used to protect access,
+// global LogTimeEntry::wrlock() is used to protect access,
// reference counts are used to ensure that individual
// LogTimeEntry lifetime is managed when not protected.
void FlushCommand::runSocketCommand(SocketClient* client) {
LogTimeEntry* entry = NULL;
LastLogTimes& times = mReader.logbuf().mTimes;
- LogTimeEntry::lock();
+ LogTimeEntry::wrlock();
LastLogTimes::iterator it = times.begin();
while (it != times.end()) {
entry = (*it);
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 2d9024a..ee38d1c 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -277,7 +277,7 @@
++cp;
}
tid = pid;
- logbuf->lock();
+ logbuf->wrlock();
uid = logbuf->pidToUid(pid);
logbuf->unlock();
memmove(pidptr, cp, strlen(cp) + 1);
@@ -322,7 +322,7 @@
pid = tid;
comm = "auditd";
} else {
- logbuf->lock();
+ logbuf->wrlock();
comm = commfree = logbuf->pidToName(pid);
logbuf->unlock();
if (!comm) {
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index ed46181..d9ec081 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -72,7 +72,7 @@
// as the act of mounting /data would trigger persist.logd.timestamp to
// be corrected. 1/30 corner case YMMV.
//
- pthread_mutex_lock(&mLogElementsLock);
+ rdlock();
LogBufferElementCollection::iterator it = mLogElements.begin();
while ((it != mLogElements.end())) {
LogBufferElement* e = *it;
@@ -87,7 +87,7 @@
}
++it;
}
- pthread_mutex_unlock(&mLogElementsLock);
+ unlock();
}
// We may have been triggered by a SIGHUP. Release any sleeping reader
@@ -95,7 +95,7 @@
//
// NB: this is _not_ performed in the context of a SIGHUP, it is
// performed during startup, and in context of reinit administrative thread
- LogTimeEntry::lock();
+ LogTimeEntry::wrlock();
LastLogTimes::iterator times = mTimes.begin();
while (times != mTimes.end()) {
@@ -111,7 +111,7 @@
LogBuffer::LogBuffer(LastLogTimes* times)
: monotonic(android_log_clockid() == CLOCK_MONOTONIC), mTimes(*times) {
- pthread_mutex_init(&mLogElementsLock, nullptr);
+ pthread_rwlock_init(&mLogElementsLock, nullptr);
log_id_for_each(i) {
lastLoggedElements[i] = nullptr;
@@ -207,15 +207,15 @@
}
if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
// Log traffic received to total
- pthread_mutex_lock(&mLogElementsLock);
+ wrlock();
stats.addTotal(elem);
- pthread_mutex_unlock(&mLogElementsLock);
+ unlock();
delete elem;
return -EACCES;
}
}
- pthread_mutex_lock(&mLogElementsLock);
+ wrlock();
LogBufferElement* currentLast = lastLoggedElements[log_id];
if (currentLast) {
LogBufferElement* dropped = droppedElements[log_id];
@@ -316,14 +316,14 @@
// check for overflow
if (total >= UINT32_MAX) {
log(currentLast);
- pthread_mutex_unlock(&mLogElementsLock);
+ unlock();
return len;
}
stats.addTotal(currentLast);
delete currentLast;
swab = total;
event->payload.data = htole32(swab);
- pthread_mutex_unlock(&mLogElementsLock);
+ unlock();
return len;
}
if (count == USHRT_MAX) {
@@ -340,7 +340,7 @@
}
droppedElements[log_id] = currentLast;
lastLoggedElements[log_id] = elem;
- pthread_mutex_unlock(&mLogElementsLock);
+ unlock();
return len;
}
if (dropped) { // State 1 or 2
@@ -358,12 +358,12 @@
lastLoggedElements[log_id] = new LogBufferElement(*elem);
log(elem);
- pthread_mutex_unlock(&mLogElementsLock);
+ unlock();
return len;
}
-// assumes mLogElementsLock held, owns elem, will look after garbage collection
+// assumes LogBuffer::wrlock() held, owns elem, look after garbage collection
void LogBuffer::log(LogBufferElement* elem) {
// cap on how far back we will sort in-place, otherwise append
static uint32_t too_far_back = 5; // five seconds
@@ -384,7 +384,7 @@
bool end_set = false;
bool end_always = false;
- LogTimeEntry::lock();
+ LogTimeEntry::rdlock();
LastLogTimes::iterator times = mTimes.begin();
while (times != mTimes.end()) {
@@ -426,7 +426,7 @@
// Prune at most 10% of the log entries or maxPrune, whichever is less.
//
-// mLogElementsLock must be held when this function is called.
+// LogBuffer::wrlock() must be held when this function is called.
void LogBuffer::maybePrune(log_id_t id) {
size_t sizes = stats.sizes(id);
unsigned long maxSize = log_buffer_size(id);
@@ -650,14 +650,14 @@
// The third thread is optional, and only gets hit if there was a whitelist
// and more needs to be pruned against the backstop of the region lock.
//
-// mLogElementsLock must be held when this function is called.
+// LogBuffer::wrlock() must be held when this function is called.
//
bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
LogTimeEntry* oldest = nullptr;
bool busy = false;
bool clearAll = pruneRows == ULONG_MAX;
- LogTimeEntry::lock();
+ LogTimeEntry::rdlock();
// Region locked?
LastLogTimes::iterator times = mTimes.begin();
@@ -1017,15 +1017,15 @@
// one entry, not another clear run, so we are looking for
// the quick side effect of the return value to tell us if
// we have a _blocked_ reader.
- pthread_mutex_lock(&mLogElementsLock);
+ wrlock();
busy = prune(id, 1, uid);
- pthread_mutex_unlock(&mLogElementsLock);
+ unlock();
// It is still busy, blocked reader(s), lets kill them all!
// otherwise, lets be a good citizen and preserve the slow
// readers and let the clear run (below) deal with determining
// if we are still blocked and return an error code to caller.
if (busy) {
- LogTimeEntry::lock();
+ LogTimeEntry::wrlock();
LastLogTimes::iterator times = mTimes.begin();
while (times != mTimes.end()) {
LogTimeEntry* entry = (*times);
@@ -1038,9 +1038,9 @@
LogTimeEntry::unlock();
}
}
- pthread_mutex_lock(&mLogElementsLock);
+ wrlock();
busy = prune(id, ULONG_MAX, uid);
- pthread_mutex_unlock(&mLogElementsLock);
+ unlock();
if (!busy || !--retry) {
break;
}
@@ -1051,9 +1051,9 @@
// get the used space associated with "id".
unsigned long LogBuffer::getSizeUsed(log_id_t id) {
- pthread_mutex_lock(&mLogElementsLock);
+ rdlock();
size_t retval = stats.sizes(id);
- pthread_mutex_unlock(&mLogElementsLock);
+ unlock();
return retval;
}
@@ -1063,17 +1063,17 @@
if (!__android_logger_valid_buffer_size(size)) {
return -1;
}
- pthread_mutex_lock(&mLogElementsLock);
+ wrlock();
log_buffer_size(id) = size;
- pthread_mutex_unlock(&mLogElementsLock);
+ unlock();
return 0;
}
// get the total space allocated to "id"
unsigned long LogBuffer::getSize(log_id_t id) {
- pthread_mutex_lock(&mLogElementsLock);
+ rdlock();
size_t retval = log_buffer_size(id);
- pthread_mutex_unlock(&mLogElementsLock);
+ unlock();
return retval;
}
@@ -1085,7 +1085,7 @@
LogBufferElementCollection::iterator it;
uid_t uid = reader->getUid();
- pthread_mutex_lock(&mLogElementsLock);
+ rdlock();
if (start == log_time::EPOCH) {
// client wants to start from the beginning
@@ -1143,7 +1143,7 @@
continue;
}
- // NB: calling out to another object with mLogElementsLock held (safe)
+ // NB: calling out to another object with wrlock() held (safe)
if (filter) {
int ret = (*filter)(element, arg);
if (ret == false) {
@@ -1166,7 +1166,7 @@
(element->getDropped() && !sameTid) ? 0 : element->getTid();
}
- pthread_mutex_unlock(&mLogElementsLock);
+ unlock();
// range locking in LastLogTimes looks after us
max = element->flushTo(reader, this, privileged, sameTid);
@@ -1176,20 +1176,20 @@
}
skip = maxSkip;
- pthread_mutex_lock(&mLogElementsLock);
+ rdlock();
}
- pthread_mutex_unlock(&mLogElementsLock);
+ unlock();
return max;
}
std::string LogBuffer::formatStatistics(uid_t uid, pid_t pid,
unsigned int logMask) {
- pthread_mutex_lock(&mLogElementsLock);
+ wrlock();
std::string ret = stats.format(uid, pid, logMask);
- pthread_mutex_unlock(&mLogElementsLock);
+ unlock();
return ret;
}
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index 1272c20..51edd86 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -76,7 +76,7 @@
class LogBuffer {
LogBufferElementCollection mLogElements;
- pthread_mutex_t mLogElementsLock;
+ pthread_rwlock_t mLogElementsLock;
LogStatistics stats;
@@ -154,7 +154,7 @@
return tags.tagToName(tag);
}
- // helper must be protected directly or implicitly by lock()/unlock()
+ // helper must be protected directly or implicitly by wrlock()/unlock()
const char* pidToName(pid_t pid) {
return stats.pidToName(pid);
}
@@ -164,11 +164,14 @@
const char* uidToName(uid_t uid) {
return stats.uidToName(uid);
}
- void lock() {
- pthread_mutex_lock(&mLogElementsLock);
+ void wrlock() {
+ pthread_rwlock_wrlock(&mLogElementsLock);
+ }
+ void rdlock() {
+ pthread_rwlock_rdlock(&mLogElementsLock);
}
void unlock() {
- pthread_mutex_unlock(&mLogElementsLock);
+ pthread_rwlock_unlock(&mLogElementsLock);
}
private:
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index 04a620c..381c974 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -121,7 +121,7 @@
}
static const char format_uid[] = "uid=%u%s%s %s %u line%s";
- parent->lock();
+ parent->wrlock();
const char* name = parent->uidToName(mUid);
parent->unlock();
const char* commName = android::tidToName(mTid);
@@ -129,7 +129,7 @@
commName = android::tidToName(mPid);
}
if (!commName) {
- parent->lock();
+ parent->wrlock();
commName = parent->pidToName(mPid);
parent->unlock();
}
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
index d23254d..a7e7208 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -579,7 +579,7 @@
const pid_t tid = pid;
uid_t uid = AID_ROOT;
if (pid) {
- logbuf->lock();
+ logbuf->wrlock();
uid = logbuf->pidToUid(pid);
logbuf->unlock();
}
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index feb105f..6d69316 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -111,7 +111,7 @@
if (!fastcmp<strncmp>(buffer, "dumpAndClose", 12)) {
// Allow writer to get some cycles, and wait for pending notifications
sched_yield();
- LogTimeEntry::lock();
+ LogTimeEntry::wrlock();
LogTimeEntry::unlock();
sched_yield();
nonBlock = true;
@@ -212,7 +212,7 @@
void LogReader::doSocketDelete(SocketClient* cli) {
LastLogTimes& times = mLogbuf.mTimes;
- LogTimeEntry::lock();
+ LogTimeEntry::wrlock();
LastLogTimes::iterator it = times.begin();
while (it != times.end()) {
LogTimeEntry* entry = (*it);
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index b41aca5..0b6b28c 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -24,19 +24,26 @@
#include <list>
-#include <android/log.h>
+#include <private/android_logger.h>
#include "LogStatistics.h"
+static const uint64_t hourSec = 60 * 60;
+static const uint64_t monthSec = 31 * 24 * hourSec;
+
size_t LogStatistics::SizesTotal;
LogStatistics::LogStatistics() : enable(false) {
+ log_time now(CLOCK_REALTIME);
log_id_for_each(id) {
mSizes[id] = 0;
mElements[id] = 0;
mDroppedElements[id] = 0;
mSizesTotal[id] = 0;
mElementsTotal[id] = 0;
+ mOldest[id] = now;
+ mNewest[id] = now;
+ mNewestDropped[id] = now;
}
}
@@ -100,6 +107,27 @@
++mElementsTotal[log_id];
}
+ log_time stamp(element->getRealTime());
+ if (mNewest[log_id] < stamp) {
+ // A major time update invalidates the statistics :-(
+ log_time diff = stamp - mNewest[log_id];
+ mNewest[log_id] = stamp;
+
+ if (diff.tv_sec > hourSec) {
+ // approximate Do-Your-Best fixup
+ diff += mOldest[log_id];
+ if ((diff > stamp) && ((diff - stamp).tv_sec < hourSec)) {
+ diff = stamp;
+ }
+ if (diff <= stamp) {
+ mOldest[log_id] = diff;
+ if (mNewestDropped[log_id] < diff) {
+ mNewestDropped[log_id] = diff;
+ }
+ }
+ }
+ }
+
if (log_id == LOG_ID_KERNEL) {
return;
}
@@ -135,6 +163,10 @@
--mDroppedElements[log_id];
}
+ if (mOldest[log_id] < element->getRealTime()) {
+ mOldest[log_id] = element->getRealTime();
+ }
+
if (log_id == LOG_ID_KERNEL) {
return;
}
@@ -169,6 +201,10 @@
mSizes[log_id] -= size;
++mDroppedElements[log_id];
+ if (mNewestDropped[log_id] < element->getRealTime()) {
+ mNewestDropped[log_id] = element->getRealTime();
+ }
+
uidTable[log_id].drop(element->getUid(), element);
if (element->getUid() == AID_SYSTEM) {
pidSystemTable[log_id].drop(element->getPid(), element);
@@ -192,6 +228,7 @@
}
// caller must own and free character string
+// Requires parent LogBuffer::wrlock() to be held
const char* LogStatistics::uidToName(uid_t uid) const {
// Local hard coded favourites
if (uid == AID_LOGD) {
@@ -468,6 +505,45 @@
return formatLine(name, size, pruned);
}
+static std::string formatMsec(uint64_t val) {
+ static const unsigned subsecDigits = 3;
+ static const uint64_t sec = MS_PER_SEC;
+
+ static const uint64_t minute = 60 * sec;
+ static const uint64_t hour = 60 * minute;
+ static const uint64_t day = 24 * hour;
+
+ std::string output;
+ if (val < sec) return output;
+
+ if (val >= day) {
+ output = android::base::StringPrintf("%" PRIu64 "d ", val / day);
+ val = (val % day) + day;
+ }
+ if (val >= minute) {
+ if (val >= hour) {
+ output += android::base::StringPrintf("%" PRIu64 ":",
+ (val / hour) % (day / hour));
+ }
+ output += android::base::StringPrintf(
+ (val >= hour) ? "%02" PRIu64 ":" : "%" PRIu64 ":",
+ (val / minute) % (hour / minute));
+ }
+ output +=
+ android::base::StringPrintf((val >= minute) ? "%02" PRIu64 : "%" PRIu64,
+ (val / sec) % (minute / sec));
+ val %= sec;
+ unsigned digits = subsecDigits;
+ while (digits && ((val % 10) == 0)) {
+ val /= 10;
+ --digits;
+ }
+ if (digits) {
+ output += android::base::StringPrintf(".%0*" PRIu64, digits, val);
+ }
+ return output;
+}
+
std::string LogStatistics::format(uid_t uid, pid_t pid,
unsigned int logMask) const {
static const unsigned short spaces_total = 19;
@@ -537,6 +613,67 @@
output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize,
totalEls);
+ static const char SpanStr[] = "\nLogspan";
+ spaces = 10 - strlen(SpanStr);
+ output += SpanStr;
+
+ // Total reports the greater of the individual maximum time span, or the
+ // validated minimum start and maximum end time span if it makes sense.
+ uint64_t minTime = UINT64_MAX;
+ uint64_t maxTime = 0;
+ uint64_t maxSpan = 0;
+ totalSize = 0;
+
+ log_id_for_each(id) {
+ if (!(logMask & (1 << id))) continue;
+
+ // validity checking
+ uint64_t oldest = mOldest[id].msec();
+ uint64_t newest = mNewest[id].msec();
+ if (newest <= oldest) {
+ spaces += spaces_total;
+ continue;
+ }
+
+ uint64_t span = newest - oldest;
+ if (span > (monthSec * MS_PER_SEC)) {
+ spaces += spaces_total;
+ continue;
+ }
+
+ // total span
+ if (minTime > oldest) minTime = oldest;
+ if (maxTime < newest) maxTime = newest;
+ if (span > maxSpan) maxSpan = span;
+ totalSize += span;
+
+ uint64_t dropped = mNewestDropped[id].msec();
+ if (dropped < oldest) dropped = oldest;
+ if (dropped > newest) dropped = newest;
+
+ oldLength = output.length();
+ output += android::base::StringPrintf("%*s%s", spaces, "",
+ formatMsec(span).c_str());
+ unsigned permille = ((newest - dropped) * 1000 + (span / 2)) / span;
+ if ((permille > 1) && (permille < 999)) {
+ output += android::base::StringPrintf("(%u", permille / 10);
+ permille %= 10;
+ if (permille) {
+ output += android::base::StringPrintf(".%u", permille);
+ }
+ output += android::base::StringPrintf("%%)");
+ }
+ spaces -= output.length() - oldLength;
+ spaces += spaces_total;
+ }
+ if ((maxTime > minTime) && ((maxTime -= minTime) < totalSize) &&
+ (maxTime > maxSpan)) {
+ maxSpan = maxTime;
+ }
+ if (spaces < 0) spaces = 0;
+ output += android::base::StringPrintf("%*s%s", spaces, "",
+ formatMsec(maxSpan).c_str());
+
static const char OverheadStr[] = "\nOverhead";
spaces = 10 - strlen(OverheadStr);
output += OverheadStr;
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index e171e4a..e6f01d6 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -28,6 +28,7 @@
#include <android-base/stringprintf.h>
#include <android/log.h>
+#include <log/log_time.h>
#include <private/android_filesystem_config.h>
#include "LogBufferElement.h"
@@ -520,6 +521,9 @@
size_t mDroppedElements[LOG_ID_MAX];
size_t mSizesTotal[LOG_ID_MAX];
size_t mElementsTotal[LOG_ID_MAX];
+ log_time mOldest[LOG_ID_MAX];
+ log_time mNewest[LOG_ID_MAX];
+ log_time mNewestDropped[LOG_ID_MAX];
static size_t SizesTotal;
bool enable;
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
index ccc550a..25c2ad2 100644
--- a/logd/LogTimes.cpp
+++ b/logd/LogTimes.cpp
@@ -78,7 +78,7 @@
void LogTimeEntry::threadStop(void* obj) {
LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
- lock();
+ wrlock();
if (me->mNonBlock) {
me->error_Locked();
@@ -134,7 +134,7 @@
me->leadingDropped = true;
- lock();
+ wrlock();
log_time start = me->mStart;
@@ -160,7 +160,7 @@
start = logbuf.flushTo(client, start, me->mLastTid, privileged,
security, FilterSecondPass, me);
- lock();
+ wrlock();
if (start == LogBufferElement::FLUSH_ERROR) {
me->error_Locked();
@@ -191,7 +191,7 @@
int LogTimeEntry::FilterFirstPass(const LogBufferElement* element, void* obj) {
LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
- LogTimeEntry::lock();
+ LogTimeEntry::wrlock();
if (me->leadingDropped) {
if (element->getDropped()) {
@@ -219,7 +219,7 @@
int LogTimeEntry::FilterSecondPass(const LogBufferElement* element, void* obj) {
LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
- LogTimeEntry::lock();
+ LogTimeEntry::wrlock();
me->mStart = element->getRealTime();
diff --git a/logd/LogTimes.h b/logd/LogTimes.h
index ec8252e..9ca2aea 100644
--- a/logd/LogTimes.h
+++ b/logd/LogTimes.h
@@ -61,7 +61,10 @@
const log_time mEnd; // only relevant if mNonBlock
// Protect List manipulations
- static void lock(void) {
+ static void wrlock(void) {
+ pthread_mutex_lock(×Lock);
+ }
+ static void rdlock(void) {
pthread_mutex_lock(×Lock);
}
static void unlock(void) {
@@ -104,7 +107,7 @@
mError = true;
}
void error(void) {
- lock();
+ wrlock();
error_Locked();
unlock();
}