Merge "init: Use classes for parsing and clean up memory allocations"
diff --git a/adb/Android.mk b/adb/Android.mk
index e271a63..41016ee 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -79,6 +79,12 @@
sysdeps_win32.cpp \
usb_windows.cpp \
+LIBADB_TEST_linux_SRCS := \
+ fdevent_test.cpp \
+
+LIBADB_TEST_darwin_SRCS := \
+ fdevent_test.cpp \
+
include $(CLEAR_VARS)
LOCAL_CLANG := true
LOCAL_MODULE := libadbd
@@ -88,7 +94,6 @@
adb_auth_client.cpp \
fdevent.cpp \
jdwp_service.cpp \
- qemu_tracing.cpp \
usb_linux_client.cpp \
LOCAL_SANITIZE := $(adb_target_sanitize)
@@ -118,6 +123,8 @@
ifeq ($(HOST_OS),windows)
LOCAL_C_INCLUDES += development/host/windows/usb/api/
+else
+ LOCAL_MULTILIB := 64
endif
include $(BUILD_HOST_STATIC_LIBRARY)
@@ -126,7 +133,10 @@
LOCAL_CLANG := true
LOCAL_MODULE := adbd_test
LOCAL_CFLAGS := -DADB_HOST=0 $(LIBADB_CFLAGS)
-LOCAL_SRC_FILES := $(LIBADB_TEST_SRCS)
+LOCAL_SRC_FILES := \
+ $(LIBADB_TEST_SRCS) \
+ $(LIBADB_TEST_linux_SRCS) \
+
LOCAL_SANITIZE := $(adb_target_sanitize)
LOCAL_STATIC_LIBRARIES := libadbd
LOCAL_SHARED_LIBRARIES := liblog libbase libcutils
@@ -139,7 +149,11 @@
LOCAL_CLANG := $(adb_host_clang)
LOCAL_MODULE := adb_test
LOCAL_CFLAGS := -DADB_HOST=1 $(LIBADB_CFLAGS)
-LOCAL_SRC_FILES := $(LIBADB_TEST_SRCS) services.cpp
+LOCAL_SRC_FILES := \
+ $(LIBADB_TEST_SRCS) \
+ $(LIBADB_TEST_$(HOST_OS)_SRCS) \
+ services.cpp \
+
LOCAL_SANITIZE := $(adb_host_sanitize)
LOCAL_SHARED_LIBRARIES := liblog libbase
LOCAL_STATIC_LIBRARIES := \
@@ -184,7 +198,6 @@
ifeq ($(HOST_OS),linux)
LOCAL_LDLIBS += -lrt -ldl -lpthread
- LOCAL_CFLAGS += -DWORKAROUND_BUG6558362
endif
ifeq ($(HOST_OS),darwin)
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 29c9481..eb01da8 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -243,7 +243,12 @@
D("adb: offline\n");
//Close the associated usb
t->online = 0;
- run_transport_disconnects(t);
+
+ // This is necessary to avoid a race condition that occurred when a transport closes
+ // while a client socket is still active.
+ close_all_sockets(t);
+
+ t->RunDisconnects();
}
#if DEBUG_PACKETS
@@ -575,6 +580,107 @@
#if ADB_HOST
+#ifdef _WIN32
+
+static bool _make_handle_noninheritable(HANDLE h) {
+ if (h != INVALID_HANDLE_VALUE && h != NULL) {
+ if (!SetHandleInformation(h, HANDLE_FLAG_INHERIT, 0)) {
+ // 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, SystemErrorCodeToString(GetLastError()).c_str());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Create anonymous pipe, preventing inheritance of the read pipe and setting
+// security of the write pipe to sa.
+static bool _create_anonymous_pipe(unique_handle* pipe_read_out,
+ unique_handle* pipe_write_out,
+ SECURITY_ATTRIBUTES* sa) {
+ 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",
+ SystemErrorCodeToString(GetLastError()).c_str());
+ return false;
+ }
+
+ unique_handle pipe_read(pipe_read_raw);
+ pipe_read_raw = NULL;
+ unique_handle pipe_write(pipe_write_raw);
+ pipe_write_raw = NULL;
+
+ if (!_make_handle_noninheritable(pipe_read.get())) {
+ return false;
+ }
+
+ *pipe_read_out = std::move(pipe_read);
+ *pipe_write_out = std::move(pipe_write);
+
+ return true;
+}
+
+// Read from a pipe (that we take ownership of) and write what is returned to
+// GetStdHandle(nStdHandle). Return on error or when the pipe is closed.
+static unsigned _redirect_pipe_thread(HANDLE h, DWORD nStdHandle) {
+ // Take ownership of the HANDLE and close when we're done.
+ unique_handle read_pipe(h);
+ const HANDLE write_handle = GetStdHandle(nStdHandle);
+ const char* output_name = nStdHandle == STD_OUTPUT_HANDLE ?
+ "stdout" : "stderr";
+
+ while (true) {
+ char buf[64 * 1024];
+ DWORD bytes_read = 0;
+ if (!ReadFile(read_pipe.get(), buf, sizeof(buf), &bytes_read, NULL)) {
+ const DWORD err = GetLastError();
+ // ERROR_BROKEN_PIPE is expected when the subprocess closes
+ // the other end of the pipe.
+ if (err == ERROR_BROKEN_PIPE) {
+ return EXIT_SUCCESS;
+ } else {
+ fprintf(stderr, "Failed to read from %s: %s\n", output_name,
+ SystemErrorCodeToString(err).c_str());
+ return EXIT_FAILURE;
+ }
+ }
+
+ // Don't try to write if our stdout/stderr was not setup by the
+ // parent process.
+ if (write_handle != NULL && write_handle != INVALID_HANDLE_VALUE) {
+ DWORD bytes_written = 0;
+ if (!WriteFile(write_handle, buf, bytes_read, &bytes_written,
+ NULL)) {
+ fprintf(stderr, "Failed to write to %s: %s\n", output_name,
+ SystemErrorCodeToString(GetLastError()).c_str());
+ return EXIT_FAILURE;
+ }
+
+ if (bytes_written != bytes_read) {
+ fprintf(stderr, "Only wrote %lu of %lu bytes to %s\n",
+ bytes_written, bytes_read, output_name);
+ return EXIT_FAILURE;
+ }
+ }
+ }
+}
+
+static unsigned __stdcall _redirect_stdout_thread(HANDLE h) {
+ adb_thread_setname("stdout redirect");
+ return _redirect_pipe_thread(h, STD_OUTPUT_HANDLE);
+}
+
+static unsigned __stdcall _redirect_stderr_thread(HANDLE h) {
+ adb_thread_setname("stderr redirect");
+ return _redirect_pipe_thread(h, STD_ERROR_HANDLE);
+}
+
+#endif
+
int launch_server(int server_port)
{
#if defined(_WIN32)
@@ -582,58 +688,42 @@
/* we create a PIPE that will be used to wait for the server's "OK" */
/* message since the pipe handles must be inheritable, we use a */
/* security attribute */
- HANDLE nul_read, nul_write;
- HANDLE pipe_read, pipe_write;
- HANDLE stdout_handle, stderr_handle;
SECURITY_ATTRIBUTES sa;
- STARTUPINFOW startup;
- PROCESS_INFORMATION pinfo;
- WCHAR program_path[ MAX_PATH ];
- int ret;
-
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;
- /* Redirect stdin and stderr to Windows /dev/null. If we instead pass our
- * stdin/stderr handles and they are console handles, when the adb server
- * starts up, the C Runtime will see console handles for a process that
- * isn't connected to a console and it will configure stderr to be closed.
- * At that point, freopen() could be used to reopen stderr, but it would
- * take more massaging to fixup the file descriptor number that freopen()
- * uses. It's simplest to avoid all of this complexity by just redirecting
- * stdin/stderr to `nul' and then the C Runtime acts as expected.
- */
- nul_read = CreateFileW(L"nul", GENERIC_READ,
- FILE_SHARE_READ | FILE_SHARE_WRITE, &sa,
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- if (nul_read == INVALID_HANDLE_VALUE) {
- fprintf(stderr, "CreateFileW(nul, GENERIC_READ) failed: %s\n",
+ // Redirect stdin to Windows /dev/null. If we instead pass an original
+ // stdin/stdout/stderr handle and it is a console handle, when the adb
+ // server starts up, the C Runtime will see a console handle for a process
+ // that isn't connected to a console and it will configure
+ // stdin/stdout/stderr to be closed. At that point, freopen() could be used
+ // to reopen stderr/out, but it would take more massaging to fixup the file
+ // descriptor number that freopen() uses. It's simplest to avoid all of this
+ // complexity by just redirecting stdin to `nul' and then the C Runtime acts
+ // as expected.
+ unique_handle nul_read(CreateFileW(L"nul", GENERIC_READ,
+ 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",
SystemErrorCodeToString(GetLastError()).c_str());
return -1;
}
- nul_write = CreateFileW(L"nul", GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE, &sa,
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- if (nul_write == INVALID_HANDLE_VALUE) {
- fprintf(stderr, "CreateFileW(nul, GENERIC_WRITE) failed: %s\n",
- SystemErrorCodeToString(GetLastError()).c_str());
- CloseHandle(nul_read);
+ // create pipes with non-inheritable read handle, inheritable write handle
+ unique_handle ack_read, ack_write;
+ if (!_create_anonymous_pipe(&ack_read, &ack_write, &sa)) {
return -1;
}
-
- /* create pipe, and ensure its read handle isn't inheritable */
- ret = CreatePipe( &pipe_read, &pipe_write, &sa, 0 );
- if (!ret) {
- fprintf(stderr, "CreatePipe() failed: %s\n",
- SystemErrorCodeToString(GetLastError()).c_str());
- CloseHandle(nul_read);
- CloseHandle(nul_write);
+ unique_handle stdout_read, stdout_write;
+ if (!_create_anonymous_pipe(&stdout_read, &stdout_write, &sa)) {
return -1;
}
-
- SetHandleInformation( pipe_read, HANDLE_FLAG_INHERIT, 0 );
+ unique_handle stderr_read, stderr_write;
+ if (!_create_anonymous_pipe(&stderr_read, &stderr_write, &sa)) {
+ return -1;
+ }
/* Some programs want to launch an adb command and collect its output by
* calling CreateProcess with inheritable stdout/stderr handles, then
@@ -645,52 +735,64 @@
* the calling process is stuck while read()-ing from the stdout/stderr
* descriptors, because they're connected to corresponding handles in the
* adb server process (even if the latter never uses/writes to them).
+ * Note that even if we don't pass these handles in the STARTUPINFO struct,
+ * if they're marked inheritable, they're still inherited, requiring us to
+ * deal with this.
+ *
+ * If we're still having problems with inheriting random handles in the
+ * future, consider using PROC_THREAD_ATTRIBUTE_HANDLE_LIST to explicitly
+ * specify which handles should be inherited: http://blogs.msdn.com/b/oldnewthing/archive/2011/12/16/10248328.aspx
*/
- stdout_handle = GetStdHandle( STD_OUTPUT_HANDLE );
- stderr_handle = GetStdHandle( STD_ERROR_HANDLE );
- if (stdout_handle != INVALID_HANDLE_VALUE) {
- SetHandleInformation( stdout_handle, HANDLE_FLAG_INHERIT, 0 );
+ if (!_make_handle_noninheritable(GetStdHandle(STD_INPUT_HANDLE))) {
+ return -1;
}
- if (stderr_handle != INVALID_HANDLE_VALUE) {
- SetHandleInformation( stderr_handle, HANDLE_FLAG_INHERIT, 0 );
+ if (!_make_handle_noninheritable(GetStdHandle(STD_OUTPUT_HANDLE))) {
+ return -1;
+ }
+ if (!_make_handle_noninheritable(GetStdHandle(STD_ERROR_HANDLE))) {
+ return -1;
}
+ STARTUPINFOW startup;
ZeroMemory( &startup, sizeof(startup) );
startup.cb = sizeof(startup);
- startup.hStdInput = nul_read;
- startup.hStdOutput = nul_write;
- startup.hStdError = nul_write;
+ startup.hStdInput = nul_read.get();
+ startup.hStdOutput = stdout_write.get();
+ startup.hStdError = stderr_write.get();
startup.dwFlags = STARTF_USESTDHANDLES;
- ZeroMemory( &pinfo, sizeof(pinfo) );
+ // Verify that the pipe_write handle value can be passed on the command line
+ // as %d and that the rest of adb code can pass it around in an int.
+ const int ack_write_as_int = cast_handle_to_int(ack_write.get());
+ if (cast_int_to_handle(ack_write_as_int) != ack_write.get()) {
+ // 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());
+ return -1;
+ }
- /* get path of current program */
- DWORD module_result = GetModuleFileNameW(NULL, program_path,
- arraysize(program_path));
- if ((module_result == arraysize(program_path)) || (module_result == 0)) {
+ // get path of current program
+ WCHAR program_path[MAX_PATH];
+ const DWORD module_result = GetModuleFileNameW(NULL, program_path,
+ arraysize(program_path));
+ if ((module_result >= arraysize(program_path)) || (module_result == 0)) {
// String truncation or some other error.
- fprintf(stderr, "GetModuleFileNameW() failed: %s\n",
+ fprintf(stderr, "Cannot get executable path: %s\n",
SystemErrorCodeToString(GetLastError()).c_str());
return -1;
}
- // Verify that the pipe_write handle value can be passed on the command line
- // as %d and that the rest of adb code can pass it around in an int.
- const int pipe_write_as_int = cast_handle_to_int(pipe_write);
- if (cast_int_to_handle(pipe_write_as_int) != pipe_write) {
- // 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, "CreatePipe handle value too large: 0x%p\n",
- pipe_write);
- return -1;
- }
-
- WCHAR args[64];
+ WCHAR args[64];
snwprintf(args, arraysize(args),
L"adb -P %d fork-server server --reply-fd %d", server_port,
- pipe_write_as_int);
- ret = CreateProcessW(
+ ack_write_as_int);
+
+ PROCESS_INFORMATION pinfo;
+ ZeroMemory(&pinfo, sizeof(pinfo));
+
+ if (!CreateProcessW(
program_path, /* program path */
args,
/* the fork-server argument will set the
@@ -702,38 +804,113 @@
NULL, /* use parent's environment block */
NULL, /* use parent's starting directory */
&startup, /* startup info, i.e. std handles */
- &pinfo );
-
- CloseHandle( nul_read );
- CloseHandle( nul_write );
- CloseHandle( pipe_write );
-
- if (!ret) {
- fprintf(stderr, "CreateProcess failed: %s\n",
+ &pinfo )) {
+ fprintf(stderr, "Cannot create process: %s\n",
SystemErrorCodeToString(GetLastError()).c_str());
- CloseHandle( pipe_read );
return -1;
}
- CloseHandle( pinfo.hProcess );
- CloseHandle( pinfo.hThread );
+ unique_handle process_handle(pinfo.hProcess);
+ pinfo.hProcess = NULL;
- /* wait for the "OK\n" message */
+ // Close handles that we no longer need to complete the rest.
+ CloseHandle(pinfo.hThread);
+ pinfo.hThread = NULL;
+
+ nul_read.reset();
+ ack_write.reset();
+ stdout_write.reset();
+ stderr_write.reset();
+
+ // Start threads to read from subprocess stdout/stderr and write to ours
+ // to make subprocess errors easier to diagnose.
+
+ // In the past, reading from a pipe before the child process's C Runtime
+ // started up and called GetFileType() caused a hang: http://blogs.msdn.com/b/oldnewthing/archive/2011/12/02/10243553.aspx#10244216
+ // This is reportedly fixed in Windows Vista: https://support.microsoft.com/en-us/kb/2009703
+ // I was unable to reproduce the problem on Windows XP. It sounds like a
+ // Windows Update may have fixed this: https://www.duckware.com/tech/peeknamedpipe.html
+ unique_handle stdout_thread(reinterpret_cast<HANDLE>(
+ _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));
+ return -1;
+ }
+ stdout_read.release(); // Transfer ownership to new thread
+
+ unique_handle stderr_thread(reinterpret_cast<HANDLE>(
+ _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));
+ return -1;
+ }
+ stderr_read.release(); // Transfer ownership to new thread
+
+ bool got_ack = false;
+
+ // Wait for the "OK\n" message, for the pipe to be closed, or other error.
{
- char temp[3];
- DWORD count;
+ char temp[3];
+ DWORD count = 0;
- ret = ReadFile( pipe_read, temp, 3, &count, NULL );
- CloseHandle( pipe_read );
- if ( !ret ) {
- fprintf(stderr, "could not read ok from ADB Server, error: %s\n",
- SystemErrorCodeToString(GetLastError()).c_str());
- return -1;
+ if (ReadFile(ack_read.get(), temp, sizeof(temp), &count, NULL)) {
+ const CHAR expected[] = "OK\n";
+ const DWORD expected_length = arraysize(expected) - 1;
+ if (count == expected_length &&
+ memcmp(temp, expected, expected_length) == 0) {
+ got_ack = true;
+ } else {
+ fprintf(stderr, "ADB server didn't ACK\n");
+ }
+ } else {
+ const DWORD err = GetLastError();
+ // If the ACK was not written and the process exited, GetLastError()
+ // is probably ERROR_BROKEN_PIPE, in which case that info is not
+ // useful to the user.
+ fprintf(stderr, "could not read ok from ADB Server%s\n",
+ err == ERROR_BROKEN_PIPE ? "" :
+ android::base::StringPrintf(": %s",
+ SystemErrorCodeToString(err).c_str()).c_str());
}
- if (count != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
- fprintf(stderr, "ADB server didn't ACK\n" );
- return -1;
+ }
+
+ // Always try to wait a bit for threads reading stdout/stderr to finish.
+ // If the process started ok, it should close the pipes causing the threads
+ // to finish. If the process had an error, it should exit, also causing
+ // the pipes to be closed. In that case we want to read all of the output
+ // and write it out so that the user can diagnose failures.
+ const DWORD thread_timeout_ms = 15 * 1000;
+ const HANDLE threads[] = { stdout_thread.get(), stderr_thread.get() };
+ const DWORD wait_result = WaitForMultipleObjects(arraysize(threads),
+ threads, TRUE, thread_timeout_ms);
+ 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");
+ // 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);
}
+ return -1;
+ }
+
+ if (wait_result != WAIT_OBJECT_0) {
+ fprintf(stderr, "Unexpected result waiting for threads: %lu: %s\n",
+ wait_result, SystemErrorCodeToString(GetLastError()).c_str());
+ return -1;
+ }
+
+ // For now ignore the thread exit codes and assume they worked properly.
+
+ if (!got_ack) {
+ return -1;
}
#else /* !defined(_WIN32) */
char path[PATH_MAX];
@@ -967,8 +1144,7 @@
if (!strncmp(service, "disconnect:", 11)) {
const std::string address(service + 11);
if (address.empty()) {
- // disconnect from all TCP devices
- unregister_all_tcp_transports();
+ kick_all_tcp_devices();
return SendOkay(reply_fd, "disconnected everything");
}
@@ -985,7 +1161,7 @@
return SendFail(reply_fd, android::base::StringPrintf("no such device '%s'",
serial.c_str()));
}
- unregister_transport(t);
+ kick_transport(t);
return SendOkay(reply_fd, android::base::StringPrintf("disconnected %s", address.c_str()));
}
diff --git a/adb/adb.h b/adb/adb.h
index 6855f3b..8b3359e 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -157,8 +157,6 @@
{
void (*func)(void* opaque, atransport* t);
void* opaque;
- adisconnect* next;
- adisconnect* prev;
};
@@ -229,8 +227,8 @@
void connect_to_remote(asocket *s, const char *destination);
void connect_to_smartsocket(asocket *s);
-void fatal(const char *fmt, ...);
-void fatal_errno(const char *fmt, ...);
+void fatal(const char *fmt, ...) __attribute__((noreturn));
+void fatal_errno(const char *fmt, ...) __attribute__((noreturn));
void handle_packet(apacket *p, atransport *t);
diff --git a/adb/adb_auth_client.cpp b/adb/adb_auth_client.cpp
index be28202..c3af024 100644
--- a/adb/adb_auth_client.cpp
+++ b/adb/adb_auth_client.cpp
@@ -47,7 +47,7 @@
static int framework_fd = -1;
static void usb_disconnected(void* unused, atransport* t);
-static struct adisconnect usb_disconnect = { usb_disconnected, 0, 0, 0 };
+static struct adisconnect usb_disconnect = { usb_disconnected, nullptr};
static atransport* usb_transport;
static bool needs_retry = false;
@@ -164,7 +164,6 @@
static void usb_disconnected(void* unused, atransport* t)
{
D("USB disconnect\n");
- remove_transport_disconnect(usb_transport, &usb_disconnect);
usb_transport = NULL;
needs_retry = false;
}
@@ -196,7 +195,7 @@
if (!usb_transport) {
usb_transport = t;
- add_transport_disconnect(t, &usb_disconnect);
+ t->AddDisconnect(&usb_disconnect);
}
if (framework_fd < 0) {
diff --git a/adb/adb_listeners.cpp b/adb/adb_listeners.cpp
index 8fb2d19..d5b1fd5 100644
--- a/adb/adb_listeners.cpp
+++ b/adb/adb_listeners.cpp
@@ -101,13 +101,15 @@
free((char*)l->connect_to);
if (l->transport) {
- remove_transport_disconnect(l->transport, &l->disconnect);
+ l->transport->RemoveDisconnect(&l->disconnect);
}
free(l);
}
-static void listener_disconnect(void* listener, atransport* t) {
- free_listener(reinterpret_cast<alistener*>(listener));
+static void listener_disconnect(void* arg, atransport*) {
+ alistener* listener = reinterpret_cast<alistener*>(arg);
+ listener->transport = nullptr;
+ free_listener(listener);
}
static int local_name_to_fd(const char* name, std::string* error) {
@@ -159,7 +161,7 @@
for (l = listener_list.next; l != &listener_list; l = l->next) {
if (!strcmp(local_name, l->local_name)) {
- listener_disconnect(l, l->transport);
+ free_listener(l);
return INSTALL_STATUS_OK;
}
}
@@ -174,7 +176,7 @@
// Never remove smart sockets.
if (l->connect_to[0] == '*')
continue;
- listener_disconnect(l, l->transport);
+ free_listener(l);
}
}
@@ -209,9 +211,9 @@
free((void*) l->connect_to);
l->connect_to = cto;
if (l->transport != transport) {
- remove_transport_disconnect(l->transport, &l->disconnect);
+ l->transport->RemoveDisconnect(&l->disconnect);
l->transport = transport;
- add_transport_disconnect(l->transport, &l->disconnect);
+ l->transport->AddDisconnect(&l->disconnect);
}
return INSTALL_STATUS_OK;
}
@@ -260,7 +262,7 @@
if (transport) {
listener->disconnect.opaque = listener;
listener->disconnect.func = listener_disconnect;
- add_transport_disconnect(transport, &listener->disconnect);
+ transport->AddDisconnect(&listener->disconnect);
}
return INSTALL_STATUS_OK;
diff --git a/adb/adb_trace.h b/adb/adb_trace.h
index dbc7ec8..4e03165 100644
--- a/adb/adb_trace.h
+++ b/adb/adb_trace.h
@@ -40,22 +40,7 @@
TRACE_SERVICES,
TRACE_AUTH,
TRACE_FDEVENT,
-} ;
-
-#if !ADB_HOST
-/*
- * When running inside the emulator, guest's adbd can connect to 'adb-debug'
- * qemud service that can display adb trace messages (on condition that emulator
- * has been started with '-debug adb' option).
- */
-
-/* Delivers a trace message to the emulator via QEMU pipe. */
-void adb_qemu_trace(const char* fmt, ...);
-/* Macro to use to send ADB trace messages to the emulator. */
-#define DQ(...) adb_qemu_trace(__VA_ARGS__)
-#else
-#define DQ(...) ((void)0)
-#endif /* !ADB_HOST */
+};
extern int adb_trace_mask;
extern unsigned char adb_trace_output_count;
@@ -65,51 +50,43 @@
/* you must define TRACE_TAG before using this macro */
#if ADB_HOST
-# define D(...) \
- do { \
- if (ADB_TRACING) { \
- int save_errno = errno; \
- adb_mutex_lock(&D_lock); \
- fprintf(stderr, "%16s: %5d:%5lu | ", \
- __FUNCTION__, \
- getpid(), adb_thread_id()); \
- errno = save_errno; \
- fprintf(stderr, __VA_ARGS__ ); \
- fflush(stderr); \
- adb_mutex_unlock(&D_lock); \
- errno = save_errno; \
- } \
+# define D(fmt, ...) \
+ do { \
+ if (ADB_TRACING) { \
+ int saved_errno = errno; \
+ adb_mutex_lock(&D_lock); \
+ errno = saved_errno; \
+ fprintf(stderr, "%5d:%5lu %s | " fmt, \
+ getpid(), adb_thread_id(), __FUNCTION__, ## __VA_ARGS__); \
+ fflush(stderr); \
+ adb_mutex_unlock(&D_lock); \
+ errno = saved_errno; \
+ } \
} while (0)
-# define DR(...) \
- do { \
- if (ADB_TRACING) { \
- int save_errno = errno; \
- adb_mutex_lock(&D_lock); \
- errno = save_errno; \
- fprintf(stderr, __VA_ARGS__ ); \
- fflush(stderr); \
- adb_mutex_unlock(&D_lock); \
- errno = save_errno; \
- } \
+# define DR(...) \
+ do { \
+ if (ADB_TRACING) { \
+ int saved_errno = errno; \
+ adb_mutex_lock(&D_lock); \
+ errno = saved_errno; \
+ fprintf(stderr, __VA_ARGS__); \
+ fflush(stderr); \
+ adb_mutex_unlock(&D_lock); \
+ errno = saved_errno; \
+ } \
} while (0)
#else
-# define D(...) \
- do { \
- if (ADB_TRACING) { \
- __android_log_print( \
- ANDROID_LOG_INFO, \
- __FUNCTION__, \
- __VA_ARGS__ ); \
- } \
+# define D(...) \
+ do { \
+ if (ADB_TRACING) { \
+ __android_log_print(ANDROID_LOG_INFO, __FUNCTION__, __VA_ARGS__); \
+ } \
} while (0)
-# define DR(...) \
- do { \
- if (ADB_TRACING) { \
- __android_log_print( \
- ANDROID_LOG_INFO, \
- __FUNCTION__, \
- __VA_ARGS__ ); \
- } \
+# define DR(...) \
+ do { \
+ if (ADB_TRACING) { \
+ __android_log_print(ANDROID_LOG_INFO, __FUNCTION__, __VA_ARGS__); \
+ } \
} while (0)
#endif /* ADB_HOST */
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index 39bb02b..8d644d9 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -36,46 +36,12 @@
#include "adb_listeners.h"
#include "transport.h"
-#if defined(WORKAROUND_BUG6558362) && defined(__linux__)
-static const bool kWorkaroundBug6558362 = true;
-#else
-static const bool kWorkaroundBug6558362 = false;
-#endif
-
-static void adb_workaround_affinity(void) {
-#if defined(__linux__)
- const char affinity_env[] = "ADB_CPU_AFFINITY_BUG6558362";
- const char* cpunum_str = getenv(affinity_env);
- if (cpunum_str == nullptr || *cpunum_str == '\0') {
- return;
- }
-
- char* strtol_res;
- int cpu_num = strtol(cpunum_str, &strtol_res, 0);
- if (*strtol_res != '\0') {
- fatal("bad number (%s) in env var %s. Expecting 0..n.\n", cpunum_str,
- affinity_env);
- }
-
- cpu_set_t cpu_set;
- sched_getaffinity(0, sizeof(cpu_set), &cpu_set);
- D("orig cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]);
-
- CPU_ZERO(&cpu_set);
- CPU_SET(cpu_num, &cpu_set);
- sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
-
- sched_getaffinity(0, sizeof(cpu_set), &cpu_set);
- D("new cpu_set[0]=0x%08lx\n", cpu_set.__bits[0]);
-#else
- // No workaround was ever implemented for the other platforms.
-#endif
-}
-
#if defined(_WIN32)
static const char kNullFileName[] = "NUL";
static BOOL WINAPI ctrlc_handler(DWORD type) {
+ // TODO: Consider trying to kill a starting up adb server (if we're in
+ // launch_server) by calling GenerateConsoleCtrlEvent().
exit(STATUS_CONTROL_C_EXIT);
return TRUE;
}
@@ -128,17 +94,26 @@
}
unix_close(fd);
-#ifdef _WIN32
- // On Windows, stderr is buffered by default, so switch to non-buffered
- // to match Linux.
- setvbuf(stderr, NULL, _IONBF, 0);
-#endif
fprintf(stderr, "--- adb starting (pid %d) ---\n", getpid());
LOG(INFO) << adb_version();
}
int adb_main(int is_daemon, int server_port, int ack_reply_fd) {
#if defined(_WIN32)
+ // adb start-server starts us up with stdout and stderr hooked up to
+ // anonymous pipes to. When the C Runtime sees this, it makes stderr and
+ // stdout buffered, but to improve the chance that error output is seen,
+ // unbuffer stdout and stderr just like if we were run at the console.
+ // This also keeps stderr unbuffered when it is redirected to adb.log.
+ if (is_daemon) {
+ if (setvbuf(stdout, NULL, _IONBF, 0) == -1) {
+ fatal("cannot make stdout unbuffered: %s", strerror(errno));
+ }
+ if (setvbuf(stderr, NULL, _IONBF, 0) == -1) {
+ fatal("cannot make stderr unbuffered: %s", strerror(errno));
+ }
+ }
+
SetConsoleCtrlHandler(ctrlc_handler, TRUE);
#else
signal(SIGPIPE, SIG_IGN);
@@ -146,10 +121,6 @@
init_transport_registration();
- if (kWorkaroundBug6558362 && is_daemon) {
- adb_workaround_affinity();
- }
-
usb_init();
local_init(DEFAULT_ADB_LOCAL_TRANSPORT_PORT);
adb_auth_init();
@@ -162,6 +133,12 @@
// Inform our parent that we are up and running.
if (is_daemon) {
+ close_stdin();
+ setup_daemon_logging();
+
+ // Any error output written to stderr now goes to adb.log. We could
+ // keep around a copy of the stderr fd and use that to write any errors
+ // encountered by the following code, but that is probably overkill.
#if defined(_WIN32)
const HANDLE ack_reply_handle = cast_int_to_handle(ack_reply_fd);
const CHAR ack[] = "OK\n";
@@ -184,8 +161,6 @@
}
unix_close(ack_reply_fd);
#endif
- close_stdin();
- setup_daemon_logging();
}
D("Event loop starting\n");
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index e1e21ed..6325e64 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -276,10 +276,7 @@
count--;
while (count > 0) {
int len = adb_read(fd, buf, count);
- if (len == 0) {
- break;
- } else if (len < 0) {
- if (errno == EINTR) continue;
+ if (len <= 0) {
break;
}
@@ -332,11 +329,7 @@
break;
}
if (len < 0) {
- if (errno == EINTR) {
- D("copy_to_file() : EINTR, retrying\n");
- continue;
- }
- D("copy_to_file() : error %d\n", errno);
+ D("copy_to_file(): read failed: %s\n", strerror(errno));
break;
}
if (outFd == STDOUT_FILENO) {
@@ -381,17 +374,15 @@
fdi = fds[1];
free(fds);
+ adb_thread_setname("stdin reader");
+
while (true) {
/* fdi is really the client's stdin, so use read, not adb_read here */
D("stdin_read_thread(): pre unix_read(fdi=%d,...)\n", fdi);
r = unix_read(fdi, buf, 1024);
D("stdin_read_thread(): post unix_read(fdi=%d,...)\n", fdi);
- if(r == 0) break;
- if(r < 0) {
- if(errno == EINTR) continue;
- break;
- }
- for(n = 0; n < r; n++){
+ if (r <= 0) break;
+ for (n = 0; n < r; n++){
switch(buf[n]) {
case '\n':
state = 1;
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index dc89639..2eba625 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -35,7 +35,6 @@
#include "adb_auth.h"
#include "adb_listeners.h"
#include "transport.h"
-#include "qemu_tracing.h"
static const char* root_seclabel = nullptr;
@@ -262,10 +261,6 @@
adb_trace_init(argv);
- /* If adbd runs inside the emulator this will enable adb tracing via
- * adb-debug qemud service in the emulator. */
- adb_qemu_trace_init();
-
D("Handling main()\n");
return adbd_main(DEFAULT_ADB_PORT);
}
diff --git a/adb/device.py b/adb/device.py
index 5b33ff2..c5b5eea 100644
--- a/adb/device.py
+++ b/adb/device.py
@@ -17,6 +17,7 @@
import os
import re
import subprocess
+import tempfile
class FindDeviceError(RuntimeError):
@@ -99,6 +100,36 @@
return _get_unique_device(product)
+# Call this instead of subprocess.check_output() to work-around issue in Python
+# 2's subprocess class on Windows where it doesn't support Unicode. This
+# writes the command line to a UTF-8 batch file that is properly interpreted
+# by cmd.exe.
+def _subprocess_check_output(*popenargs, **kwargs):
+ # Only do this slow work-around if Unicode is in the cmd line.
+ if (os.name == 'nt' and
+ any(isinstance(arg, unicode) for arg in popenargs[0])):
+ # cmd.exe requires a suffix to know that it is running a batch file
+ tf = tempfile.NamedTemporaryFile('wb', suffix='.cmd', delete=False)
+ # @ in batch suppresses echo of the current line.
+ # Change the codepage to 65001, the UTF-8 codepage.
+ tf.write('@chcp 65001 > nul\r\n')
+ tf.write('@')
+ # Properly quote all the arguments and encode in UTF-8.
+ tf.write(subprocess.list2cmdline(popenargs[0]).encode('utf-8'))
+ tf.close()
+
+ try:
+ result = subprocess.check_output(['cmd.exe', '/c', tf.name],
+ **kwargs)
+ except subprocess.CalledProcessError as e:
+ # Show real command line instead of the cmd.exe command line.
+ raise subprocess.CalledProcessError(e.returncode, popenargs[0],
+ output=e.output)
+ finally:
+ os.remove(tf.name)
+ return result
+ else:
+ return subprocess.check_output(*popenargs, **kwargs)
class AndroidDevice(object):
# Delimiter string to indicate the start of the exit code.
@@ -166,13 +197,13 @@
def _simple_call(self, cmd):
logging.info(' '.join(self.adb_cmd + cmd))
- return subprocess.check_output(
+ return _subprocess_check_output(
self.adb_cmd + cmd, stderr=subprocess.STDOUT)
def shell(self, cmd):
logging.info(' '.join(self.adb_cmd + ['shell'] + cmd))
cmd = self._make_shell_cmd(cmd)
- out = subprocess.check_output(cmd)
+ out = _subprocess_check_output(cmd)
rc, out = self._parse_shell_output(out)
if rc != 0:
error = subprocess.CalledProcessError(rc, cmd)
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index e722d66..d25bbfb 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -205,8 +205,8 @@
n = epoll_wait(epoll_fd, events, 256, -1);
- if(n < 0) {
- if(errno == EINTR) return;
+ if (n < 0) {
+ if (errno == EINTR) return;
perror("epoll_wait");
exit(1);
}
diff --git a/adb/fdevent.h b/adb/fdevent.h
index 8d84b29..ca1494c 100644
--- a/adb/fdevent.h
+++ b/adb/fdevent.h
@@ -23,7 +23,6 @@
#define FDE_READ 0x0001
#define FDE_WRITE 0x0002
#define FDE_ERROR 0x0004
-#define FDE_TIMEOUT 0x0008
/* features that may be set (via the events set/add/del interface) */
#define FDE_DONT_CLOSE 0x0080
diff --git a/adb/fdevent_test.cpp b/adb/fdevent_test.cpp
new file mode 100644
index 0000000..f7622b5
--- /dev/null
+++ b/adb/fdevent_test.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "fdevent.h"
+
+#include <gtest/gtest.h>
+
+#include <queue>
+#include <string>
+#include <vector>
+
+#include <pthread.h>
+#include <signal.h>
+
+#include "adb_io.h"
+
+class SignalHandlerRegister {
+ public:
+ SignalHandlerRegister(const std::vector<int>& signums, void (*handler)(int)) {
+ for (auto& sig : signums) {
+ sig_t old_handler = signal(sig, handler);
+ saved_signal_handlers_.push_back(std::make_pair(sig, old_handler));
+ }
+ }
+
+ ~SignalHandlerRegister() {
+ for (auto& pair : saved_signal_handlers_) {
+ signal(pair.first, pair.second);
+ }
+ }
+
+ private:
+ std::vector<std::pair<int, sig_t>> saved_signal_handlers_;
+};
+
+class FdHandler {
+ public:
+ FdHandler(int read_fd, int write_fd) : read_fd_(read_fd), write_fd_(write_fd) {
+ fdevent_install(&read_fde_, read_fd_, FdEventCallback, this);
+ fdevent_add(&read_fde_, FDE_READ | FDE_ERROR);
+ fdevent_install(&write_fde_, write_fd_, FdEventCallback, this);
+ fdevent_add(&write_fde_, FDE_ERROR);
+ }
+
+ private:
+ static void FdEventCallback(int fd, unsigned events, void* userdata) {
+ FdHandler* handler = reinterpret_cast<FdHandler*>(userdata);
+ ASSERT_EQ(0u, (events & ~(FDE_READ | FDE_WRITE))) << "unexpected events: " << events;
+ if (events & FDE_READ) {
+ ASSERT_EQ(fd, handler->read_fd_);
+ char c;
+ ASSERT_EQ(1, read(fd, &c, 1));
+ handler->queue_.push(c);
+ fdevent_add(&handler->write_fde_, FDE_WRITE);
+ }
+ if (events & FDE_WRITE) {
+ ASSERT_EQ(fd, handler->write_fd_);
+ ASSERT_FALSE(handler->queue_.empty());
+ char c = handler->queue_.front();
+ handler->queue_.pop();
+ ASSERT_EQ(1, write(fd, &c, 1));
+ if (handler->queue_.empty()) {
+ fdevent_del(&handler->write_fde_, FDE_WRITE);
+ }
+ }
+ }
+
+ private:
+ const int read_fd_;
+ const int write_fd_;
+ fdevent read_fde_;
+ fdevent write_fde_;
+ std::queue<char> queue_;
+};
+
+static void signal_handler(int) {
+ pthread_exit(nullptr);
+}
+
+struct ThreadArg {
+ int first_read_fd;
+ int last_write_fd;
+ size_t middle_pipe_count;
+};
+
+static void FdEventThreadFunc(ThreadArg* arg) {
+ SignalHandlerRegister signal_handler_register({SIGUSR1}, signal_handler);
+
+ std::vector<int> read_fds;
+ std::vector<int> write_fds;
+
+ read_fds.push_back(arg->first_read_fd);
+ for (size_t i = 0; i < arg->middle_pipe_count; ++i) {
+ int fds[2];
+ ASSERT_EQ(0, pipe(fds));
+ read_fds.push_back(fds[0]);
+ write_fds.push_back(fds[1]);
+ }
+ write_fds.push_back(arg->last_write_fd);
+
+ std::vector<std::unique_ptr<FdHandler>> fd_handlers;
+ for (size_t i = 0; i < read_fds.size(); ++i) {
+ fd_handlers.push_back(std::unique_ptr<FdHandler>(new FdHandler(read_fds[i], write_fds[i])));
+ }
+
+ fdevent_loop();
+}
+
+TEST(fdevent, smoke) {
+ const size_t PIPE_COUNT = 10;
+ const size_t MESSAGE_LOOP_COUNT = 100;
+ const std::string MESSAGE = "fdevent_test";
+ int fd_pair1[2];
+ int fd_pair2[2];
+ ASSERT_EQ(0, pipe(fd_pair1));
+ ASSERT_EQ(0, pipe(fd_pair2));
+ pthread_t thread;
+ ThreadArg thread_arg;
+ thread_arg.first_read_fd = fd_pair1[0];
+ thread_arg.last_write_fd = fd_pair2[1];
+ thread_arg.middle_pipe_count = PIPE_COUNT;
+ int writer = fd_pair1[1];
+ int reader = fd_pair2[0];
+
+ ASSERT_EQ(0, pthread_create(&thread, nullptr,
+ reinterpret_cast<void* (*)(void*)>(FdEventThreadFunc),
+ &thread_arg));
+
+ for (size_t i = 0; i < MESSAGE_LOOP_COUNT; ++i) {
+ std::string read_buffer = MESSAGE;
+ std::string write_buffer(MESSAGE.size(), 'a');
+ ASSERT_TRUE(WriteFdExactly(writer, read_buffer.c_str(), read_buffer.size()));
+ ASSERT_TRUE(ReadFdExactly(reader, &write_buffer[0], write_buffer.size()));
+ ASSERT_EQ(read_buffer, write_buffer);
+ }
+
+ ASSERT_EQ(0, pthread_kill(thread, SIGUSR1));
+ ASSERT_EQ(0, pthread_join(thread, nullptr));
+}
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index ab11619..94876ee 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -179,44 +179,41 @@
return sync_start_stat(sc, path) && sync_finish_stat(sc, timestamp, mode, size);
}
-static int write_data_file(SyncConnection& sc, const char* path, syncsendbuf* sbuf, bool show_progress) {
- int err = 0;
+static bool write_data_file(SyncConnection& sc, const char* path, syncsendbuf* sbuf, bool show_progress) {
unsigned long long size = 0;
-
- int lfd = adb_open(path, O_RDONLY);
- if (lfd < 0) {
- fprintf(stderr, "cannot open '%s': %s\n", path, strerror(errno));
- return -1;
- }
-
if (show_progress) {
// Determine local file size.
struct stat st;
- if (stat(path, &st)) {
+ if (stat(path, &st) == -1) {
fprintf(stderr, "cannot stat '%s': %s\n", path, strerror(errno));
- return -1;
+ return false;
}
size = st.st_size;
}
+ int lfd = adb_open(path, O_RDONLY);
+ if (lfd < 0) {
+ fprintf(stderr, "cannot open '%s': %s\n", path, strerror(errno));
+ return false;
+ }
+
sbuf->id = ID_DATA;
while (true) {
int ret = adb_read(lfd, sbuf->data, sc.max);
- if (!ret)
- break;
-
- if (ret < 0) {
- if(errno == EINTR)
- continue;
- fprintf(stderr, "cannot read '%s': %s\n", path, strerror(errno));
+ if (ret <= 0) {
+ if (ret < 0) {
+ fprintf(stderr, "cannot read '%s': %s\n", path, strerror(errno));
+ adb_close(lfd);
+ return false;
+ }
break;
}
sbuf->size = ret;
if (!WriteFdExactly(sc.fd, sbuf, sizeof(unsigned) * 2 + ret)) {
- err = -1;
- break;
+ adb_close(lfd);
+ return false;
}
sc.total_bytes += ret;
@@ -226,17 +223,17 @@
}
adb_close(lfd);
- return err;
+ return true;
}
#if defined(_WIN32)
-extern int write_data_link(SyncConnection& sc, const char* path, syncsendbuf* sbuf) __attribute__((error("no symlinks on Windows")));
+extern bool write_data_link(SyncConnection& sc, const char* path, syncsendbuf* sbuf) __attribute__((error("no symlinks on Windows")));
#else
-static int write_data_link(SyncConnection& sc, const char* path, syncsendbuf* sbuf) {
+static bool write_data_link(SyncConnection& sc, const char* path, syncsendbuf* sbuf) {
ssize_t len = readlink(path, sbuf->data, sc.max - 1);
if (len < 0) {
fprintf(stderr, "error reading link '%s': %s\n", path, strerror(errno));
- return -1;
+ return false;
}
sbuf->data[len] = '\0';
@@ -244,12 +241,12 @@
sbuf->id = ID_DATA;
if (!WriteFdExactly(sc.fd, sbuf, sizeof(unsigned) * 2 + len + 1)) {
- return -1;
+ return false;
}
sc.total_bytes += len + 1;
- return 0;
+ return true;
}
#endif
@@ -262,9 +259,9 @@
if (!SendRequest(sc.fd, ID_SEND, path_and_mode.c_str())) goto fail;
if (S_ISREG(mode)) {
- write_data_file(sc, lpath, sbuf, show_progress);
+ if (!write_data_file(sc, lpath, sbuf, show_progress)) return false;
} else if (S_ISLNK(mode)) {
- write_data_link(sc, lpath, sbuf);
+ if (!write_data_link(sc, lpath, sbuf)) return false;
} else {
goto fail;
}
@@ -330,6 +327,7 @@
while (true) {
if(!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
+ adb_close(lfd);
return -1;
}
id = msg.data.id;
diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp
index 3e46447..3793b8e 100644
--- a/adb/file_sync_service.cpp
+++ b/adb/file_sync_service.cpp
@@ -71,6 +71,7 @@
if (chown(partial_path.c_str(), uid, gid) == -1) {
return false;
}
+ // Not all filesystems support setting SELinux labels. http://b/23530370.
selinux_android_restorecon(partial_path.c_str(), 0);
}
}
@@ -128,101 +129,90 @@
return WriteFdExactly(s, &msg.dent, sizeof(msg.dent));
}
-static bool fail_message(int s, const std::string& reason) {
+static bool SendSyncFail(int fd, const std::string& reason) {
D("sync: failure: %s\n", reason.c_str());
syncmsg msg;
msg.data.id = ID_FAIL;
msg.data.size = reason.size();
- return WriteFdExactly(s, &msg.data, sizeof(msg.data)) && WriteFdExactly(s, reason);
+ return WriteFdExactly(fd, &msg.data, sizeof(msg.data)) && WriteFdExactly(fd, reason);
}
-// TODO: callers of this have already failed, and should probably ignore its
-// return value (http://b/23437039).
-static bool fail_errno(int s) {
- return fail_message(s, strerror(errno));
+static bool SendSyncFailErrno(int fd, const std::string& reason) {
+ return SendSyncFail(fd, android::base::StringPrintf("%s: %s", reason.c_str(), strerror(errno)));
}
-static bool handle_send_file(int s, char *path, uid_t uid,
+static bool handle_send_file(int s, const char* path, uid_t uid,
gid_t gid, mode_t mode, std::vector<char>& buffer, bool do_unlink) {
syncmsg msg;
unsigned int timestamp = 0;
int fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
- if(fd < 0 && errno == ENOENT) {
+ if (fd < 0 && errno == ENOENT) {
if (!secure_mkdirs(path)) {
- if (fail_errno(s)) return false;
- fd = -1;
- } else {
- fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
+ SendSyncFailErrno(s, "secure_mkdirs failed");
+ goto fail;
}
+ fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
}
- if(fd < 0 && errno == EEXIST) {
+ if (fd < 0 && errno == EEXIST) {
fd = adb_open_mode(path, O_WRONLY | O_CLOEXEC, mode);
}
- if(fd < 0) {
- if (fail_errno(s)) return false;
- fd = -1;
+ if (fd < 0) {
+ SendSyncFailErrno(s, "couldn't create file");
+ goto fail;
} else {
- if(fchown(fd, uid, gid) != 0) {
- fail_errno(s);
- errno = 0;
+ if (fchown(fd, uid, gid) == -1) {
+ SendSyncFailErrno(s, "fchown failed");
+ goto fail;
}
- /*
- * fchown clears the setuid bit - restore it if present.
- * Ignore the result of calling fchmod. It's not supported
- * by all filesystems. b/12441485
- */
+ // Not all filesystems support setting SELinux labels. http://b/23530370.
+ selinux_android_restorecon(path, 0);
+
+ // fchown clears the setuid bit - restore it if present.
+ // Ignore the result of calling fchmod. It's not supported
+ // by all filesystems. b/12441485
fchmod(fd, mode);
}
while (true) {
unsigned int len;
- if(!ReadFdExactly(s, &msg.data, sizeof(msg.data)))
- goto fail;
+ if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) goto fail;
- if(msg.data.id != ID_DATA) {
- if(msg.data.id == ID_DONE) {
+ if (msg.data.id != ID_DATA) {
+ if (msg.data.id == ID_DONE) {
timestamp = msg.data.size;
break;
}
- fail_message(s, "invalid data message");
+ SendSyncFail(s, "invalid data message");
goto fail;
}
len = msg.data.size;
if (len > buffer.size()) { // TODO: resize buffer?
- fail_message(s, "oversize data message");
+ SendSyncFail(s, "oversize data message");
goto fail;
}
+
if (!ReadFdExactly(s, &buffer[0], len)) goto fail;
- if (fd < 0) continue;
-
if (!WriteFdExactly(fd, &buffer[0], len)) {
- int saved_errno = errno;
- adb_close(fd);
- if (do_unlink) adb_unlink(path);
- fd = -1;
- errno = saved_errno;
- if (fail_errno(s)) return false;
+ SendSyncFailErrno(s, "write failed");
+ goto fail;
}
}
- if(fd >= 0) {
- struct utimbuf u;
- adb_close(fd);
- selinux_android_restorecon(path, 0);
- u.actime = timestamp;
- u.modtime = timestamp;
- utime(path, &u);
+ adb_close(fd);
- msg.status.id = ID_OKAY;
- msg.status.msglen = 0;
- if (!WriteFdExactly(s, &msg.status, sizeof(msg.status))) return false;
- }
- return true;
+ utimbuf u;
+ u.actime = timestamp;
+ u.modtime = timestamp;
+ utime(path, &u);
+
+ msg.status.id = ID_OKAY;
+ msg.status.msglen = 0;
+ return WriteFdExactly(s, &msg.status, sizeof(msg.status));
fail:
if (fd >= 0) adb_close(fd);
@@ -231,9 +221,9 @@
}
#if defined(_WIN32)
-extern bool handle_send_link(int s, char *path, std::vector<char>& buffer) __attribute__((error("no symlinks on Windows")));
+extern bool handle_send_link(int s, const std::string& path, std::vector<char>& buffer) __attribute__((error("no symlinks on Windows")));
#else
-static bool handle_send_link(int s, char *path, std::vector<char>& buffer) {
+static bool handle_send_link(int s, const std::string& path, std::vector<char>& buffer) {
syncmsg msg;
unsigned int len;
int ret;
@@ -241,27 +231,27 @@
if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) return false;
if (msg.data.id != ID_DATA) {
- fail_message(s, "invalid data message: expected ID_DATA");
+ SendSyncFail(s, "invalid data message: expected ID_DATA");
return false;
}
len = msg.data.size;
if (len > buffer.size()) { // TODO: resize buffer?
- fail_message(s, "oversize data message");
+ SendSyncFail(s, "oversize data message");
return false;
}
if (!ReadFdExactly(s, &buffer[0], len)) return false;
- ret = symlink(&buffer[0], path);
+ ret = symlink(&buffer[0], path.c_str());
if (ret && errno == ENOENT) {
if (!secure_mkdirs(path)) {
- fail_errno(s);
+ SendSyncFailErrno(s, "secure_mkdirs failed");
return false;
}
- ret = symlink(&buffer[0], path);
+ ret = symlink(&buffer[0], path.c_str());
}
if (ret) {
- fail_errno(s);
+ SendSyncFailErrno(s, "symlink failed");
return false;
}
@@ -272,7 +262,7 @@
msg.status.msglen = 0;
if (!WriteFdExactly(s, &msg.status, sizeof(msg.status))) return false;
} else {
- fail_message(s, "invalid data message: expected ID_DONE");
+ SendFail(s, "invalid data message: expected ID_DONE");
return false;
}
@@ -280,59 +270,55 @@
}
#endif
-static bool do_send(int s, char* path, std::vector<char>& buffer) {
- unsigned int mode;
- bool is_link = false;
- bool do_unlink;
-
- char* tmp = strrchr(path,',');
- if(tmp) {
- *tmp = 0;
- errno = 0;
- mode = strtoul(tmp + 1, NULL, 0);
- is_link = S_ISLNK((mode_t) mode);
- mode &= 0777;
- }
- if(!tmp || errno) {
- mode = 0644;
- is_link = 0;
- do_unlink = true;
- } else {
- struct stat st;
- /* Don't delete files before copying if they are not "regular" */
- do_unlink = lstat(path, &st) || S_ISREG(st.st_mode) || S_ISLNK(st.st_mode);
- if (do_unlink) {
- adb_unlink(path);
- }
+static bool do_send(int s, const std::string& spec, std::vector<char>& buffer) {
+ // 'spec' is of the form "/some/path,0755". Break it up.
+ size_t comma = spec.find_last_of(',');
+ if (comma == std::string::npos) {
+ SendFail(s, "missing , in ID_SEND");
+ return false;
}
- if (is_link) {
- return handle_send_link(s, path, buffer);
+ std::string path = spec.substr(0, comma);
+
+ errno = 0;
+ mode_t mode = strtoul(spec.substr(comma + 1).c_str(), nullptr, 0);
+ if (errno != 0) {
+ SendFail(s, "bad mode");
+ return false;
}
+ // Don't delete files before copying if they are not "regular" or symlinks.
+ struct stat st;
+ bool do_unlink = (lstat(path.c_str(), &st) == -1) || S_ISREG(st.st_mode) || S_ISLNK(st.st_mode);
+ if (do_unlink) {
+ adb_unlink(path.c_str());
+ }
+
+ if (S_ISLNK(mode)) {
+ return handle_send_link(s, path.c_str(), buffer);
+ }
+
+ // Copy user permission bits to "group" and "other" permissions.
+ mode &= 0777;
+ mode |= ((mode >> 3) & 0070);
+ mode |= ((mode >> 3) & 0007);
+
uid_t uid = -1;
gid_t gid = -1;
uint64_t cap = 0;
-
- /* copy user permission bits to "group" and "other" permissions */
- mode |= ((mode >> 3) & 0070);
- mode |= ((mode >> 3) & 0007);
-
- tmp = path;
- if(*tmp == '/') {
- tmp++;
- }
if (should_use_fs_config(path)) {
- fs_config(tmp, 0, &uid, &gid, &mode, &cap);
+ unsigned int broken_api_hack = mode;
+ fs_config(path.c_str(), 0, &uid, &gid, &broken_api_hack, &cap);
+ mode = broken_api_hack;
}
- return handle_send_file(s, path, uid, gid, mode, buffer, do_unlink);
+ return handle_send_file(s, path.c_str(), uid, gid, mode, buffer, do_unlink);
}
static bool do_recv(int s, const char* path, std::vector<char>& buffer) {
int fd = adb_open(path, O_RDONLY | O_CLOEXEC);
if (fd < 0) {
- if (fail_errno(s)) return false;
- return true;
+ SendSyncFailErrno(s, "open failed");
+ return false;
}
syncmsg msg;
@@ -341,10 +327,9 @@
int r = adb_read(fd, &buffer[0], buffer.size());
if (r <= 0) {
if (r == 0) break;
- if (errno == EINTR) continue;
- bool status = fail_errno(s);
+ SendSyncFailErrno(s, "read failed");
adb_close(fd);
- return status;
+ return false;
}
msg.data.size = r;
if (!WriteFdExactly(s, &msg.data, sizeof(msg.data)) || !WriteFdExactly(s, &buffer[0], r)) {
@@ -365,17 +350,17 @@
SyncRequest request;
if (!ReadFdExactly(fd, &request, sizeof(request))) {
- fail_message(fd, "command read failure");
+ SendSyncFail(fd, "command read failure");
return false;
}
size_t path_length = request.path_length;
if (path_length > 1024) {
- fail_message(fd, "path too long");
+ SendSyncFail(fd, "path too long");
return false;
}
char name[1025];
if (!ReadFdExactly(fd, name, path_length)) {
- fail_message(fd, "filename read failure");
+ SendSyncFail(fd, "filename read failure");
return false;
}
name[path_length] = 0;
@@ -399,7 +384,7 @@
case ID_QUIT:
return false;
default:
- fail_message(fd, android::base::StringPrintf("unknown command '%.4s' (%08x)",
+ SendSyncFail(fd, android::base::StringPrintf("unknown command '%.4s' (%08x)",
id, request.id));
return false;
}
diff --git a/adb/qemu_tracing.cpp b/adb/qemu_tracing.cpp
deleted file mode 100644
index f31eae8..0000000
--- a/adb/qemu_tracing.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Implements ADB tracing inside the emulator.
- */
-
-#include <stdarg.h>
-
-#include "sysdeps.h"
-#include "qemu_tracing.h"
-
-/*
- * Redefine open and write for qemu_pipe.h that contains inlined references
- * to those routines. We will redifine them back after qemu_pipe.h inclusion.
- */
-
-#undef open
-#undef write
-#define open adb_open
-#define write adb_write
-#include <hardware/qemu_pipe.h>
-#undef open
-#undef write
-#define open ___xxx_open
-#define write ___xxx_write
-
-/* A handle to adb-debug qemud service in the emulator. */
-int adb_debug_qemu = -1;
-
-/* Initializes connection with the adb-debug qemud service in the emulator. */
-int adb_qemu_trace_init(void)
-{
- char con_name[32];
-
- if (adb_debug_qemu >= 0) {
- return 0;
- }
-
- /* adb debugging QEMUD service connection request. */
- snprintf(con_name, sizeof(con_name), "qemud:adb-debug");
- adb_debug_qemu = qemu_pipe_open(con_name);
- return (adb_debug_qemu >= 0) ? 0 : -1;
-}
-
-void adb_qemu_trace(const char* fmt, ...)
-{
- va_list args;
- va_start(args, fmt);
- char msg[1024];
-
- if (adb_debug_qemu >= 0) {
- vsnprintf(msg, sizeof(msg), fmt, args);
- adb_write(adb_debug_qemu, msg, strlen(msg));
- }
-}
diff --git a/adb/qemu_tracing.h b/adb/qemu_tracing.h
deleted file mode 100644
index ff42d4f..0000000
--- a/adb/qemu_tracing.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Implements ADB tracing inside the emulator.
- */
-
-#ifndef __QEMU_TRACING_H
-#define __QEMU_TRACING_H
-
-/* Initializes connection with the adb-debug qemud service in the emulator. */
-int adb_qemu_trace_init(void);
-void adb_qemu_trace(const char* fmt, ...);
-
-#endif /* __QEMU_TRACING_H */
diff --git a/adb/services.cpp b/adb/services.cpp
index c8c2d54..4606804 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -67,6 +67,7 @@
void *service_bootstrap_func(void *x)
{
stinfo* sti = reinterpret_cast<stinfo*>(x);
+ adb_thread_setname(android::base::StringPrintf("service %d", sti->fd));
sti->func(sti->fd, sti->cookie);
free(sti);
return 0;
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index d8ea2ee..9c13936 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -360,9 +360,12 @@
} else {
p->len = max_payload - avail;
+ // s->peer->enqueue() may call s->close() and free s,
+ // so save variables for debug printing below.
+ unsigned saved_id = s->id;
+ int saved_fd = s->fd;
r = s->peer->enqueue(s->peer, p);
- D("LS(%d): fd=%d post peer->enqueue(). r=%d\n", s->id, s->fd,
- r);
+ D("LS(%u): fd=%d post peer->enqueue(). r=%d\n", saved_id, saved_fd, r);
if (r < 0) {
/* error return means they closed us as a side-effect
@@ -468,14 +471,6 @@
}
#endif /* ADB_HOST */
-/* a Remote socket is used to send/receive data to/from a given transport object
-** it needs to be closed when the transport is forcibly destroyed by the user
-*/
-struct aremotesocket {
- asocket socket;
- adisconnect disconnect;
-};
-
static int remote_socket_enqueue(asocket *s, apacket *p)
{
D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d\n",
@@ -523,33 +518,17 @@
D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d\n",
s->id, s->fd, s->peer?s->peer->fd:-1);
D("RS(%d): closed\n", s->id);
- remove_transport_disconnect( s->transport, &((aremotesocket*)s)->disconnect );
free(s);
}
-static void remote_socket_disconnect(void* _s, atransport* t)
-{
- asocket* s = reinterpret_cast<asocket*>(_s);
- asocket* peer = s->peer;
-
- D("remote_socket_disconnect RS(%d)\n", s->id);
- if (peer) {
- peer->peer = NULL;
- peer->close(peer);
- }
- remove_transport_disconnect( s->transport, &((aremotesocket*)s)->disconnect );
- free(s);
-}
-
-/* Create an asocket to exchange packets with a remote service through transport
- |t|. Where |id| is the socket id of the corresponding service on the other
- side of the transport (it is allocated by the remote side and _cannot_ be 0).
- Returns a new non-NULL asocket handle. */
+// Create a remote socket to exchange packets with a remote service through transport
+// |t|. Where |id| is the socket id of the corresponding service on the other
+// side of the transport (it is allocated by the remote side and _cannot_ be 0).
+// Returns a new non-NULL asocket handle.
asocket *create_remote_socket(unsigned id, atransport *t)
{
if (id == 0) fatal("invalid remote socket id (0)");
- asocket* s = reinterpret_cast<asocket*>(calloc(1, sizeof(aremotesocket)));
- adisconnect* dis = &reinterpret_cast<aremotesocket*>(s)->disconnect;
+ asocket* s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket)));
if (s == NULL) fatal("cannot allocate socket");
s->id = id;
@@ -559,9 +538,6 @@
s->close = remote_socket_close;
s->transport = t;
- dis->func = remote_socket_disconnect;
- dis->opaque = s;
- add_transport_disconnect( t, dis );
D("RS(%d): created\n", s->id);
return s;
}
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 6f3c443..5918a94 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -71,6 +71,7 @@
#include <windows.h>
#include <ws2tcpip.h>
+#include <memory> // unique_ptr
#include <string> // Prototypes for narrow() and widen() use std::(w)string.
#include "fdevent.h"
@@ -110,6 +111,13 @@
return (tid != static_cast<uintptr_t>(-1L));
}
+static __inline__ int adb_thread_setname(const std::string& name) {
+ // TODO: See https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx for how to set
+ // the thread name in Windows. Unfortunately, it only works during debugging, but
+ // our build process doesn't generate PDB files needed for debugging.
+ return 0;
+}
+
static __inline__ unsigned long adb_thread_id()
{
return GetCurrentThreadId();
@@ -355,6 +363,21 @@
return reinterpret_cast<HANDLE>(static_cast<INT_PTR>(fd));
}
+// Deleter for unique_handle. Adapted from many sources, including:
+// http://stackoverflow.com/questions/14841396/stdunique-ptr-deleters-and-the-win32-api
+// https://visualstudiomagazine.com/articles/2013/09/01/get-a-handle-on-the-windows-api.aspx
+class handle_deleter {
+public:
+ typedef HANDLE pointer;
+
+ void operator()(HANDLE h);
+};
+
+// Like std::unique_ptr, but for Windows HANDLE objects that should be
+// CloseHandle()'d. Operator bool() only checks if the handle != nullptr,
+// but does not check if the handle != INVALID_HANDLE_VALUE.
+typedef std::unique_ptr<HANDLE, handle_deleter> unique_handle;
+
#else /* !_WIN32 a.k.a. Unix */
#include "fdevent.h"
@@ -601,7 +624,26 @@
return (errno == 0);
}
-static __inline__ int adb_socket_setbufsize( int fd, int bufsize )
+static __inline__ int adb_thread_setname(const std::string& name) {
+#ifdef __APPLE__
+ return pthread_setname_np(name.c_str());
+#else
+ const char *s = name.c_str();
+
+ // pthread_setname_np fails rather than truncating long strings.
+ const int max_task_comm_len = 16; // including the null terminator
+ if (name.length() > (max_task_comm_len - 1)) {
+ char buf[max_task_comm_len];
+ strncpy(buf, name.c_str(), sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = '\0';
+ s = buf;
+ }
+
+ return pthread_setname_np(pthread_self(), s) ;
+#endif
+}
+
+static __inline__ int adb_socket_setbufsize(int fd, int bufsize )
{
int opt = bufsize;
return setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index f534d61..015f89e 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -112,6 +112,22 @@
return msg;
}
+void handle_deleter::operator()(HANDLE h) {
+ // CreateFile() is documented to return INVALID_HANDLE_FILE on error,
+ // implying that NULL is a valid handle, but this is probably impossible.
+ // Other APIs like CreateEvent() are documented to return NULL on error,
+ // implying that INVALID_HANDLE_VALUE is a valid handle, but this is also
+ // probably impossible. Thus, consider both NULL and INVALID_HANDLE_VALUE
+ // as invalid handles. std::unique_ptr won't call a deleter with NULL, so we
+ // only need to check for INVALID_HANDLE_VALUE.
+ if (h != INVALID_HANDLE_VALUE) {
+ if (!CloseHandle(h)) {
+ D("CloseHandle(%p) failed: %s\n", h,
+ SystemErrorCodeToString(GetLastError()).c_str());
+ }
+ }
+}
+
/**************************************************************************/
/**************************************************************************/
/***** *****/
diff --git a/adb/test_device.py b/adb/test_device.py
index c893ad4..2006937 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -215,12 +215,18 @@
def test_install_argument_escaping(self):
"""Make sure that install argument escaping works."""
# http://b/20323053
- tf = tempfile.NamedTemporaryFile('wb', suffix='-text;ls;1.apk')
+ tf = tempfile.NamedTemporaryFile('wb', suffix='-text;ls;1.apk',
+ delete=False)
+ tf.close()
self.assertIn("-text;ls;1.apk", self.device.install(tf.name))
+ os.remove(tf.name)
# http://b/3090932
- tf = tempfile.NamedTemporaryFile('wb', suffix="-Live Hold'em.apk")
+ tf = tempfile.NamedTemporaryFile('wb', suffix="-Live Hold'em.apk",
+ delete=False)
+ tf.close()
self.assertIn("-Live Hold'em.apk", self.device.install(tf.name))
+ os.remove(tf.name)
class RootUnrootTest(DeviceTest):
@@ -451,19 +457,24 @@
def test_unicode_paths(self):
"""Ensure that we can support non-ASCII paths, even on Windows."""
- name = u'로보카 폴리'.encode('utf-8')
+ name = u'로보카 폴리'
## push.
- tf = tempfile.NamedTemporaryFile('wb', suffix=name)
- self.device.push(tf.name, '/data/local/tmp/adb-test-{}'.format(name))
+ tf = tempfile.NamedTemporaryFile('wb', suffix=name, delete=False)
+ tf.close()
+ self.device.push(tf.name, u'/data/local/tmp/adb-test-{}'.format(name))
+ os.remove(tf.name)
self.device.shell(['rm', '-f', '/data/local/tmp/adb-test-*'])
# pull.
- cmd = ['touch', '"/data/local/tmp/adb-test-{}"'.format(name)]
+ cmd = ['touch', u'"/data/local/tmp/adb-test-{}"'.format(name)]
self.device.shell(cmd)
- tf = tempfile.NamedTemporaryFile('wb', suffix=name)
- self.device.pull('/data/local/tmp/adb-test-{}'.format(name), tf.name)
+ tf = tempfile.NamedTemporaryFile('wb', suffix=name, delete=False)
+ tf.close()
+ self.device.pull(u'/data/local/tmp/adb-test-{}'.format(name), tf.name)
+ os.remove(tf.name)
+ self.device.shell(['rm', '-f', '/data/local/tmp/adb-test-*'])
def main():
diff --git a/adb/transport.cpp b/adb/transport.cpp
index ea673f2..5a962de 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -28,6 +28,7 @@
#include <list>
+#include <base/logging.h>
#include <base/stringprintf.h>
#include <base/strings.h>
@@ -41,53 +42,6 @@
ADB_MUTEX_DEFINE( transport_lock );
-void kick_transport(atransport* t)
-{
- if (t && !t->kicked)
- {
- int kicked;
-
- adb_mutex_lock(&transport_lock);
- kicked = t->kicked;
- if (!kicked)
- t->kicked = 1;
- adb_mutex_unlock(&transport_lock);
-
- if (!kicked)
- t->kick(t);
- }
-}
-
-// Each atransport contains a list of adisconnects (t->disconnects).
-// An adisconnect contains a link to the next/prev adisconnect, a function
-// pointer to a disconnect callback which takes a void* piece of user data and
-// the atransport, and some user data for the callback (helpfully named
-// "opaque").
-//
-// The list is circular. New items are added to the entry member of the list
-// (t->disconnects) by add_transport_disconnect.
-//
-// run_transport_disconnects invokes each function in the list.
-//
-// Gotchas:
-// * run_transport_disconnects assumes that t->disconnects is non-null, so
-// this can't be run on a zeroed atransport.
-// * The callbacks in this list are not removed when called, and this function
-// is not guarded against running more than once. As such, ensure that this
-// function is not called multiple times on the same atransport.
-// TODO(danalbert): Just fix this so that it is guarded once you have tests.
-void run_transport_disconnects(atransport* t)
-{
- adisconnect* dis = t->disconnects.next;
-
- D("%s: run_transport_disconnects\n", t->serial);
- while (dis != &t->disconnects) {
- adisconnect* next = dis->next;
- dis->func( dis->opaque, t );
- dis = next;
- }
-}
-
static void dump_packet(const char* name, const char* func, apacket* p) {
unsigned command = p->msg.command;
int len = p->msg.data_length;
@@ -140,8 +94,7 @@
len -= r;
p += r;
} else {
- D("%s: read_packet (fd=%d), error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno));
- if((r < 0) && (errno == EINTR)) continue;
+ D("%s: read_packet (fd=%d), error ret=%d: %s\n", name, fd, r, strerror(errno));
return -1;
}
}
@@ -171,8 +124,7 @@
len -= r;
p += r;
} else {
- D("%s: write_packet (fd=%d) error ret=%d errno=%d: %s\n", name, fd, r, errno, strerror(errno));
- if((r < 0) && (errno == EINTR)) continue;
+ D("%s: write_packet (fd=%d) error ret=%d: %s\n", name, fd, r, strerror(errno));
return -1;
}
}
@@ -223,25 +175,27 @@
}
}
-/* The transport is opened by transport_register_func before
-** the input and output threads are started.
-**
-** The output thread issues a SYNC(1, token) message to let
-** the input thread know to start things up. In the event
-** of transport IO failure, the output thread will post a
-** SYNC(0,0) message to ensure shutdown.
-**
-** The transport will not actually be closed until both
-** threads exit, but the input thread will kick the transport
-** on its way out to disconnect the underlying device.
-*/
-
-static void *output_thread(void *_t)
+// The transport is opened by transport_register_func before
+// the read_transport and write_transport threads are started.
+//
+// The read_transport thread issues a SYNC(1, token) message to let
+// the write_transport thread know to start things up. In the event
+// of transport IO failure, the read_transport thread will post a
+// SYNC(0,0) message to ensure shutdown.
+//
+// The transport will not actually be closed until both threads exit, but the threads
+// will kick the transport on their way out to disconnect the underlying device.
+//
+// read_transport thread reads data from a transport (representing a usb/tcp connection),
+// and makes the main thread call handle_packet().
+static void *read_transport_thread(void *_t)
{
atransport *t = reinterpret_cast<atransport*>(_t);
apacket *p;
- D("%s: starting transport output thread on fd %d, SYNC online (%d)\n",
+ adb_thread_setname(android::base::StringPrintf("<-%s",
+ (t->serial != nullptr ? t->serial : "transport")));
+ D("%s: starting read_transport thread on fd %d, SYNC online (%d)\n",
t->serial, t->fd, t->sync_token + 1);
p = get_apacket();
p->msg.command = A_SYNC;
@@ -285,19 +239,23 @@
}
oops:
- D("%s: transport output thread is exiting\n", t->serial);
+ D("%s: read_transport thread is exiting\n", t->serial);
kick_transport(t);
transport_unref(t);
return 0;
}
-static void *input_thread(void *_t)
+// write_transport thread gets packets sent by the main thread (through send_packet()),
+// and writes to a transport (representing a usb/tcp connection).
+static void *write_transport_thread(void *_t)
{
atransport *t = reinterpret_cast<atransport*>(_t);
apacket *p;
int active = 0;
- D("%s: starting transport input thread, reading from fd %d\n",
+ adb_thread_setname(android::base::StringPrintf("->%s",
+ (t->serial != nullptr ? t->serial : "transport")));
+ D("%s: starting write_transport thread, reading from fd %d\n",
t->serial, t->fd);
for(;;){
@@ -332,16 +290,25 @@
put_apacket(p);
}
- // this is necessary to avoid a race condition that occured when a transport closes
- // while a client socket is still active.
- close_all_sockets(t);
-
- D("%s: transport input thread is exiting, fd %d\n", t->serial, t->fd);
+ D("%s: write_transport thread is exiting, fd %d\n", t->serial, t->fd);
kick_transport(t);
transport_unref(t);
return 0;
}
+static void kick_transport_locked(atransport* t) {
+ CHECK(t != nullptr);
+ if (!t->kicked) {
+ t->kicked = true;
+ t->kick(t);
+ }
+}
+
+void kick_transport(atransport* t) {
+ adb_mutex_lock(&transport_lock);
+ kick_transport_locked(t);
+ adb_mutex_unlock(&transport_lock);
+}
static int transport_registration_send = -1;
static int transport_registration_recv = -1;
@@ -489,9 +456,7 @@
len -= r;
p += r;
} else {
- if((r < 0) && (errno == EINTR)) continue;
- D("transport_read_action: on fd %d, error %d: %s\n",
- fd, errno, strerror(errno));
+ D("transport_read_action: on fd %d: %s\n", fd, strerror(errno));
return -1;
}
}
@@ -511,9 +476,7 @@
len -= r;
p += r;
} else {
- if((r < 0) && (errno == EINTR)) continue;
- D("transport_write_action: on fd %d, error %d: %s\n",
- fd, errno, strerror(errno));
+ D("transport_write_action: on fd %d: %s\n", fd, strerror(errno));
return -1;
}
}
@@ -549,8 +512,6 @@
transport_list.remove(t);
adb_mutex_unlock(&transport_lock);
- run_transport_disconnects(t);
-
if (t->product)
free(t->product);
if (t->serial)
@@ -589,12 +550,12 @@
fdevent_set(&(t->transport_fde), FDE_READ);
- if (!adb_thread_create(input_thread, t)) {
- fatal_errno("cannot create input thread");
+ if (!adb_thread_create(write_transport_thread, t)) {
+ fatal_errno("cannot create write_transport thread");
}
- if (!adb_thread_create(output_thread, t)) {
- fatal_errno("cannot create output thread");
+ if (!adb_thread_create(read_transport_thread, t)) {
+ fatal_errno("cannot create read_transport thread");
}
}
@@ -603,8 +564,6 @@
transport_list.push_front(t);
adb_mutex_unlock(&transport_lock);
- t->disconnects.next = t->disconnects.prev = &t->disconnects;
-
update_transports();
}
@@ -652,48 +611,22 @@
}
-static void transport_unref_locked(atransport *t)
-{
+static void transport_unref(atransport* t) {
+ CHECK(t != nullptr);
+ adb_mutex_lock(&transport_lock);
+ CHECK_GT(t->ref_count, 0u);
t->ref_count--;
if (t->ref_count == 0) {
D("transport: %s unref (kicking and closing)\n", t->serial);
- if (!t->kicked) {
- t->kicked = 1;
- t->kick(t);
- }
+ kick_transport_locked(t);
t->close(t);
remove_transport(t);
} else {
- D("transport: %s unref (count=%d)\n", t->serial, t->ref_count);
+ D("transport: %s unref (count=%zu)\n", t->serial, t->ref_count);
}
-}
-
-static void transport_unref(atransport *t)
-{
- if (t) {
- adb_mutex_lock(&transport_lock);
- transport_unref_locked(t);
- adb_mutex_unlock(&transport_lock);
- }
-}
-
-void add_transport_disconnect(atransport* t, adisconnect* dis)
-{
- adb_mutex_lock(&transport_lock);
- dis->next = &t->disconnects;
- dis->prev = dis->next->prev;
- dis->prev->next = dis;
- dis->next->prev = dis;
adb_mutex_unlock(&transport_lock);
}
-void remove_transport_disconnect(atransport* t, adisconnect* dis)
-{
- dis->prev->next = dis->next;
- dis->next->prev = dis->prev;
- dis->next = dis->prev = dis;
-}
-
static int qual_match(const char *to_test,
const char *prefix, const char *qual, bool sanitize_qual)
{
@@ -868,6 +801,21 @@
return has_feature(feature) && supported_features().count(feature) > 0;
}
+void atransport::AddDisconnect(adisconnect* disconnect) {
+ disconnects_.push_back(disconnect);
+}
+
+void atransport::RemoveDisconnect(adisconnect* disconnect) {
+ disconnects_.remove(disconnect);
+}
+
+void atransport::RunDisconnects() {
+ for (auto& disconnect : disconnects_) {
+ disconnect->func(disconnect->opaque, this);
+ }
+ disconnects_.clear();
+}
+
#if ADB_HOST
static void append_transport_info(std::string* result, const char* key,
@@ -977,7 +925,7 @@
atransport* result = nullptr;
adb_mutex_lock(&transport_lock);
- for (auto t : transport_list) {
+ for (auto& t : transport_list) {
if (t->serial && strcmp(serial, t->serial) == 0) {
result = t;
break;
@@ -988,35 +936,18 @@
return result;
}
-void unregister_transport(atransport *t)
-{
+void kick_all_tcp_devices() {
adb_mutex_lock(&transport_lock);
- transport_list.remove(t);
- adb_mutex_unlock(&transport_lock);
-
- kick_transport(t);
- transport_unref(t);
-}
-
-// Unregisters all non-emulator TCP transports.
-void unregister_all_tcp_transports() {
- adb_mutex_lock(&transport_lock);
- for (auto it = transport_list.begin(); it != transport_list.end(); ) {
- atransport* t = *it;
+ for (auto& t : transport_list) {
+ // TCP/IP devices have adb_port == 0.
if (t->type == kTransportLocal && t->adb_port == 0) {
- // We cannot call kick_transport when holding transport_lock.
- if (!t->kicked) {
- t->kicked = 1;
- t->kick(t);
- }
- transport_unref_locked(t);
-
- it = transport_list.erase(it);
- } else {
- ++it;
+ // Kicking breaks the read_transport thread of this transport out of any read, then
+ // the read_transport thread will notify the main thread to make this transport
+ // offline. Then the main thread will notify the write_transport thread to exit.
+ // Finally, this transport will be closed and freed in the main thread.
+ kick_transport_locked(t);
}
}
-
adb_mutex_unlock(&transport_lock);
}
diff --git a/adb/transport.h b/adb/transport.h
index e809407..3b56c55 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -19,6 +19,7 @@
#include <sys/types.h>
+#include <list>
#include <string>
#include <unordered_set>
@@ -52,7 +53,7 @@
int fd = -1;
int transport_socket = -1;
fdevent transport_fde;
- int ref_count = 0;
+ size_t ref_count = 0;
uint32_t sync_token = 0;
ConnectionState connection_state = kCsOffline;
bool online = false;
@@ -71,9 +72,6 @@
int adb_port = -1; // Use for emulators (local transport)
bool kicked = false;
- // A list of adisconnect callbacks called when the transport is kicked.
- adisconnect disconnects = {};
-
void* key = nullptr;
unsigned char token[TOKEN_SIZE] = {};
fdevent auth_fde;
@@ -96,6 +94,10 @@
// feature.
bool CanUseFeature(const std::string& feature) const;
+ void AddDisconnect(adisconnect* disconnect);
+ void RemoveDisconnect(adisconnect* disconnect);
+ void RunDisconnects();
+
private:
// A set of features transmitted in the banner with the initial connection.
// This is stored in the banner as 'features=feature0,feature1,etc'.
@@ -103,6 +105,9 @@
int protocol_version;
size_t max_payload;
+ // A list of adisconnect callbacks called when the transport is kicked.
+ std::list<adisconnect*> disconnects_;
+
DISALLOW_COPY_AND_ASSIGN(atransport);
};
@@ -114,18 +119,13 @@
*/
atransport* acquire_one_transport(ConnectionState state, TransportType type,
const char* serial, std::string* error_out);
-void add_transport_disconnect(atransport* t, adisconnect* dis);
-void remove_transport_disconnect(atransport* t, adisconnect* dis);
void kick_transport(atransport* t);
-void run_transport_disconnects(atransport* t);
void update_transports(void);
-/* transports are ref-counted
-** get_device_transport does an acquire on your behalf before returning
-*/
void init_transport_registration(void);
std::string list_transports(bool long_listing);
atransport* find_transport(const char* serial);
+void kick_all_tcp_devices();
void register_usb_transport(usb_handle* h, const char* serial,
const char* devpath, unsigned writeable);
@@ -136,10 +136,6 @@
// This should only be used for transports with connection_state == kCsNoPerm.
void unregister_usb_transport(usb_handle* usb);
-/* these should only be used for the "adb disconnect" command */
-void unregister_transport(atransport* t);
-void unregister_all_tcp_transports();
-
int check_header(apacket* p, atransport* t);
int check_data(apacket* p);
diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp
index 6a17497..6821cfc 100644
--- a/adb/transport_local.cpp
+++ b/adb/transport_local.cpp
@@ -123,6 +123,7 @@
#if ADB_HOST
static void *client_socket_thread(void *x)
{
+ adb_thread_setname("client_socket_thread");
D("transport: client_socket_thread() starting\n");
while (true) {
int port = DEFAULT_ADB_LOCAL_TRANSPORT_PORT;
@@ -146,6 +147,7 @@
socklen_t alen;
int port = (int) (uintptr_t) arg;
+ adb_thread_setname("server socket");
D("transport: server_socket_thread() starting\n");
serverfd = -1;
for(;;) {
@@ -231,6 +233,7 @@
char tmp[256];
char con_name[32];
+ adb_thread_setname("qemu socket");
D("transport: qemu_socket_thread() starting\n");
/* adb QEMUD service connection request. */
diff --git a/adb/transport_test.cpp b/adb/transport_test.cpp
index 743d97d..10872ac 100644
--- a/adb/transport_test.cpp
+++ b/adb/transport_test.cpp
@@ -51,9 +51,6 @@
EXPECT_EQ(adb_port, rhs.adb_port);
EXPECT_EQ(kicked, rhs.kicked);
- EXPECT_EQ(
- 0, memcmp(&disconnects, &rhs.disconnects, sizeof(adisconnect)));
-
EXPECT_EQ(key, rhs.key);
EXPECT_EQ(0, memcmp(token, rhs.token, TOKEN_SIZE));
EXPECT_EQ(0, memcmp(&auth_fde, &rhs.auth_fde, sizeof(fdevent)));
@@ -118,12 +115,33 @@
ASSERT_EQ(expected, t);
}
-// Disabled because the function currently segfaults for a zeroed atransport. I
-// want to make sure I understand how this is working at all before I try fixing
-// that.
-TEST(transport, DISABLED_run_transport_disconnects_zeroed_atransport) {
+static void DisconnectFunc(void* arg, atransport*) {
+ int* count = reinterpret_cast<int*>(arg);
+ ++*count;
+}
+
+TEST(transport, RunDisconnects) {
atransport t;
- run_transport_disconnects(&t);
+ // RunDisconnects() can be called with an empty atransport.
+ t.RunDisconnects();
+
+ int count = 0;
+ adisconnect disconnect;
+ disconnect.func = DisconnectFunc;
+ disconnect.opaque = &count;
+ t.AddDisconnect(&disconnect);
+ t.RunDisconnects();
+ ASSERT_EQ(1, count);
+
+ // disconnect should have been removed automatically.
+ t.RunDisconnects();
+ ASSERT_EQ(1, count);
+
+ count = 0;
+ t.AddDisconnect(&disconnect);
+ t.RemoveDisconnect(&disconnect);
+ t.RunDisconnects();
+ ASSERT_EQ(0, count);
}
TEST(transport, add_feature) {
diff --git a/adb/usb_linux.cpp b/adb/usb_linux.cpp
index dd22712..65b8735 100644
--- a/adb/usb_linux.cpp
+++ b/adb/usb_linux.cpp
@@ -572,6 +572,7 @@
}
static void* device_poll_thread(void* unused) {
+ adb_thread_setname("device poll");
D("Created device thread\n");
while (true) {
// TODO: Use inotify.
@@ -591,6 +592,6 @@
sigaction(SIGALRM, &actions, nullptr);
if (!adb_thread_create(device_poll_thread, nullptr)) {
- fatal_errno("cannot create input thread");
+ fatal_errno("cannot create device_poll thread");
}
}
diff --git a/adb/usb_linux_client.cpp b/adb/usb_linux_client.cpp
index c6ad00d..e1d7594 100644
--- a/adb/usb_linux_client.cpp
+++ b/adb/usb_linux_client.cpp
@@ -209,6 +209,8 @@
struct usb_handle *usb = (struct usb_handle *)x;
int fd;
+ adb_thread_setname("usb open");
+
while (true) {
// wait until the USB device needs opening
adb_mutex_lock(&usb->lock);
@@ -403,6 +405,8 @@
{
struct usb_handle *usb = (struct usb_handle *)x;
+ adb_thread_setname("usb ffs open");
+
while (true) {
// wait until the USB device needs opening
adb_mutex_lock(&usb->lock);
@@ -431,17 +435,12 @@
static int bulk_write(int bulk_in, const uint8_t* buf, size_t length)
{
size_t count = 0;
- int ret;
- do {
- ret = adb_write(bulk_in, buf + count, length - count);
- if (ret < 0) {
- if (errno != EINTR)
- return ret;
- } else {
- count += ret;
- }
- } while (count < length);
+ while (count < length) {
+ int ret = adb_write(bulk_in, buf + count, length - count);
+ if (ret < 0) return -1;
+ count += ret;
+ }
D("[ bulk_write done fd=%d ]\n", bulk_in);
return count;
@@ -462,20 +461,15 @@
static int bulk_read(int bulk_out, uint8_t* buf, size_t length)
{
size_t count = 0;
- int ret;
- do {
- ret = adb_read(bulk_out, buf + count, length - count);
+ while (count < length) {
+ int ret = adb_read(bulk_out, buf + count, length - count);
if (ret < 0) {
- if (errno != EINTR) {
- D("[ bulk_read failed fd=%d length=%zu count=%zu ]\n",
- bulk_out, length, count);
- return ret;
- }
- } else {
- count += ret;
+ D("[ bulk_read failed fd=%d length=%zu count=%zu ]\n", bulk_out, length, count);
+ return -1;
}
- } while (count < length);
+ count += ret;
+ }
return count;
}
diff --git a/adb/usb_osx.cpp b/adb/usb_osx.cpp
index 2ba3ff7..8037606 100644
--- a/adb/usb_osx.cpp
+++ b/adb/usb_osx.cpp
@@ -118,7 +118,7 @@
IOUSBDeviceInterface197 **dev = NULL;
HRESULT result;
SInt32 score;
- UInt32 locationId;
+ uint32_t locationId;
UInt8 if_class, subclass, protocol;
UInt16 vendor;
UInt16 product;
@@ -403,6 +403,7 @@
void* RunLoopThread(void* unused)
{
+ adb_thread_setname("RunLoop");
InitUSB();
currentRunLoop = CFRunLoopGetCurrent();
@@ -438,7 +439,7 @@
adb_cond_init(&start_cond, NULL);
if (!adb_thread_create(RunLoopThread, nullptr)) {
- fatal_errno("cannot create input thread");
+ fatal_errno("cannot create RunLoop thread");
}
// Wait for initialization to finish
diff --git a/adb/usb_windows.cpp b/adb/usb_windows.cpp
index b8cc5cf..ab36475 100644
--- a/adb/usb_windows.cpp
+++ b/adb/usb_windows.cpp
@@ -171,6 +171,7 @@
}
void* device_poll_thread(void* unused) {
+ adb_thread_setname("Device Poll");
D("Created device thread\n");
while(1) {
@@ -208,6 +209,7 @@
// of a developer's interactive session, a window message pump is more
// appropriate.
D("Created power notification thread\n");
+ adb_thread_setname("Power Notifier");
// Window class names are process specific.
static const WCHAR kPowerNotificationWindowClassName[] =
diff --git a/base/file.cpp b/base/file.cpp
index 9a340b7..3468dcf 100644
--- a/base/file.cpp
+++ b/base/file.cpp
@@ -28,6 +28,10 @@
#include "cutils/log.h"
#include "utils/Compat.h"
+#if !defined(_WIN32)
+#define O_BINARY 0
+#endif
+
namespace android {
namespace base {
@@ -45,8 +49,7 @@
bool ReadFileToString(const std::string& path, std::string* content) {
content->clear();
- int fd =
- TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
+ int fd = TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_BINARY));
if (fd == -1) {
return false;
}
@@ -80,9 +83,8 @@
#if !defined(_WIN32)
bool WriteStringToFile(const std::string& content, const std::string& path,
mode_t mode, uid_t owner, gid_t group) {
- int fd = TEMP_FAILURE_RETRY(
- open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
- mode));
+ int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
+ int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode));
if (fd == -1) {
ALOGE("android::WriteStringToFile open failed: %s", strerror(errno));
return false;
@@ -108,9 +110,8 @@
#endif
bool WriteStringToFile(const std::string& content, const std::string& path) {
- int fd = TEMP_FAILURE_RETRY(
- open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW,
- DEFFILEMODE));
+ int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
+ int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, DEFFILEMODE));
if (fd == -1) {
return false;
}
diff --git a/crash_reporter/user_collector.cc b/crash_reporter/user_collector.cc
index ee24648..61ccc37 100644
--- a/crash_reporter/user_collector.cc
+++ b/crash_reporter/user_collector.cc
@@ -24,6 +24,7 @@
#include <stdint.h>
#include <sys/cdefs.h> // For __WORDSIZE
#include <sys/types.h> // For getpwuid_r, getgrnam_r, WEXITSTATUS.
+#include <unistd.h> // For setgroups
#include <string>
#include <vector>
@@ -37,6 +38,7 @@
#include <chromeos/process.h>
#include <chromeos/syslog_logging.h>
#include <cutils/properties.h>
+#include <private/android_filesystem_config.h>
static const char kCollectionErrorSignature[] =
"crash_reporter-user-collection";
@@ -77,6 +79,11 @@
core2md_failure_ = core2md_failure;
directory_failure_ = directory_failure;
filter_in_ = filter_in;
+
+ gid_t groups[] = { AID_SYSTEM, AID_DBUS };
+ if (setgroups(arraysize(groups), groups) != 0) {
+ PLOG(FATAL) << "Unable to set groups to system and dbus";
+ }
}
UserCollector::~UserCollector() {
diff --git a/fastboot/bootimg_utils.cpp b/fastboot/bootimg_utils.cpp
index d8905a6..c1028ef 100644
--- a/fastboot/bootimg_utils.cpp
+++ b/fastboot/bootimg_utils.cpp
@@ -32,32 +32,27 @@
#include <stdlib.h>
#include <string.h>
-void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline)
+void bootimg_set_cmdline(boot_img_hdr* h, const char* cmdline)
{
strcpy((char*) h->cmdline, cmdline);
}
-boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size, unsigned kernel_offset,
- void *ramdisk, unsigned ramdisk_size, unsigned ramdisk_offset,
- void *second, unsigned second_size, unsigned second_offset,
- unsigned page_size, unsigned base, unsigned tags_offset,
- unsigned *bootimg_size)
+boot_img_hdr* mkbootimg(void* kernel, int64_t kernel_size, off_t kernel_offset,
+ void* ramdisk, int64_t ramdisk_size, off_t ramdisk_offset,
+ void* second, int64_t second_size, off_t second_offset,
+ size_t page_size, size_t base, off_t tags_offset,
+ int64_t* bootimg_size)
{
- unsigned kernel_actual;
- unsigned ramdisk_actual;
- unsigned second_actual;
- unsigned page_mask;
+ size_t page_mask = page_size - 1;
- page_mask = page_size - 1;
-
- kernel_actual = (kernel_size + page_mask) & (~page_mask);
- ramdisk_actual = (ramdisk_size + page_mask) & (~page_mask);
- second_actual = (second_size + page_mask) & (~page_mask);
+ int64_t kernel_actual = (kernel_size + page_mask) & (~page_mask);
+ int64_t ramdisk_actual = (ramdisk_size + page_mask) & (~page_mask);
+ int64_t second_actual = (second_size + page_mask) & (~page_mask);
*bootimg_size = page_size + kernel_actual + ramdisk_actual + second_actual;
boot_img_hdr* hdr = reinterpret_cast<boot_img_hdr*>(calloc(*bootimg_size, 1));
- if (hdr == 0) {
+ if (hdr == nullptr) {
return hdr;
}
@@ -74,12 +69,9 @@
hdr->page_size = page_size;
+ memcpy(hdr->magic + page_size, kernel, kernel_size);
+ memcpy(hdr->magic + page_size + kernel_actual, ramdisk, ramdisk_size);
+ memcpy(hdr->magic + page_size + kernel_actual + ramdisk_actual, second, second_size);
- memcpy(hdr->magic + page_size,
- kernel, kernel_size);
- memcpy(hdr->magic + page_size + kernel_actual,
- ramdisk, ramdisk_size);
- memcpy(hdr->magic + page_size + kernel_actual + ramdisk_actual,
- second, second_size);
return hdr;
}
diff --git a/fastboot/bootimg_utils.h b/fastboot/bootimg_utils.h
index b1a86cd..fcc8662 100644
--- a/fastboot/bootimg_utils.h
+++ b/fastboot/bootimg_utils.h
@@ -30,20 +30,14 @@
#define _FASTBOOT_BOOTIMG_UTILS_H_
#include <bootimg.h>
+#include <inttypes.h>
+#include <sys/types.h>
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
-void bootimg_set_cmdline(boot_img_hdr *h, const char *cmdline);
-boot_img_hdr *mkbootimg(void *kernel, unsigned kernel_size, unsigned kernel_offset,
- void *ramdisk, unsigned ramdisk_size, unsigned ramdisk_offset,
- void *second, unsigned second_size, unsigned second_offset,
- unsigned page_size, unsigned base, unsigned tags_offset,
- unsigned *bootimg_size);
-
-#if defined(__cplusplus)
-}
-#endif
+void bootimg_set_cmdline(boot_img_hdr* h, const char* cmdline);
+boot_img_hdr* mkbootimg(void* kernel, int64_t kernel_size, off_t kernel_offset,
+ void* ramdisk, int64_t ramdisk_size, off_t ramdisk_offset,
+ void* second, int64_t second_size, off_t second_offset,
+ size_t page_size, size_t base, off_t tags_offset,
+ int64_t* bootimg_size);
#endif
diff --git a/fastboot/engine.cpp b/fastboot/engine.cpp
index 66b8140..a0e990a 100644
--- a/fastboot/engine.cpp
+++ b/fastboot/engine.cpp
@@ -31,7 +31,6 @@
#include <errno.h>
#include <stdarg.h>
-#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -39,12 +38,6 @@
#include <sys/types.h>
#include <unistd.h>
-#ifdef USE_MINGW
-#include <fcntl.h>
-#else
-#include <sys/mman.h>
-#endif
-
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
#define OP_DOWNLOAD 1
@@ -58,15 +51,17 @@
#define CMD_SIZE 64
-struct Action
-{
+struct Action {
unsigned op;
- Action *next;
+ Action* next;
char cmd[CMD_SIZE];
- const char *prod;
- void *data;
- unsigned size;
+ const char* prod;
+ void* data;
+
+ // The protocol only supports 32-bit sizes, so you'll have to break
+ // anything larger into chunks.
+ uint32_t size;
const char *msg;
int (*func)(Action* a, int status, const char* resp);
@@ -267,7 +262,7 @@
}
void fb_queue_require(const char *prod, const char *var,
- int invert, unsigned nvalues, const char **value)
+ bool invert, size_t nvalues, const char **value)
{
Action *a;
a = queue_action(OP_QUERY, "getvar:%s", var);
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 4dbf32f..e2971f2 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -34,7 +34,6 @@
#include <getopt.h>
#include <inttypes.h>
#include <limits.h>
-#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -67,12 +66,12 @@
static int64_t sparse_limit = -1;
static int64_t target_sparse_limit = -1;
-unsigned page_size = 2048;
-unsigned base_addr = 0x10000000;
-unsigned kernel_offset = 0x00008000;
-unsigned ramdisk_offset = 0x01000000;
-unsigned second_offset = 0x00f00000;
-unsigned tags_offset = 0x00000100;
+static unsigned page_size = 2048;
+static unsigned base_addr = 0x10000000;
+static unsigned kernel_offset = 0x00008000;
+static unsigned ramdisk_offset = 0x01000000;
+static unsigned second_offset = 0x00f00000;
+static unsigned tags_offset = 0x00000100;
enum fb_buffer_type {
FB_BUFFER,
@@ -81,8 +80,8 @@
struct fastboot_buffer {
enum fb_buffer_type type;
- void *data;
- unsigned int sz;
+ void* data;
+ int64_t sz;
};
static struct {
@@ -97,8 +96,7 @@
{"vendor.img", "vendor.sig", "vendor", true},
};
-char *find_item(const char *item, const char *product)
-{
+static char* find_item(const char* item, const char* product) {
char *dir;
const char *fn;
char path[PATH_MAX + 128];
@@ -139,36 +137,26 @@
return strdup(path);
}
-static int64_t file_size(int fd)
-{
- struct stat st;
- int ret;
-
- ret = fstat(fd, &st);
-
- return ret ? -1 : st.st_size;
+static int64_t get_file_size(int fd) {
+ struct stat sb;
+ return fstat(fd, &sb) == -1 ? -1 : sb.st_size;
}
-static void *load_fd(int fd, unsigned *_sz)
-{
- char *data;
- int sz;
+static void* load_fd(int fd, int64_t* sz) {
int errno_tmp;
+ char* data = nullptr;
- data = 0;
-
- sz = file_size(fd);
- if (sz < 0) {
+ *sz = get_file_size(fd);
+ if (*sz < 0) {
goto oops;
}
- data = (char*) malloc(sz);
- if(data == 0) goto oops;
+ data = (char*) malloc(*sz);
+ if (data == nullptr) goto oops;
- if(read(fd, data, sz) != sz) goto oops;
+ if(read(fd, data, *sz) != *sz) goto oops;
close(fd);
- if(_sz) *_sz = sz;
return data;
oops:
@@ -179,17 +167,13 @@
return 0;
}
-static void *load_file(const char *fn, unsigned *_sz)
-{
- int fd;
-
- fd = open(fn, O_RDONLY | O_BINARY);
- if(fd < 0) return 0;
-
- return load_fd(fd, _sz);
+static void* load_file(const char* fn, int64_t* sz) {
+ int fd = open(fn, O_RDONLY | O_BINARY);
+ if (fd == -1) return nullptr;
+ return load_fd(fd, sz);
}
-int match_fastboot_with_serial(usb_ifc_info* info, const char* local_serial) {
+static int match_fastboot_with_serial(usb_ifc_info* info, const char* local_serial) {
// Require a matching vendor id if the user specified one with -i.
if (vendor_id != 0 && info->dev_vendor != vendor_id) {
return -1;
@@ -206,14 +190,12 @@
return 0;
}
-int match_fastboot(usb_ifc_info *info)
-{
+static int match_fastboot(usb_ifc_info* info) {
return match_fastboot_with_serial(info, serial);
}
-int list_devices_callback(usb_ifc_info *info)
-{
- if (match_fastboot_with_serial(info, NULL) == 0) {
+static int list_devices_callback(usb_ifc_info* info) {
+ if (match_fastboot_with_serial(info, nullptr) == 0) {
const char* serial = info->serial_number;
if (!info->writable) {
serial = "no permissions"; // like "adb devices"
@@ -234,8 +216,7 @@
return -1;
}
-usb_handle *open_device(void)
-{
+static usb_handle* open_device() {
static usb_handle *usb = 0;
int announce = 1;
@@ -252,15 +233,14 @@
}
}
-void list_devices(void) {
+static void list_devices() {
// We don't actually open a USB device here,
// just getting our callback called so we can
// list all the connected devices.
usb_open(list_devices_callback);
}
-void usage(void)
-{
+static void usage() {
fprintf(stderr,
/* 1234567890123456789012345678901234567890123456789012345678901234567890123456 */
"usage: fastboot [ <option> ] <command>\n"
@@ -315,31 +295,26 @@
);
}
-void *load_bootable_image(const char *kernel, const char *ramdisk,
- const char *secondstage, unsigned *sz,
- const char *cmdline)
-{
- void *kdata = 0, *rdata = 0, *sdata = 0;
- unsigned ksize = 0, rsize = 0, ssize = 0;
- void *bdata;
- unsigned bsize;
-
- if(kernel == 0) {
+static void* load_bootable_image(const char* kernel, const char* ramdisk,
+ const char* secondstage, int64_t* sz,
+ const char* cmdline) {
+ if (kernel == nullptr) {
fprintf(stderr, "no image specified\n");
return 0;
}
- kdata = load_file(kernel, &ksize);
- if(kdata == 0) {
+ int64_t ksize;
+ void* kdata = load_file(kernel, &ksize);
+ if (kdata == nullptr) {
fprintf(stderr, "cannot load '%s': %s\n", kernel, strerror(errno));
return 0;
}
- /* is this actually a boot image? */
+ // Is this actually a boot image?
if(!memcmp(kdata, BOOT_MAGIC, BOOT_MAGIC_SIZE)) {
- if(cmdline) bootimg_set_cmdline((boot_img_hdr*) kdata, cmdline);
+ if (cmdline) bootimg_set_cmdline((boot_img_hdr*) kdata, cmdline);
- if(ramdisk) {
+ if (ramdisk) {
fprintf(stderr, "cannot boot a boot.img *and* ramdisk\n");
return 0;
}
@@ -348,39 +323,44 @@
return kdata;
}
- if(ramdisk) {
+ void* rdata = nullptr;
+ int64_t rsize = 0;
+ if (ramdisk) {
rdata = load_file(ramdisk, &rsize);
- if(rdata == 0) {
+ if (rdata == nullptr) {
fprintf(stderr,"cannot load '%s': %s\n", ramdisk, strerror(errno));
return 0;
}
}
+ void* sdata = nullptr;
+ int64_t ssize = 0;
if (secondstage) {
sdata = load_file(secondstage, &ssize);
- if(sdata == 0) {
+ if (sdata == nullptr) {
fprintf(stderr,"cannot load '%s': %s\n", secondstage, strerror(errno));
return 0;
}
}
fprintf(stderr,"creating boot image...\n");
- bdata = mkbootimg(kdata, ksize, kernel_offset,
+ int64_t bsize = 0;
+ void* bdata = mkbootimg(kdata, ksize, kernel_offset,
rdata, rsize, ramdisk_offset,
sdata, ssize, second_offset,
page_size, base_addr, tags_offset, &bsize);
- if(bdata == 0) {
+ if (bdata == nullptr) {
fprintf(stderr,"failed to create boot.img\n");
return 0;
}
- if(cmdline) bootimg_set_cmdline((boot_img_hdr*) bdata, cmdline);
- fprintf(stderr,"creating boot image - %d bytes\n", bsize);
+ if (cmdline) bootimg_set_cmdline((boot_img_hdr*) bdata, cmdline);
+ fprintf(stderr, "creating boot image - %" PRId64 " bytes\n", bsize);
*sz = bsize;
return bdata;
}
-static void* unzip_file(ZipArchiveHandle zip, const char* entry_name, unsigned* sz)
+static void* unzip_file(ZipArchiveHandle zip, const char* entry_name, int64_t* sz)
{
ZipString zip_entry_name(entry_name);
ZipEntry zip_entry;
@@ -392,8 +372,8 @@
*sz = zip_entry.uncompressed_length;
uint8_t* data = reinterpret_cast<uint8_t*>(malloc(zip_entry.uncompressed_length));
- if (data == NULL) {
- fprintf(stderr, "failed to allocate %u bytes for '%s'\n", *sz, entry_name);
+ if (data == nullptr) {
+ fprintf(stderr, "failed to allocate %" PRId64 " bytes for '%s'\n", *sz, entry_name);
return 0;
}
@@ -438,7 +418,7 @@
static int unzip_to_file(ZipArchiveHandle zip, char* entry_name) {
FILE* fp = tmpfile();
- if (fp == NULL) {
+ if (fp == nullptr) {
fprintf(stderr, "failed to create temporary file for '%s': %s\n",
entry_name, strerror(errno));
return -1;
@@ -478,7 +458,7 @@
static int setup_requirement_line(char *name)
{
char *val[MAX_OPTIONS];
- char *prod = NULL;
+ char *prod = nullptr;
unsigned n, count;
char *x;
int invert = 0;
@@ -539,13 +519,10 @@
return 0;
}
-static void setup_requirements(char *data, unsigned sz)
-{
- char *s;
-
- s = data;
+static void setup_requirements(char* data, int64_t sz) {
+ char* s = data;
while (sz-- > 0) {
- if(*s == '\n') {
+ if (*s == '\n') {
*s++ = 0;
if (setup_requirement_line(data)) {
die("out of memory");
@@ -557,8 +534,7 @@
}
}
-void queue_info_dump(void)
-{
+static void queue_info_dump() {
fb_queue_notice("--------------------------------------------");
fb_queue_display("version-bootloader", "Bootloader Version...");
fb_queue_display("version-baseband", "Baseband Version.....");
@@ -573,7 +549,7 @@
die("cannot sparse read file\n");
}
- int files = sparse_file_resparse(s, max_size, NULL, 0);
+ int files = sparse_file_resparse(s, max_size, nullptr, 0);
if (files < 0) {
die("Failed to resparse\n");
}
@@ -598,7 +574,7 @@
int status = fb_getvar(usb, response, "max-download-size");
if (!status) {
- limit = strtoul(response, NULL, 0);
+ limit = strtoul(response, nullptr, 0);
if (limit > 0) {
fprintf(stderr, "target reported max download size of %" PRId64 " bytes\n",
limit);
@@ -643,35 +619,27 @@
/* The function fb_format_supported() currently returns the value
* we want, so just call it.
*/
- return fb_format_supported(usb, part, NULL);
+ return fb_format_supported(usb, part, nullptr);
}
-static int load_buf_fd(usb_handle *usb, int fd,
- struct fastboot_buffer *buf)
-{
- int64_t sz64;
- void *data;
- int64_t limit;
-
-
- sz64 = file_size(fd);
- if (sz64 < 0) {
+static int load_buf_fd(usb_handle* usb, int fd, struct fastboot_buffer* buf) {
+ int64_t sz = get_file_size(fd);
+ if (sz == -1) {
return -1;
}
- lseek(fd, 0, SEEK_SET);
- limit = get_sparse_limit(usb, sz64);
+ lseek64(fd, 0, SEEK_SET);
+ int64_t limit = get_sparse_limit(usb, sz);
if (limit) {
- struct sparse_file **s = load_sparse_files(fd, limit);
- if (s == NULL) {
+ sparse_file** s = load_sparse_files(fd, limit);
+ if (s == nullptr) {
return -1;
}
buf->type = FB_BUFFER_SPARSE;
buf->data = s;
} else {
- unsigned int sz;
- data = load_fd(fd, &sz);
- if (data == 0) return -1;
+ void* data = load_fd(fd, &sz);
+ if (data == nullptr) return -1;
buf->type = FB_BUFFER;
buf->data = data;
buf->sz = sz;
@@ -701,8 +669,8 @@
case FB_BUFFER_SPARSE:
s = reinterpret_cast<sparse_file**>(buf->data);
while (*s) {
- int64_t sz64 = sparse_file_len(*s, true, false);
- fb_queue_flash_sparse(pname, *s++, sz64);
+ int64_t sz = sparse_file_len(*s, true, false);
+ fb_queue_flash_sparse(pname, *s++, sz);
}
break;
case FB_BUFFER:
@@ -713,8 +681,7 @@
}
}
-void do_flash(usb_handle *usb, const char *pname, const char *fname)
-{
+static void do_flash(usb_handle* usb, const char* pname, const char* fname) {
struct fastboot_buffer buf;
if (load_buf(usb, fname, &buf)) {
@@ -723,17 +690,15 @@
flash_buf(pname, &buf);
}
-void do_update_signature(ZipArchiveHandle zip, char *fn)
-{
- unsigned sz;
+static void do_update_signature(ZipArchiveHandle zip, char* fn) {
+ int64_t sz;
void* data = unzip_file(zip, fn, &sz);
- if (data == 0) return;
+ if (data == nullptr) return;
fb_queue_download("signature", data, sz);
fb_queue_command("signature", "installing signature");
}
-void do_update(usb_handle *usb, const char *filename, int erase_first)
-{
+static void do_update(usb_handle* usb, const char* filename, bool erase_first) {
queue_info_dump();
fb_queue_query_save("product", cur_product, sizeof(cur_product));
@@ -745,9 +710,9 @@
die("failed to open zip file '%s': %s", filename, ErrorCodeString(error));
}
- unsigned sz;
+ int64_t sz;
void* data = unzip_file(zip, "android-info.txt", &sz);
- if (data == 0) {
+ if (data == nullptr) {
CloseArchive(zip);
die("update package '%s' has no android-info.txt", filename);
}
@@ -780,36 +745,33 @@
CloseArchive(zip);
}
-void do_send_signature(char *fn)
-{
- void *data;
- unsigned sz;
- char *xtn;
-
- xtn = strrchr(fn, '.');
+static void do_send_signature(char* fn) {
+ char* xtn = strrchr(fn, '.');
if (!xtn) return;
+
if (strcmp(xtn, ".img")) return;
- strcpy(xtn,".sig");
- data = load_file(fn, &sz);
- strcpy(xtn,".img");
- if (data == 0) return;
+ strcpy(xtn, ".sig");
+
+ int64_t sz;
+ void* data = load_file(fn, &sz);
+ strcpy(xtn, ".img");
+ if (data == nullptr) return;
fb_queue_download("signature", data, sz);
fb_queue_command("signature", "installing signature");
}
-void do_flashall(usb_handle *usb, int erase_first)
-{
+static void do_flashall(usb_handle* usb, int erase_first) {
queue_info_dump();
fb_queue_query_save("product", cur_product, sizeof(cur_product));
char* fname = find_item("info", product);
- if (fname == 0) die("cannot find android-info.txt");
+ if (fname == nullptr) die("cannot find android-info.txt");
- unsigned sz;
+ int64_t sz;
void* data = load_file(fname, &sz);
- if (data == 0) die("could not load android-info.txt: %s", strerror(errno));
+ if (data == nullptr) die("could not load android-info.txt: %s", strerror(errno));
setup_requirements(reinterpret_cast<char*>(data), sz);
@@ -832,8 +794,7 @@
#define skip(n) do { argc -= (n); argv += (n); } while (0)
#define require(n) do { if (argc < (n)) {usage(); exit(1);}} while (0)
-int do_oem_command(int argc, char **argv)
-{
+static int do_oem_command(int argc, char** argv) {
char command[256];
if (argc <= 1) return 0;
@@ -890,16 +851,15 @@
return num;
}
-void fb_perform_format(usb_handle* usb,
- const char *partition, int skip_if_not_supported,
- const char *type_override, const char *size_override)
-{
+static void fb_perform_format(usb_handle* usb,
+ const char *partition, int skip_if_not_supported,
+ const char *type_override, const char *size_override) {
char pTypeBuff[FB_RESPONSE_SZ + 1], pSizeBuff[FB_RESPONSE_SZ + 1];
char *pType = pTypeBuff;
char *pSize = pSizeBuff;
unsigned int limit = INT_MAX;
struct fastboot_buffer buf;
- const char *errMsg = NULL;
+ const char *errMsg = nullptr;
const struct fs_generator *gen;
uint64_t pSz;
int status;
@@ -949,7 +909,7 @@
return;
}
- pSz = strtoll(pSize, (char **)NULL, 16);
+ pSz = strtoll(pSize, (char **)nullptr, 16);
fd = fileno(tmpfile());
if (fs_generator_generate(gen, fd, pSz)) {
@@ -982,9 +942,9 @@
int wants_wipe = 0;
int wants_reboot = 0;
int wants_reboot_bootloader = 0;
- int erase_first = 1;
+ bool erase_first = true;
void *data;
- unsigned sz;
+ int64_t sz;
int status;
int c;
int longindex;
@@ -1020,7 +980,7 @@
usage();
return 1;
case 'i': {
- char *endptr = NULL;
+ char *endptr = nullptr;
unsigned long val;
val = strtoul(optarg, &endptr, 0);
@@ -1036,7 +996,7 @@
long_listing = 1;
break;
case 'n':
- page_size = (unsigned)strtoul(optarg, NULL, 0);
+ page_size = (unsigned)strtoul(optarg, nullptr, 0);
if (!page_size) die("invalid page size");
break;
case 'p':
@@ -1058,7 +1018,7 @@
}
break;
case 'u':
- erase_first = 0;
+ erase_first = false;
break;
case 'w':
wants_wipe = 1;
@@ -1067,8 +1027,8 @@
return 1;
case 0:
if (strcmp("unbuffered", longopts[longindex].name) == 0) {
- setvbuf(stdout, NULL, _IONBF, 0);
- setvbuf(stderr, NULL, _IONBF, 0);
+ setvbuf(stdout, nullptr, _IONBF, 0);
+ setvbuf(stderr, nullptr, _IONBF, 0);
} else if (strcmp("version", longopts[longindex].name) == 0) {
fprintf(stdout, "fastboot version %s\n", FASTBOOT_REVISION);
return 0;
@@ -1108,7 +1068,7 @@
} else if(!strcmp(*argv, "erase")) {
require(2);
- if (fb_format_supported(usb, argv[1], NULL)) {
+ if (fb_format_supported(usb, argv[1], nullptr)) {
fprintf(stderr, "******** Did you mean to fastboot format this partition?\n");
}
@@ -1116,8 +1076,8 @@
skip(2);
} else if(!strncmp(*argv, "format", strlen("format"))) {
char *overrides;
- char *type_override = NULL;
- char *size_override = NULL;
+ char *type_override = nullptr;
+ char *size_override = nullptr;
require(2);
/*
* Parsing for: "format[:[type][:[size]]]"
@@ -1138,8 +1098,8 @@
}
type_override = overrides;
}
- if (type_override && !type_override[0]) type_override = NULL;
- if (size_override && !size_override[0]) size_override = NULL;
+ if (type_override && !type_override[0]) type_override = nullptr;
+ if (size_override && !size_override[0]) size_override = nullptr;
if (erase_first && needs_erase(usb, argv[1])) {
fb_queue_erase(argv[1]);
}
@@ -1148,7 +1108,7 @@
} else if(!strcmp(*argv, "signature")) {
require(2);
data = load_file(argv[1], &sz);
- if (data == 0) die("could not load '%s': %s", argv[1], strerror(errno));
+ if (data == nullptr) die("could not load '%s': %s", argv[1], strerror(errno));
if (sz != 256) die("signature must be 256 bytes");
fb_queue_download("signature", data, sz);
fb_queue_command("signature", "installing signature");
@@ -1258,9 +1218,9 @@
if (wants_wipe) {
fb_queue_erase("userdata");
- fb_perform_format(usb, "userdata", 1, NULL, NULL);
+ fb_perform_format(usb, "userdata", 1, nullptr, nullptr);
fb_queue_erase("cache");
- fb_perform_format(usb, "cache", 1, NULL, NULL);
+ fb_perform_format(usb, "cache", 1, nullptr, nullptr);
}
if (wants_reboot) {
fb_queue_reboot();
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index 481c501..091a70f 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -29,18 +29,17 @@
#ifndef _FASTBOOT_H_
#define _FASTBOOT_H_
-#include "usb.h"
+#include <inttypes.h>
+#include <stdlib.h>
-#if defined(__cplusplus)
-extern "C" {
-#endif
+#include "usb.h"
struct sparse_file;
/* protocol.c - fastboot protocol */
int fb_command(usb_handle *usb, const char *cmd);
int fb_command_response(usb_handle *usb, const char *cmd, char *response);
-int fb_download_data(usb_handle *usb, const void *data, unsigned size);
+int fb_download_data(usb_handle *usb, const void *data, uint32_t size);
int fb_download_data_sparse(usb_handle *usb, struct sparse_file *s);
char *fb_get_error(void);
@@ -50,17 +49,17 @@
/* engine.c - high level command queue engine */
int fb_getvar(struct usb_handle *usb, char *response, const char *fmt, ...);
int fb_format_supported(usb_handle *usb, const char *partition, const char *type_override);
-void fb_queue_flash(const char *ptn, void *data, unsigned sz);
-void fb_queue_flash_sparse(const char *ptn, struct sparse_file *s, unsigned sz);
+void fb_queue_flash(const char *ptn, void *data, uint32_t sz);
+void fb_queue_flash_sparse(const char *ptn, struct sparse_file *s, uint32_t sz);
void fb_queue_erase(const char *ptn);
-void fb_queue_format(const char *ptn, int skip_if_not_supported, unsigned int max_chunk_sz);
-void fb_queue_require(const char *prod, const char *var, int invert,
- unsigned nvalues, const char **value);
+void fb_queue_format(const char *ptn, int skip_if_not_supported, int32_t max_chunk_sz);
+void fb_queue_require(const char *prod, const char *var, bool invert,
+ size_t nvalues, const char **value);
void fb_queue_display(const char *var, const char *prettyname);
-void fb_queue_query_save(const char *var, char *dest, unsigned dest_size);
+void fb_queue_query_save(const char *var, char *dest, uint32_t dest_size);
void fb_queue_reboot(void);
void fb_queue_command(const char *cmd, const char *msg);
-void fb_queue_download(const char *name, void *data, unsigned size);
+void fb_queue_download(const char *name, void *data, uint32_t size);
void fb_queue_notice(const char *notice);
void fb_queue_wait_for_disconnect(void);
int fb_execute_queue(usb_handle *usb);
@@ -76,8 +75,4 @@
/* Current product */
extern char cur_product[FB_RESPONSE_SZ + 1];
-#if defined(__cplusplus)
-}
-#endif
-
#endif
diff --git a/fastboot/fastboot_protocol.txt b/fastboot/fastboot_protocol.txt
index 37b1959..bb73d8a 100644
--- a/fastboot/fastboot_protocol.txt
+++ b/fastboot/fastboot_protocol.txt
@@ -41,7 +41,7 @@
d. DATA -> the requested command is ready for the data phase.
A DATA response packet will be 12 bytes long, in the form of
- DATA00000000 where the 8 digit hexidecimal number represents
+ DATA00000000 where the 8 digit hexadecimal number represents
the total data size to transfer.
3. Data phase. Depending on the command, the host or client will
diff --git a/fastboot/fs.cpp b/fastboot/fs.cpp
index d8f9e16..c58a505 100644
--- a/fastboot/fs.cpp
+++ b/fastboot/fs.cpp
@@ -6,21 +6,12 @@
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
-#include <stdarg.h>
-#include <stdbool.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
-#include <sparse/sparse.h>
#include <unistd.h>
-#ifdef USE_MINGW
-#include <fcntl.h>
-#else
-#include <sys/mman.h>
-#endif
-
-
+#include <sparse/sparse.h>
static int generate_ext4_image(int fd, long long partSize)
{
@@ -48,15 +39,13 @@
#endif
};
-const struct fs_generator* fs_get_generator(const char *fs_type)
-{
- unsigned i;
-
- for (i = 0; i < sizeof(generators) / sizeof(*generators); i++)
- if (!strcmp(generators[i].fs_type, fs_type))
+const struct fs_generator* fs_get_generator(const char* fs_type) {
+ for (size_t i = 0; i < sizeof(generators) / sizeof(*generators); i++) {
+ if (strcmp(generators[i].fs_type, fs_type) == 0) {
return generators + i;
-
- return NULL;
+ }
+ }
+ return nullptr;
}
int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize)
diff --git a/fastboot/fs.h b/fastboot/fs.h
index 307772b..8444081 100644
--- a/fastboot/fs.h
+++ b/fastboot/fs.h
@@ -3,18 +3,10 @@
#include <stdint.h>
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
struct fs_generator;
const struct fs_generator* fs_get_generator(const char *fs_type);
int fs_generator_generate(const struct fs_generator* gen, int tmpFileNo, long long partSize);
-#if defined(__cplusplus)
-}
-#endif
-
#endif
diff --git a/fastboot/protocol.cpp b/fastboot/protocol.cpp
index 00c8a03..cbd48e8 100644
--- a/fastboot/protocol.cpp
+++ b/fastboot/protocol.cpp
@@ -26,8 +26,6 @@
* SUCH DAMAGE.
*/
-#define min(a, b) \
- ({ typeof(a) _a = (a); typeof(b) _b = (b); (_a < _b) ? _a : _b; })
#define round_down(a, b) \
({ typeof(a) _a = (a); typeof(b) _b = (b); _a - (_a % _b); })
@@ -36,6 +34,8 @@
#include <string.h>
#include <errno.h>
+#include <algorithm>
+
#include <sparse/sparse.h>
#include "fastboot.h"
@@ -47,40 +47,38 @@
return ERROR;
}
-static int check_response(usb_handle *usb, unsigned int size, char *response)
-{
- unsigned char status[65];
- int r;
+static int check_response(usb_handle* usb, uint32_t size, char* response) {
+ char status[65];
- for(;;) {
- r = usb_read(usb, status, 64);
- if(r < 0) {
+ while (true) {
+ int r = usb_read(usb, status, 64);
+ if (r < 0) {
sprintf(ERROR, "status read failed (%s)", strerror(errno));
usb_close(usb);
return -1;
}
status[r] = 0;
- if(r < 4) {
+ if (r < 4) {
sprintf(ERROR, "status malformed (%d bytes)", r);
usb_close(usb);
return -1;
}
- if(!memcmp(status, "INFO", 4)) {
+ if (!memcmp(status, "INFO", 4)) {
fprintf(stderr,"(bootloader) %s\n", status + 4);
continue;
}
- if(!memcmp(status, "OKAY", 4)) {
- if(response) {
+ if (!memcmp(status, "OKAY", 4)) {
+ if (response) {
strcpy(response, (char*) status + 4);
}
return 0;
}
- if(!memcmp(status, "FAIL", 4)) {
- if(r > 4) {
+ if (!memcmp(status, "FAIL", 4)) {
+ if (r > 4) {
sprintf(ERROR, "remote: %s", status + 4);
} else {
strcpy(ERROR, "remote failure");
@@ -88,9 +86,9 @@
return -1;
}
- if(!memcmp(status, "DATA", 4) && size > 0){
- unsigned dsize = strtoul((char*) status + 4, 0, 16);
- if(dsize > size) {
+ if (!memcmp(status, "DATA", 4) && size > 0){
+ uint32_t dsize = strtol(status + 4, 0, 16);
+ if (dsize > size) {
strcpy(ERROR, "data size too large");
usb_close(usb);
return -1;
@@ -106,22 +104,19 @@
return -1;
}
-static int _command_start(usb_handle *usb, const char *cmd, unsigned size,
- char *response)
-{
- int cmdsize = strlen(cmd);
-
- if(response) {
- response[0] = 0;
- }
-
- if(cmdsize > 64) {
- sprintf(ERROR,"command too large");
+static int _command_start(usb_handle* usb, const char* cmd, uint32_t size, char* response) {
+ size_t cmdsize = strlen(cmd);
+ if (cmdsize > 64) {
+ sprintf(ERROR, "command too large");
return -1;
}
- if(usb_write(usb, cmd, cmdsize) != cmdsize) {
- sprintf(ERROR,"command write failed (%s)", strerror(errno));
+ if (response) {
+ response[0] = 0;
+ }
+
+ if (usb_write(usb, cmd, cmdsize) != static_cast<int>(cmdsize)) {
+ sprintf(ERROR, "command write failed (%s)", strerror(errno));
usb_close(usb);
return -1;
}
@@ -129,45 +124,32 @@
return check_response(usb, size, response);
}
-static int _command_data(usb_handle *usb, const void *data, unsigned size)
-{
- int r;
-
- r = usb_write(usb, data, size);
- if(r < 0) {
+static int _command_data(usb_handle* usb, const void* data, uint32_t size) {
+ int r = usb_write(usb, data, size);
+ if (r < 0) {
sprintf(ERROR, "data transfer failure (%s)", strerror(errno));
usb_close(usb);
return -1;
}
- if(r != ((int) size)) {
+ if (r != ((int) size)) {
sprintf(ERROR, "data transfer failure (short transfer)");
usb_close(usb);
return -1;
}
-
return r;
}
-static int _command_end(usb_handle *usb)
-{
- int r;
- r = check_response(usb, 0, 0);
- if(r < 0) {
- return -1;
- }
- return 0;
+static int _command_end(usb_handle* usb) {
+ return check_response(usb, 0, 0) < 0 ? -1 : 0;
}
-static int _command_send(usb_handle *usb, const char *cmd,
- const void *data, unsigned size,
- char *response)
-{
- int r;
+static int _command_send(usb_handle* usb, const char* cmd, const void* data, uint32_t size,
+ char* response) {
if (size == 0) {
return -1;
}
- r = _command_start(usb, cmd, size, response);
+ int r = _command_start(usb, cmd, size, response);
if (r < 0) {
return -1;
}
@@ -178,42 +160,29 @@
}
r = _command_end(usb);
- if(r < 0) {
+ if (r < 0) {
return -1;
}
return size;
}
-static int _command_send_no_data(usb_handle *usb, const char *cmd,
- char *response)
-{
+static int _command_send_no_data(usb_handle* usb, const char* cmd, char* response) {
return _command_start(usb, cmd, 0, response);
}
-int fb_command(usb_handle *usb, const char *cmd)
-{
+int fb_command(usb_handle* usb, const char* cmd) {
return _command_send_no_data(usb, cmd, 0);
}
-int fb_command_response(usb_handle *usb, const char *cmd, char *response)
-{
+int fb_command_response(usb_handle* usb, const char* cmd, char* response) {
return _command_send_no_data(usb, cmd, response);
}
-int fb_download_data(usb_handle *usb, const void *data, unsigned size)
-{
+int fb_download_data(usb_handle* usb, const void* data, uint32_t size) {
char cmd[64];
- int r;
-
sprintf(cmd, "download:%08x", size);
- r = _command_send(usb, cmd, data, size, 0);
-
- if(r < 0) {
- return -1;
- } else {
- return 0;
- }
+ return _command_send(usb, cmd, data, size, 0) < 0 ? -1 : 0;
}
#define USB_BUF_SIZE 1024
@@ -228,7 +197,7 @@
const char* ptr = reinterpret_cast<const char*>(data);
if (usb_buf_len) {
- to_write = min(USB_BUF_SIZE - usb_buf_len, len);
+ to_write = std::min(USB_BUF_SIZE - usb_buf_len, len);
memcpy(usb_buf + usb_buf_len, ptr, to_write);
usb_buf_len += to_write;
@@ -270,32 +239,25 @@
return 0;
}
-static int fb_download_data_sparse_flush(usb_handle *usb)
-{
- int r;
-
+static int fb_download_data_sparse_flush(usb_handle* usb) {
if (usb_buf_len > 0) {
- r = _command_data(usb, usb_buf, usb_buf_len);
- if (r != usb_buf_len) {
+ if (_command_data(usb, usb_buf, usb_buf_len) != usb_buf_len) {
return -1;
}
usb_buf_len = 0;
}
-
return 0;
}
-int fb_download_data_sparse(usb_handle *usb, struct sparse_file *s)
-{
- char cmd[64];
- int r;
+int fb_download_data_sparse(usb_handle* usb, struct sparse_file* s) {
int size = sparse_file_len(s, true, false);
if (size <= 0) {
return -1;
}
+ char cmd[64];
sprintf(cmd, "download:%08x", size);
- r = _command_start(usb, cmd, size, 0);
+ int r = _command_start(usb, cmd, size, 0);
if (r < 0) {
return -1;
}
diff --git a/fastboot/usb.h b/fastboot/usb.h
index c7b748e..0fda41a 100644
--- a/fastboot/usb.h
+++ b/fastboot/usb.h
@@ -29,16 +29,9 @@
#ifndef _USB_H_
#define _USB_H_
-#if defined(__cplusplus)
-extern "C" {
-#endif
+struct usb_handle;
-typedef struct usb_handle usb_handle;
-
-typedef struct usb_ifc_info usb_ifc_info;
-
-struct usb_ifc_info
-{
+struct usb_ifc_info {
/* from device descriptor */
unsigned short dev_vendor;
unsigned short dev_product;
@@ -68,8 +61,4 @@
int usb_write(usb_handle *h, const void *_data, int len);
int usb_wait_for_disconnect(usb_handle *h);
-#if defined(__cplusplus)
-}
-#endif
-
#endif
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c
index 8b0f714..d77d41f 100644
--- a/fs_mgr/fs_mgr_fstab.c
+++ b/fs_mgr/fs_mgr_fstab.c
@@ -20,6 +20,8 @@
#include <string.h>
#include <sys/mount.h>
+#include <cutils/properties.h>
+
#include "fs_mgr_priv.h"
struct fs_mgr_flag_values {
@@ -70,6 +72,7 @@
{ "zramsize=", MF_ZRAMSIZE },
{ "verify", MF_VERIFY },
{ "noemulatedsd", MF_NOEMULATEDSD },
+ { "slotselect", MF_SLOTSELECT },
{ "defaults", 0 },
{ 0, 0 },
};
@@ -307,6 +310,23 @@
fstab->recs[cnt].partnum = flag_vals.partnum;
fstab->recs[cnt].swap_prio = flag_vals.swap_prio;
fstab->recs[cnt].zram_size = flag_vals.zram_size;
+
+ /* If an A/B partition, modify block device to be the real block device */
+ if (fstab->recs[cnt].fs_mgr_flags & MF_SLOTSELECT) {
+ char propbuf[PROPERTY_VALUE_MAX];
+ char *tmp;
+
+ /* use the kernel parameter if set */
+ property_get("ro.boot.slot_suffix", propbuf, "");
+
+ if (asprintf(&tmp, "%s%s", fstab->recs[cnt].blk_device, propbuf) > 0) {
+ free(fstab->recs[cnt].blk_device);
+ fstab->recs[cnt].blk_device = tmp;
+ } else {
+ ERROR("Error updating block device name\n");
+ goto err;
+ }
+ }
cnt++;
}
fclose(fstab_file);
@@ -448,3 +468,8 @@
{
return fstab->fs_mgr_flags & MF_NOEMULATEDSD;
}
+
+int fs_mgr_is_slotselect(struct fstab_rec *fstab)
+{
+ return fstab->fs_mgr_flags & MF_SLOTSELECT;
+}
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h
index d56111a..cc02bac 100644
--- a/fs_mgr/fs_mgr_priv.h
+++ b/fs_mgr/fs_mgr_priv.h
@@ -77,6 +77,7 @@
#define MF_NOEMULATEDSD 0x800 /* no emulated sdcard daemon, sd card is the only
external storage */
#define MF_FILEENCRYPTION 0x2000
+#define MF_SLOTSELECT 0x8000
#define DM_BUF_SIZE 4096
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index ed773d0..e280fdc 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -194,6 +194,15 @@
getIntField(mHealthdConfig->batteryCapacityPath);
props.batteryVoltage = getIntField(mHealthdConfig->batteryVoltagePath) / 1000;
+ if (!mHealthdConfig->batteryCurrentNowPath.isEmpty())
+ props.batteryCurrent = getIntField(mHealthdConfig->batteryCurrentNowPath) / 1000;
+
+ if (!mHealthdConfig->batteryFullChargePath.isEmpty())
+ props.batteryFullCharge = getIntField(mHealthdConfig->batteryFullChargePath);
+
+ if (!mHealthdConfig->batteryCycleCountPath.isEmpty())
+ props.batteryCycleCount = getIntField(mHealthdConfig->batteryCycleCountPath);
+
props.batteryTemperature = mBatteryFixedTemperature ?
mBatteryFixedTemperature :
getIntField(mHealthdConfig->batteryTemperaturePath);
@@ -245,7 +254,7 @@
if (logthis) {
char dmesgline[256];
-
+ size_t len;
if (props.batteryPresent) {
snprintf(dmesgline, sizeof(dmesgline),
"battery l=%d v=%d t=%s%d.%d h=%d st=%d",
@@ -255,19 +264,27 @@
abs(props.batteryTemperature % 10), props.batteryHealth,
props.batteryStatus);
+ len = strlen(dmesgline);
if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
- int c = getIntField(mHealthdConfig->batteryCurrentNowPath);
- char b[20];
+ len += snprintf(dmesgline + len, sizeof(dmesgline) - len,
+ " c=%d", props.batteryCurrent);
+ }
- snprintf(b, sizeof(b), " c=%d", c / 1000);
- strlcat(dmesgline, b, sizeof(dmesgline));
+ if (!mHealthdConfig->batteryFullChargePath.isEmpty()) {
+ len += snprintf(dmesgline + len, sizeof(dmesgline) - len,
+ " fc=%d", props.batteryFullCharge);
+ }
+
+ if (!mHealthdConfig->batteryCycleCountPath.isEmpty()) {
+ len += snprintf(dmesgline + len, sizeof(dmesgline) - len,
+ " cc=%d", props.batteryCycleCount);
}
} else {
snprintf(dmesgline, sizeof(dmesgline),
"battery none");
}
- size_t len = strlen(dmesgline);
+ len = strlen(dmesgline);
snprintf(dmesgline + len, sizeof(dmesgline) - len, " chg=%s%s%s",
props.chargerAcOnline ? "a" : "",
props.chargerUsbOnline ? "u" : "",
@@ -394,6 +411,21 @@
snprintf(vs, sizeof(vs), "charge counter: %d\n", v);
write(fd, vs, strlen(vs));
}
+
+ if (!mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
+ snprintf(vs, sizeof(vs), "current now: %d\n", props.batteryCurrent);
+ write(fd, vs, strlen(vs));
+ }
+
+ if (!mHealthdConfig->batteryCycleCountPath.isEmpty()) {
+ snprintf(vs, sizeof(vs), "cycle count: %d\n", props.batteryCycleCount);
+ write(fd, vs, strlen(vs));
+ }
+
+ if (!mHealthdConfig->batteryFullChargePath.isEmpty()) {
+ snprintf(vs, sizeof(vs), "Full charge: %d\n", props.batteryFullCharge);
+ write(fd, vs, strlen(vs));
+ }
}
void BatteryMonitor::init(struct healthd_config *hc) {
@@ -476,6 +508,14 @@
}
}
+ if (mHealthdConfig->batteryFullChargePath.isEmpty()) {
+ path.clear();
+ path.appendFormat("%s/%s/charge_full",
+ POWER_SUPPLY_SYSFS_PATH, name);
+ if (access(path, R_OK) == 0)
+ mHealthdConfig->batteryFullChargePath = path;
+ }
+
if (mHealthdConfig->batteryCurrentNowPath.isEmpty()) {
path.clear();
path.appendFormat("%s/%s/current_now",
@@ -484,6 +524,14 @@
mHealthdConfig->batteryCurrentNowPath = path;
}
+ if (mHealthdConfig->batteryCycleCountPath.isEmpty()) {
+ path.clear();
+ path.appendFormat("%s/%s/cycle_count",
+ POWER_SUPPLY_SYSFS_PATH, name);
+ if (access(path, R_OK) == 0)
+ mHealthdConfig->batteryCycleCountPath = path;
+ }
+
if (mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
path.clear();
path.appendFormat("%s/%s/current_avg",
@@ -553,6 +601,12 @@
KLOG_WARNING(LOG_TAG, "BatteryTemperaturePath not found\n");
if (mHealthdConfig->batteryTechnologyPath.isEmpty())
KLOG_WARNING(LOG_TAG, "BatteryTechnologyPath not found\n");
+ if (mHealthdConfig->batteryCurrentNowPath.isEmpty())
+ KLOG_WARNING(LOG_TAG, "BatteryCurrentNowPath not found\n");
+ if (mHealthdConfig->batteryFullChargePath.isEmpty())
+ KLOG_WARNING(LOG_TAG, "BatteryFullChargePath not found\n");
+ if (mHealthdConfig->batteryCycleCountPath.isEmpty())
+ KLOG_WARNING(LOG_TAG, "BatteryCycleCountPath not found\n");
}
if (property_get("ro.boot.fake_battery", pval, NULL) > 0
diff --git a/healthd/healthd.cpp b/healthd/healthd.cpp
index 1fee855..cc6824a 100644
--- a/healthd/healthd.cpp
+++ b/healthd/healthd.cpp
@@ -52,6 +52,8 @@
.batteryCurrentNowPath = String8(String8::kEmptyString),
.batteryCurrentAvgPath = String8(String8::kEmptyString),
.batteryChargeCounterPath = String8(String8::kEmptyString),
+ .batteryFullChargePath = String8(String8::kEmptyString),
+ .batteryCycleCountPath = String8(String8::kEmptyString),
.energyCounter = NULL,
.screen_on = NULL,
};
diff --git a/healthd/healthd.h b/healthd/healthd.h
index 4704f0b..048fcd5 100644
--- a/healthd/healthd.h
+++ b/healthd/healthd.h
@@ -65,6 +65,8 @@
android::String8 batteryCurrentNowPath;
android::String8 batteryCurrentAvgPath;
android::String8 batteryChargeCounterPath;
+ android::String8 batteryFullChargePath;
+ android::String8 batteryCycleCountPath;
int (*energyCounter)(int64_t *);
bool (*screen_on)(android::BatteryProperties *props);
diff --git a/include/cutils/trace.h b/include/cutils/trace.h
index 6d9b3bc..9c077d6 100644
--- a/include/cutils/trace.h
+++ b/include/cutils/trace.h
@@ -71,7 +71,7 @@
#define ATRACE_TAG_LAST ATRACE_TAG_PACKAGE_MANAGER
// Reserved for initialization.
-#define ATRACE_TAG_NOT_READY (1LL<<63)
+#define ATRACE_TAG_NOT_READY (1ULL<<63)
#define ATRACE_TAG_VALID_MASK ((ATRACE_TAG_LAST - 1) | ATRACE_TAG_LAST)
diff --git a/include/log/log.h b/include/log/log.h
index 0b17574..1cdf7bc 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -563,6 +563,12 @@
#define android_btWriteLog(tag, type, payload, len) \
__android_log_btwrite(tag, type, payload, len)
+#define android_errorWriteLog(tag, subTag) \
+ __android_log_error_write(tag, subTag, -1, NULL, 0)
+
+#define android_errorWriteWithInfoLog(tag, subTag, uid, data, dataLen) \
+ __android_log_error_write(tag, subTag, uid, data, dataLen)
+
/*
* IF_ALOG uses android_testLog, but IF_ALOG can be overridden.
* android_testLog will remain constant in its purpose as a wrapper
@@ -612,6 +618,9 @@
*/
int __android_log_is_loggable(int prio, const char *tag, int def);
+int __android_log_error_write(int tag, const char *subTag, int32_t uid, const char *data,
+ uint32_t dataLen);
+
/*
* Send a simple string to the log.
*/
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 5330949..f9060c4 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -123,6 +123,8 @@
LOCAL_C_INCLUDES := $(libcutils_c_includes)
LOCAL_STATIC_LIBRARIES := liblog
LOCAL_CFLAGS += -Werror -Wall -Wextra -std=gnu90
+LOCAL_CLANG := true
+LOCAL_SANITIZE := integer
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
@@ -133,6 +135,8 @@
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_CFLAGS += -Werror -Wall -Wextra
LOCAL_C_INCLUDES := $(libcutils_c_includes)
+LOCAL_CLANG := true
+LOCAL_SANITIZE := integer
include $(BUILD_SHARED_LIBRARY)
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libcutils/arch-mips/android_memset.c b/libcutils/arch-mips/android_memset.c
index a6b7496..c0fe3d1 100644
--- a/libcutils/arch-mips/android_memset.c
+++ b/libcutils/arch-mips/android_memset.c
@@ -30,6 +30,9 @@
#include <cutils/memory.h>
+#ifdef __clang__
+__attribute__((no_sanitize("integer")))
+#endif
void android_memset16(uint16_t* dst, uint16_t value, size_t size)
{
/* optimized version of
@@ -46,7 +49,7 @@
}
/* dst is now 32-bit-aligned */
/* fill body with 32-bit pairs */
- uint32_t value32 = (value << 16) | value;
+ uint32_t value32 = (((uint32_t)value) << 16) | ((uint32_t)value);
android_memset32((uint32_t*) dst, value32, size<<1);
if (size & 1) {
dst[size-1] = value; /* fill unpaired last elem */
@@ -54,6 +57,9 @@
}
+#ifdef __clang__
+__attribute__((no_sanitize("integer")))
+#endif
void android_memset32(uint32_t* dst, uint32_t value, size_t size)
{
/* optimized version of
@@ -70,7 +76,7 @@
}
/* dst is now 64-bit aligned */
/* fill body with 64-bit pairs */
- uint64_t value64 = (((uint64_t)value)<<32) | value;
+ uint64_t value64 = (((uint64_t)value) << 32) | ((uint64_t)value);
uint64_t* dst64 = (uint64_t*)dst;
while (size >= 12) {
@@ -86,7 +92,8 @@
/* fill remainder with original 32-bit single-elem loop */
dst = (uint32_t*) dst64;
- while (size--) {
+ while (size != 0) {
+ size--;
*dst++ = value;
}
diff --git a/libcutils/hashmap.c b/libcutils/hashmap.c
index 65539ea..ede3b98 100644
--- a/libcutils/hashmap.c
+++ b/libcutils/hashmap.c
@@ -77,6 +77,9 @@
/**
* Hashes the given key.
*/
+#ifdef __clang__
+__attribute__((no_sanitize("integer")))
+#endif
static inline int hashKey(Hashmap* map, void* key) {
int h = map->hash(key);
@@ -152,6 +155,10 @@
free(map);
}
+#ifdef __clang__
+__attribute__((no_sanitize("integer")))
+#endif
+/* FIXME: relies on signed integer overflow, which is undefined behavior */
int hashmapHash(void* key, size_t keySize) {
int h = keySize;
char* data = (char*) key;
diff --git a/libcutils/str_parms.c b/libcutils/str_parms.c
index 924289a..4f23d09 100644
--- a/libcutils/str_parms.c
+++ b/libcutils/str_parms.c
@@ -42,6 +42,9 @@
}
/* use djb hash unless we find it inadequate */
+#ifdef __clang__
+__attribute__((no_sanitize("integer")))
+#endif
static int str_hash_fn(void *str)
{
uint32_t hash = 5381;
diff --git a/libcutils/strdup16to8.c b/libcutils/strdup16to8.c
index 1a8ba86..4dc987e 100644
--- a/libcutils/strdup16to8.c
+++ b/libcutils/strdup16to8.c
@@ -55,7 +55,8 @@
/* Fast path for the usual case where 3*len is < SIZE_MAX-1.
*/
if (len < (SIZE_MAX-1)/3) {
- while (len--) {
+ while (len != 0) {
+ len--;
unsigned int uic = *utf16Str++;
if (uic > 0x07ff)
@@ -69,7 +70,8 @@
}
/* The slower but paranoid version */
- while (len--) {
+ while (len != 0) {
+ len--;
unsigned int uic = *utf16Str++;
size_t utf8Cur = utf8Len;
@@ -112,7 +114,8 @@
* strnlen16to8() properly or at a minimum checked the result of
* its malloc(SIZE_MAX) in case of overflow.
*/
- while (len--) {
+ while (len != 0) {
+ len--;
unsigned int uic = *utf16Str++;
if (uic > 0x07ff) {
diff --git a/liblog/Android.mk b/liblog/Android.mk
index 930dcf7..5eed634 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -24,7 +24,7 @@
# so make sure we do not regret hard-coding it as follows:
liblog_cflags := -DLIBLOG_LOG_TAG=1005
-liblog_sources := logd_write.c
+liblog_sources := logd_write.c log_event_write.c
# some files must not be compiled when building against Mingw
# they correspond to features not used by our host development tools
diff --git a/liblog/log_event_write.c b/liblog/log_event_write.c
new file mode 100644
index 0000000..0bc42d5
--- /dev/null
+++ b/liblog/log_event_write.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include <log/log.h>
+#include <log/logger.h>
+
+#define MAX_EVENT_PAYLOAD 512
+#define MAX_SUBTAG_LEN 32
+
+static inline void copy4LE(uint8_t *buf, size_t pos, int val)
+{
+ buf[pos] = val & 0xFF;
+ buf[pos+1] = (val >> 8) & 0xFF;
+ buf[pos+2] = (val >> 16) & 0xFF;
+ buf[pos+3] = (val >> 24) & 0xFF;
+}
+
+int __android_log_error_write(int tag, const char *subTag, int32_t uid, const char *data,
+ uint32_t dataLen)
+{
+ uint8_t buf[MAX_EVENT_PAYLOAD];
+ size_t pos = 0;
+ uint32_t subTagLen = 0;
+ uint32_t roomLeftForData = 0;
+
+ if ((subTag == NULL) || ((data == NULL) && (dataLen != 0))) return -EINVAL;
+
+ subTagLen = strlen(subTag);
+
+ // Truncate subtags that are too long.
+ subTagLen = subTagLen > MAX_SUBTAG_LEN ? MAX_SUBTAG_LEN : subTagLen;
+
+ // Truncate dataLen if it is too long.
+ roomLeftForData = MAX_EVENT_PAYLOAD -
+ (1 + // EVENT_TYPE_LIST
+ 1 + // Number of elements in list
+ 1 + // EVENT_TYPE_STRING
+ sizeof(subTagLen) +
+ subTagLen +
+ 1 + // EVENT_TYPE_INT
+ sizeof(uid) +
+ 1 + // EVENT_TYPE_STRING
+ sizeof(dataLen));
+ dataLen = dataLen > roomLeftForData ? roomLeftForData : dataLen;
+
+ buf[pos++] = EVENT_TYPE_LIST;
+ buf[pos++] = 3; // Number of elements in the list (subTag, uid, data)
+
+ // Write sub tag.
+ buf[pos++] = EVENT_TYPE_STRING;
+ copy4LE(buf, pos, subTagLen);
+ pos += 4;
+ memcpy(&buf[pos], subTag, subTagLen);
+ pos += subTagLen;
+
+ // Write UID.
+ buf[pos++] = EVENT_TYPE_INT;
+ copy4LE(buf, pos, uid);
+ pos += 4;
+
+ // Write data.
+ buf[pos++] = EVENT_TYPE_STRING;
+ copy4LE(buf, pos, dataLen);
+ pos += 4;
+ if (dataLen != 0)
+ {
+ memcpy(&buf[pos], data, dataLen);
+ pos += dataLen;
+ }
+
+ return __android_log_bwrite(tag, buf, pos);
+}
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index abe0239..c987041 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -17,6 +17,7 @@
#include <fcntl.h>
#include <inttypes.h>
#include <signal.h>
+#include <string.h>
#include <cutils/properties.h>
#include <gtest/gtest.h>
@@ -876,3 +877,398 @@
property_set(key, hold[2]);
property_set(key + base_offset, hold[3]);
}
+
+static inline int32_t get4LE(const char* src)
+{
+ return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
+}
+
+TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__typical) {
+ const int TAG = 123456781;
+ const char SUBTAG[] = "test-subtag";
+ const int UID = -1;
+ const int DATA_LEN = 200;
+ struct logger_list *logger_list;
+
+ pid_t pid = getpid();
+
+ ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+ LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
+
+ ASSERT_LT(0, android_errorWriteWithInfoLog(
+ TAG, SUBTAG, UID, max_payload_buf, DATA_LEN));
+
+ sleep(2);
+
+ int count = 0;
+
+ for (;;) {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+ break;
+ }
+
+ char *eventData = log_msg.msg();
+
+ // Tag
+ int tag = get4LE(eventData);
+ eventData += 4;
+
+ if (tag != TAG) {
+ continue;
+ }
+
+ // List type
+ ASSERT_EQ(EVENT_TYPE_LIST, eventData[0]);
+ eventData++;
+
+ // Number of elements in list
+ ASSERT_EQ(3, eventData[0]);
+ eventData++;
+
+ // Element #1: string type for subtag
+ ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
+ eventData++;
+
+ ASSERT_EQ((int) strlen(SUBTAG), get4LE(eventData));
+ eventData +=4;
+
+ if (memcmp(SUBTAG, eventData, strlen(SUBTAG))) {
+ continue;
+ }
+ eventData += strlen(SUBTAG);
+
+ // Element #2: int type for uid
+ ASSERT_EQ(EVENT_TYPE_INT, eventData[0]);
+ eventData++;
+
+ ASSERT_EQ(UID, get4LE(eventData));
+ eventData += 4;
+
+ // Element #3: string type for data
+ ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
+ eventData++;
+
+ ASSERT_EQ(DATA_LEN, get4LE(eventData));
+ eventData += 4;
+
+ if (memcmp(max_payload_buf, eventData, DATA_LEN)) {
+ continue;
+ }
+
+ ++count;
+ }
+
+ EXPECT_EQ(1, count);
+
+ android_logger_list_close(logger_list);
+}
+
+TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__data_too_large) {
+ const int TAG = 123456782;
+ const char SUBTAG[] = "test-subtag";
+ const int UID = -1;
+ const int DATA_LEN = sizeof(max_payload_buf);
+ struct logger_list *logger_list;
+
+ pid_t pid = getpid();
+
+ ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+ LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
+
+ ASSERT_LT(0, android_errorWriteWithInfoLog(
+ TAG, SUBTAG, UID, max_payload_buf, DATA_LEN));
+
+ sleep(2);
+
+ int count = 0;
+
+ for (;;) {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+ break;
+ }
+
+ char *eventData = log_msg.msg();
+ char *original = eventData;
+
+ // Tag
+ int tag = get4LE(eventData);
+ eventData += 4;
+
+ if (tag != TAG) {
+ continue;
+ }
+
+ // List type
+ ASSERT_EQ(EVENT_TYPE_LIST, eventData[0]);
+ eventData++;
+
+ // Number of elements in list
+ ASSERT_EQ(3, eventData[0]);
+ eventData++;
+
+ // Element #1: string type for subtag
+ ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
+ eventData++;
+
+ ASSERT_EQ((int) strlen(SUBTAG), get4LE(eventData));
+ eventData +=4;
+
+ if (memcmp(SUBTAG, eventData, strlen(SUBTAG))) {
+ continue;
+ }
+ eventData += strlen(SUBTAG);
+
+ // Element #2: int type for uid
+ ASSERT_EQ(EVENT_TYPE_INT, eventData[0]);
+ eventData++;
+
+ ASSERT_EQ(UID, get4LE(eventData));
+ eventData += 4;
+
+ // Element #3: string type for data
+ ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
+ eventData++;
+
+ size_t dataLen = get4LE(eventData);
+ eventData += 4;
+
+ if (memcmp(max_payload_buf, eventData, dataLen)) {
+ continue;
+ }
+ eventData += dataLen;
+
+ // 4 bytes for the tag, and 512 bytes for the log since the max_payload_buf should be
+ // truncated.
+ ASSERT_EQ(4 + 512, eventData - original);
+
+ ++count;
+ }
+
+ EXPECT_EQ(1, count);
+
+ android_logger_list_close(logger_list);
+}
+
+TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__null_data) {
+ const int TAG = 123456783;
+ const char SUBTAG[] = "test-subtag";
+ const int UID = -1;
+ const int DATA_LEN = 200;
+ struct logger_list *logger_list;
+
+ pid_t pid = getpid();
+
+ ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+ LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
+
+ ASSERT_GT(0, android_errorWriteWithInfoLog(
+ TAG, SUBTAG, UID, NULL, DATA_LEN));
+
+ sleep(2);
+
+ int count = 0;
+
+ for (;;) {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+ break;
+ }
+
+ char *eventData = log_msg.msg();
+
+ // Tag
+ int tag = get4LE(eventData);
+ eventData += 4;
+
+ if (tag == TAG) {
+ // This tag should not have been written because the data was null
+ count++;
+ break;
+ }
+ }
+
+ EXPECT_EQ(0, count);
+
+ android_logger_list_close(logger_list);
+}
+
+TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__subtag_too_long) {
+ const int TAG = 123456784;
+ const char SUBTAG[] = "abcdefghijklmnopqrstuvwxyz now i know my abc";
+ const int UID = -1;
+ const int DATA_LEN = 200;
+ struct logger_list *logger_list;
+
+ pid_t pid = getpid();
+
+ ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+ LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
+
+ ASSERT_LT(0, android_errorWriteWithInfoLog(
+ TAG, SUBTAG, UID, max_payload_buf, DATA_LEN));
+
+ sleep(2);
+
+ int count = 0;
+
+ for (;;) {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+ break;
+ }
+
+ char *eventData = log_msg.msg();
+
+ // Tag
+ int tag = get4LE(eventData);
+ eventData += 4;
+
+ if (tag != TAG) {
+ continue;
+ }
+
+ // List type
+ ASSERT_EQ(EVENT_TYPE_LIST, eventData[0]);
+ eventData++;
+
+ // Number of elements in list
+ ASSERT_EQ(3, eventData[0]);
+ eventData++;
+
+ // Element #1: string type for subtag
+ ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
+ eventData++;
+
+ // The subtag is longer than 32 and should be truncated to that.
+ ASSERT_EQ(32, get4LE(eventData));
+ eventData +=4;
+
+ if (memcmp(SUBTAG, eventData, 32)) {
+ continue;
+ }
+ eventData += 32;
+
+ // Element #2: int type for uid
+ ASSERT_EQ(EVENT_TYPE_INT, eventData[0]);
+ eventData++;
+
+ ASSERT_EQ(UID, get4LE(eventData));
+ eventData += 4;
+
+ // Element #3: string type for data
+ ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
+ eventData++;
+
+ ASSERT_EQ(DATA_LEN, get4LE(eventData));
+ eventData += 4;
+
+ if (memcmp(max_payload_buf, eventData, DATA_LEN)) {
+ continue;
+ }
+
+ ++count;
+ }
+
+ EXPECT_EQ(1, count);
+
+ android_logger_list_close(logger_list);
+}
+
+TEST(liblog, android_errorWriteLog__android_logger_list_read__success) {
+ const int TAG = 123456785;
+ const char SUBTAG[] = "test-subtag";
+ struct logger_list *logger_list;
+
+ pid_t pid = getpid();
+
+ ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+ LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
+
+ ASSERT_LT(0, android_errorWriteLog(TAG, SUBTAG));
+
+ sleep(2);
+
+ int count = 0;
+
+ for (;;) {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+ break;
+ }
+
+ char *eventData = log_msg.msg();
+
+ // Tag
+ int tag = get4LE(eventData);
+ eventData += 4;
+
+ if (tag != TAG) {
+ continue;
+ }
+
+ // List type
+ ASSERT_EQ(EVENT_TYPE_LIST, eventData[0]);
+ eventData++;
+
+ // Number of elements in list
+ ASSERT_EQ(3, eventData[0]);
+ eventData++;
+
+ // Element #1: string type for subtag
+ ASSERT_EQ(EVENT_TYPE_STRING, eventData[0]);
+ eventData++;
+
+ ASSERT_EQ((int) strlen(SUBTAG), get4LE(eventData));
+ eventData +=4;
+
+ if (memcmp(SUBTAG, eventData, strlen(SUBTAG))) {
+ continue;
+ }
+ ++count;
+ }
+
+ EXPECT_EQ(1, count);
+
+ android_logger_list_close(logger_list);
+}
+
+TEST(liblog, android_errorWriteLog__android_logger_list_read__null_subtag) {
+ const int TAG = 123456786;
+ struct logger_list *logger_list;
+
+ pid_t pid = getpid();
+
+ ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+ LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
+
+ ASSERT_GT(0, android_errorWriteLog(TAG, NULL));
+
+ sleep(2);
+
+ int count = 0;
+
+ for (;;) {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+ break;
+ }
+
+ char *eventData = log_msg.msg();
+
+ // Tag
+ int tag = get4LE(eventData);
+ eventData += 4;
+
+ if (tag == TAG) {
+ // This tag should not have been written because the data was null
+ count++;
+ break;
+ }
+ }
+
+ EXPECT_EQ(0, count);
+
+ android_logger_list_close(logger_list);
+}
diff --git a/libutils/VectorImpl.cpp b/libutils/VectorImpl.cpp
index bdb54b1..2f770f5 100644
--- a/libutils/VectorImpl.cpp
+++ b/libutils/VectorImpl.cpp
@@ -198,7 +198,10 @@
_do_copy(next, curr, 1);
next = curr;
--j;
- curr = reinterpret_cast<char*>(array) + mItemSize*(j);
+ curr = NULL;
+ if (j >= 0) {
+ curr = reinterpret_cast<char*>(array) + mItemSize*(j);
+ }
} while (j>=0 && (cmp(curr, temp, state) > 0));
_do_destroy(next, 1);
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 6ea4109..a93369e 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -413,6 +413,12 @@
it = f->second;
}
}
+ static const timespec too_old = {
+ EXPIRE_HOUR_THRESHOLD * 60 * 60, 0
+ };
+ LogBufferElementCollection::iterator lastt;
+ lastt = mLogElements.end();
+ --lastt;
LogBufferElementLast last;
while (it != mLogElements.end()) {
LogBufferElement *e = *it;
@@ -464,27 +470,24 @@
continue;
}
+ if ((e->getRealTime() < ((*lastt)->getRealTime() - too_old))
+ || (e->getRealTime() > (*lastt)->getRealTime())) {
+ break;
+ }
+
// unmerged drop message
if (dropped) {
last.add(e);
- mLastWorstUid[id][e->getUid()] = it;
+ if ((e->getUid() == worst)
+ || (mLastWorstUid[id].find(e->getUid())
+ == mLastWorstUid[id].end())) {
+ mLastWorstUid[id][e->getUid()] = it;
+ }
++it;
continue;
}
if (e->getUid() != worst) {
- if (leading) {
- static const timespec too_old = {
- EXPIRE_HOUR_THRESHOLD * 60 * 60, 0
- };
- LogBufferElementCollection::iterator last;
- last = mLogElements.end();
- --last;
- if ((e->getRealTime() < ((*last)->getRealTime() - too_old))
- || (e->getRealTime() > (*last)->getRealTime())) {
- break;
- }
- }
leading = false;
last.clear(e);
++it;
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
index 1e6f55f..febf775 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -48,7 +48,7 @@
char c;
while (((c = *s++)) && (++len <= max_prio_len)) {
if (!isdigit(c)) {
- return (c == '>') ? s : NULL;
+ return ((c == '>') && (*s == '[')) ? s : NULL;
}
}
return NULL;
@@ -294,6 +294,22 @@
}
}
+pid_t LogKlog::sniffPid(const char *cp) {
+ while (*cp) {
+ // Mediatek kernels with modified printk
+ if (*cp == '[') {
+ int pid = 0;
+ char dummy;
+ if (sscanf(cp, "[%d:%*[a-z_./0-9:A-Z]]%c", &pid, &dummy) == 2) {
+ return pid;
+ }
+ break; // Only the first one
+ }
+ ++cp;
+ }
+ return 0;
+}
+
// Passed the entire SYSLOG_ACTION_READ_ALL buffer and interpret a
// compensated start time.
void LogKlog::synchronize(const char *buf) {
@@ -417,9 +433,9 @@
// sniff for start marker
const char klogd_message[] = "logd.klogd: ";
- if (!strncmp(buf, klogd_message, sizeof(klogd_message) - 1)) {
- char *endp;
- uint64_t sig = strtoll(buf + sizeof(klogd_message) - 1, &endp, 10);
+ const char *start = strstr(buf, klogd_message);
+ if (start) {
+ uint64_t sig = strtoll(start + sizeof(klogd_message) - 1, NULL, 10);
if (sig == signature.nsec()) {
if (initialized) {
enableLogging = true;
@@ -435,10 +451,10 @@
return 0;
}
- // Parse pid, tid and uid (not possible)
- const pid_t pid = 0;
- const pid_t tid = 0;
- const uid_t uid = 0;
+ // Parse pid, tid and uid
+ const pid_t pid = sniffPid(buf);
+ const pid_t tid = pid;
+ const uid_t uid = pid ? logbuf->pidToUid(pid) : 0;
// Parse (rules at top) to pull out a tag from the incoming kernel message.
// Some may view the following as an ugly heuristic, the desire is to
@@ -450,7 +466,7 @@
if (!*buf) {
return 0;
}
- const char *start = buf;
+ start = buf;
const char *tag = "";
const char *etag = tag;
if (!isspace(*buf)) {
@@ -461,7 +477,14 @@
// <PRI>[<TIME>] "[INFO]"<tag> ":" message
bt = buf + 6;
}
- for(et = bt; *et && (*et != ':') && !isspace(*et); ++et);
+ for(et = bt; *et && (*et != ':') && !isspace(*et); ++et) {
+ // skip ':' within [ ... ]
+ if (*et == '[') {
+ while (*et && *et != ']') {
+ ++et;
+ }
+ }
+ }
for(cp = et; isspace(*cp); ++cp);
size_t size;
@@ -557,7 +580,17 @@
etag = tag = "";
}
}
- size_t l = etag - tag;
+ // Suppress additional stutter in tag:
+ // eg: [143:healthd]healthd -> [143:healthd]
+ size_t taglen = etag - tag;
+ // Mediatek-special printk induced stutter
+ char *np = strrchr(tag, ']');
+ if (np && (++np < etag)) {
+ size_t s = etag - np;
+ if (((s + s) < taglen) && !strncmp(np, np - 1 - s, s)) {
+ taglen = np - tag;
+ }
+ }
// skip leading space
while (isspace(*buf)) {
++buf;
@@ -568,11 +601,11 @@
--b;
}
// trick ... allow tag with empty content to be logged. log() drops empty
- if (!b && l) {
+ if (!b && taglen) {
buf = " ";
b = 1;
}
- size_t n = 1 + l + 1 + b + 1;
+ size_t n = 1 + taglen + 1 + b + 1;
// Allocate a buffer to hold the interpreted log message
int rc = n;
@@ -581,15 +614,15 @@
rc = -ENOMEM;
return rc;
}
- char *np = newstr;
+ np = newstr;
// Convert priority into single-byte Android logger priority
*np = convertKernelPrioToAndroidPrio(pri);
++np;
// Copy parsed tag following priority
- strncpy(np, tag, l);
- np += l;
+ strncpy(np, tag, taglen);
+ np += taglen;
*np = '\0';
++np;
diff --git a/logd/LogKlog.h b/logd/LogKlog.h
index 24b2685..7e4fde0 100644
--- a/logd/LogKlog.h
+++ b/logd/LogKlog.h
@@ -47,6 +47,7 @@
protected:
void sniffTime(log_time &now, const char **buf, bool reverse);
+ pid_t sniffPid(const char *buf);
void calculateCorrection(const log_time &monotonic, const char *real_string);
virtual bool onDataAvailable(SocketClient *cli);
diff --git a/metricsd/Android.mk b/metricsd/Android.mk
index 9fd8eda..89fa222 100644
--- a/metricsd/Android.mk
+++ b/metricsd/Android.mk
@@ -110,6 +110,7 @@
libprotobuf-cpp-lite \
libchromeos-http \
libchromeos-dbus \
+ libcutils \
libdbus
LOCAL_SRC_FILES := $(metrics_daemon_sources)
LOCAL_STATIC_LIBRARIES := metrics_daemon_protos
diff --git a/metricsd/constants.h b/metricsd/constants.h
index 56dac0d..15c15d9 100644
--- a/metricsd/constants.h
+++ b/metricsd/constants.h
@@ -24,6 +24,11 @@
static const char kMetricsServer[] = "https://clients4.google.com/uma/v2";
static const char kConsentFilePath[] = "/data/misc/metrics/enabled";
static const char kDefaultVersion[] = "0.0.0.0";
+
+// System properties used.
+static const char kBuildTargetIdProperty[] = "ro.product.build_target_id";
+static const char kChannelProperty[] = "ro.product.channel";
+static const char kProductVersionProperty[] = "ro.product.version";
} // namespace metrics
#endif // METRICS_CONSTANTS_H_
diff --git a/metricsd/metrics_daemon.cc b/metricsd/metrics_daemon.cc
index 069f68e..5855cee 100644
--- a/metricsd/metrics_daemon.cc
+++ b/metricsd/metrics_daemon.cc
@@ -32,7 +32,7 @@
#include <base/strings/string_split.h>
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
-#include <base/sys_info.h>
+#include <cutils/properties.h>
#include <dbus/dbus.h>
#include <dbus/message.h>
@@ -209,10 +209,13 @@
if (version_hash_is_cached)
return cached_version_hash;
version_hash_is_cached = true;
- std::string version = metrics::kDefaultVersion;
+
+ char version[PROPERTY_VALUE_MAX];
// The version might not be set for development devices. In this case, use the
// zero version.
- base::SysInfo::GetLsbReleaseValue("BRILLO_VERSION", &version);
+ property_get(metrics::kProductVersionProperty, version,
+ metrics::kDefaultVersion);
+
cached_version_hash = base::Hash(version);
if (testing_) {
cached_version_hash = 42; // return any plausible value for the hash
diff --git a/metricsd/uploader/system_profile_cache.cc b/metricsd/uploader/system_profile_cache.cc
index 7dd0323..21ec229 100644
--- a/metricsd/uploader/system_profile_cache.cc
+++ b/metricsd/uploader/system_profile_cache.cc
@@ -21,7 +21,7 @@
#include <base/logging.h>
#include <base/strings/string_number_conversions.h>
#include <base/strings/string_util.h>
-#include <base/sys_info.h>
+#include <cutils/properties.h>
#include <string>
#include <vector>
@@ -73,21 +73,28 @@
CHECK(!initialized_)
<< "this should be called only once in the metrics_daemon lifetime.";
- if (!base::SysInfo::GetLsbReleaseValue("BRILLO_BUILD_TARGET_ID",
- &profile_.build_target_id)) {
- LOG(ERROR) << "BRILLO_BUILD_TARGET_ID is not set in /etc/lsb-release.";
+ char property_value[PROPERTY_VALUE_MAX];
+ property_get(metrics::kBuildTargetIdProperty, property_value, "");
+ profile_.build_target_id = std::string(property_value);
+
+ if (profile_.build_target_id.empty()) {
+ LOG(ERROR) << "System property " << metrics::kBuildTargetIdProperty
+ << " is not set.";
return false;
}
- std::string channel;
- if (!base::SysInfo::GetLsbReleaseValue("BRILLO_CHANNEL", &channel) ||
- !base::SysInfo::GetLsbReleaseValue("BRILLO_VERSION", &profile_.version)) {
+ property_get(metrics::kChannelProperty, property_value, "");
+ std::string channel(property_value);
+
+ property_get(metrics::kProductVersionProperty, property_value, "");
+ profile_.version = std::string(property_value);
+
+ if (channel.empty() || profile_.version.empty()) {
// If the channel or version is missing, the image is not official.
// In this case, set the channel to unknown and the version to 0.0.0.0 to
// avoid polluting the production data.
channel = "";
profile_.version = metrics::kDefaultVersion;
-
}
profile_.client_id =
testing_ ? "client_id_test" :
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 2ae7ed2..24f702f 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -53,7 +53,6 @@
start \
stop \
top \
- uptime \
ALL_TOOLS = $(BSD_TOOLS) $(OUR_TOOLS)
diff --git a/toolbox/uptime.c b/toolbox/uptime.c
deleted file mode 100644
index ebfb15e..0000000
--- a/toolbox/uptime.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (c) 2010, The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of Google, Inc. nor the names of its contributors
- * may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-
-static void format_time(int time, char* buffer) {
- int seconds = time % 60;
- time /= 60;
- int minutes = time % 60;
- time /= 60;
- int hours = time % 24;
- int days = time / 24;
-
- if (days > 0) {
- sprintf(buffer, "%d day%s, %02d:%02d:%02d", days, (days == 1) ? "" : "s", hours, minutes, seconds);
- } else {
- sprintf(buffer, "%02d:%02d:%02d", hours, minutes, seconds);
- }
-}
-
-int uptime_main(int argc __attribute__((unused)), char *argv[] __attribute__((unused))) {
- FILE* file = fopen("/proc/uptime", "r");
- if (!file) {
- fprintf(stderr, "Could not open /proc/uptime\n");
- return -1;
- }
- float idle_time;
- if (fscanf(file, "%*f %f", &idle_time) != 1) {
- fprintf(stderr, "Could not parse /proc/uptime\n");
- fclose(file);
- return -1;
- }
- fclose(file);
-
- struct timespec up_timespec;
- if (clock_gettime(CLOCK_MONOTONIC, &up_timespec) == -1) {
- fprintf(stderr, "Could not get monotonic time: %s\n", strerror(errno));
- return -1;
- }
- float up_time = up_timespec.tv_sec + up_timespec.tv_nsec / 1e9;
-
- struct timespec elapsed_timespec;
- if (clock_gettime(CLOCK_BOOTTIME, &elapsed_timespec) == -1) {
- fprintf(stderr, "Could not get boot time: %s\n", strerror(errno));
- return -1;
- }
- int elapsed = elapsed_timespec.tv_sec;
-
- char up_string[100], idle_string[100], sleep_string[100];
- format_time(elapsed, up_string);
- format_time((int)idle_time, idle_string);
- format_time((int)(elapsed - up_time), sleep_string);
- printf("up time: %s, idle time: %s, sleep time: %s\n", up_string, idle_string, sleep_string);
-
- return 0;
-}