Merge "Lose uptime to toybox."
diff --git a/adb/Android.mk b/adb/Android.mk
index e2d0bb1..f9d4441 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -88,7 +88,6 @@
adb_auth_client.cpp \
fdevent.cpp \
jdwp_service.cpp \
- qemu_tracing.cpp \
usb_linux_client.cpp \
LOCAL_SANITIZE := $(adb_target_sanitize)
@@ -118,6 +117,8 @@
ifeq ($(HOST_OS),windows)
LOCAL_C_INCLUDES += development/host/windows/usb/api/
+else
+ LOCAL_MULTILIB := 64
endif
include $(BUILD_HOST_STATIC_LIBRARY)
@@ -277,6 +278,8 @@
LOCAL_MODULE := adbd
+LOCAL_INIT_RC := adbd.rc
+
LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
diff --git a/adb/SERVICES.TXT b/adb/SERVICES.TXT
index 63000f2..30c21f7 100644
--- a/adb/SERVICES.TXT
+++ b/adb/SERVICES.TXT
@@ -237,7 +237,7 @@
Note that there is no single-shot service to retrieve the list only once.
sync:
- This starts the file synchronisation service, used to implement "adb push"
+ This starts the file synchronization service, used to implement "adb push"
and "adb pull". Since this service is pretty complex, it will be detailed
in a companion document named SYNC.TXT
diff --git a/adb/SYNC.TXT b/adb/SYNC.TXT
index e74d217..06d7804 100644
--- a/adb/SYNC.TXT
+++ b/adb/SYNC.TXT
@@ -25,12 +25,9 @@
The following sync requests are accepted:
LIST - List the files in a folder
+RECV - Retrieve a file from device
SEND - Send a file to device
-RECV - Retreive a file from device
-
-Not yet documented:
STAT - Stat a file
-ULNK - Unlink (remove) a file. (Not currently supported)
For all of the sync request above the must be followed by length number of
bytes containing an utf-8 string with a remote filename.
@@ -40,7 +37,7 @@
respond with zero or more directory entries or "dents".
The directory entries will be returned in the following form
-1. A four-byte sync response id beeing "DENT"
+1. A four-byte sync response id "DENT"
2. A four-byte integer representing file mode.
3. A four-byte integer representing file size.
4. A four-byte integer representing last modified time.
@@ -60,13 +57,13 @@
adb push disk_image /some_block_device
to work.
-After this the actual file is sent in chunks. Each chucks has the following
+After this the actual file is sent in chunks. Each chunk has the following
format.
A sync request with id "DATA" and length equal to the chunk size. After
follows chunk size number of bytes. This is repeated until the file is
-transfered. Each chunk must not be larger than 64k.
+transferred. Each chunk must not be larger than 64k.
-When the file is tranfered a sync request "DONE" is sent, where length is set
+When the file is transferred a sync request "DONE" is sent, where length is set
to the last modified time for the file. The server responds to this last
request (but not to chuck requests) with an "OKAY" sync response (length can
be ignored).
@@ -77,8 +74,8 @@
the file that will be returned. Just as for the SEND sync request the file
received is split up into chunks. The sync response id is "DATA" and length is
the chuck size. After follows chunk size number of bytes. This is repeated
-until the file is transfered. Each chuck will not be larger than 64k.
+until the file is transferred. Each chuck will not be larger than 64k.
-When the file is transfered a sync resopnse "DONE" is retrieved where the
+When the file is transferred a sync response "DONE" is retrieved where the
length can be ignored.
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_client.cpp b/adb/adb_client.cpp
index 4bf647c..a1bbb78 100644
--- a/adb/adb_client.cpp
+++ b/adb/adb_client.cpp
@@ -44,28 +44,6 @@
static int __adb_server_port = DEFAULT_ADB_PORT;
static const char* __adb_server_name = NULL;
-static std::string perror_str(const char* msg) {
- return android::base::StringPrintf("%s: %s", msg, strerror(errno));
-}
-
-static bool ReadProtocolString(int fd, std::string* s, std::string* error) {
- char buf[5];
- if (!ReadFdExactly(fd, buf, 4)) {
- *error = perror_str("protocol fault (couldn't read status length)");
- return false;
- }
- buf[4] = 0;
-
- unsigned long len = strtoul(buf, 0, 16);
- s->resize(len, '\0');
- if (!ReadFdExactly(fd, &(*s)[0], len)) {
- *error = perror_str("protocol fault (couldn't read status message)");
- return false;
- }
-
- return true;
-}
-
void adb_set_transport(TransportType type, const char* serial)
{
__adb_transport = type;
@@ -175,7 +153,7 @@
return -1;
}
- if(!SendProtocolString(fd, service)) {
+ if (!SendProtocolString(fd, service)) {
*error = perror_str("write failure during connection");
adb_close(fd);
return -1;
diff --git a/adb/adb_io.cpp b/adb/adb_io.cpp
index 5ae6ec3..7092609 100644
--- a/adb/adb_io.cpp
+++ b/adb/adb_io.cpp
@@ -32,7 +32,27 @@
length = 0xffff;
}
- return WriteFdFmt(fd, "%04x", length) && WriteFdExactly(fd, s);
+ // The cost of sending two strings outweighs the cost of formatting.
+ // "adb sync" performance is affected by this.
+ return WriteFdFmt(fd, "%04x%.*s", length, length, s.c_str());
+}
+
+bool ReadProtocolString(int fd, std::string* s, std::string* error) {
+ char buf[5];
+ if (!ReadFdExactly(fd, buf, 4)) {
+ *error = perror_str("protocol fault (couldn't read status length)");
+ return false;
+ }
+ buf[4] = 0;
+
+ unsigned long len = strtoul(buf, 0, 16);
+ s->resize(len, '\0');
+ if (!ReadFdExactly(fd, &(*s)[0], len)) {
+ *error = perror_str("protocol fault (couldn't read status message)");
+ return false;
+ }
+
+ return true;
}
bool SendOkay(int fd) {
diff --git a/adb/adb_io.h b/adb/adb_io.h
index 8d50a6d..9c3b2a5 100644
--- a/adb/adb_io.h
+++ b/adb/adb_io.h
@@ -30,23 +30,22 @@
// Writes a protocol-format string; a four hex digit length followed by the string data.
bool SendProtocolString(int fd, const std::string& s);
-/*
- * Reads exactly len bytes from fd into buf.
- *
- * Returns false if there is an error or if EOF was reached before len bytes
- * were read. If EOF was found, errno will be set to 0.
- *
- * If this function fails, the contents of buf are undefined.
- */
-bool ReadFdExactly(int fd, void *buf, size_t len);
+// Reads a protocol-format string; a four hex digit length followed by the string data.
+bool ReadProtocolString(int fd, std::string* s, std::string* error);
-/*
- * Writes exactly len bytes from buf to fd.
- *
- * Returns false if there is an error or if the fd was closed before the write
- * completed. If the other end of the fd (such as in a socket, pipe, or fifo),
- * is closed, errno will be set to 0.
- */
+// Reads exactly len bytes from fd into buf.
+//
+// Returns false if there is an error or if EOF was reached before len bytes
+// were read. If EOF was found, errno will be set to 0.
+//
+// If this function fails, the contents of buf are undefined.
+bool ReadFdExactly(int fd, void* buf, size_t len);
+
+// Writes exactly len bytes from buf to fd.
+//
+// Returns false if there is an error or if the fd was closed before the write
+// completed. If the other end of the fd (such as in a socket, pipe, or fifo),
+// is closed, errno will be set to 0.
bool WriteFdExactly(int fd, const void* buf, size_t len);
// Same as above, but for strings.
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/adb_utils.cpp b/adb/adb_utils.cpp
index ca843bd..e5dc692 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -225,3 +225,7 @@
<< " (" << *canonical_address << ")";
return true;
}
+
+std::string perror_str(const char* msg) {
+ return android::base::StringPrintf("%s: %s", msg, strerror(errno));
+}
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index 739efcc..b38ec59 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -44,4 +44,6 @@
std::string* host, int* port,
std::string* error);
+std::string perror_str(const char* msg);
+
#endif
diff --git a/adb/adbd.rc b/adb/adbd.rc
new file mode 100644
index 0000000..b91d8b5
--- /dev/null
+++ b/adb/adbd.rc
@@ -0,0 +1,14 @@
+on post-fs-data
+ mkdir /data/misc/adb 02750 system shell
+ mkdir /data/adb 0700 root root
+
+# adbd is controlled via property triggers in init.<platform>.usb.rc
+service adbd /sbin/adbd --root_seclabel=u:r:su:s0
+ class core
+ socket adbd stream 660 system system
+ disabled
+ seclabel u:r:adbd:s0
+
+# adbd on at boot in emulator
+on property:ro.kernel.qemu=1
+ start adbd
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index 206442a..f6ddeb4 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -76,6 +76,8 @@
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,16 +130,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);
@@ -161,6 +173,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";
@@ -183,8 +201,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 c7b7675..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);
- for(;;) {
+ 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;
@@ -889,14 +880,14 @@
}
static void parse_push_pull_args(const char **arg, int narg, char const **path1,
- char const **path2, int *show_progress,
+ char const **path2, bool* show_progress,
int *copy_attrs) {
- *show_progress = 0;
+ *show_progress = false;
*copy_attrs = 0;
while (narg > 0) {
if (!strcmp(*arg, "-p")) {
- *show_progress = 1;
+ *show_progress = true;
} else if (!strcmp(*arg, "-a")) {
*copy_attrs = 1;
} else {
@@ -1331,33 +1322,25 @@
/* do_sync_*() commands */
else if (!strcmp(argv[0], "ls")) {
if (argc != 2) return usage();
- return do_sync_ls(argv[1]);
+ return do_sync_ls(argv[1]) ? 0 : 1;
}
else if (!strcmp(argv[0], "push")) {
- int show_progress = 0;
- int copy_attrs = 0; // unused
+ bool show_progress = false;
+ int copy_attrs = 0;
const char* lpath = NULL, *rpath = NULL;
parse_push_pull_args(&argv[1], argc - 1, &lpath, &rpath, &show_progress, ©_attrs);
-
- if ((lpath != NULL) && (rpath != NULL)) {
- return do_sync_push(lpath, rpath, show_progress);
- }
-
- return usage();
+ if (!lpath || !rpath || copy_attrs != 0) return usage();
+ return do_sync_push(lpath, rpath, show_progress) ? 0 : 1;
}
else if (!strcmp(argv[0], "pull")) {
- int show_progress = 0;
+ bool show_progress = false;
int copy_attrs = 0;
const char* rpath = NULL, *lpath = ".";
parse_push_pull_args(&argv[1], argc - 1, &rpath, &lpath, &show_progress, ©_attrs);
-
- if (rpath != NULL) {
- return do_sync_pull(rpath, lpath, show_progress, copy_attrs);
- }
-
- return usage();
+ if (!rpath) return usage();
+ return do_sync_pull(rpath, lpath, show_progress, copy_attrs) ? 0 : 1;
}
else if (!strcmp(argv[0], "install")) {
if (argc < 2) return usage();
@@ -1401,20 +1384,20 @@
std::string vendor_src_path = product_file("vendor");
std::string oem_src_path = product_file("oem");
- int rc = 0;
- if (rc == 0 && (src.empty() || src == "system")) {
- rc = do_sync_sync(system_src_path, "/system", list_only);
+ bool okay = true;
+ if (okay && (src.empty() || src == "system")) {
+ okay = do_sync_sync(system_src_path, "/system", list_only);
}
- if (rc == 0 && (src.empty() || src == "vendor") && directory_exists(vendor_src_path)) {
- rc = do_sync_sync(vendor_src_path, "/vendor", list_only);
+ if (okay && (src.empty() || src == "vendor") && directory_exists(vendor_src_path)) {
+ okay = do_sync_sync(vendor_src_path, "/vendor", list_only);
}
- if (rc == 0 && (src.empty() || src == "oem") && directory_exists(oem_src_path)) {
- rc = do_sync_sync(oem_src_path, "/oem", list_only);
+ if (okay && (src.empty() || src == "oem") && directory_exists(oem_src_path)) {
+ okay = do_sync_sync(oem_src_path, "/oem", list_only);
}
- if (rc == 0 && (src.empty() || src == "data")) {
- rc = do_sync_sync(data_src_path, "/data", list_only);
+ if (okay && (src.empty() || src == "data")) {
+ okay = do_sync_sync(data_src_path, "/data", list_only);
}
- return rc;
+ return okay ? 0 : 1;
}
/* passthrough commands */
else if (!strcmp(argv[0],"get-state") ||
@@ -1535,20 +1518,16 @@
return -1;
}
+ int result = -1;
const char* apk_file = argv[last_apk];
std::string apk_dest = android::base::StringPrintf(where, adb_basename(apk_file).c_str());
- int err = do_sync_push(apk_file, apk_dest.c_str(), 0 /* no show progress */);
- if (err) {
- goto cleanup_apk;
- } else {
- argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */
- }
-
- err = pm_command(transport, serial, argc, argv);
+ if (!do_sync_push(apk_file, apk_dest.c_str(), false)) goto cleanup_apk;
+ argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */
+ result = pm_command(transport, serial, argc, argv);
cleanup_apk:
delete_file(transport, serial, apk_dest);
- return err;
+ return result;
}
static int install_multiple_app(TransportType transport, const char* serial, int argc,
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 bc1364b..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.
@@ -112,7 +143,8 @@
_RETURN_CODE_PROBE_STRING = 'echo "{0}$?"'.format(_RETURN_CODE_DELIMITER)
# Maximum search distance from the output end to find the delimiter.
- _RETURN_CODE_SEARCH_LENGTH = len('{0}255\n'.format(_RETURN_CODE_DELIMITER))
+ # adb on Windows returns \r\n even if adbd returns \n.
+ _RETURN_CODE_SEARCH_LENGTH = len('{0}255\r\n'.format(_RETURN_CODE_DELIMITER))
def __init__(self, serial, product=None):
self.serial = serial
@@ -165,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 a8abade..d25bbfb 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -2,16 +2,16 @@
**
** Copyright 2006, Brian Swetland <swetland@frotz.net>
**
-** 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
+** 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
+** 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
+** 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.
*/
@@ -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);
}
@@ -688,7 +688,7 @@
fdevent_subproc_setup();
#endif // !ADB_HOST
- for(;;) {
+ while (true) {
D("--- ---- waiting for events\n");
fdevent_process();
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index da80013..94876ee 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -27,6 +27,8 @@
#include <time.h>
#include <utime.h>
+#include <memory>
+
#include "sysdeps.h"
#include "adb.h"
@@ -35,36 +37,21 @@
#include "adb_utils.h"
#include "file_sync_service.h"
+#include <base/strings.h>
#include <base/stringprintf.h>
-static unsigned long long total_bytes;
-static long long start_time;
+struct syncsendbuf {
+ unsigned id;
+ unsigned size;
+ char data[SYNC_DATA_MAX];
+};
-static long long NOW()
-{
+static syncsendbuf send_buffer;
+
+static long long NOW() {
struct timeval tv;
gettimeofday(&tv, 0);
- return ((long long) tv.tv_usec) +
- 1000000LL * ((long long) tv.tv_sec);
-}
-
-static void BEGIN()
-{
- total_bytes = 0;
- start_time = NOW();
-}
-
-static void END()
-{
- long long t = NOW() - start_time;
- if(total_bytes == 0) return;
-
- if (t == 0) /* prevent division by 0 :-) */
- t = 1000000;
-
- fprintf(stderr,"%lld KB/s (%lld bytes in %lld.%03llds)\n",
- ((total_bytes * 1000000LL) / t) / 1024LL,
- total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
+ return ((long long) tv.tv_usec) + 1000000LL * ((long long) tv.tv_sec);
}
static void print_transfer_progress(uint64_t bytes_current,
@@ -82,363 +69,255 @@
fflush(stderr);
}
-static void sync_quit(int fd) {
- syncmsg msg;
-
- msg.req.id = ID_QUIT;
- msg.req.namelen = 0;
-
- WriteFdExactly(fd, &msg.req, sizeof(msg.req));
-}
-
-typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char *name, void *cookie);
-
-static int sync_ls(int fd, const char* path, sync_ls_cb func, void* cookie) {
- int len = strlen(path);
- if (len > 1024) goto fail;
-
- syncmsg msg;
- msg.req.id = ID_LIST;
- msg.req.namelen = htoll(len);
-
- if (!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) || !WriteFdExactly(fd, path, len)) {
- goto fail;
+static bool SendRequest(int fd, int id, const char* path) {
+ size_t path_length = strlen(path);
+ if (path_length > 1024) {
+ fprintf(stderr, "SendRequest failed: path too long: %zu", path_length);
+ return false;
}
- for (;;) {
- if (!ReadFdExactly(fd, &msg.dent, sizeof(msg.dent))) break;
- if (msg.dent.id == ID_DONE) return 0;
- if (msg.dent.id != ID_DENT) break;
+ // Sending header and payload in a single write makes a noticeable
+ // difference to "adb sync" performance.
+ char buf[sizeof(SyncRequest) + path_length] __attribute__((aligned(8)));
+ SyncRequest* req = reinterpret_cast<SyncRequest*>(buf);
+ req->id = id;
+ req->path_length = path_length;
+ char* data = reinterpret_cast<char*>(req + 1);
+ memcpy(data, path, path_length);
- len = ltohl(msg.dent.namelen);
- if (len > 256) break;
-
- char buf[257];
- if (!ReadFdExactly(fd, buf, len)) break;
- buf[len] = 0;
-
- func(ltohl(msg.dent.mode), ltohl(msg.dent.size), ltohl(msg.dent.time), buf, cookie);
- }
-
-fail:
- adb_close(fd);
- return -1;
+ return WriteFdExactly(fd, buf, sizeof(buf));
}
-struct syncsendbuf {
- unsigned id;
- unsigned size;
- char data[SYNC_DATA_MAX];
+class SyncConnection {
+ public:
+ SyncConnection() : total_bytes(0), start_time_(NOW()) {
+ max = SYNC_DATA_MAX; // TODO: decide at runtime.
+
+ std::string error;
+ fd = adb_connect("sync:", &error);
+ if (fd < 0) {
+ fprintf(stderr, "error: %s\n", error.c_str());
+ }
+ }
+
+ ~SyncConnection() {
+ if (!IsValid()) return;
+
+ SendQuit();
+ ShowTransferRate();
+ adb_close(fd);
+ }
+
+ bool IsValid() { return fd >= 0; }
+
+ uint64_t total_bytes;
+
+ // TODO: add a char[max] buffer here, to replace syncsendbuf...
+ int fd;
+ size_t max;
+
+ private:
+ uint64_t start_time_;
+
+ void SendQuit() {
+ SendRequest(fd, ID_QUIT, ""); // TODO: add a SendResponse?
+ }
+
+ void ShowTransferRate() {
+ uint64_t t = NOW() - start_time_;
+ if (total_bytes == 0 || t == 0) return;
+
+ fprintf(stderr, "%lld KB/s (%" PRId64 " bytes in %lld.%03llds)\n",
+ ((total_bytes * 1000000LL) / t) / 1024LL,
+ total_bytes, (t / 1000000LL), (t % 1000000LL) / 1000LL);
+ }
};
-static syncsendbuf send_buffer;
+typedef void (*sync_ls_cb)(unsigned mode, unsigned size, unsigned time, const char* name, void* cookie);
-static int sync_readtime(int fd, const char* path, unsigned int* timestamp, unsigned int* mode) {
- syncmsg msg;
- int len = strlen(path);
+static bool sync_ls(int fd, const char* path, sync_ls_cb func, void* cookie) {
+ if (!SendRequest(fd, ID_LIST, path)) return false;
- msg.req.id = ID_STAT;
- msg.req.namelen = htoll(len);
+ while (true) {
+ syncmsg msg;
+ if (!ReadFdExactly(fd, &msg.dent, sizeof(msg.dent))) return false;
- if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
- !WriteFdExactly(fd, path, len)) {
- return -1;
+ if (msg.dent.id == ID_DONE) return true;
+ if (msg.dent.id != ID_DENT) return false;
+
+ size_t len = msg.dent.namelen;
+ if (len > 256) return false; // TODO: resize buffer? continue?
+
+ char buf[257];
+ if (!ReadFdExactly(fd, buf, len)) return false;
+ buf[len] = 0;
+
+ func(msg.dent.mode, msg.dent.size, msg.dent.time, buf, cookie);
}
-
- if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) {
- return -1;
- }
-
- if(msg.stat.id != ID_STAT) {
- return -1;
- }
-
- *timestamp = ltohl(msg.stat.time);
- *mode = ltohl(msg.stat.mode);
- return 0;
}
-static int sync_start_readtime(int fd, const char *path)
-{
- syncmsg msg;
- int len = strlen(path);
-
- msg.req.id = ID_STAT;
- msg.req.namelen = htoll(len);
-
- if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
- !WriteFdExactly(fd, path, len)) {
- return -1;
- }
-
- return 0;
+static bool sync_start_stat(SyncConnection& sc, const char* path) {
+ return SendRequest(sc.fd, ID_STAT, path);
}
-static int sync_finish_readtime(int fd, unsigned int *timestamp,
- unsigned int *mode, unsigned int *size)
-{
+static bool sync_finish_stat(SyncConnection& sc, unsigned int* timestamp,
+ unsigned int* mode, unsigned int* size) {
syncmsg msg;
+ if (!ReadFdExactly(sc.fd, &msg.stat, sizeof(msg.stat)) || msg.stat.id != ID_STAT) {
+ return false;
+ }
- if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat)))
- return -1;
+ if (timestamp) *timestamp = msg.stat.time;
+ if (mode) *mode = msg.stat.mode;
+ if (size) *size = msg.stat.size;
- if(msg.stat.id != ID_STAT)
- return -1;
-
- *timestamp = ltohl(msg.stat.time);
- *mode = ltohl(msg.stat.mode);
- *size = ltohl(msg.stat.size);
-
- return 0;
+ return true;
}
-static int sync_readmode(int fd, const char* path, unsigned* mode) {
- syncmsg msg;
- int len = strlen(path);
-
- msg.req.id = ID_STAT;
- msg.req.namelen = htoll(len);
-
- if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
- !WriteFdExactly(fd, path, len)) {
- return -1;
- }
-
- if(!ReadFdExactly(fd, &msg.stat, sizeof(msg.stat))) {
- return -1;
- }
-
- if(msg.stat.id != ID_STAT) {
- return -1;
- }
-
- *mode = ltohl(msg.stat.mode);
- return 0;
+static bool sync_stat(SyncConnection& sc, const char* path,
+ unsigned int* timestamp, unsigned int* mode, unsigned int* size) {
+ return sync_start_stat(sc, path) && sync_finish_stat(sc, timestamp, mode, size);
}
-static int write_data_file(int fd, const char *path, syncsendbuf *sbuf, bool show_progress)
-{
- int lfd, err = 0;
+static bool write_data_file(SyncConnection& sc, const char* path, syncsendbuf* sbuf, bool show_progress) {
unsigned long long size = 0;
-
- 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)) {
- fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno));
- return -1;
+ if (stat(path, &st) == -1) {
+ fprintf(stderr, "cannot stat '%s': %s\n", path, strerror(errno));
+ 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;
- for(;;) {
- int ret;
-
- ret = adb_read(lfd, sbuf->data, SYNC_DATA_MAX);
- if(!ret)
- break;
-
- if(ret < 0) {
- if(errno == EINTR)
- continue;
- fprintf(stderr,"cannot read '%s': %s\n", path, strerror(errno));
+ while (true) {
+ int ret = adb_read(lfd, sbuf->data, sc.max);
+ if (ret <= 0) {
+ if (ret < 0) {
+ fprintf(stderr, "cannot read '%s': %s\n", path, strerror(errno));
+ adb_close(lfd);
+ return false;
+ }
break;
}
- sbuf->size = htoll(ret);
- if(!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + ret)){
- err = -1;
- break;
+ sbuf->size = ret;
+ if (!WriteFdExactly(sc.fd, sbuf, sizeof(unsigned) * 2 + ret)) {
+ adb_close(lfd);
+ return false;
}
- total_bytes += ret;
+ sc.total_bytes += ret;
if (show_progress) {
- print_transfer_progress(total_bytes, size);
+ print_transfer_progress(sc.total_bytes, size);
}
}
adb_close(lfd);
- return err;
-}
-
-static int write_data_buffer(int fd, char* file_buffer, int size, syncsendbuf *sbuf,
- bool show_progress)
-{
- int err = 0;
- int total = 0;
-
- sbuf->id = ID_DATA;
- while (total < size) {
- int count = size - total;
- if (count > SYNC_DATA_MAX) {
- count = SYNC_DATA_MAX;
- }
-
- memcpy(sbuf->data, &file_buffer[total], count);
- sbuf->size = htoll(count);
- if(!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + count)){
- err = -1;
- break;
- }
- total += count;
- total_bytes += count;
-
- if (show_progress) {
- print_transfer_progress(total, size);
- }
- }
-
- return err;
+ return true;
}
#if defined(_WIN32)
-extern int write_data_link(int fd, 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(int fd, const char *path, syncsendbuf *sbuf)
-{
- int len = readlink(path, sbuf->data, SYNC_DATA_MAX-1);
+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';
- sbuf->size = htoll(len + 1);
+ sbuf->size = len + 1;
sbuf->id = ID_DATA;
- if (!WriteFdExactly(fd, sbuf, sizeof(unsigned) * 2 + len + 1)) {
- return -1;
+ if (!WriteFdExactly(sc.fd, sbuf, sizeof(unsigned) * 2 + len + 1)) {
+ return false;
}
- total_bytes += len + 1;
+ sc.total_bytes += len + 1;
- return 0;
+ return true;
}
#endif
-static int sync_send(int fd, const char *lpath, const char *rpath,
- unsigned mtime, mode_t mode, bool show_progress)
+static bool sync_send(SyncConnection& sc, const char *lpath, const char *rpath,
+ unsigned mtime, mode_t mode, bool show_progress)
{
+ syncsendbuf* sbuf = &send_buffer;
+
+ std::string path_and_mode = android::base::StringPrintf("%s,%d", rpath, mode);
+ if (!SendRequest(sc.fd, ID_SEND, path_and_mode.c_str())) goto fail;
+
+ if (S_ISREG(mode)) {
+ if (!write_data_file(sc, lpath, sbuf, show_progress)) return false;
+ } else if (S_ISLNK(mode)) {
+ if (!write_data_link(sc, lpath, sbuf)) return false;
+ } else {
+ goto fail;
+ }
+
syncmsg msg;
- int len, r;
- syncsendbuf *sbuf = &send_buffer;
- char* file_buffer = NULL;
- int size = 0;
- char tmp[64];
-
- len = strlen(rpath);
- if(len > 1024) goto fail;
-
- snprintf(tmp, sizeof(tmp), ",%d", mode);
- r = strlen(tmp);
-
- msg.req.id = ID_SEND;
- msg.req.namelen = htoll(len + r);
-
- if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
- !WriteFdExactly(fd, rpath, len) || !WriteFdExactly(fd, tmp, r)) {
- free(file_buffer);
- goto fail;
- }
-
- if (file_buffer) {
- write_data_buffer(fd, file_buffer, size, sbuf, show_progress);
- free(file_buffer);
- } else if (S_ISREG(mode))
- write_data_file(fd, lpath, sbuf, show_progress);
- else if (S_ISLNK(mode))
- write_data_link(fd, lpath, sbuf);
- else
- goto fail;
-
msg.data.id = ID_DONE;
- msg.data.size = htoll(mtime);
- if(!WriteFdExactly(fd, &msg.data, sizeof(msg.data)))
- goto fail;
+ msg.data.size = mtime;
+ if (!WriteFdExactly(sc.fd, &msg.data, sizeof(msg.data))) goto fail;
- if(!ReadFdExactly(fd, &msg.status, sizeof(msg.status)))
- return -1;
+ if (!ReadFdExactly(sc.fd, &msg.status, sizeof(msg.status))) goto fail;
- if(msg.status.id != ID_OKAY) {
- if(msg.status.id == ID_FAIL) {
- len = ltohl(msg.status.msglen);
- if(len > 256) len = 256;
- if(!ReadFdExactly(fd, sbuf->data, len)) {
- return -1;
- }
+ if (msg.status.id != ID_OKAY) {
+ if (msg.status.id == ID_FAIL) {
+ size_t len = msg.status.msglen;
+ if (len > 256) len = 256;
+ if (!ReadFdExactly(sc.fd, sbuf->data, len)) goto fail;
sbuf->data[len] = 0;
- } else
+ } else {
strcpy(sbuf->data, "unknown reason");
-
- fprintf(stderr,"failed to copy '%s' to '%s': %s\n", lpath, rpath, sbuf->data);
- return -1;
+ }
+ fprintf(stderr, "failed to copy '%s' to '%s': %s\n", lpath, rpath, sbuf->data);
+ return false;
}
- return 0;
+ return true;
fail:
- fprintf(stderr,"protocol failure\n");
- adb_close(fd);
- return -1;
+ fprintf(stderr, "protocol failure\n");
+ return false;
}
-static int sync_recv(int fd, const char* rpath, const char* lpath, bool show_progress) {
+static int sync_recv(SyncConnection& sc, const char* rpath, const char* lpath, bool show_progress) {
syncmsg msg;
- int len;
int lfd = -1;
char *buffer = send_buffer.data;
unsigned id;
- unsigned long long size = 0;
- len = strlen(rpath);
- if(len > 1024) return -1;
+ size_t len = strlen(rpath);
+ if (len > 1024) return -1;
+ unsigned size = 0;
if (show_progress) {
- // Determine remote file size.
- syncmsg stat_msg;
- stat_msg.req.id = ID_STAT;
- stat_msg.req.namelen = htoll(len);
-
- if (!WriteFdExactly(fd, &stat_msg.req, sizeof(stat_msg.req)) ||
- !WriteFdExactly(fd, rpath, len)) {
- return -1;
- }
-
- if (!ReadFdExactly(fd, &stat_msg.stat, sizeof(stat_msg.stat))) {
- return -1;
- }
-
- if (stat_msg.stat.id != ID_STAT) return -1;
-
- size = ltohl(stat_msg.stat.size);
+ if (!sync_stat(sc, rpath, nullptr, nullptr, &size)) return -1;
}
- msg.req.id = ID_RECV;
- msg.req.namelen = htoll(len);
- if(!WriteFdExactly(fd, &msg.req, sizeof(msg.req)) ||
- !WriteFdExactly(fd, rpath, len)) {
- return -1;
- }
+ if (!SendRequest(sc.fd, ID_RECV, rpath)) return -1;
+ if (!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) return -1;
- if(!ReadFdExactly(fd, &msg.data, sizeof(msg.data))) {
- return -1;
- }
id = msg.data.id;
- if((id == ID_DATA) || (id == ID_DONE)) {
+ if (id == ID_DATA || id == ID_DONE) {
adb_unlink(lpath);
mkdirs(lpath);
lfd = adb_creat(lpath, 0644);
if(lfd < 0) {
- fprintf(stderr,"cannot create '%s': %s\n", lpath, strerror(errno));
+ fprintf(stderr, "cannot create '%s': %s\n", lpath, strerror(errno));
return -1;
}
goto handle_data;
@@ -446,37 +325,38 @@
goto remote_error;
}
- for(;;) {
- if(!ReadFdExactly(fd, &msg.data, sizeof(msg.data))) {
+ while (true) {
+ if(!ReadFdExactly(sc.fd, &msg.data, sizeof(msg.data))) {
+ adb_close(lfd);
return -1;
}
id = msg.data.id;
handle_data:
- len = ltohl(msg.data.size);
- if(id == ID_DONE) break;
- if(id != ID_DATA) goto remote_error;
- if(len > SYNC_DATA_MAX) {
- fprintf(stderr,"data overrun\n");
+ len = msg.data.size;
+ if (id == ID_DONE) break;
+ if (id != ID_DATA) goto remote_error;
+ if (len > sc.max) {
+ fprintf(stderr, "msg.data.size too large: %zu (max %zu)\n", len, sc.max);
adb_close(lfd);
return -1;
}
- if(!ReadFdExactly(fd, buffer, len)) {
+ if(!ReadFdExactly(sc.fd, buffer, len)) {
adb_close(lfd);
return -1;
}
if(!WriteFdExactly(lfd, buffer, len)) {
- fprintf(stderr,"cannot write '%s': %s\n", rpath, strerror(errno));
+ fprintf(stderr, "cannot write '%s': %s\n", rpath, strerror(errno));
adb_close(lfd);
return -1;
}
- total_bytes += len;
+ sc.total_bytes += len;
if (show_progress) {
- print_transfer_progress(total_bytes, size);
+ print_transfer_progress(sc.total_bytes, size);
}
}
@@ -488,9 +368,9 @@
adb_unlink(lpath);
if(id == ID_FAIL) {
- len = ltohl(msg.data.size);
+ len = msg.data.size;
if(len > 256) len = 256;
- if(!ReadFdExactly(fd, buffer, len)) {
+ if(!ReadFdExactly(sc.fd, buffer, len)) {
return -1;
}
buffer[len] = 0;
@@ -498,31 +378,20 @@
memcpy(buffer, &id, 4);
buffer[4] = 0;
}
- fprintf(stderr,"failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer);
+ fprintf(stderr, "failed to copy '%s' to '%s': %s\n", rpath, lpath, buffer);
return 0;
}
-/* --- */
static void do_sync_ls_cb(unsigned mode, unsigned size, unsigned time,
- const char *name, void *cookie)
-{
+ const char* name, void* /*cookie*/) {
printf("%08x %08x %08x %s\n", mode, size, time, name);
}
-int do_sync_ls(const char* path) {
- std::string error;
- int fd = adb_connect("sync:", &error);
- if (fd < 0) {
- fprintf(stderr,"error: %s\n", error.c_str());
- return 1;
- }
+bool do_sync_ls(const char* path) {
+ SyncConnection sc;
+ if (!sc.IsValid()) return false;
- if (sync_ls(fd, path, do_sync_ls_cb, 0)) {
- return 1;
- }
-
- sync_quit(fd);
- return 0;
+ return sync_ls(sc.fd, path, do_sync_ls_cb, 0);
}
struct copyinfo
@@ -545,7 +414,7 @@
copyinfo *ci = reinterpret_cast<copyinfo*>(malloc(sizeof(copyinfo) + ssize + dsize));
if(ci == 0) {
- fprintf(stderr,"out of memory\n");
+ fprintf(stderr, "out of memory\n");
abort();
}
@@ -562,54 +431,41 @@
return ci;
}
+static bool IsDotOrDotDot(const char* name) {
+ return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
+}
-static int local_build_list(copyinfo **filelist,
- const char *lpath, const char *rpath)
-{
- DIR *d;
- struct dirent *de;
- struct stat st;
+static int local_build_list(copyinfo** filelist, const char* lpath, const char* rpath) {
copyinfo *dirlist = 0;
copyinfo *ci, *next;
- d = opendir(lpath);
- if(d == 0) {
- fprintf(stderr,"cannot open '%s': %s\n", lpath, strerror(errno));
+ std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir(lpath), closedir);
+ if (!dir) {
+ fprintf(stderr, "cannot open '%s': %s\n", lpath, strerror(errno));
return -1;
}
- while((de = readdir(d))) {
+ dirent *de;
+ while ((de = readdir(dir.get()))) {
+ if (IsDotOrDotDot(de->d_name)) continue;
+
char stat_path[PATH_MAX];
- char *name = de->d_name;
-
- if(name[0] == '.') {
- if(name[1] == 0) continue;
- if((name[1] == '.') && (name[2] == 0)) continue;
- }
-
- /*
- * We could use d_type if HAVE_DIRENT_D_TYPE is defined, but reiserfs
- * always returns DT_UNKNOWN, so we just use stat() for all cases.
- */
- if (strlen(lpath) + strlen(de->d_name) + 1 > sizeof(stat_path))
+ if (strlen(lpath) + strlen(de->d_name) + 1 > sizeof(stat_path)) {
+ fprintf(stderr, "skipping long path '%s%s'\n", lpath, de->d_name);
continue;
+ }
strcpy(stat_path, lpath);
strcat(stat_path, de->d_name);
- if(!lstat(stat_path, &st)) {
+ struct stat st;
+ if (!lstat(stat_path, &st)) {
if (S_ISDIR(st.st_mode)) {
- ci = mkcopyinfo(lpath, rpath, name, 1);
+ ci = mkcopyinfo(lpath, rpath, de->d_name, 1);
ci->next = dirlist;
dirlist = ci;
} else {
- ci = mkcopyinfo(lpath, rpath, name, 0);
- if(lstat(ci->src, &st)) {
- fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
- free(ci);
- closedir(d);
- return -1;
- }
- if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
+ ci = mkcopyinfo(lpath, rpath, de->d_name, 0);
+ if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
fprintf(stderr, "skipping special file '%s'\n", ci->src);
free(ci);
} else {
@@ -625,9 +481,9 @@
}
}
- closedir(d);
-
- for(ci = dirlist; ci != 0; ci = next) {
+ // Close this directory and recurse.
+ dir.reset();
+ for (ci = dirlist; ci != 0; ci = next) {
next = ci->next;
local_build_list(filelist, ci->src, ci->dst);
free(ci);
@@ -636,60 +492,55 @@
return 0;
}
-
-static int copy_local_dir_remote(int fd, const char *lpath, const char *rpath, int checktimestamps, int listonly)
-{
+static bool copy_local_dir_remote(SyncConnection& sc, const char* lpath, const char* rpath,
+ bool check_timestamps, bool list_only) {
copyinfo *filelist = 0;
copyinfo *ci, *next;
int pushed = 0;
int skipped = 0;
- if((lpath[0] == 0) || (rpath[0] == 0)) return -1;
- if(lpath[strlen(lpath) - 1] != '/') {
+ if ((lpath[0] == 0) || (rpath[0] == 0)) return false;
+ if (lpath[strlen(lpath) - 1] != '/') {
int tmplen = strlen(lpath)+2;
char *tmp = reinterpret_cast<char*>(malloc(tmplen));
- if(tmp == 0) return -1;
+ if(tmp == 0) return false;
snprintf(tmp, tmplen, "%s/",lpath);
lpath = tmp;
}
- if(rpath[strlen(rpath) - 1] != '/') {
+ if (rpath[strlen(rpath) - 1] != '/') {
int tmplen = strlen(rpath)+2;
char *tmp = reinterpret_cast<char*>(malloc(tmplen));
- if(tmp == 0) return -1;
+ if(tmp == 0) return false;
snprintf(tmp, tmplen, "%s/",rpath);
rpath = tmp;
}
- if(local_build_list(&filelist, lpath, rpath)) {
- return -1;
+ if (local_build_list(&filelist, lpath, rpath)) {
+ return false;
}
- if(checktimestamps){
- for(ci = filelist; ci != 0; ci = ci->next) {
- if(sync_start_readtime(fd, ci->dst)) {
- return 1;
- }
+ if (check_timestamps) {
+ for (ci = filelist; ci != 0; ci = ci->next) {
+ if (!sync_start_stat(sc, ci->dst)) return false;
}
for(ci = filelist; ci != 0; ci = ci->next) {
unsigned int timestamp, mode, size;
- if(sync_finish_readtime(fd, ×tamp, &mode, &size))
- return 1;
- if(size == ci->size) {
+ if (!sync_finish_stat(sc, ×tamp, &mode, &size)) return false;
+ if (size == ci->size) {
/* for links, we cannot update the atime/mtime */
- if((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
- (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
+ if ((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
+ (S_ISLNK(ci->mode & mode) && timestamp >= ci->time)) {
ci->flag = 1;
+ }
}
}
}
- for(ci = filelist; ci != 0; ci = next) {
+ for (ci = filelist; ci != 0; ci = next) {
next = ci->next;
- if(ci->flag == 0) {
- fprintf(stderr,"%spush: %s -> %s\n", listonly ? "would " : "", ci->src, ci->dst);
- if(!listonly &&
- sync_send(fd, ci->src, ci->dst, ci->time, ci->mode,
- 0 /* no show progress */)) {
- return 1;
+ if (ci->flag == 0) {
+ fprintf(stderr, "%spush: %s -> %s\n", list_only ? "would " : "", ci->src, ci->dst);
+ if (!list_only && !sync_send(sc, ci->src, ci->dst, ci->time, ci->mode, false)) {
+ return false;
}
pushed++;
} else {
@@ -698,55 +549,37 @@
free(ci);
}
- fprintf(stderr,"%d file%s pushed. %d file%s skipped.\n",
+ fprintf(stderr, "%d file%s pushed. %d file%s skipped.\n",
pushed, (pushed == 1) ? "" : "s",
skipped, (skipped == 1) ? "" : "s");
- return 0;
+ return true;
}
-
-int do_sync_push(const char* lpath, const char* rpath, bool show_progress) {
- std::string error;
- int fd = adb_connect("sync:", &error);
- if (fd < 0) {
- fprintf(stderr,"error: %s\n", error.c_str());
- return 1;
- }
+bool do_sync_push(const char* lpath, const char* rpath, bool show_progress) {
+ SyncConnection sc;
+ if (!sc.IsValid()) return false;
struct stat st;
if (stat(lpath, &st)) {
- fprintf(stderr,"cannot stat '%s': %s\n", lpath, strerror(errno));
- sync_quit(fd);
- return 1;
+ fprintf(stderr, "cannot stat '%s': %s\n", lpath, strerror(errno));
+ return false;
}
if (S_ISDIR(st.st_mode)) {
- BEGIN();
- if (copy_local_dir_remote(fd, lpath, rpath, 0, 0)) {
- return 1;
- }
- } else {
- unsigned mode;
- if (sync_readmode(fd, rpath, &mode)) {
- return 1;
- }
- std::string path_holder;
- if ((mode != 0) && S_ISDIR(mode)) {
- // If we're copying a local file to a remote directory,
- // we really want to copy to remote_dir + "/" + local_filename.
- path_holder = android::base::StringPrintf("%s/%s", rpath, adb_basename(lpath).c_str());
- rpath = path_holder.c_str();
- }
- BEGIN();
- if (sync_send(fd, lpath, rpath, st.st_mtime, st.st_mode, show_progress)) {
- return 1;
- }
+ return copy_local_dir_remote(sc, lpath, rpath, false, false);
}
- END();
- sync_quit(fd);
- return 0;
+ unsigned mode;
+ if (!sync_stat(sc, rpath, nullptr, &mode, nullptr)) return false;
+ std::string path_holder;
+ if (mode != 0 && S_ISDIR(mode)) {
+ // If we're copying a local file to a remote directory,
+ // we really want to copy to remote_dir + "/" + local_filename.
+ path_holder = android::base::StringPrintf("%s/%s", rpath, adb_basename(lpath).c_str());
+ rpath = path_holder.c_str();
+ }
+ return sync_send(sc, lpath, rpath, st.st_mtime, st.st_mode, show_progress);
}
@@ -766,11 +599,8 @@
if (S_ISDIR(mode)) {
copyinfo **dirlist = args->dirlist;
- /* Don't try recursing down "." or ".." */
- if (name[0] == '.') {
- if (name[1] == '\0') return;
- if ((name[1] == '.') && (name[2] == '\0')) return;
- }
+ // Don't try recursing down "." or "..".
+ if (IsDotOrDotDot(name)) return;
ci = mkcopyinfo(args->rpath, args->lpath, name, 1);
ci->next = *dirlist;
@@ -789,9 +619,8 @@
}
}
-static int remote_build_list(int syncfd, copyinfo **filelist,
- const char *rpath, const char *lpath)
-{
+static bool remote_build_list(int syncfd, copyinfo **filelist,
+ const char *rpath, const char *lpath) {
copyinfo *dirlist = NULL;
sync_ls_build_list_cb_args args;
@@ -800,22 +629,22 @@
args.rpath = rpath;
args.lpath = lpath;
- /* Put the files/dirs in rpath on the lists. */
- if (sync_ls(syncfd, rpath, sync_ls_build_list_cb, (void *)&args)) {
- return 1;
+ // Put the files/dirs in rpath on the lists.
+ if (!sync_ls(syncfd, rpath, sync_ls_build_list_cb, (void *)&args)) {
+ return false;
}
- /* Recurse into each directory we found. */
+ // Recurse into each directory we found.
while (dirlist != NULL) {
copyinfo *next = dirlist->next;
- if (remote_build_list(syncfd, filelist, dirlist->src, dirlist->dst)) {
- return 1;
+ if (!remote_build_list(syncfd, filelist, dirlist->src, dirlist->dst)) {
+ return false;
}
free(dirlist);
dirlist = next;
}
- return 0;
+ return true;
}
static int set_time_and_mode(const char *lpath, time_t time, unsigned int mode)
@@ -831,101 +660,57 @@
return r1 ? : r2;
}
-/* Return a copy of the path string with / appended if needed */
-static char *add_slash_to_path(const char *path)
-{
- if (path[strlen(path) - 1] != '/') {
- size_t len = strlen(path) + 2;
- char *path_with_slash = reinterpret_cast<char*>(malloc(len));
- if (path_with_slash == NULL)
- return NULL;
- snprintf(path_with_slash, len, "%s/", path);
- return path_with_slash;
- } else {
- return strdup(path);
- }
-}
+static bool copy_remote_dir_local(SyncConnection& sc, const char* rpath, const char* lpath,
+ int copy_attrs) {
+ // Make sure that both directory paths end in a slash.
+ std::string rpath_clean(rpath);
+ std::string lpath_clean(lpath);
+ if (rpath_clean.empty() || lpath_clean.empty()) return false;
+ if (rpath_clean.back() != '/') rpath_clean.push_back('/');
+ if (lpath_clean.back() != '/') lpath_clean.push_back('/');
-static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath,
- int copy_attrs)
-{
- copyinfo *filelist = 0;
- copyinfo *ci, *next;
+ // Recursively build the list of files to copy.
+ fprintf(stderr, "pull: building file list...\n");
+ copyinfo* filelist = nullptr;
+ if (!remote_build_list(sc.fd, &filelist, rpath_clean.c_str(), lpath_clean.c_str())) return false;
+
int pulled = 0;
int skipped = 0;
- char *rpath_clean = NULL;
- char *lpath_clean = NULL;
- int ret = 0;
-
- if (rpath[0] == '\0' || lpath[0] == '\0') {
- ret = -1;
- goto finish;
- }
-
- /* Make sure that both directory paths end in a slash. */
- rpath_clean = add_slash_to_path(rpath);
- if (!rpath_clean) {
- ret = -1;
- goto finish;
- }
- lpath_clean = add_slash_to_path(lpath);
- if (!lpath_clean) {
- ret = -1;
- goto finish;
- }
-
- /* Recursively build the list of files to copy. */
- fprintf(stderr, "pull: building file list...\n");
- if (remote_build_list(fd, &filelist, rpath_clean, lpath_clean)) {
- ret = -1;
- goto finish;
- }
-
- for (ci = filelist; ci != 0; ci = next) {
- next = ci->next;
+ copyinfo* ci = filelist;
+ while (ci) {
+ copyinfo* next = ci->next;
if (ci->flag == 0) {
fprintf(stderr, "pull: %s -> %s\n", ci->src, ci->dst);
- if (sync_recv(fd, ci->src, ci->dst, 0 /* no show progress */)) {
- ret = -1;
- goto finish;
+ if (sync_recv(sc, ci->src, ci->dst, false)) {
+ return false;
}
if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) {
- ret = -1;
- goto finish;
+ return false;
}
pulled++;
} else {
skipped++;
}
free(ci);
+ ci = next;
}
fprintf(stderr, "%d file%s pulled. %d file%s skipped.\n",
pulled, (pulled == 1) ? "" : "s",
skipped, (skipped == 1) ? "" : "s");
-
-finish:
- free(lpath_clean);
- free(rpath_clean);
- return ret;
+ return true;
}
-int do_sync_pull(const char* rpath, const char* lpath, bool show_progress, int copy_attrs) {
- std::string error;
- int fd = adb_connect("sync:", &error);
- if (fd < 0) {
- fprintf(stderr,"error: %s\n", error.c_str());
- return 1;
- }
+bool do_sync_pull(const char* rpath, const char* lpath, bool show_progress, int copy_attrs) {
+ SyncConnection sc;
+ if (!sc.IsValid()) return false;
unsigned mode, time;
- if (sync_readtime(fd, rpath, &time, &mode)) {
- return 1;
- }
+ if (!sync_stat(sc, rpath, &time, &mode, nullptr)) return false;
if (mode == 0) {
- fprintf(stderr,"remote object '%s' does not exist\n", rpath);
- return 1;
+ fprintf(stderr, "remote object '%s' does not exist\n", rpath);
+ return false;
}
if (S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
@@ -939,44 +724,27 @@
lpath = path_holder.c_str();
}
}
- BEGIN();
- if (sync_recv(fd, rpath, lpath, show_progress)) {
- return 1;
+ if (sync_recv(sc, rpath, lpath, show_progress)) {
+ return false;
} else {
if (copy_attrs && set_time_and_mode(lpath, time, mode)) {
- return 1;
+ return false;
}
}
- } else if(S_ISDIR(mode)) {
- BEGIN();
- if (copy_remote_dir_local(fd, rpath, lpath, copy_attrs)) {
- return 1;
- }
- } else {
- fprintf(stderr,"remote object '%s' not a file or directory\n", rpath);
- return 1;
+ return true;
+ } else if (S_ISDIR(mode)) {
+ return copy_remote_dir_local(sc, rpath, lpath, copy_attrs);
}
- END();
- sync_quit(fd);
- return 0;
+
+ fprintf(stderr, "remote object '%s' not a file or directory\n", rpath);
+ return false;
}
-int do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only)
-{
+bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only) {
fprintf(stderr, "syncing %s...\n", rpath.c_str());
- std::string error;
- int fd = adb_connect("sync:", &error);
- if (fd < 0) {
- fprintf(stderr, "error: %s\n", error.c_str());
- return 1;
- }
+ SyncConnection sc;
+ if (!sc.IsValid()) return false;
- BEGIN();
- if (copy_local_dir_remote(fd, lpath.c_str(), rpath.c_str(), 1, list_only)) {
- return 1;
- }
- END();
- sync_quit(fd);
- return 0;
+ return copy_local_dir_remote(sc, lpath.c_str(), rpath.c_str(), true, list_only);
}
diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp
index ea019f4..3793b8e 100644
--- a/adb/file_sync_service.cpp
+++ b/adb/file_sync_service.cpp
@@ -34,6 +34,7 @@
#include "adb_io.h"
#include "private/android_filesystem_config.h"
+#include <base/stringprintf.h>
#include <base/strings.h>
static bool should_use_fs_config(const std::string& path) {
@@ -70,44 +71,30 @@
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);
}
}
return true;
}
-static int do_stat(int s, const char *path)
-{
+static bool do_stat(int s, const char* path) {
syncmsg msg;
- struct stat st;
-
msg.stat.id = ID_STAT;
- if(lstat(path, &st)) {
- msg.stat.mode = 0;
- msg.stat.size = 0;
- msg.stat.time = 0;
- } else {
- msg.stat.mode = htoll(st.st_mode);
- msg.stat.size = htoll(st.st_size);
- msg.stat.time = htoll(st.st_mtime);
- }
+ struct stat st;
+ memset(&st, 0, sizeof(st));
+ // TODO: add a way to report that the stat failed!
+ lstat(path, &st);
+ msg.stat.mode = st.st_mode;
+ msg.stat.size = st.st_size;
+ msg.stat.time = st.st_mtime;
- return WriteFdExactly(s, &msg.stat, sizeof(msg.stat)) ? 0 : -1;
+ return WriteFdExactly(s, &msg.stat, sizeof(msg.stat));
}
-static int do_list(int s, const char *path)
-{
- struct dirent *de;
- struct stat st;
-
- char tmp[1024 + 256 + 1];
- char *fname;
-
- size_t len = strlen(path);
- memcpy(tmp, path, len);
- tmp[len] = '/';
- fname = tmp + len + 1;
+static bool do_list(int s, const char* path) {
+ dirent* de;
syncmsg msg;
msg.dent.id = ID_DENT;
@@ -116,22 +103,19 @@
if (!d) goto done;
while ((de = readdir(d.get()))) {
- int len = strlen(de->d_name);
+ std::string filename(android::base::StringPrintf("%s/%s", path, de->d_name));
- /* not supposed to be possible, but
- if it does happen, let's not buffer overrun */
- if(len > 256) continue;
+ struct stat st;
+ if (lstat(filename.c_str(), &st) == 0) {
+ size_t d_name_length = strlen(de->d_name);
+ msg.dent.mode = st.st_mode;
+ msg.dent.size = st.st_size;
+ msg.dent.time = st.st_mtime;
+ msg.dent.namelen = d_name_length;
- strcpy(fname, de->d_name);
- if(lstat(tmp, &st) == 0) {
- msg.dent.mode = htoll(st.st_mode);
- msg.dent.size = htoll(st.st_size);
- msg.dent.time = htoll(st.st_mtime);
- msg.dent.namelen = htoll(len);
-
- if(!WriteFdExactly(s, &msg.dent, sizeof(msg.dent)) ||
- !WriteFdExactly(s, de->d_name, len)) {
- return -1;
+ if (!WriteFdExactly(s, &msg.dent, sizeof(msg.dent)) ||
+ !WriteFdExactly(s, de->d_name, d_name_length)) {
+ return false;
}
}
}
@@ -142,255 +126,215 @@
msg.dent.size = 0;
msg.dent.time = 0;
msg.dent.namelen = 0;
- return WriteFdExactly(s, &msg.dent, sizeof(msg.dent)) ? 0 : -1;
+ return WriteFdExactly(s, &msg.dent, sizeof(msg.dent));
}
-static int fail_message(int s, const char *reason)
-{
+static bool SendSyncFail(int fd, const std::string& reason) {
+ D("sync: failure: %s\n", reason.c_str());
+
syncmsg msg;
- int len = strlen(reason);
-
- D("sync: failure: %s\n", reason);
-
msg.data.id = ID_FAIL;
- msg.data.size = htoll(len);
- if(!WriteFdExactly(s, &msg.data, sizeof(msg.data)) ||
- !WriteFdExactly(s, reason, len)) {
- return -1;
- } else {
- return 0;
- }
+ msg.data.size = reason.size();
+ return WriteFdExactly(fd, &msg.data, sizeof(msg.data)) && WriteFdExactly(fd, reason);
}
-static int 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 int handle_send_file(int s, char *path, uid_t uid,
- gid_t gid, mode_t mode, char *buffer, bool do_unlink)
-{
+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;
- fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
- if(fd < 0 && errno == ENOENT) {
+ int fd = adb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
+ if (fd < 0 && errno == ENOENT) {
if (!secure_mkdirs(path)) {
- if(fail_errno(s))
- return -1;
- 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 -1;
- 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);
}
- for(;;) {
+ 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) {
- timestamp = ltohl(msg.data.size);
+ 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 = ltohl(msg.data.size);
- if(len > SYNC_DATA_MAX) {
- fail_message(s, "oversize data message");
+ len = msg.data.size;
+ if (len > buffer.size()) { // TODO: resize buffer?
+ SendSyncFail(s, "oversize data message");
goto fail;
}
- if(!ReadFdExactly(s, buffer, len))
- goto fail;
- if(fd < 0)
- continue;
- if(!WriteFdExactly(fd, buffer, len)) {
- int saved_errno = errno;
- adb_close(fd);
- if (do_unlink) adb_unlink(path);
- fd = -1;
- errno = saved_errno;
- if(fail_errno(s)) return -1;
+ if (!ReadFdExactly(s, &buffer[0], len)) goto fail;
+
+ if (!WriteFdExactly(fd, &buffer[0], len)) {
+ 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 -1;
- }
- return 0;
+ 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);
+ if (fd >= 0) adb_close(fd);
if (do_unlink) adb_unlink(path);
- return -1;
+ return false;
}
#if defined(_WIN32)
-extern int handle_send_link(int s, char *path, 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 int handle_send_link(int s, char *path, char *buffer)
-{
+static bool handle_send_link(int s, const std::string& path, std::vector<char>& buffer) {
syncmsg msg;
unsigned int len;
int ret;
- if(!ReadFdExactly(s, &msg.data, sizeof(msg.data)))
- return -1;
+ 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");
- return -1;
+ if (msg.data.id != ID_DATA) {
+ SendSyncFail(s, "invalid data message: expected ID_DATA");
+ return false;
}
- len = ltohl(msg.data.size);
- if(len > SYNC_DATA_MAX) {
- fail_message(s, "oversize data message");
- return -1;
+ len = msg.data.size;
+ if (len > buffer.size()) { // TODO: resize buffer?
+ SendSyncFail(s, "oversize data message");
+ return false;
}
- if(!ReadFdExactly(s, buffer, len))
- return -1;
+ if (!ReadFdExactly(s, &buffer[0], len)) return false;
- ret = symlink(buffer, path);
- if(ret && errno == ENOENT) {
+ ret = symlink(&buffer[0], path.c_str());
+ if (ret && errno == ENOENT) {
if (!secure_mkdirs(path)) {
- fail_errno(s);
- return -1;
+ SendSyncFailErrno(s, "secure_mkdirs failed");
+ return false;
}
- ret = symlink(buffer, path);
+ ret = symlink(&buffer[0], path.c_str());
}
- if(ret) {
- fail_errno(s);
- return -1;
+ if (ret) {
+ SendSyncFailErrno(s, "symlink failed");
+ return false;
}
- if(!ReadFdExactly(s, &msg.data, sizeof(msg.data)))
- return -1;
+ if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) return false;
- if(msg.data.id == ID_DONE) {
+ if (msg.data.id == ID_DONE) {
msg.status.id = ID_OKAY;
msg.status.msglen = 0;
- if(!WriteFdExactly(s, &msg.status, sizeof(msg.status)))
- return -1;
+ if (!WriteFdExactly(s, &msg.status, sizeof(msg.status))) return false;
} else {
- fail_message(s, "invalid data message: expected ID_DONE");
- return -1;
+ SendFail(s, "invalid data message: expected ID_DONE");
+ return false;
}
- return 0;
+ return true;
}
#endif
-static int do_send(int s, char *path, 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 int do_recv(int s, const char *path, char *buffer)
-{
- syncmsg msg;
- int fd, r;
-
- fd = adb_open(path, O_RDONLY | O_CLOEXEC);
- if(fd < 0) {
- if(fail_errno(s)) return -1;
- return 0;
+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) {
+ SendSyncFailErrno(s, "open failed");
+ return false;
}
+ syncmsg msg;
msg.data.id = ID_DATA;
- for(;;) {
- r = adb_read(fd, buffer, SYNC_DATA_MAX);
- if(r <= 0) {
- if(r == 0) break;
- if(errno == EINTR) continue;
- r = fail_errno(s);
+ while (true) {
+ int r = adb_read(fd, &buffer[0], buffer.size());
+ if (r <= 0) {
+ if (r == 0) break;
+ SendSyncFailErrno(s, "read failed");
adb_close(fd);
- return r;
+ return false;
}
- msg.data.size = htoll(r);
- if(!WriteFdExactly(s, &msg.data, sizeof(msg.data)) ||
- !WriteFdExactly(s, buffer, r)) {
+ msg.data.size = r;
+ if (!WriteFdExactly(s, &msg.data, sizeof(msg.data)) || !WriteFdExactly(s, &buffer[0], r)) {
adb_close(fd);
- return -1;
+ return false;
}
}
@@ -398,66 +342,62 @@
msg.data.id = ID_DONE;
msg.data.size = 0;
- if(!WriteFdExactly(s, &msg.data, sizeof(msg.data))) {
- return -1;
- }
-
- return 0;
+ return WriteFdExactly(s, &msg.data, sizeof(msg.data));
}
-void file_sync_service(int fd, void *cookie)
-{
- syncmsg msg;
+static bool handle_sync_command(int fd, std::vector<char>& buffer) {
+ D("sync: waiting for request\n");
+
+ SyncRequest request;
+ if (!ReadFdExactly(fd, &request, sizeof(request))) {
+ SendSyncFail(fd, "command read failure");
+ return false;
+ }
+ size_t path_length = request.path_length;
+ if (path_length > 1024) {
+ SendSyncFail(fd, "path too long");
+ return false;
+ }
char name[1025];
- unsigned namelen;
+ if (!ReadFdExactly(fd, name, path_length)) {
+ SendSyncFail(fd, "filename read failure");
+ return false;
+ }
+ name[path_length] = 0;
- char *buffer = reinterpret_cast<char*>(malloc(SYNC_DATA_MAX));
- if(buffer == 0) goto fail;
+ const char* id = reinterpret_cast<const char*>(&request.id);
+ D("sync: '%.4s' '%s'\n", id, name);
- for(;;) {
- D("sync: waiting for command\n");
-
- if(!ReadFdExactly(fd, &msg.req, sizeof(msg.req))) {
- fail_message(fd, "command read failure");
- break;
- }
- namelen = ltohl(msg.req.namelen);
- if(namelen > 1024) {
- fail_message(fd, "invalid namelen");
- break;
- }
- if(!ReadFdExactly(fd, name, namelen)) {
- fail_message(fd, "filename read failure");
- break;
- }
- name[namelen] = 0;
-
- msg.req.namelen = 0;
- D("sync: '%s' '%s'\n", (char*) &msg.req, name);
-
- switch(msg.req.id) {
- case ID_STAT:
- if(do_stat(fd, name)) goto fail;
- break;
- case ID_LIST:
- if(do_list(fd, name)) goto fail;
- break;
- case ID_SEND:
- if(do_send(fd, name, buffer)) goto fail;
- break;
- case ID_RECV:
- if(do_recv(fd, name, buffer)) goto fail;
- break;
- case ID_QUIT:
- goto fail;
- default:
- fail_message(fd, "unknown command");
- goto fail;
- }
+ switch (request.id) {
+ case ID_STAT:
+ if (!do_stat(fd, name)) return false;
+ break;
+ case ID_LIST:
+ if (!do_list(fd, name)) return false;
+ break;
+ case ID_SEND:
+ if (!do_send(fd, name, buffer)) return false;
+ break;
+ case ID_RECV:
+ if (!do_recv(fd, name, buffer)) return false;
+ break;
+ case ID_QUIT:
+ return false;
+ default:
+ SendSyncFail(fd, android::base::StringPrintf("unknown command '%.4s' (%08x)",
+ id, request.id));
+ return false;
}
-fail:
- if(buffer != 0) free(buffer);
+ return true;
+}
+
+void file_sync_service(int fd, void* cookie) {
+ std::vector<char> buffer(SYNC_DATA_MAX);
+
+ while (handle_sync_command(fd, buffer)) {
+ }
+
D("sync: done\n");
adb_close(fd);
}
diff --git a/adb/file_sync_service.h b/adb/file_sync_service.h
index 1d3e3bd..67ed3fc 100644
--- a/adb/file_sync_service.h
+++ b/adb/file_sync_service.h
@@ -19,14 +19,10 @@
#include <string>
-#define htoll(x) (x)
-#define ltohl(x) (x)
-
#define MKID(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24))
#define ID_STAT MKID('S','T','A','T')
#define ID_LIST MKID('L','I','S','T')
-#define ID_ULNK MKID('U','L','N','K')
#define ID_SEND MKID('S','E','N','D')
#define ID_RECV MKID('R','E','C','V')
#define ID_DENT MKID('D','E','N','T')
@@ -36,41 +32,41 @@
#define ID_FAIL MKID('F','A','I','L')
#define ID_QUIT MKID('Q','U','I','T')
+struct SyncRequest {
+ uint32_t id; // ID_STAT, et cetera.
+ uint32_t path_length; // <= 1024
+ // Followed by 'path_length' bytes of path (not NUL-terminated).
+} __attribute__((packed)) ;
+
union syncmsg {
- unsigned id;
- struct {
- unsigned id;
- unsigned namelen;
- } req;
- struct {
+ struct __attribute__((packed)) {
unsigned id;
unsigned mode;
unsigned size;
unsigned time;
} stat;
- struct {
+ struct __attribute__((packed)) {
unsigned id;
unsigned mode;
unsigned size;
unsigned time;
unsigned namelen;
} dent;
- struct {
+ struct __attribute__((packed)) {
unsigned id;
unsigned size;
} data;
- struct {
+ struct __attribute__((packed)) {
unsigned id;
unsigned msglen;
} status;
-} ;
+};
-
-void file_sync_service(int fd, void *cookie);
-int do_sync_ls(const char *path);
-int do_sync_push(const char *lpath, const char *rpath, bool show_progress);
-int do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only);
-int do_sync_pull(const char *rpath, const char *lpath, bool show_progress, int pullTime);
+void file_sync_service(int fd, void* cookie);
+bool do_sync_ls(const char* path);
+bool do_sync_push(const char* lpath, const char* rpath, bool show_progress);
+bool do_sync_sync(const std::string& lpath, const std::string& rpath, bool list_only);
+bool do_sync_pull(const char* rpath, const char* lpath, bool show_progress, int copy_attrs);
#define SYNC_DATA_MAX (64*1024)
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 255be09..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;
@@ -438,8 +439,7 @@
}
#endif
-int service_to_fd(const char *name)
-{
+int service_to_fd(const char* name) {
int ret = -1;
if(!strncmp(name, "tcp:", 4)) {
@@ -503,13 +503,11 @@
} else if(!strncmp(name, "unroot:", 7)) {
ret = create_service_thread(restart_unroot_service, NULL);
} else if(!strncmp(name, "backup:", 7)) {
- ret = create_subproc_thread(
- android::base::StringPrintf("/system/bin/bu backup %s",
- (name + 7)).c_str(),
- SubprocessType::kRaw);
- } else if(!strncmp(name, "restore:", 8)) {
- ret = create_subproc_thread("/system/bin/bu restore",
+ ret = create_subproc_thread(android::base::StringPrintf("/system/bin/bu backup %s",
+ (name + 7)).c_str(),
SubprocessType::kRaw);
+ } else if(!strncmp(name, "restore:", 8)) {
+ ret = create_subproc_thread("/system/bin/bu restore", SubprocessType::kRaw);
} else if(!strncmp(name, "tcpip:", 6)) {
int port;
if (sscanf(name + 6, "%d", &port) != 1) {
@@ -667,8 +665,7 @@
#endif
#if ADB_HOST
-asocket* host_service_to_socket(const char* name, const char *serial)
-{
+asocket* host_service_to_socket(const char* name, const char* serial) {
if (!strcmp(name,"track-devices")) {
return create_device_tracker();
} else if (!strncmp(name, "wait-for-", strlen("wait-for-"))) {
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 2ea4d44..43691dc 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;
}
}
@@ -241,6 +193,7 @@
atransport *t = reinterpret_cast<atransport*>(_t);
apacket *p;
+ adb_thread_setname(android::base::StringPrintf("->%s", t->serial));
D("%s: starting transport output thread on fd %d, SYNC online (%d)\n",
t->serial, t->fd, t->sync_token + 1);
p = get_apacket();
@@ -297,6 +250,7 @@
apacket *p;
int active = 0;
+ adb_thread_setname(android::base::StringPrintf("<-%s", t->serial));
D("%s: starting transport input thread, reading from fd %d\n",
t->serial, t->fd);
@@ -332,16 +286,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);
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 +452,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 +472,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 +508,6 @@
transport_list.remove(t);
adb_mutex_unlock(&transport_lock);
- run_transport_disconnects(t);
-
if (t->product)
free(t->product);
if (t->serial)
@@ -603,8 +560,6 @@
transport_list.push_front(t);
adb_mutex_unlock(&transport_lock);
- t->disconnects.next = t->disconnects.prev = &t->disconnects;
-
update_transports();
}
@@ -652,48 +607,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)
{
@@ -865,8 +794,22 @@
}
bool atransport::CanUseFeature(const std::string& feature) const {
- return has_feature(feature) &&
- supported_features().count(feature) > 0;
+ 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
@@ -978,7 +921,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;
@@ -989,35 +932,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 output thread of this transport out of any read, then
+ // the output thread will notify the main thread to make this transport
+ // offline. Then the main thread will notify the input 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..6ccc8e2 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.
diff --git a/adb/usb_linux_client.cpp b/adb/usb_linux_client.cpp
index b1b3538..e1d7594 100644
--- a/adb/usb_linux_client.cpp
+++ b/adb/usb_linux_client.cpp
@@ -64,6 +64,14 @@
struct usb_endpoint_descriptor_no_audio sink;
} __attribute__((packed));
+struct ss_func_desc {
+ struct usb_interface_descriptor intf;
+ struct usb_endpoint_descriptor_no_audio source;
+ struct usb_ss_ep_comp_descriptor source_comp;
+ struct usb_endpoint_descriptor_no_audio sink;
+ struct usb_ss_ep_comp_descriptor sink_comp;
+} __attribute__((packed));
+
struct desc_v1 {
struct usb_functionfs_descs_head_v1 {
__le32 magic;
@@ -79,7 +87,9 @@
// The rest of the structure depends on the flags in the header.
__le32 fs_count;
__le32 hs_count;
+ __le32 ss_count;
struct func_desc fs_descs, hs_descs;
+ struct ss_func_desc ss_descs;
} __attribute__((packed));
static struct func_desc fs_descriptors = {
@@ -136,6 +146,41 @@
},
};
+static struct ss_func_desc ss_descriptors = {
+ .intf = {
+ .bLength = sizeof(ss_descriptors.intf),
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = ADB_CLASS,
+ .bInterfaceSubClass = ADB_SUBCLASS,
+ .bInterfaceProtocol = ADB_PROTOCOL,
+ .iInterface = 1, /* first string from the provided table */
+ },
+ .source = {
+ .bLength = sizeof(ss_descriptors.source),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = MAX_PACKET_SIZE_SS,
+ },
+ .source_comp = {
+ .bLength = sizeof(ss_descriptors.source_comp),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ },
+ .sink = {
+ .bLength = sizeof(ss_descriptors.sink),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 2 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = MAX_PACKET_SIZE_SS,
+ },
+ .sink_comp = {
+ .bLength = sizeof(ss_descriptors.sink_comp),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ },
+};
+
#define STR_INTERFACE_ "ADB Interface"
static const struct {
@@ -164,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);
@@ -284,11 +331,14 @@
v2_descriptor.header.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2);
v2_descriptor.header.length = cpu_to_le32(sizeof(v2_descriptor));
- v2_descriptor.header.flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC;
+ v2_descriptor.header.flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC |
+ FUNCTIONFS_HAS_SS_DESC;
v2_descriptor.fs_count = 3;
v2_descriptor.hs_count = 3;
+ v2_descriptor.ss_count = 5;
v2_descriptor.fs_descs = fs_descriptors;
v2_descriptor.hs_descs = hs_descriptors;
+ v2_descriptor.ss_descs = ss_descriptors;
if (h->control < 0) { // might have already done this before
D("OPENING %s\n", USB_FFS_ADB_EP0);
@@ -355,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);
@@ -383,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;
@@ -414,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 afa08c1..d9e2fb2 100644
--- a/adb/usb_osx.cpp
+++ b/adb/usb_osx.cpp
@@ -29,6 +29,9 @@
#include <inttypes.h>
#include <stdio.h>
+#include <base/logging.h>
+#include <base/stringprintf.h>
+
#include "adb.h"
#include "transport.h"
@@ -81,7 +84,7 @@
matchingDict = IOServiceMatching(kIOUSBInterfaceClassName);
if (!matchingDict) {
- DBG("ERR: Couldn't create USB matching dictionary.\n");
+ LOG(ERROR) << "Couldn't create USB matching dictionary.";
return -1;
}
@@ -115,7 +118,7 @@
IOUSBDeviceInterface197 **dev = NULL;
HRESULT result;
SInt32 score;
- UInt32 locationId;
+ uint32_t locationId;
UInt8 if_class, subclass, protocol;
UInt16 vendor;
UInt16 product;
@@ -132,7 +135,7 @@
&plugInInterface, &score);
IOObjectRelease(usbInterface);
if ((kIOReturnSuccess != kr) || (!plugInInterface)) {
- DBG("ERR: Unable to create an interface plug-in (%08x)\n", kr);
+ LOG(ERROR) << "Unable to create an interface plug-in (" << std::hex << kr << ")";
continue;
}
@@ -143,7 +146,7 @@
//* We only needed the plugin to get the interface, so discard it
(*plugInInterface)->Release(plugInInterface);
if (result || !iface) {
- DBG("ERR: Couldn't query the interface (%08x)\n", (int) result);
+ LOG(ERROR) << "Couldn't query the interface (" << std::hex << result << ")";
continue;
}
@@ -152,7 +155,8 @@
kr = (*iface)->GetInterfaceProtocol(iface, &protocol);
if(if_class != ADB_CLASS || subclass != ADB_SUBCLASS || protocol != ADB_PROTOCOL) {
// Ignore non-ADB devices.
- DBG("Ignoring interface with incorrect class/subclass/protocol - %d, %d, %d\n", if_class, subclass, protocol);
+ LOG(DEBUG) << "Ignoring interface with incorrect class/subclass/protocol - " << if_class
+ << ", " << subclass << ", " << protocol;
(*iface)->Release(iface);
continue;
}
@@ -163,7 +167,7 @@
//* Gotta love OS X
kr = (*iface)->GetDevice(iface, &usbDevice);
if (kIOReturnSuccess != kr || !usbDevice) {
- DBG("ERR: Couldn't grab device from interface (%08x)\n", kr);
+ LOG(ERROR) << "Couldn't grab device from interface (" << std::hex << kr << ")";
continue;
}
@@ -177,7 +181,7 @@
//* only needed this to find the plugin
(void)IOObjectRelease(usbDevice);
if ((kIOReturnSuccess != kr) || (!plugInInterface)) {
- DBG("ERR: Unable to create a device plug-in (%08x)\n", kr);
+ LOG(ERROR) << "Unable to create a device plug-in (" << std::hex << kr << ")";
continue;
}
@@ -186,8 +190,7 @@
//* only needed this to query the plugin
(*plugInInterface)->Release(plugInInterface);
if (result || !dev) {
- DBG("ERR: Couldn't create a device interface (%08x)\n",
- (int) result);
+ LOG(ERROR) << "Couldn't create a device interface (" << std::hex << result << ")";
continue;
}
@@ -197,74 +200,74 @@
kr = (*dev)->GetDeviceProduct(dev, &product);
kr = (*dev)->GetLocationID(dev, &locationId);
if (kr == 0) {
- snprintf(devpathBuf, sizeof(devpathBuf), "usb:%" PRIu32 "X",
- (unsigned int)locationId);
+ snprintf(devpathBuf, sizeof(devpathBuf), "usb:%" PRIu32 "X", locationId);
devpath = devpathBuf;
}
kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex);
- if (serialIndex > 0) {
- IOUSBDevRequest req;
- UInt16 buffer[256];
- UInt16 languages[128];
+ if (serialIndex > 0) {
+ IOUSBDevRequest req;
+ UInt16 buffer[256];
+ UInt16 languages[128];
- memset(languages, 0, sizeof(languages));
+ memset(languages, 0, sizeof(languages));
- req.bmRequestType =
- USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
- req.bRequest = kUSBRqGetDescriptor;
- req.wValue = (kUSBStringDesc << 8) | 0;
- req.wIndex = 0;
- req.pData = languages;
- req.wLength = sizeof(languages);
- kr = (*dev)->DeviceRequest(dev, &req);
+ req.bmRequestType =
+ USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
+ req.bRequest = kUSBRqGetDescriptor;
+ req.wValue = (kUSBStringDesc << 8) | 0;
+ req.wIndex = 0;
+ req.pData = languages;
+ req.wLength = sizeof(languages);
+ kr = (*dev)->DeviceRequest(dev, &req);
- if (kr == kIOReturnSuccess && req.wLenDone > 0) {
+ if (kr == kIOReturnSuccess && req.wLenDone > 0) {
- int langCount = (req.wLenDone - 2) / 2, lang;
+ int langCount = (req.wLenDone - 2) / 2, lang;
- for (lang = 1; lang <= langCount; lang++) {
+ for (lang = 1; lang <= langCount; lang++) {
- memset(buffer, 0, sizeof(buffer));
- memset(&req, 0, sizeof(req));
+ memset(buffer, 0, sizeof(buffer));
+ memset(&req, 0, sizeof(req));
- req.bmRequestType =
- USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
- req.bRequest = kUSBRqGetDescriptor;
- req.wValue = (kUSBStringDesc << 8) | serialIndex;
- req.wIndex = languages[lang];
- req.pData = buffer;
- req.wLength = sizeof(buffer);
- kr = (*dev)->DeviceRequest(dev, &req);
+ req.bmRequestType =
+ USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
+ req.bRequest = kUSBRqGetDescriptor;
+ req.wValue = (kUSBStringDesc << 8) | serialIndex;
+ req.wIndex = languages[lang];
+ req.pData = buffer;
+ req.wLength = sizeof(buffer);
+ kr = (*dev)->DeviceRequest(dev, &req);
- if (kr == kIOReturnSuccess && req.wLenDone > 0) {
- int i, count;
+ if (kr == kIOReturnSuccess && req.wLenDone > 0) {
+ int i, count;
- // skip first word, and copy the rest to the serial string,
- // changing shorts to bytes.
- count = (req.wLenDone - 1) / 2;
- for (i = 0; i < count; i++)
- serial[i] = buffer[i + 1];
- serial[i] = 0;
- break;
- }
- }
- }
- }
+ // skip first word, and copy the rest to the serial string,
+ // changing shorts to bytes.
+ count = (req.wLenDone - 1) / 2;
+ for (i = 0; i < count; i++)
+ serial[i] = buffer[i + 1];
+ serial[i] = 0;
+ break;
+ }
+ }
+ }
+ }
+
(*dev)->Release(dev);
- DBG("INFO: Found vid=%04x pid=%04x serial=%s\n", vendor, product,
- serial);
+ LOG(INFO) << android::base::StringPrintf("Found vid=%04x pid=%04x serial=%s\n",
+ vendor, product, serial);
usb_handle* handle = CheckInterface((IOUSBInterfaceInterface190**)iface,
vendor, product);
if (handle == NULL) {
- DBG("ERR: Could not find device interface: %08x\n", kr);
+ LOG(ERROR) << "Could not find device interface";
(*iface)->Release(iface);
continue;
}
- DBG("AndroidDeviceAdded calling register_usb_transport\n");
+ LOG(DEBUG) << "AndroidDeviceAdded calling register_usb_transport";
register_usb_transport(handle, (serial[0] ? serial : NULL), devpath, 1);
// Register for an interest notification of this device being removed.
@@ -278,7 +281,7 @@
&handle->usbNotification);
if (kIOReturnSuccess != kr) {
- DBG("ERR: Unable to create interest notification (%08x)\n", kr);
+ LOG(ERROR) << "Unable to create interest notification (" << std::hex << kr << ")";
}
}
}
@@ -290,10 +293,10 @@
if (messageType == kIOMessageServiceIsTerminated) {
if (!handle) {
- DBG("ERR: NULL handle\n");
+ LOG(ERROR) << "NULL handle";
return;
}
- DBG("AndroidInterfaceNotify\n");
+ LOG(DEBUG) << "AndroidInterfaceNotify";
IOObjectRelease(handle->usbNotification);
usb_kick(handle);
}
@@ -305,7 +308,7 @@
static bool ClearPipeStallBothEnds(IOUSBInterfaceInterface190** interface, UInt8 bulkEp) {
IOReturn rc = (*interface)->ClearPipeStallBothEnds(interface, bulkEp);
if (rc != kIOReturnSuccess) {
- DBG("ERR: Could not clear pipe: (%08x)\n", rc);
+ LOG(ERROR) << "Could not clear pipe stall both ends: " << std::hex << rc;
return false;
}
return true;
@@ -325,14 +328,14 @@
//* the endpoints in the interface descriptor to be instantiated
kr = (*interface)->USBInterfaceOpen(interface);
if (kr != kIOReturnSuccess) {
- DBG("ERR: Could not open interface: (%08x)\n", kr);
+ LOG(ERROR) << "Could not open interface: " << std::hex << kr;
return NULL;
}
//* Get the number of endpoints associated with this interface
kr = (*interface)->GetNumEndpoints(interface, &interfaceNumEndpoints);
if (kr != kIOReturnSuccess) {
- DBG("ERR: Unable to get number of endpoints: (%08x)\n", kr);
+ LOG(ERROR) << "Unable to get number of endpoints: " << std::hex << kr;
goto err_get_num_ep;
}
@@ -340,7 +343,7 @@
if ((*interface)->GetInterfaceClass(interface, &interfaceClass) != kIOReturnSuccess ||
(*interface)->GetInterfaceSubClass(interface, &interfaceSubClass) != kIOReturnSuccess ||
(*interface)->GetInterfaceProtocol(interface, &interfaceProtocol) != kIOReturnSuccess) {
- DBG("ERR: Unable to get interface class, subclass and protocol\n");
+ LOG(ERROR) << "Unable to get interface class, subclass and protocol";
goto err_get_interface_class;
}
@@ -365,7 +368,8 @@
kr = (*interface)->GetPipeProperties(interface, endpoint, &direction,
&number, &transferType, &maxPacketSize, &interval);
if (kr != kIOReturnSuccess) {
- DBG("ERR: FindDeviceInterface - could not get pipe properties (%08x)\n", kr);
+ LOG(ERROR) << "FindDeviceInterface - could not get pipe properties: "
+ << std::hex << kr;
goto err_get_pipe_props;
}
@@ -399,6 +403,7 @@
void* RunLoopThread(void* unused)
{
+ adb_thread_setname("RunLoop");
InitUSB();
currentRunLoop = CFRunLoopGetCurrent();
@@ -414,12 +419,12 @@
IOObjectRelease(notificationIterator);
IONotificationPortDestroy(notificationPort);
- DBG("RunLoopThread done\n");
+ LOG(DEBUG) << "RunLoopThread done";
return NULL;
}
static void usb_cleanup() {
- DBG("usb_cleanup\n");
+ LOG(DEBUG) << "usb_cleanup";
close_usb_devices();
if (currentRunLoop)
CFRunLoopStop(currentRunLoop);
@@ -460,18 +465,17 @@
return -1;
if (NULL == handle->interface) {
- DBG("ERR: usb_write interface was null\n");
+ LOG(ERROR) << "usb_write interface was null";
return -1;
}
if (0 == handle->bulkOut) {
- DBG("ERR: bulkOut endpoint not assigned\n");
+ LOG(ERROR) << "bulkOut endpoint not assigned";
return -1;
}
result =
- (*handle->interface)->WritePipe(
- handle->interface, handle->bulkOut, (void *)buf, len);
+ (*handle->interface)->WritePipe(handle->interface, handle->bulkOut, (void *)buf, len);
if ((result == 0) && (handle->zero_mask)) {
/* we need 0-markers and our transfer */
@@ -485,7 +489,7 @@
if (0 == result)
return 0;
- DBG("ERR: usb_write failed with status %d\n", result);
+ LOG(ERROR) << "usb_write failed with status: " << std::hex << result;
return -1;
}
@@ -503,19 +507,19 @@
}
if (NULL == handle->interface) {
- DBG("ERR: usb_read interface was null\n");
+ LOG(ERROR) << "usb_read interface was null";
return -1;
}
if (0 == handle->bulkIn) {
- DBG("ERR: bulkIn endpoint not assigned\n");
+ LOG(ERROR) << "bulkIn endpoint not assigned";
return -1;
}
result = (*handle->interface)->ReadPipe(handle->interface, handle->bulkIn, buf, &numBytes);
if (kIOUSBPipeStalled == result) {
- DBG(" Pipe stalled, clearing stall.\n");
+ LOG(ERROR) << "Pipe stalled, clearing stall.\n";
(*handle->interface)->ClearPipeStall(handle->interface, handle->bulkIn);
result = (*handle->interface)->ReadPipe(handle->interface, handle->bulkIn, buf, &numBytes);
}
@@ -523,7 +527,7 @@
if (kIOReturnSuccess == result)
return 0;
else {
- DBG("ERR: usb_read failed with status %x\n", result);
+ LOG(ERROR) << "usb_read failed with status: " << std::hex << result;
}
return -1;
@@ -536,6 +540,7 @@
void usb_kick(usb_handle *handle)
{
+ LOG(INFO) << "Kicking handle";
/* release the interface */
if (!handle)
return;
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/crash_reporter/Android.mk b/crash_reporter/Android.mk
new file mode 100644
index 0000000..6b98af4
--- /dev/null
+++ b/crash_reporter/Android.mk
@@ -0,0 +1,129 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+ifeq ($(HOST_OS),linux)
+
+crash_reporter_cpp_extension := .cc
+
+crash_reporter_src := crash_collector.cc \
+ kernel_collector.cc \
+ kernel_warning_collector.cc \
+ udev_collector.cc \
+ unclean_shutdown_collector.cc \
+ user_collector.cc
+
+crash_reporter_includes := external/gtest/include
+
+crash_reporter_test_src := crash_collector_test.cc \
+ crash_reporter_logs_test.cc \
+ kernel_collector_test.cc \
+ testrunner.cc \
+ udev_collector_test.cc \
+ unclean_shutdown_collector_test.cc \
+ user_collector_test.cc
+
+warn_collector_src := warn_collector.l
+
+# Crash reporter static library.
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libcrash
+LOCAL_CPP_EXTENSION := $(crash_reporter_cpp_extension)
+LOCAL_C_INCLUDES := $(crash_reporter_includes)
+LOCAL_RTTI_FLAG := -frtti
+LOCAL_SHARED_LIBRARIES := libchrome \
+ libchromeos \
+ libcutils \
+ libdbus \
+ libmetrics \
+ libpcrecpp
+LOCAL_SRC_FILES := $(crash_reporter_src)
+include $(BUILD_STATIC_LIBRARY)
+
+# Crash reporter client.
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := crash_reporter
+LOCAL_CPP_EXTENSION := $(crash_reporter_cpp_extension)
+LOCAL_C_INCLUDES := $(crash_reporter_includes)
+LOCAL_REQUIRED_MODULES := core2md \
+ crash_reporter_logs.conf \
+ crash_sender \
+ dbus-send \
+ init.crash_reporter.rc
+LOCAL_RTTI_FLAG := -frtti
+LOCAL_SHARED_LIBRARIES := libchrome \
+ libchromeos \
+ libcutils \
+ libdbus \
+ libmetrics \
+ libpcrecpp
+LOCAL_SRC_FILES := crash_reporter.cc
+LOCAL_STATIC_LIBRARIES := libcrash
+include $(BUILD_EXECUTABLE)
+
+# Crash sender script.
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := crash_sender
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)
+LOCAL_SRC_FILES := crash_sender
+include $(BUILD_PREBUILT)
+
+# Warn collector client.
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := warn_collector
+LOCAL_CPP_EXTENSION := $(crash_reporter_cpp_extension)
+LOCAL_SHARED_LIBRARIES := libmetrics
+LOCAL_SRC_FILES := $(warn_collector_src)
+include $(BUILD_EXECUTABLE)
+
+# Crash reporter init script.
+# ========================================================
+ifdef TARGET_COPY_OUT_INITRCD
+include $(CLEAR_VARS)
+LOCAL_MODULE := init.crash_reporter.rc
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(PRODUCT_OUT)/$(TARGET_COPY_OUT_INITRCD)
+LOCAL_SRC_FILES := init.crash_reporter.rc
+include $(BUILD_PREBUILT)
+endif
+
+# Crash reporter logs conf file.
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := crash_reporter_logs.conf
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(PRODUCT_OUT)/system/etc
+LOCAL_SRC_FILES := crash_reporter_logs.conf
+include $(BUILD_PREBUILT)
+
+# Crash reporter tests.
+# ========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := crash_reporter_tests
+LOCAL_CPP_EXTENSION := $(crash_reporter_cpp_extension)
+LOCAL_SHARED_LIBRARIES := libchrome \
+ libchromeos \
+ libdbus \
+ libpcrecpp
+LOCAL_SRC_FILES := $(crash_reporter_test_src)
+LOCAL_STATIC_LIBRARIES := libcrash libgmock
+include $(BUILD_NATIVE_TEST)
+
+endif # HOST_OS == linux
diff --git a/crash_reporter/MODULE_LICENSE_BSD b/crash_reporter/MODULE_LICENSE_BSD
deleted file mode 100644
index e69de29..0000000
--- a/crash_reporter/MODULE_LICENSE_BSD
+++ /dev/null
diff --git a/crash_reporter/NOTICE b/crash_reporter/NOTICE
deleted file mode 100644
index b9e779f..0000000
--- a/crash_reporter/NOTICE
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2014 The Chromium OS Authors. 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.
diff --git a/crash_reporter/crash_collector.cc b/crash_reporter/crash_collector.cc
index 69fe939..77755f4 100644
--- a/crash_reporter/crash_collector.cc
+++ b/crash_reporter/crash_collector.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2012 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 "crash_collector.h"
@@ -36,7 +48,7 @@
const char kLeaveCoreFile[] = "/root/.leave_core";
const char kLsbRelease[] = "/etc/lsb-release";
const char kShellPath[] = "/bin/sh";
-const char kSystemCrashPath[] = "/var/spool/crash";
+const char kSystemCrashPath[] = "/data/misc/crash_reporter/crash";
const char kUploadVarPrefix[] = "upload_var_";
const char kUploadFilePrefix[] = "upload_file_";
@@ -148,23 +160,13 @@
}
FilePath CrashCollector::GetCrashDirectoryInfo(
- uid_t process_euid,
- uid_t default_user_id,
- gid_t default_user_group,
mode_t *mode,
uid_t *directory_owner,
gid_t *directory_group) {
- if (process_euid == default_user_id) {
- *mode = kUserCrashPathMode;
- *directory_owner = default_user_id;
- *directory_group = default_user_group;
- return FilePath(kFallbackUserCrashPath);
- } else {
- *mode = kSystemCrashPathMode;
- *directory_owner = kRootOwner;
- *directory_group = kRootGroup;
- return FilePath(kSystemCrashPath);
- }
+ *mode = kSystemCrashPathMode;
+ *directory_owner = kRootOwner;
+ *directory_group = kRootGroup;
+ return FilePath(kSystemCrashPath);
}
bool CrashCollector::GetUserInfoFromName(const std::string &name,
@@ -188,9 +190,6 @@
bool CrashCollector::GetCreatedCrashDirectoryByEuid(uid_t euid,
FilePath *crash_directory,
bool *out_of_capacity) {
- uid_t default_user_id;
- gid_t default_user_group;
-
if (out_of_capacity) *out_of_capacity = false;
// For testing.
@@ -199,20 +198,11 @@
return true;
}
- if (!GetUserInfoFromName(kDefaultUserName,
- &default_user_id,
- &default_user_group)) {
- LOG(ERROR) << "Could not find default user info";
- return false;
- }
mode_t directory_mode;
uid_t directory_owner;
gid_t directory_group;
*crash_directory =
- GetCrashDirectoryInfo(euid,
- default_user_id,
- default_user_group,
- &directory_mode,
+ GetCrashDirectoryInfo(&directory_mode,
&directory_owner,
&directory_group);
@@ -238,6 +228,8 @@
if (!CheckHasCapacity(*crash_directory)) {
if (out_of_capacity) *out_of_capacity = true;
+ LOG(ERROR) << "Directory " << crash_directory->value()
+ << " is out of capacity.";
return false;
}
@@ -309,6 +301,8 @@
bool CrashCollector::CheckHasCapacity(const FilePath &crash_directory) {
DIR* dir = opendir(crash_directory.value().c_str());
if (!dir) {
+ LOG(WARNING) << "Unable to open crash directory "
+ << crash_directory.value();
return false;
}
struct dirent ent_buf;
diff --git a/crash_reporter/crash_collector.h b/crash_reporter/crash_collector.h
index 0d335cd..cfd76fd 100644
--- a/crash_reporter/crash_collector.h
+++ b/crash_reporter/crash_collector.h
@@ -1,6 +1,18 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
#ifndef CRASH_REPORTER_CRASH_COLLECTOR_H_
#define CRASH_REPORTER_CRASH_COLLECTOR_H_
@@ -72,12 +84,9 @@
forced_crash_directory_ = forced_directory;
}
- base::FilePath GetCrashDirectoryInfo(uid_t process_euid,
- uid_t default_user_id,
- gid_t default_user_group,
- mode_t *mode,
- uid_t *directory_owner,
- gid_t *directory_group);
+ base::FilePath GetCrashDirectoryInfo(mode_t *mode,
+ uid_t *directory_owner,
+ gid_t *directory_group);
bool GetUserInfoFromName(const std::string &name,
uid_t *uid,
gid_t *gid);
diff --git a/crash_reporter/crash_collector_test.cc b/crash_reporter/crash_collector_test.cc
index 13fb76a..32cbe9f 100644
--- a/crash_reporter/crash_collector_test.cc
+++ b/crash_reporter/crash_collector_test.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2012 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 "crash_collector_test.h"
@@ -83,54 +95,6 @@
EXPECT_EQ("_", collector_.Sanitize(" "));
}
-TEST_F(CrashCollectorTest, GetCrashDirectoryInfo) {
- FilePath path;
- const int kRootUid = 0;
- const int kRootGid = 0;
- const int kNtpUid = 5;
- const int kChronosUid = 1000;
- const int kChronosGid = 1001;
- const mode_t kExpectedSystemMode = 01755;
- const mode_t kExpectedUserMode = 0755;
-
- mode_t directory_mode;
- uid_t directory_owner;
- gid_t directory_group;
-
- path = collector_.GetCrashDirectoryInfo(kRootUid,
- kChronosUid,
- kChronosGid,
- &directory_mode,
- &directory_owner,
- &directory_group);
- EXPECT_EQ("/var/spool/crash", path.value());
- EXPECT_EQ(kExpectedSystemMode, directory_mode);
- EXPECT_EQ(kRootUid, directory_owner);
- EXPECT_EQ(kRootGid, directory_group);
-
- path = collector_.GetCrashDirectoryInfo(kNtpUid,
- kChronosUid,
- kChronosGid,
- &directory_mode,
- &directory_owner,
- &directory_group);
- EXPECT_EQ("/var/spool/crash", path.value());
- EXPECT_EQ(kExpectedSystemMode, directory_mode);
- EXPECT_EQ(kRootUid, directory_owner);
- EXPECT_EQ(kRootGid, directory_group);
-
- path = collector_.GetCrashDirectoryInfo(kChronosUid,
- kChronosUid,
- kChronosGid,
- &directory_mode,
- &directory_owner,
- &directory_group);
- EXPECT_EQ("/var/spool/crash", path.value());
- EXPECT_EQ(kExpectedUserMode, directory_mode);
- EXPECT_EQ(kChronosUid, directory_owner);
- EXPECT_EQ(kChronosGid, directory_group);
-}
-
TEST_F(CrashCollectorTest, FormatDumpBasename) {
struct tm tm = {0};
tm.tm_sec = 15;
diff --git a/crash_reporter/crash_collector_test.h b/crash_reporter/crash_collector_test.h
index c875d44..cfbb97b 100644
--- a/crash_reporter/crash_collector_test.h
+++ b/crash_reporter/crash_collector_test.h
@@ -1,6 +1,18 @@
-// Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
#ifndef CRASH_REPORTER_CRASH_COLLECTOR_TEST_H_
#define CRASH_REPORTER_CRASH_COLLECTOR_TEST_H_
diff --git a/crash_reporter/crash_reporter.cc b/crash_reporter/crash_reporter.cc
index 0e45992..23bd342 100644
--- a/crash_reporter/crash_reporter.cc
+++ b/crash_reporter/crash_reporter.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2012 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 <fcntl.h> // for open
@@ -74,7 +86,7 @@
static void CountUserCrash() {
SendCrashMetrics(kCrashKindUser, "user");
std::string command = StringPrintf(
- "/usr/bin/dbus-send --type=signal --system / \"%s\" &",
+ "/system/bin/dbus-send --type=signal --system / \"%s\" &",
kUserCrashSignal);
// Announce through D-Bus whenever a user crash happens. This is
// used by the metrics daemon to log active use time between
diff --git a/crash_reporter/crash_reporter_logs.conf b/crash_reporter/crash_reporter_logs.conf
index f5ca80c..7db308c 100644
--- a/crash_reporter/crash_reporter_logs.conf
+++ b/crash_reporter/crash_reporter_logs.conf
@@ -1,6 +1,16 @@
-# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can
-# be found in the LICENSE file.
+# Copyright (C) 2012 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.
# This file is parsed by chromeos::KeyValueStore. It has the format:
#
diff --git a/crash_reporter/crash_reporter_logs_test.cc b/crash_reporter/crash_reporter_logs_test.cc
index 9879470..c9ca02d 100644
--- a/crash_reporter/crash_reporter_logs_test.cc
+++ b/crash_reporter/crash_reporter_logs_test.cc
@@ -1,6 +1,18 @@
-// Copyright 2015 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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 <string>
diff --git a/crash_reporter/crash_sender b/crash_reporter/crash_sender
index 641ae2d..fa2f8fc 100755
--- a/crash_reporter/crash_sender
+++ b/crash_reporter/crash_sender
@@ -1,8 +1,18 @@
#!/bin/sh
-# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
set -e
diff --git a/crash_reporter/init.crash_reporter.rc b/crash_reporter/init.crash_reporter.rc
new file mode 100644
index 0000000..6882b77
--- /dev/null
+++ b/crash_reporter/init.crash_reporter.rc
@@ -0,0 +1,18 @@
+on property:crash_reporter.coredump.enabled=1
+ write /proc/sys/kernel/core_pattern \
+ "|/system/bin/crash_reporter --user=%P:%s:%u:%e"
+
+on property:crash_reporter.coredump.enabled=0
+ write /proc/sys/kernel/core_pattern "core"
+
+on boot
+ # Allow catching multiple unrelated concurrent crashes, but use a finite
+ # number to prevent infinitely recursing on crash handling.
+ write /proc/sys/kernel/core_pipe_limit 4
+
+ # Create crash directories.
+ mkdir /data/misc/crash_reporter 0700 root root
+
+service crash_reporter /system/bin/crash_reporter --init
+ class late_start
+ oneshot
diff --git a/crash_reporter/kernel_collector.cc b/crash_reporter/kernel_collector.cc
index b3cbede..12b00b9 100644
--- a/crash_reporter/kernel_collector.cc
+++ b/crash_reporter/kernel_collector.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2012 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 "kernel_collector.h"
diff --git a/crash_reporter/kernel_collector.h b/crash_reporter/kernel_collector.h
index 5fc4ac2..206ee26 100644
--- a/crash_reporter/kernel_collector.h
+++ b/crash_reporter/kernel_collector.h
@@ -1,6 +1,18 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
#ifndef CRASH_REPORTER_KERNEL_COLLECTOR_H_
#define CRASH_REPORTER_KERNEL_COLLECTOR_H_
diff --git a/crash_reporter/kernel_collector_test.cc b/crash_reporter/kernel_collector_test.cc
index a534803..e690b77 100644
--- a/crash_reporter/kernel_collector_test.cc
+++ b/crash_reporter/kernel_collector_test.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2012 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 "kernel_collector_test.h"
diff --git a/crash_reporter/kernel_collector_test.h b/crash_reporter/kernel_collector_test.h
index d450134..f689e7d 100644
--- a/crash_reporter/kernel_collector_test.h
+++ b/crash_reporter/kernel_collector_test.h
@@ -1,6 +1,18 @@
-// Copyright 2014 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
#ifndef CRASH_REPORTER_KERNEL_COLLECTOR_TEST_H_
#define CRASH_REPORTER_KERNEL_COLLECTOR_TEST_H_
diff --git a/crash_reporter/kernel_log_collector.sh b/crash_reporter/kernel_log_collector.sh
index d38479e..82512c2 100644
--- a/crash_reporter/kernel_log_collector.sh
+++ b/crash_reporter/kernel_log_collector.sh
@@ -1,8 +1,18 @@
#!/bin/sh
-# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
+# Copyright (C) 2013 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.
# Usage example: "kernel_log_collector.sh XXX YYY"
# This script searches logs in the /var/log/messages which have the keyword XXX.
diff --git a/crash_reporter/kernel_warning_collector.cc b/crash_reporter/kernel_warning_collector.cc
index 4cf7640..e28e8fd 100644
--- a/crash_reporter/kernel_warning_collector.cc
+++ b/crash_reporter/kernel_warning_collector.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2012 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 "kernel_warning_collector.h"
diff --git a/crash_reporter/kernel_warning_collector.h b/crash_reporter/kernel_warning_collector.h
index 82c509c..5ccb780 100644
--- a/crash_reporter/kernel_warning_collector.h
+++ b/crash_reporter/kernel_warning_collector.h
@@ -1,6 +1,18 @@
-// Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
#ifndef CRASH_REPORTER_KERNEL_WARNING_COLLECTOR_H_
#define CRASH_REPORTER_KERNEL_WARNING_COLLECTOR_H_
diff --git a/crash_reporter/list_proxies.cc b/crash_reporter/list_proxies.cc
index de6ef0a..a39441d 100644
--- a/crash_reporter/list_proxies.cc
+++ b/crash_reporter/list_proxies.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
#include <sysexits.h>
#include <unistd.h> // for isatty()
diff --git a/crash_reporter/testrunner.cc b/crash_reporter/testrunner.cc
index d45bbf8..a8c717e 100644
--- a/crash_reporter/testrunner.cc
+++ b/crash_reporter/testrunner.cc
@@ -1,6 +1,18 @@
-// Copyright 2015 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * 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 <chromeos/test_helpers.h>
#include <gtest/gtest.h>
diff --git a/crash_reporter/udev_collector.cc b/crash_reporter/udev_collector.cc
index 85f40db..576fdbd 100644
--- a/crash_reporter/udev_collector.cc
+++ b/crash_reporter/udev_collector.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2012 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 "udev_collector.h"
diff --git a/crash_reporter/udev_collector.h b/crash_reporter/udev_collector.h
index d9b37eb..e267b75 100644
--- a/crash_reporter/udev_collector.h
+++ b/crash_reporter/udev_collector.h
@@ -1,6 +1,18 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
#ifndef CRASH_REPORTER_UDEV_COLLECTOR_H_
#define CRASH_REPORTER_UDEV_COLLECTOR_H_
diff --git a/crash_reporter/udev_collector_test.cc b/crash_reporter/udev_collector_test.cc
index 4897b91..a6643fb 100644
--- a/crash_reporter/udev_collector_test.cc
+++ b/crash_reporter/udev_collector_test.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2012 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 <base/files/file_enumerator.h>
#include <base/files/file_util.h>
diff --git a/crash_reporter/unclean_shutdown_collector.cc b/crash_reporter/unclean_shutdown_collector.cc
index a6da1bb..8a092ec 100644
--- a/crash_reporter/unclean_shutdown_collector.cc
+++ b/crash_reporter/unclean_shutdown_collector.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
#include "unclean_shutdown_collector.h"
diff --git a/crash_reporter/unclean_shutdown_collector.h b/crash_reporter/unclean_shutdown_collector.h
index 2ce0842..5bc9968 100644
--- a/crash_reporter/unclean_shutdown_collector.h
+++ b/crash_reporter/unclean_shutdown_collector.h
@@ -1,6 +1,18 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
#ifndef CRASH_REPORTER_UNCLEAN_SHUTDOWN_COLLECTOR_H_
#define CRASH_REPORTER_UNCLEAN_SHUTDOWN_COLLECTOR_H_
diff --git a/crash_reporter/unclean_shutdown_collector_test.cc b/crash_reporter/unclean_shutdown_collector_test.cc
index dc420fb..c5c0662 100644
--- a/crash_reporter/unclean_shutdown_collector_test.cc
+++ b/crash_reporter/unclean_shutdown_collector_test.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
#include "unclean_shutdown_collector.h"
diff --git a/crash_reporter/user_collector.cc b/crash_reporter/user_collector.cc
index 069b581..61ccc37 100644
--- a/crash_reporter/user_collector.cc
+++ b/crash_reporter/user_collector.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2012 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 "user_collector.h"
@@ -12,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>
@@ -24,21 +37,18 @@
#include <base/strings/stringprintf.h>
#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";
-// This procfs file is used to cause kernel core file writing to
-// instead pipe the core file into a user space process. See
-// core(5) man page.
-static const char kCorePatternFile[] = "/proc/sys/kernel/core_pattern";
-static const char kCorePipeLimitFile[] = "/proc/sys/kernel/core_pipe_limit";
-// Set core_pipe_limit to 4 so that we can catch a few unrelated concurrent
-// crashes, but finite to avoid infinitely recursing on crash handling.
-static const char kCorePipeLimit[] = "4";
-static const char kCoreToMinidumpConverterPath[] = "/usr/bin/core2md";
+static const char kCorePatternProperty[] = "crash_reporter.coredump.enabled";
+static const char kCoreToMinidumpConverterPath[] = "/system/bin/core2md";
static const char kStatePrefix[] = "State:\t";
+static const char kCoreTempFolder[] = "/data/misc/crash_reporter/tmp";
+
// Define an otherwise invalid value that represents an unknown UID.
static const uid_t kUnknownUid = -1;
@@ -50,8 +60,6 @@
UserCollector::UserCollector()
: generate_diagnostics_(false),
- core_pattern_file_(kCorePatternFile),
- core_pipe_limit_file_(kCorePipeLimitFile),
initialized_(false) {
}
@@ -71,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() {
@@ -115,18 +128,8 @@
CHECK(initialized_);
LOG(INFO) << (enabled ? "Enabling" : "Disabling") << " user crash handling";
- if (base::WriteFile(FilePath(core_pipe_limit_file_), kCorePipeLimit,
- strlen(kCorePipeLimit)) !=
- static_cast<int>(strlen(kCorePipeLimit))) {
- PLOG(ERROR) << "Unable to write " << core_pipe_limit_file_;
- return false;
- }
- std::string pattern = GetPattern(enabled);
- if (base::WriteFile(FilePath(core_pattern_file_), pattern.c_str(),
- pattern.length()) != static_cast<int>(pattern.length())) {
- PLOG(ERROR) << "Unable to write " << core_pattern_file_;
- return false;
- }
+ property_set(kCorePatternProperty, enabled ? "1" : "0");
+
return true;
}
@@ -342,7 +345,7 @@
bool UserCollector::CopyStdinToCoreFile(const FilePath &core_path) {
// Copy off all stdin to a core file.
- FilePath stdin_path("/dev/fd/0");
+ FilePath stdin_path("/proc/self/fd/0");
if (base::CopyFile(stdin_path, core_path)) {
return true;
}
@@ -438,7 +441,7 @@
// Directory like /tmp/crash_reporter/1234 which contains the
// procfs entries and other temporary files used during conversion.
- FilePath container_dir(StringPrintf("/tmp/crash_reporter/%d", pid));
+ FilePath container_dir(StringPrintf("%s/%d", kCoreTempFolder, pid));
// Delete a pre-existing directory from crash reporter that may have
// been left around for diagnostics from a failed conversion attempt.
// If we don't, existing files can cause forking to fail.
diff --git a/crash_reporter/user_collector.h b/crash_reporter/user_collector.h
index 7b356ee..8c38aa2 100644
--- a/crash_reporter/user_collector.h
+++ b/crash_reporter/user_collector.h
@@ -1,6 +1,18 @@
-// Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
#ifndef CRASH_REPORTER_USER_COLLECTOR_H_
#define CRASH_REPORTER_USER_COLLECTOR_H_
@@ -47,16 +59,6 @@
bool HandleCrash(const std::string &crash_attributes,
const char *force_exec);
- // Set (override the default) core file pattern.
- void set_core_pattern_file(const std::string &pattern) {
- core_pattern_file_ = pattern;
- }
-
- // Set (override the default) core pipe limit file.
- void set_core_pipe_limit_file(const std::string &path) {
- core_pipe_limit_file_ = path;
- }
-
private:
friend class UserCollectorTest;
FRIEND_TEST(UserCollectorTest, CopyOffProcFilesBadPath);
@@ -172,8 +174,6 @@
std::string *reason);
bool generate_diagnostics_;
- std::string core_pattern_file_;
- std::string core_pipe_limit_file_;
std::string our_path_;
bool initialized_;
diff --git a/crash_reporter/user_collector_test.cc b/crash_reporter/user_collector_test.cc
index ee3ca12..4419e7c 100644
--- a/crash_reporter/user_collector_test.cc
+++ b/crash_reporter/user_collector_test.cc
@@ -1,6 +1,18 @@
-// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
+/*
+ * Copyright (C) 2012 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 "user_collector.h"
@@ -60,8 +72,6 @@
"");
base::DeleteFile(FilePath("test"), true);
mkdir("test", 0777);
- collector_.set_core_pattern_file("test/core_pattern");
- collector_.set_core_pipe_limit_file("test/core_pipe_limit");
pid_ = getpid();
chromeos::ClearLog();
}
@@ -84,49 +94,6 @@
pid_t pid_;
};
-TEST_F(UserCollectorTest, EnableOK) {
- ASSERT_TRUE(collector_.Enable());
- ExpectFileEquals("|/my/path --user=%P:%s:%u:%e",
- FilePath("test/core_pattern"));
- ExpectFileEquals("4", FilePath("test/core_pipe_limit"));
- ASSERT_EQ(s_crashes, 0);
- EXPECT_TRUE(FindLog("Enabling user crash handling"));
-}
-
-TEST_F(UserCollectorTest, EnableNoPatternFileAccess) {
- collector_.set_core_pattern_file("/does_not_exist");
- ASSERT_FALSE(collector_.Enable());
- ASSERT_EQ(s_crashes, 0);
- EXPECT_TRUE(FindLog("Enabling user crash handling"));
- EXPECT_TRUE(FindLog("Unable to write /does_not_exist"));
-}
-
-TEST_F(UserCollectorTest, EnableNoPipeLimitFileAccess) {
- collector_.set_core_pipe_limit_file("/does_not_exist");
- ASSERT_FALSE(collector_.Enable());
- ASSERT_EQ(s_crashes, 0);
- // Core pattern should not be written if we cannot access the pipe limit
- // or otherwise we may set a pattern that results in infinite recursion.
- ASSERT_FALSE(base::PathExists(FilePath("test/core_pattern")));
- EXPECT_TRUE(FindLog("Enabling user crash handling"));
- EXPECT_TRUE(FindLog("Unable to write /does_not_exist"));
-}
-
-TEST_F(UserCollectorTest, DisableOK) {
- ASSERT_TRUE(collector_.Disable());
- ExpectFileEquals("core", FilePath("test/core_pattern"));
- ASSERT_EQ(s_crashes, 0);
- EXPECT_TRUE(FindLog("Disabling user crash handling"));
-}
-
-TEST_F(UserCollectorTest, DisableNoFileAccess) {
- collector_.set_core_pattern_file("/does_not_exist");
- ASSERT_FALSE(collector_.Disable());
- ASSERT_EQ(s_crashes, 0);
- EXPECT_TRUE(FindLog("Disabling user crash handling"));
- EXPECT_TRUE(FindLog("Unable to write /does_not_exist"));
-}
-
TEST_F(UserCollectorTest, ParseCrashAttributes) {
pid_t pid;
int signal;
diff --git a/crash_reporter/warn_collector.l b/crash_reporter/warn_collector.l
index de746fe..70ab25c 100644
--- a/crash_reporter/warn_collector.l
+++ b/crash_reporter/warn_collector.l
@@ -1,6 +1,17 @@
-/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
+/*
+ * Copyright (C) 2013 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.
*
* This flex program reads /var/log/messages as it grows and saves kernel
* warnings to files. It keeps track of warnings it has seen (based on
diff --git a/crash_reporter/warn_collector_test.c b/crash_reporter/warn_collector_test.c
index 7e25d01..7ebe0a8 100644
--- a/crash_reporter/warn_collector_test.c
+++ b/crash_reporter/warn_collector_test.c
@@ -1,6 +1,17 @@
-/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
+/*
+ * Copyright (C) 2013 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.
*/
/*
diff --git a/crash_reporter/warn_collector_test.sh b/crash_reporter/warn_collector_test.sh
index d9bb6f9..a5af16c 100755
--- a/crash_reporter/warn_collector_test.sh
+++ b/crash_reporter/warn_collector_test.sh
@@ -1,7 +1,18 @@
#! /bin/bash
-# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
+
+# Copyright (C) 2013 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.
# Test for warn_collector. Run the warn collector in the background, emulate
# the kernel by appending lines to the log file "messages", and observe the log
diff --git a/crash_reporter/warn_collector_test_reporter.sh b/crash_reporter/warn_collector_test_reporter.sh
index d8f3fad..b6096ed 100755
--- a/crash_reporter/warn_collector_test_reporter.sh
+++ b/crash_reporter/warn_collector_test_reporter.sh
@@ -1,7 +1,18 @@
#! /bin/sh
-# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
+
+# Copyright (C) 2013 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.
# Replacement for the crash reporter, for testing. Log the first line of the
# "warning" file, which by convention contains the warning hash, and remove the
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
index 3fca709..f7a5f82 100644
--- a/debuggerd/Android.mk
+++ b/debuggerd/Android.mk
@@ -27,6 +27,9 @@
LOCAL_CPPFLAGS := $(common_cppflags)
+LOCAL_INIT_RC_32 := debuggerd.rc
+LOCAL_INIT_RC_64 := debuggerd64.rc
+
ifeq ($(TARGET_IS_64_BIT),true)
LOCAL_CPPFLAGS += -DTARGET_IS_64_BIT
endif
diff --git a/debuggerd/debuggerd.rc b/debuggerd/debuggerd.rc
new file mode 100644
index 0000000..4338ae9
--- /dev/null
+++ b/debuggerd/debuggerd.rc
@@ -0,0 +1,2 @@
+service debuggerd /system/bin/debuggerd
+ class main
diff --git a/debuggerd/debuggerd64.rc b/debuggerd/debuggerd64.rc
new file mode 100644
index 0000000..341a329
--- /dev/null
+++ b/debuggerd/debuggerd64.rc
@@ -0,0 +1,2 @@
+service debuggerd64 /system/bin/debuggerd64
+ class main
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 5d7b151..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,19 +167,15 @@
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) {
+ 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;
@@ -246,21 +227,20 @@
if(usb) return usb;
if(announce) {
announce = 0;
- fprintf(stderr,"< waiting for device >\n");
+ fprintf(stderr, "< waiting for %s >\n", serial ? serial : "any device");
}
usleep(1000);
}
}
-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/fastboot/usb_osx.cpp b/fastboot/usb_osx.cpp
index 7ae2aa5..45ae833 100644
--- a/fastboot/usb_osx.cpp
+++ b/fastboot/usb_osx.cpp
@@ -293,6 +293,13 @@
// So, we have a device, finally. Grab its vitals.
+
+ kr = (*dev)->USBDeviceOpen(dev);
+ if (kr != 0) {
+ WARN("USBDeviceOpen");
+ goto out;
+ }
+
kr = (*dev)->GetDeviceVendor(dev, &handle->info.dev_vendor);
if (kr != 0) {
ERR("GetDeviceVendor");
@@ -365,12 +372,16 @@
goto error;
}
+ out:
+
+ (*dev)->USBDeviceClose(dev);
(*dev)->Release(dev);
return 0;
error:
if (dev != NULL) {
+ (*dev)->USBDeviceClose(dev);
(*dev)->Release(dev);
}
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index 459daec..044c895 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -151,8 +151,8 @@
INFO("Running %s on %s\n", E2FSCK_BIN, blk_device);
ret = android_fork_execvp_ext(ARRAY_SIZE(e2fsck_argv), e2fsck_argv,
- &status, true, LOG_KLOG | LOG_FILE,
- true, FSCK_LOG_FILE);
+ &status, true, LOG_KLOG | LOG_FILE,
+ true, FSCK_LOG_FILE, NULL, 0);
if (ret < 0) {
/* No need to check for error in fork, we can't really handle it now */
@@ -169,7 +169,7 @@
ret = android_fork_execvp_ext(ARRAY_SIZE(f2fs_fsck_argv), f2fs_fsck_argv,
&status, true, LOG_KLOG | LOG_FILE,
- true, FSCK_LOG_FILE);
+ true, FSCK_LOG_FILE, NULL, 0);
if (ret < 0) {
/* No need to check for error in fork, we can't really handle it now */
ERROR("Failed trying to run %s\n", F2FS_FSCK_BIN);
@@ -795,7 +795,8 @@
/* Initialize the swap area */
mkswap_argv[1] = fstab->recs[i].blk_device;
err = android_fork_execvp_ext(ARRAY_SIZE(mkswap_argv), mkswap_argv,
- &status, true, LOG_KLOG, false, NULL);
+ &status, true, LOG_KLOG, false, NULL,
+ NULL, 0);
if (err) {
ERROR("mkswap failed for %s\n", fstab->recs[i].blk_device);
ret = -1;
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/include/utils/Errors.h b/include/utils/Errors.h
index 9402614..08ddcd2 100644
--- a/include/utils/Errors.h
+++ b/include/utils/Errors.h
@@ -23,7 +23,7 @@
namespace android {
// use this type to return error codes
-#ifdef HAVE_MS_C_RUNTIME
+#ifdef _WIN32
typedef int status_t;
#else
typedef int32_t status_t;
@@ -58,7 +58,7 @@
ALREADY_EXISTS = -EEXIST,
DEAD_OBJECT = -EPIPE,
FAILED_TRANSACTION = (UNKNOWN_ERROR + 2),
-#if !defined(HAVE_MS_C_RUNTIME)
+#if !defined(_WIN32)
BAD_INDEX = -EOVERFLOW,
NOT_ENOUGH_DATA = -ENODATA,
WOULD_BLOCK = -EWOULDBLOCK,
diff --git a/include/utils/JenkinsHash.h b/include/utils/JenkinsHash.h
index 7da5dbd..027c10c 100644
--- a/include/utils/JenkinsHash.h
+++ b/include/utils/JenkinsHash.h
@@ -29,6 +29,9 @@
/* The Jenkins hash of a sequence of 32 bit words A, B, C is:
* Whiten(Mix(Mix(Mix(0, A), B), C)) */
+#ifdef __clang__
+__attribute__((no_sanitize("integer")))
+#endif
inline uint32_t JenkinsHashMix(uint32_t hash, uint32_t data) {
hash += data;
hash += (hash << 10);
diff --git a/init/action.cpp b/init/action.cpp
index 2eb809e..dd366d3 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -154,7 +154,7 @@
const static std::string prop_str("property:");
for (std::size_t i = 0; i < args.size(); ++i) {
if (i % 2) {
- if (args[i].compare("&&")) {
+ if (args[i] != "&&") {
*err = "&& is the only symbol allowed to concatenate actions";
return false;
} else {
@@ -189,24 +189,24 @@
bool Action::CheckPropertyTriggers(const std::string& name,
const std::string& value) const
{
- bool found = !name.compare("");
+ bool found = name.empty();
if (property_triggers_.empty()) {
return true;
}
for (const auto& t : property_triggers_) {
- if (!t.first.compare(name)) {
- if (t.second.compare("*") &&
- t.second.compare(value)) {
+ const auto& trigger_name = t.first;
+ const auto& trigger_value = t.second;
+ if (trigger_name == name) {
+ if (trigger_value != "*" && trigger_value != value) {
return false;
} else {
found = true;
}
} else {
- std::string prop_val = property_get(t.first.c_str());
- if (prop_val.empty() ||
- (t.second.compare("*") &&
- t.second.compare(prop_val))) {
+ std::string prop_val = property_get(trigger_name.c_str());
+ if (prop_val.empty() || (trigger_value != "*" &&
+ trigger_value != prop_val)) {
return false;
}
}
@@ -217,7 +217,7 @@
bool Action::CheckEventTrigger(const std::string& trigger) const
{
return !event_trigger_.empty() &&
- !trigger.compare(event_trigger_) &&
+ trigger == event_trigger_ &&
CheckPropertyTriggers();
}
@@ -229,10 +229,8 @@
bool Action::TriggersEqual(const class Action& other) const
{
- return property_triggers_.size() == other.property_triggers_.size() &&
- std::equal(property_triggers_.begin(), property_triggers_.end(),
- other.property_triggers_.begin()) &&
- !event_trigger_.compare(other.event_trigger_);
+ return property_triggers_ == other.property_triggers_ &&
+ event_trigger_ == other.event_trigger_;
}
std::string Action::BuildTriggersString() const
@@ -255,19 +253,53 @@
void Action::DumpState() const
{
- INFO("on ");
std::string trigger_name = BuildTriggersString();
- INFO("%s", trigger_name.c_str());
- INFO("\n");
+ INFO("on %s\n", trigger_name.c_str());
for (const auto& c : commands_) {
std::string cmd_str = c->BuildCommandString();
- INFO(" %s", cmd_str.c_str());
+ INFO(" %s\n", cmd_str.c_str());
}
INFO("\n");
}
-ActionManager::ActionManager() : cur_command_(0)
+
+class EventTrigger : public Trigger {
+public:
+ EventTrigger(const std::string& trigger) : trigger_(trigger) {
+ }
+ bool CheckTriggers(const Action* action) override {
+ return action->CheckEventTrigger(trigger_);
+ }
+private:
+ std::string trigger_;
+};
+
+class PropertyTrigger : public Trigger {
+public:
+ PropertyTrigger(const std::string& name, const std::string& value)
+ : name_(name), value_(value) {
+ }
+ bool CheckTriggers(const Action* action) override {
+ return action->CheckPropertyTrigger(name_, value_);
+ }
+private:
+ std::string name_;
+ std::string value_;
+};
+
+class BuiltinTrigger : public Trigger {
+public:
+ BuiltinTrigger(Action* action) : action_(action) {
+ }
+ bool CheckTriggers(const Action* action) override {
+ return action == action_;
+ }
+private:
+ Action* action_;
+};
+
+ActionManager::ActionManager() : current_command_(0)
{
}
@@ -278,21 +310,13 @@
void ActionManager::QueueEventTrigger(const std::string& trigger)
{
- for (const auto& a : action_list_) {
- if (a->CheckEventTrigger(trigger)) {
- action_queue_.push(a);
- }
- }
+ trigger_queue_.push(std::make_unique<EventTrigger>(trigger));
}
void ActionManager::QueuePropertyTrigger(const std::string& name,
const std::string& value)
{
- for (const auto& a : action_list_) {
- if (a->CheckPropertyTrigger(name, value)) {
- action_queue_.push(a);
- }
- }
+ trigger_queue_.push(std::make_unique<PropertyTrigger>(name, value));
}
void ActionManager::QueueAllPropertyTriggers()
@@ -312,35 +336,45 @@
act->AddCommand(func, name_vector);
- action_queue_.push(act);
+ actions_.push_back(act);
+ trigger_queue_.push(std::make_unique<BuiltinTrigger>(act));
}
void ActionManager::ExecuteOneCommand() {
- if (action_queue_.empty()) {
+ while (current_executing_actions_.empty() && !trigger_queue_.empty()) {
+ std::copy_if(actions_.begin(), actions_.end(),
+ std::back_inserter(current_executing_actions_),
+ [this] (Action* act) {
+ return trigger_queue_.front()->CheckTriggers(act);
+ });
+ trigger_queue_.pop();
+ }
+
+ if (current_executing_actions_.empty()) {
return;
}
- Action* action = action_queue_.front();
+ Action* action = current_executing_actions_.back();
if (!action->NumCommands()) {
- action_queue_.pop();
+ current_executing_actions_.pop_back();
return;
}
- if (cur_command_ == 0) {
+ if (current_command_ == 0) {
std::string trigger_name = action->BuildTriggersString();
INFO("processing action %p (%s)\n", action, trigger_name.c_str());
}
- action->ExecuteOneCommand(cur_command_++);
- if (cur_command_ == action->NumCommands()) {
- cur_command_ = 0;
- action_queue_.pop();
+ action->ExecuteOneCommand(current_command_++);
+ if (current_command_ == action->NumCommands()) {
+ current_command_ = 0;
+ current_executing_actions_.pop_back();
}
}
bool ActionManager::HasMoreCommands() const
{
- return !action_queue_.empty();
+ return !current_executing_actions_.empty() || !trigger_queue_.empty();
}
Action* ActionManager::AddNewAction(const std::vector<std::string>& triggers,
@@ -357,21 +391,21 @@
}
auto old_act_it =
- std::find_if(action_list_.begin(), action_list_.end(),
+ std::find_if(actions_.begin(), actions_.end(),
[&act] (Action* a) { return act->TriggersEqual(*a); });
- if (old_act_it != action_list_.end()) {
+ if (old_act_it != actions_.end()) {
delete act;
return *old_act_it;
}
- action_list_.push_back(act);
+ actions_.push_back(act);
return act;
}
void ActionManager::DumpState() const
{
- for (const auto& a : action_list_) {
+ for (const auto& a : actions_) {
a->DumpState();
}
INFO("\n");
diff --git a/init/action.h b/init/action.h
index ae28fe1..5088c71 100644
--- a/init/action.h
+++ b/init/action.h
@@ -54,6 +54,12 @@
std::vector<Command*> commands_;
};
+class Trigger {
+public:
+ virtual ~Trigger() { }
+ virtual bool CheckTriggers(const Action* action) = 0;
+};
+
class ActionManager {
public:
static ActionManager& GetInstance();
@@ -74,9 +80,10 @@
ActionManager(ActionManager const&) = delete;
void operator=(ActionManager const&) = delete;
- std::vector<Action*> action_list_;
- std::queue<Action*> action_queue_;
- std::size_t cur_command_;
+ std::vector<Action*> actions_;
+ std::queue<std::unique_ptr<Trigger>> trigger_queue_;
+ std::vector<Action*> current_executing_actions_;
+ std::size_t current_command_;
};
#endif
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 470437c..97151c0 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -150,13 +150,13 @@
"/system/bin/fsck.f2fs", "-f", entry->mnt_fsname,
};
android_fork_execvp_ext(ARRAY_SIZE(f2fs_argv), (char **)f2fs_argv,
- &st, true, LOG_KLOG, true, NULL);
+ &st, true, LOG_KLOG, true, NULL, NULL, 0);
} else if (!strcmp(entry->mnt_type, "ext4")) {
const char *ext4_argv[] = {
"/system/bin/e2fsck", "-f", "-y", entry->mnt_fsname,
};
android_fork_execvp_ext(ARRAY_SIZE(ext4_argv), (char **)ext4_argv,
- &st, true, LOG_KLOG, true, NULL);
+ &st, true, LOG_KLOG, true, NULL, NULL, 0);
}
}
@@ -427,6 +427,19 @@
while (1) { pause(); } // never reached
}
+void import_late()
+{
+ static const std::vector<std::string> init_directories = {
+ "/system/etc/init",
+ "/vendor/etc/init",
+ "/odm/etc/init"
+ };
+
+ for (const auto& dir : init_directories) {
+ init_parse_config(dir.c_str());
+ }
+}
+
/*
* This function might request a reboot, in which case it will
* not return.
@@ -478,6 +491,8 @@
return -1;
}
+ import_late();
+
if (ret == FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION) {
property_set("vold.decrypt", "trigger_encryption");
} else if (ret == FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED) {
diff --git a/init/perfboot.py b/init/perfboot.py
index b0efb11..2a17ab6 100755
--- a/init/perfboot.py
+++ b/init/perfboot.py
@@ -408,7 +408,10 @@
parser.add_argument('-t', '--tags', help='Specify the filename from which '
'event tags are read. Every line contains one event '
'tag and the last event tag is used to detect that '
- 'the device has finished booting.')
+ 'the device has finished booting unless --end-tag is '
+ 'specified.')
+ parser.add_argument('--end-tag', help='An event tag on which the script '
+ 'stops measuring the boot time.')
parser.add_argument('--apk-dir', help='Specify the directory which contains '
'APK files to be installed before measuring boot time.')
return parser.parse_args()
@@ -439,10 +442,14 @@
record_list = []
event_tags = filter_event_tags(read_event_tags(args.tags), device)
+ end_tag = args.end_tag or event_tags[-1]
+ if end_tag not in event_tags:
+ sys.exit('%s is not a valid tag.' % end_tag)
+ event_tags = event_tags[0 : event_tags.index(end_tag) + 1]
init_perf(device, args.output, record_list, event_tags)
interval_adjuster = IntervalAdjuster(args.interval, device)
event_tags_re = make_event_tags_re(event_tags)
- end_tag = event_tags[-1]
+
for i in range(args.iterations):
print 'Run #%d ' % i
record = do_iteration(
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index 128bb04..97f0ef4 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -102,6 +102,11 @@
uintptr_t relative_pc = BacktraceMap::GetRelativePc(frame->map, frame->pc);
std::string line(StringPrintf("#%02zu pc %" PRIPTR " %s", frame->num, relative_pc, map_name));
+ // Special handling for non-zero offset maps, we need to print that
+ // information.
+ if (frame->map.offset != 0) {
+ line += " (offset " + StringPrintf("0x%" PRIxPTR, frame->map.offset) + ")";
+ }
if (!frame->func_name.empty()) {
line += " (" + frame->func_name;
if (frame->func_offset) {
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index 6bd7529..9ebd639 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -825,6 +825,15 @@
EXPECT_EQ("#01 pc 123456dc MapFake (ProcFake+645)",
#endif
backtrace->FormatFrameData(&frame));
+
+ // Check a non-zero map offset.
+ frame.map.offset = 0x1000;
+#if defined(__LP64__)
+ EXPECT_EQ("#01 pc 00000000123456dc MapFake (offset 0x1000) (ProcFake+645)",
+#else
+ EXPECT_EQ("#01 pc 123456dc MapFake (offset 0x1000) (ProcFake+645)",
+#endif
+ backtrace->FormatFrameData(&frame));
}
struct map_test_t {
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/libpixelflinger/Android.mk b/libpixelflinger/Android.mk
index 697db25..11e7988 100644
--- a/libpixelflinger/Android.mk
+++ b/libpixelflinger/Android.mk
@@ -70,10 +70,6 @@
# libhardware, but this at least gets us built.
LOCAL_SHARED_LIBRARIES += libhardware_legacy
LOCAL_CFLAGS += -DWITH_LIB_HARDWARE
-# t32cb16blend.S does not compile with Clang.
-LOCAL_CLANG_ASFLAGS_arm += -no-integrated-as
-# arch-arm64/col32cb16blend.S does not compile with Clang.
-LOCAL_CLANG_ASFLAGS_arm64 += -no-integrated-as
include $(BUILD_SHARED_LIBRARY)
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libpixelflinger/arch-arm64/col32cb16blend.S b/libpixelflinger/arch-arm64/col32cb16blend.S
index 18a01fd..8d9c7c4 100644
--- a/libpixelflinger/arch-arm64/col32cb16blend.S
+++ b/libpixelflinger/arch-arm64/col32cb16blend.S
@@ -26,7 +26,7 @@
* SUCH DAMAGE.
*/
.text
- .align
+ .align 0
.global scanline_col32cb16blend_arm64
diff --git a/libpixelflinger/arch-arm64/t32cb16blend.S b/libpixelflinger/arch-arm64/t32cb16blend.S
index 7da8cf5..230f47b 100644
--- a/libpixelflinger/arch-arm64/t32cb16blend.S
+++ b/libpixelflinger/arch-arm64/t32cb16blend.S
@@ -26,7 +26,7 @@
* SUCH DAMAGE.
*/
.text
- .align
+ .align 0
.global scanline_t32cb16blend_arm64
diff --git a/libpixelflinger/t32cb16blend.S b/libpixelflinger/t32cb16blend.S
index caf9eb7..1d40ad4 100644
--- a/libpixelflinger/t32cb16blend.S
+++ b/libpixelflinger/t32cb16blend.S
@@ -17,6 +17,7 @@
.text
+ .syntax unified
.align
.global scanline_t32cb16blend_arm
@@ -146,7 +147,7 @@
tst r0, #0x3
beq aligned
subs r2, r2, #1
- ldmlofd sp!, {r4-r7, lr} // return
+ ldmfdlo sp!, {r4-r7, lr} // return
bxlo lr
last:
@@ -197,6 +198,6 @@
mov r4, r5
9: adds r2, r2, #1
- ldmlofd sp!, {r4-r7, lr} // return
+ ldmfdlo sp!, {r4-r7, lr} // return
bxlo lr
b last
diff --git a/libpixelflinger/tests/arch-arm64/assembler/Android.mk b/libpixelflinger/tests/arch-arm64/assembler/Android.mk
index 448d298..bd0f24b 100644
--- a/libpixelflinger/tests/arch-arm64/assembler/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/assembler/Android.mk
@@ -5,9 +5,6 @@
arm64_assembler_test.cpp\
asm_test_jacket.S
-# asm_test_jacket.S does not compile with Clang.
-LOCAL_CLANG_ASFLAGS_arm64 += -no-integrated-as
-
LOCAL_SHARED_LIBRARIES := \
libcutils \
libpixelflinger
diff --git a/libpixelflinger/tests/arch-arm64/assembler/asm_test_jacket.S b/libpixelflinger/tests/arch-arm64/assembler/asm_test_jacket.S
index a1392c2..f44859f 100644
--- a/libpixelflinger/tests/arch-arm64/assembler/asm_test_jacket.S
+++ b/libpixelflinger/tests/arch-arm64/assembler/asm_test_jacket.S
@@ -27,7 +27,7 @@
*/
.text
- .align
+ .align 0
.global asm_test_jacket
diff --git a/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk b/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk
index 5d69203..3368eb0 100644
--- a/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.mk
@@ -5,8 +5,6 @@
col32cb16blend_test.c \
../../../arch-arm64/col32cb16blend.S
-LOCAL_CLANG_ASFLAGS_arm64 += -no-integrated-as
-
LOCAL_SHARED_LIBRARIES :=
LOCAL_C_INCLUDES :=
diff --git a/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk b/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk
index 2c1379b..8e5ec5e 100644
--- a/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk
+++ b/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.mk
@@ -5,8 +5,6 @@
t32cb16blend_test.c \
../../../arch-arm64/t32cb16blend.S
-LOCAL_CLANG_ASFLAGS_arm64 += -no-integrated-as
-
LOCAL_SHARED_LIBRARIES :=
LOCAL_C_INCLUDES :=
diff --git a/libsparse/backed_block.c b/libsparse/backed_block.c
index 3e72b57..794cd6b 100644
--- a/libsparse/backed_block.c
+++ b/libsparse/backed_block.c
@@ -221,7 +221,8 @@
}
break;
case BACKED_BLOCK_FILE:
- if (a->file.filename != b->file.filename ||
+ /* Already make sure b->type is BACKED_BLOCK_FILE */
+ if (strcmp(a->file.filename, b->file.filename) ||
a->file.offset + a->len != b->file.offset) {
return -EINVAL;
}
@@ -279,7 +280,10 @@
}
merge_bb(bbl, new_bb, new_bb->next);
- merge_bb(bbl, bb, new_bb);
+ if (!merge_bb(bbl, bb, new_bb)) {
+ /* new_bb destroyed, point to retained as last_used */
+ bbl->last_used = bb;
+ }
return 0;
}
diff --git a/libutils/Android.mk b/libutils/Android.mk
index 8f829f3..8226db2 100644
--- a/libutils/Android.mk
+++ b/libutils/Android.mk
@@ -92,6 +92,8 @@
libdl
LOCAL_MODULE := libutils
+LOCAL_CLANG := true
+LOCAL_SANITIZE := integer
include $(BUILD_STATIC_LIBRARY)
# For the device, shared
@@ -106,6 +108,8 @@
liblog
LOCAL_CFLAGS := -Werror
+LOCAL_CLANG := true
+LOCAL_SANITIZE := integer
include $(BUILD_SHARED_LIBRARY)
diff --git a/libutils/JenkinsHash.cpp b/libutils/JenkinsHash.cpp
index 52c9bb7..ff5d252 100644
--- a/libutils/JenkinsHash.cpp
+++ b/libutils/JenkinsHash.cpp
@@ -19,10 +19,14 @@
* should still be quite good.
**/
+#include <stdlib.h>
#include <utils/JenkinsHash.h>
namespace android {
+#ifdef __clang__
+__attribute__((no_sanitize("integer")))
+#endif
hash_t JenkinsHashWhiten(uint32_t hash) {
hash += (hash << 3);
hash ^= (hash >> 11);
@@ -31,6 +35,9 @@
}
uint32_t JenkinsHashMixBytes(uint32_t hash, const uint8_t* bytes, size_t size) {
+ if (size > UINT32_MAX) {
+ abort();
+ }
hash = JenkinsHashMix(hash, (uint32_t)size);
size_t i;
for (i = 0; i < (size & -4); i += 4) {
@@ -47,6 +54,9 @@
}
uint32_t JenkinsHashMixShorts(uint32_t hash, const uint16_t* shorts, size_t size) {
+ if (size > UINT32_MAX) {
+ abort();
+ }
hash = JenkinsHashMix(hash, (uint32_t)size);
size_t i;
for (i = 0; i < (size & -2); i += 2) {
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index 28be60f..69313ea 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -79,6 +79,9 @@
static char* allocFromUTF8(const char* in, size_t len)
{
if (len > 0) {
+ if (len == SIZE_MAX) {
+ return NULL;
+ }
SharedBuffer* buf = SharedBuffer::alloc(len+1);
ALOG_ASSERT(buf, "Unable to allocate shared buffer");
if (buf) {
diff --git a/libutils/VectorImpl.cpp b/libutils/VectorImpl.cpp
index 30ca663..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);
@@ -551,6 +554,10 @@
ssize_t SortedVectorImpl::_indexOrderOf(const void* item, size_t* order) const
{
+ if (order) *order = 0;
+ if (isEmpty()) {
+ return NAME_NOT_FOUND;
+ }
// binary search
ssize_t err = NAME_NOT_FOUND;
ssize_t l = 0;
diff --git a/libutils/tests/BitSet_test.cpp b/libutils/tests/BitSet_test.cpp
index 38b668a..59d913e 100644
--- a/libutils/tests/BitSet_test.cpp
+++ b/libutils/tests/BitSet_test.cpp
@@ -138,11 +138,11 @@
TEST_F(BitSet32Test, GetIndexOfBit) {
b1.markBit(1);
b1.markBit(4);
- EXPECT_EQ(b1.getIndexOfBit(1), 0);
- EXPECT_EQ(b1.getIndexOfBit(4), 1);
+ EXPECT_EQ(0U, b1.getIndexOfBit(1));
+ EXPECT_EQ(1U, b1.getIndexOfBit(4));
b1.markFirstUnmarkedBit();
- EXPECT_EQ(b1.getIndexOfBit(1), 1);
- EXPECT_EQ(b1.getIndexOfBit(4), 2);
+ EXPECT_EQ(1U, b1.getIndexOfBit(1));
+ EXPECT_EQ(2U, b1.getIndexOfBit(4));
}
class BitSet64Test : public testing::Test {
@@ -260,11 +260,11 @@
TEST_F(BitSet64Test, GetIndexOfBit) {
b1.markBit(10);
b1.markBit(40);
- EXPECT_EQ(b1.getIndexOfBit(10), 0);
- EXPECT_EQ(b1.getIndexOfBit(40), 1);
+ EXPECT_EQ(0U, b1.getIndexOfBit(10));
+ EXPECT_EQ(1U, b1.getIndexOfBit(40));
b1.markFirstUnmarkedBit();
- EXPECT_EQ(b1.getIndexOfBit(10), 1);
- EXPECT_EQ(b1.getIndexOfBit(40), 2);
+ EXPECT_EQ(1U, b1.getIndexOfBit(10));
+ EXPECT_EQ(2U, b1.getIndexOfBit(40));
}
} // namespace android
diff --git a/libutils/tests/LruCache_test.cpp b/libutils/tests/LruCache_test.cpp
index 6534211..6155def 100644
--- a/libutils/tests/LruCache_test.cpp
+++ b/libutils/tests/LruCache_test.cpp
@@ -220,7 +220,7 @@
cache.put(ComplexKey(0), ComplexValue(0));
cache.put(ComplexKey(1), ComplexValue(1));
- EXPECT_EQ(2, cache.size());
+ EXPECT_EQ(2U, cache.size());
assertInstanceCount(2, 3); // the null value counts as an instance
}
@@ -229,7 +229,7 @@
cache.put(ComplexKey(0), ComplexValue(0));
cache.put(ComplexKey(1), ComplexValue(1));
- EXPECT_EQ(2, cache.size());
+ EXPECT_EQ(2U, cache.size());
assertInstanceCount(2, 3);
cache.clear();
assertInstanceCount(0, 1);
@@ -241,7 +241,7 @@
cache.put(ComplexKey(0), ComplexValue(0));
cache.put(ComplexKey(1), ComplexValue(1));
- EXPECT_EQ(2, cache.size());
+ EXPECT_EQ(2U, cache.size());
assertInstanceCount(2, 3);
cache.removeOldest();
cache.clear();
@@ -255,13 +255,13 @@
cache.put(ComplexKey(0), ComplexValue(0));
cache.put(ComplexKey(1), ComplexValue(1));
- EXPECT_EQ(2, cache.size());
+ EXPECT_EQ(2U, cache.size());
assertInstanceCount(2, 3);
cache.clear();
assertInstanceCount(0, 1);
cache.put(ComplexKey(0), ComplexValue(0));
cache.put(ComplexKey(1), ComplexValue(1));
- EXPECT_EQ(2, cache.size());
+ EXPECT_EQ(2U, cache.size());
assertInstanceCount(2, 3);
}
@@ -273,7 +273,7 @@
cache.put(1, "one");
cache.put(2, "two");
cache.put(3, "three");
- EXPECT_EQ(3, cache.size());
+ EXPECT_EQ(3U, cache.size());
cache.removeOldest();
EXPECT_EQ(1, callback.callbackCount);
EXPECT_EQ(1, callback.lastKey);
@@ -288,7 +288,7 @@
cache.put(1, "one");
cache.put(2, "two");
cache.put(3, "three");
- EXPECT_EQ(3, cache.size());
+ EXPECT_EQ(3U, cache.size());
cache.clear();
EXPECT_EQ(3, callback.callbackCount);
}
diff --git a/libutils/tests/Vector_test.cpp b/libutils/tests/Vector_test.cpp
index d29c054..0ba7161 100644
--- a/libutils/tests/Vector_test.cpp
+++ b/libutils/tests/Vector_test.cpp
@@ -45,26 +45,26 @@
vector.add(2);
vector.add(3);
- EXPECT_EQ(vector.size(), 3);
+ EXPECT_EQ(3U, vector.size());
// copy the vector
other = vector;
- EXPECT_EQ(other.size(), 3);
+ EXPECT_EQ(3U, other.size());
// add an element to the first vector
vector.add(4);
// make sure the sizes are correct
- EXPECT_EQ(vector.size(), 4);
- EXPECT_EQ(other.size(), 3);
+ EXPECT_EQ(4U, vector.size());
+ EXPECT_EQ(3U, other.size());
// add an element to the copy
other.add(5);
// make sure the sizes are correct
- EXPECT_EQ(vector.size(), 4);
- EXPECT_EQ(other.size(), 4);
+ EXPECT_EQ(4U, vector.size());
+ EXPECT_EQ(4U, other.size());
// make sure the content of both vectors are correct
EXPECT_EQ(vector[3], 4);
diff --git a/lmkd/Android.mk b/lmkd/Android.mk
index 39081d6..8c88661 100644
--- a/lmkd/Android.mk
+++ b/lmkd/Android.mk
@@ -7,4 +7,6 @@
LOCAL_MODULE := lmkd
+LOCAL_INIT_RC := lmkd.rc
+
include $(BUILD_EXECUTABLE)
diff --git a/lmkd/lmkd.rc b/lmkd/lmkd.rc
new file mode 100644
index 0000000..83c5ff0
--- /dev/null
+++ b/lmkd/lmkd.rc
@@ -0,0 +1,4 @@
+service lmkd /system/bin/lmkd
+ class core
+ critical
+ socket lmkd seqpacket 0660 system system
diff --git a/logcat/Android.mk b/logcat/Android.mk
index 7115f9b..844ab8b 100644
--- a/logcat/Android.mk
+++ b/logcat/Android.mk
@@ -11,6 +11,8 @@
LOCAL_CFLAGS := -Werror
+LOCAL_INIT_RC := logcatd.rc
+
include $(BUILD_EXECUTABLE)
include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/logcat/logcatd.rc b/logcat/logcatd.rc
new file mode 100644
index 0000000..0bc581e
--- /dev/null
+++ b/logcat/logcatd.rc
@@ -0,0 +1,13 @@
+on property:persist.logd.logpersistd=logcatd
+ # all exec/services are called with umask(077), so no gain beyond 0700
+ mkdir /data/misc/logd 0700 logd log
+ # logd for write to /data/misc/logd, log group for read from pstore (-L)
+ exec - logd log -- /system/bin/logcat -L -b all -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 64 -n 256
+ start logcatd
+
+service logcatd /system/bin/logcat -b all -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 64 -n 256
+ class late_start
+ disabled
+ # logd for write to /data/misc/logd, log group for read from log daemon
+ user logd
+ group log
diff --git a/logd/Android.mk b/logd/Android.mk
index 615d030..01c51c7 100644
--- a/logd/Android.mk
+++ b/logd/Android.mk
@@ -4,6 +4,8 @@
LOCAL_MODULE:= logd
+LOCAL_INIT_RC := logd.rc
+
LOCAL_SRC_FILES := \
main.cpp \
LogCommand.cpp \
@@ -25,7 +27,7 @@
libsysutils \
liblog \
libcutils \
- libutils
+ libbase
# This is what we want to do:
# event_logtags = $(shell \
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index 489bea6..031c740 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -25,6 +25,9 @@
#include <sys/socket.h>
#include <sys/types.h>
+#include <string>
+
+#include <base/stringprintf.h>
#include <cutils/sockets.h>
#include <private/android_filesystem_config.h>
#include <sysutils/SocketClient.h>
@@ -189,22 +192,13 @@
mBuf(*buf) {
}
-static void package_string(char **strp) {
- const char *a = *strp;
- if (!a) {
- a = "";
- }
-
+static std::string package_string(const std::string &str) {
// Calculate total buffer size prefix, count is the string length w/o nul
char fmt[32];
- for(size_t l = strlen(a), y = 0, x = 6; y != x; y = x, x = strlen(fmt) - 2) {
+ for(size_t l = str.length(), y = 0, x = 6; y != x; y = x, x = strlen(fmt) - 2) {
snprintf(fmt, sizeof(fmt), "%zu\n%%s\n\f", l + x);
}
-
- char *b = *strp;
- *strp = NULL;
- asprintf(strp, fmt, a);
- free(b);
+ return android::base::StringPrintf(fmt, str.c_str());
}
int CommandListener::GetStatisticsCmd::runCommand(SocketClient *cli,
@@ -228,16 +222,7 @@
}
}
- char *buf = NULL;
-
- mBuf.formatStatistics(&buf, uid, logMask);
- if (!buf) {
- cli->sendMsg("Failed");
- } else {
- package_string(&buf);
- cli->sendMsg(buf);
- free(buf);
- }
+ cli->sendMsg(package_string(mBuf.formatStatistics(uid, logMask)).c_str());
return 0;
}
@@ -249,15 +234,7 @@
int CommandListener::GetPruneListCmd::runCommand(SocketClient *cli,
int /*argc*/, char ** /*argv*/) {
setname();
- char *buf = NULL;
- mBuf.formatPrune(&buf);
- if (!buf) {
- cli->sendMsg("Failed");
- } else {
- package_string(&buf);
- cli->sendMsg(buf);
- free(buf);
- }
+ cli->sendMsg(package_string(mBuf.formatPrune()).c_str());
return 0;
}
@@ -274,20 +251,15 @@
return 0;
}
- char *cp = NULL;
+ std::string str;
for (int i = 1; i < argc; ++i) {
- char *p = cp;
- if (p) {
- cp = NULL;
- asprintf(&cp, "%s %s", p, argv[i]);
- free(p);
- } else {
- asprintf(&cp, "%s", argv[i]);
+ if (str.length()) {
+ str += " ";
}
+ str += argv[i];
}
- int ret = mBuf.initPrune(cp);
- free(cp);
+ int ret = mBuf.initPrune(str.c_str());
if (ret) {
cli->sendMsg("Invalid");
diff --git a/logd/FlushCommand.cpp b/logd/FlushCommand.cpp
index d584925..823a842 100644
--- a/logd/FlushCommand.cpp
+++ b/logd/FlushCommand.cpp
@@ -72,7 +72,7 @@
return;
}
entry = new LogTimeEntry(mReader, client, mNonBlock, mTail, mLogMask, mPid, mStart);
- times.push_back(entry);
+ times.push_front(entry);
}
client->incRef();
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index b9e8973..c609870 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -217,34 +217,35 @@
return len;
}
-// If we're using more than 256K of memory for log entries, prune
-// at least 10% of the log entries. For sizes above 1M, prune at
-// least 1% of the log entries.
+// Prune at most 10% of the log entries or 256, whichever is less.
//
// mLogElementsLock must be held when this function is called.
void LogBuffer::maybePrune(log_id_t id) {
size_t sizes = stats.sizes(id);
unsigned long maxSize = log_buffer_size(id);
if (sizes > maxSize) {
- size_t sizeOver, minElements, elements = stats.elements(id);
- if (maxSize > (4 * LOG_BUFFER_SIZE)) {
- sizeOver = sizes - ((maxSize * 99) / 100);
- minElements = elements / 100;
- } else {
- sizeOver = sizes - ((maxSize * 9) / 10);
- minElements = elements / 10;
- }
+ size_t sizeOver = sizes - ((maxSize * 9) / 10);
+ size_t elements = stats.elements(id);
+ size_t minElements = elements / 10;
unsigned long pruneRows = elements * sizeOver / sizes;
if (pruneRows <= minElements) {
pruneRows = minElements;
}
+ if (pruneRows > 256) {
+ pruneRows = 256;
+ }
prune(id, pruneRows);
}
}
LogBufferElementCollection::iterator LogBuffer::erase(LogBufferElementCollection::iterator it) {
LogBufferElement *e = *it;
+ log_id_t id = e->getLogId();
+ LogBufferIteratorMap::iterator f = mLastWorstUid[id].find(e->getUid());
+ if ((f != mLastWorstUid[id].end()) && (it == f->second)) {
+ mLastWorstUid[id].erase(f);
+ }
it = mLogElements.erase(it);
stats.subtract(e);
delete e;
@@ -403,8 +404,17 @@
bool kick = false;
bool leading = true;
+ it = mLogElements.begin();
+ if (worst != (uid_t) -1) {
+ LogBufferIteratorMap::iterator f = mLastWorstUid[id].find(worst);
+ if ((f != mLastWorstUid[id].end())
+ && (f->second != mLogElements.end())) {
+ leading = false;
+ it = f->second;
+ }
+ }
LogBufferElementLast last;
- for(it = mLogElements.begin(); it != mLogElements.end();) {
+ while (it != mLogElements.end()) {
LogBufferElement *e = *it;
if (oldest && (oldest->mStart <= e->getSequence())) {
@@ -454,8 +464,14 @@
continue;
}
+ // unmerged drop message
if (dropped) {
last.add(e);
+ if ((e->getUid() == worst)
+ || (mLastWorstUid[id].find(e->getUid())
+ == mLastWorstUid[id].end())) {
+ mLastWorstUid[id][e->getUid()] = it;
+ }
++it;
continue;
}
@@ -500,6 +516,7 @@
delete e;
} else {
last.add(e);
+ mLastWorstUid[id][e->getUid()] = it;
++it;
}
}
@@ -677,10 +694,12 @@
return max;
}
-void LogBuffer::formatStatistics(char **strp, uid_t uid, unsigned int logMask) {
+std::string LogBuffer::formatStatistics(uid_t uid, unsigned int logMask) {
pthread_mutex_lock(&mLogElementsLock);
- stats.format(strp, uid, logMask);
+ std::string ret = stats.format(uid, logMask);
pthread_mutex_unlock(&mLogElementsLock);
+
+ return ret;
}
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index a13fded..fcb05f5 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -19,9 +19,11 @@
#include <sys/types.h>
+#include <list>
+#include <string>
+
#include <log/log.h>
#include <sysutils/SocketClient.h>
-#include <utils/List.h>
#include <private/android_filesystem_config.h>
@@ -30,7 +32,7 @@
#include "LogStatistics.h"
#include "LogWhiteBlackList.h"
-typedef android::List<LogBufferElement *> LogBufferElementCollection;
+typedef std::list<LogBufferElement *> LogBufferElementCollection;
class LogBuffer {
LogBufferElementCollection mLogElements;
@@ -39,6 +41,11 @@
LogStatistics stats;
PruneList mPrune;
+ // watermark of any worst/chatty uid processing
+ typedef std::unordered_map<uid_t,
+ LogBufferElementCollection::iterator>
+ LogBufferIteratorMap;
+ LogBufferIteratorMap mLastWorstUid[LOG_ID_MAX];
unsigned long mMaxSize[LOG_ID_MAX];
@@ -61,15 +68,14 @@
int setSize(log_id_t id, unsigned long size);
unsigned long getSizeUsed(log_id_t id);
// *strp uses malloc, use free to release.
- void formatStatistics(char **strp, uid_t uid, unsigned int logMask);
+ std::string formatStatistics(uid_t uid, unsigned int logMask);
void enableStatistics() {
stats.enableStatistics();
}
- int initPrune(char *cp) { return mPrune.init(cp); }
- // *strp uses malloc, use free to release.
- void formatPrune(char **strp) { mPrune.format(strp); }
+ int initPrune(const char *cp) { return mPrune.init(cp); }
+ std::string formatPrune() { return mPrune.format(); }
// helper must be protected directly or implicitly by lock()/unlock()
char *pidToName(pid_t pid) { return stats.pidToName(pid); }
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/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 48c2fe6..61fd559 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -20,9 +20,9 @@
#include <string.h>
#include <unistd.h>
+#include <base/stringprintf.h>
#include <log/logger.h>
#include <private/android_filesystem_config.h>
-#include <utils/String8.h>
#include "LogStatistics.h"
@@ -183,8 +183,10 @@
return name;
}
-static void format_line(android::String8 &output,
- android::String8 &name, android::String8 &size, android::String8 &pruned) {
+static std::string format_line(
+ const std::string &name,
+ const std::string &size,
+ const std::string &pruned) {
static const size_t pruned_len = 6;
static const size_t total_len = 70 + pruned_len;
@@ -193,26 +195,21 @@
total_len - name.length() - drop_len - 1);
if (pruned.length()) {
- output.appendFormat("%s%*s%*s\n", name.string(),
- (int)size_len, size.string(),
- (int)drop_len, pruned.string());
+ return android::base::StringPrintf("%s%*s%*s\n", name.c_str(),
+ (int)size_len, size.c_str(),
+ (int)drop_len, pruned.c_str());
} else {
- output.appendFormat("%s%*s\n", name.string(),
- (int)size_len, size.string());
+ return android::base::StringPrintf("%s%*s\n", name.c_str(),
+ (int)size_len, size.c_str());
}
}
-void LogStatistics::format(char **buf, uid_t uid, unsigned int logMask) {
+std::string LogStatistics::format(uid_t uid, unsigned int logMask) {
static const unsigned short spaces_total = 19;
- if (*buf) {
- free(*buf);
- *buf = NULL;
- }
-
// Report on total logging, current and for all time
- android::String8 output("size/num");
+ std::string output = "size/num";
size_t oldLength;
short spaces = 1;
@@ -224,12 +221,13 @@
if (spaces < 0) {
spaces = 0;
}
- output.appendFormat("%*s%s", spaces, "", android_log_id_to_name(id));
+ output += android::base::StringPrintf("%*s%s", spaces, "",
+ android_log_id_to_name(id));
spaces += spaces_total + oldLength - output.length();
}
spaces = 4;
- output.appendFormat("\nTotal");
+ output += android::base::StringPrintf("\nTotal");
log_id_for_each(id) {
if (!(logMask & (1 << id))) {
@@ -239,13 +237,14 @@
if (spaces < 0) {
spaces = 0;
}
- output.appendFormat("%*s%zu/%zu", spaces, "",
- sizesTotal(id), elementsTotal(id));
+ output += android::base::StringPrintf("%*s%zu/%zu", spaces, "",
+ sizesTotal(id),
+ elementsTotal(id));
spaces += spaces_total + oldLength - output.length();
}
spaces = 6;
- output.appendFormat("\nNow");
+ output += android::base::StringPrintf("\nNow");
log_id_for_each(id) {
if (!(logMask & (1 << id))) {
@@ -258,7 +257,8 @@
if (spaces < 0) {
spaces = 0;
}
- output.appendFormat("%*s%zu/%zu", spaces, "", sizes(id), els);
+ output += android::base::StringPrintf("%*s%zu/%zu", spaces, "",
+ sizes(id), els);
spaces -= output.length() - oldLength;
}
spaces += spaces_total;
@@ -284,53 +284,54 @@
}
if (!headerPrinted) {
- output.appendFormat("\n\n");
- android::String8 name("");
+ output += android::base::StringPrintf("\n\n");
+ std::string name;
if (uid == AID_ROOT) {
- name.appendFormat(
+ name = android::base::StringPrintf(
"Chattiest UIDs in %s log buffer:",
android_log_id_to_name(id));
} else {
- name.appendFormat(
+ name = android::base::StringPrintf(
"Logging for your UID in %s log buffer:",
android_log_id_to_name(id));
}
- android::String8 size("Size");
- android::String8 pruned("Pruned");
+ std::string size = "Size";
+ std::string pruned = "Pruned";
if (!worstUidEnabledForLogid(id)) {
- pruned.setTo("");
+ pruned = "";
}
- format_line(output, name, size, pruned);
+ output += format_line(name, size, pruned);
- name.setTo("UID PACKAGE");
- size.setTo("BYTES");
- pruned.setTo("LINES");
+ name = "UID PACKAGE";
+ size = "BYTES";
+ pruned = "LINES";
if (!worstUidEnabledForLogid(id)) {
- pruned.setTo("");
+ pruned = "";
}
- format_line(output, name, size, pruned);
+ output += format_line(name, size, pruned);
headerPrinted = true;
}
- android::String8 name("");
- name.appendFormat("%u", u);
+ std::string name = android::base::StringPrintf("%u", u);
char *n = uidToName(u);
if (n) {
- name.appendFormat("%*s%s", (int)std::max(6 - name.length(), (size_t)1), "", n);
+ name += android::base::StringPrintf(
+ "%*s%s", (int)std::max(6 - name.length(), (size_t)1),
+ "", n);
free(n);
}
- android::String8 size("");
- size.appendFormat("%zu", entry->getSizes());
+ std::string size = android::base::StringPrintf("%zu",
+ entry->getSizes());
- android::String8 pruned("");
+ std::string pruned = "";
size_t dropped = entry->getDropped();
if (dropped) {
- pruned.appendFormat("%zu", dropped);
+ pruned = android::base::StringPrintf("%zu", dropped);
}
- format_line(output, name, size, pruned);
+ output += format_line(name, size, pruned);
}
}
@@ -347,48 +348,52 @@
}
if (!headerPrinted) {
- output.appendFormat("\n\n");
- android::String8 name("");
+ output += android::base::StringPrintf("\n\n");
+ std::string name;
if (uid == AID_ROOT) {
- name.appendFormat("Chattiest PIDs:");
+ name = android::base::StringPrintf("Chattiest PIDs:");
} else {
- name.appendFormat("Logging for this PID:");
+ name = android::base::StringPrintf("Logging for this PID:");
}
- android::String8 size("Size");
- android::String8 pruned("Pruned");
- format_line(output, name, size, pruned);
+ std::string size = "Size";
+ std::string pruned = "Pruned";
+ output += format_line(name, size, pruned);
- name.setTo(" PID/UID COMMAND LINE");
- size.setTo("BYTES");
- pruned.setTo("LINES");
- format_line(output, name, size, pruned);
+ name = " PID/UID COMMAND LINE";
+ size = "BYTES";
+ pruned = "LINES";
+ output += format_line(name, size, pruned);
headerPrinted = true;
}
- android::String8 name("");
- name.appendFormat("%5u/%u", entry->getKey(), u);
+ std::string name = android::base::StringPrintf("%5u/%u",
+ entry->getKey(), u);
const char *n = entry->getName();
if (n) {
- name.appendFormat("%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", n);
+ name += android::base::StringPrintf(
+ "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
+ "", n);
} else {
char *un = uidToName(u);
if (un) {
- name.appendFormat("%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", un);
+ name += android::base::StringPrintf(
+ "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
+ "", un);
free(un);
}
}
- android::String8 size("");
- size.appendFormat("%zu", entry->getSizes());
+ std::string size = android::base::StringPrintf("%zu",
+ entry->getSizes());
- android::String8 pruned("");
+ std::string pruned = "";
size_t dropped = entry->getDropped();
if (dropped) {
- pruned.appendFormat("%zu", dropped);
+ pruned = android::base::StringPrintf("%zu", dropped);
}
- format_line(output, name, size, pruned);
+ output += format_line(name, size, pruned);
}
}
@@ -406,46 +411,50 @@
}
if (!headerPrinted) { // Only print header if we have table to print
- output.appendFormat("\n\n");
- android::String8 name("Chattiest TIDs:");
- android::String8 size("Size");
- android::String8 pruned("Pruned");
- format_line(output, name, size, pruned);
+ output += android::base::StringPrintf("\n\n");
+ std::string name = "Chattiest TIDs:";
+ std::string size = "Size";
+ std::string pruned = "Pruned";
+ output += format_line(name, size, pruned);
- name.setTo(" TID/UID COMM");
- size.setTo("BYTES");
- pruned.setTo("LINES");
- format_line(output, name, size, pruned);
+ name = " TID/UID COMM";
+ size = "BYTES";
+ pruned = "LINES";
+ output += format_line(name, size, pruned);
headerPrinted = true;
}
- android::String8 name("");
- name.appendFormat("%5u/%u", entry->getKey(), u);
+ std::string name = android::base::StringPrintf("%5u/%u",
+ entry->getKey(), u);
const char *n = entry->getName();
if (n) {
- name.appendFormat("%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", n);
+ name += android::base::StringPrintf(
+ "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
+ "", n);
} else {
// if we do not have a PID name, lets punt to try UID name?
char *un = uidToName(u);
if (un) {
- name.appendFormat("%*s%s", (int)std::max(12 - name.length(), (size_t)1), "", un);
+ name += android::base::StringPrintf(
+ "%*s%s", (int)std::max(12 - name.length(), (size_t)1),
+ "", un);
free(un);
}
// We tried, better to not have a name at all, we still
// have TID/UID by number to report in any case.
}
- android::String8 size("");
- size.appendFormat("%zu", entry->getSizes());
+ std::string size = android::base::StringPrintf("%zu",
+ entry->getSizes());
- android::String8 pruned("");
+ std::string pruned = "";
size_t dropped = entry->getDropped();
if (dropped) {
- pruned.appendFormat("%zu", dropped);
+ pruned = android::base::StringPrintf("%zu", dropped);
}
- format_line(output, name, size, pruned);
+ output += format_line(name, size, pruned);
}
}
@@ -461,40 +470,44 @@
continue;
}
- android::String8 pruned("");
+ std::string pruned = "";
if (!headerPrinted) {
- output.appendFormat("\n\n");
- android::String8 name("Chattiest events log buffer TAGs:");
- android::String8 size("Size");
- format_line(output, name, size, pruned);
+ output += android::base::StringPrintf("\n\n");
+ std::string name = "Chattiest events log buffer TAGs:";
+ std::string size = "Size";
+ output += format_line(name, size, pruned);
- name.setTo(" TAG/UID TAGNAME");
- size.setTo("BYTES");
- format_line(output, name, size, pruned);
+ name = " TAG/UID TAGNAME";
+ size = "BYTES";
+ output += format_line(name, size, pruned);
headerPrinted = true;
}
- android::String8 name("");
+ std::string name;
if (u == (uid_t)-1) {
- name.appendFormat("%7u", entry->getKey());
+ name = android::base::StringPrintf("%7u",
+ entry->getKey());
} else {
- name.appendFormat("%7u/%u", entry->getKey(), u);
+ name = android::base::StringPrintf("%7u/%u",
+ entry->getKey(), u);
}
const char *n = entry->getName();
if (n) {
- name.appendFormat("%*s%s", (int)std::max(14 - name.length(), (size_t)1), "", n);
+ name += android::base::StringPrintf(
+ "%*s%s", (int)std::max(14 - name.length(), (size_t)1),
+ "", n);
}
- android::String8 size("");
- size.appendFormat("%zu", entry->getSizes());
+ std::string size = android::base::StringPrintf("%zu",
+ entry->getSizes());
- format_line(output, name, size, pruned);
+ output += format_line(name, size, pruned);
}
}
- *buf = strdup(output.string());
+ return output;
}
namespace android {
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index 760d6b2..61000d2 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -331,8 +331,7 @@
size_t sizesTotal(log_id_t id) const { return mSizesTotal[id]; }
size_t elementsTotal(log_id_t id) const { return mElementsTotal[id]; }
- // *strp = malloc, balance with free
- void format(char **strp, uid_t uid, unsigned int logMask);
+ std::string format(uid_t uid, unsigned int logMask);
// helper (must be locked directly or implicitly by mLogElementsLock)
char *pidToName(pid_t pid);
diff --git a/logd/LogTimes.h b/logd/LogTimes.h
index 783bce6..39bcdd4 100644
--- a/logd/LogTimes.h
+++ b/logd/LogTimes.h
@@ -20,8 +20,10 @@
#include <pthread.h>
#include <time.h>
#include <sys/types.h>
+
+#include <list>
+
#include <sysutils/SocketClient.h>
-#include <utils/List.h>
#include <log/log.h>
class LogReader;
@@ -107,6 +109,6 @@
static int FilterSecondPass(const LogBufferElement *element, void *me);
};
-typedef android::List<LogTimeEntry *> LastLogTimes;
+typedef std::list<LogTimeEntry *> LastLogTimes;
-#endif
+#endif // _LOGD_LOG_TIMES_H__
diff --git a/logd/LogWhiteBlackList.cpp b/logd/LogWhiteBlackList.cpp
index 277b3ca..ad005ec 100644
--- a/logd/LogWhiteBlackList.cpp
+++ b/logd/LogWhiteBlackList.cpp
@@ -16,7 +16,7 @@
#include <ctype.h>
-#include <utils/String8.h>
+#include <base/stringprintf.h>
#include "LogWhiteBlackList.h"
@@ -35,46 +35,40 @@
return uid - mUid;
}
-void Prune::format(char **strp) {
+std::string Prune::format() {
if (mUid != uid_all) {
if (mPid != pid_all) {
- asprintf(strp, "%u/%u", mUid, mPid);
- } else {
- asprintf(strp, "%u", mUid);
+ return android::base::StringPrintf("%u/%u", mUid, mPid);
}
- } else if (mPid != pid_all) {
- asprintf(strp, "/%u", mPid);
- } else { // NB: mPid == pid_all can not happen if mUid == uid_all
- asprintf(strp, "/");
+ return android::base::StringPrintf("%u", mUid);
}
+ if (mPid != pid_all) {
+ return android::base::StringPrintf("/%u", mPid);
+ }
+ // NB: mPid == pid_all can not happen if mUid == uid_all
+ return std::string("/");
}
PruneList::PruneList() : mWorstUidEnabled(true) {
- mNaughty.clear();
- mNice.clear();
}
PruneList::~PruneList() {
PruneCollection::iterator it;
for (it = mNice.begin(); it != mNice.end();) {
- delete (*it);
it = mNice.erase(it);
}
for (it = mNaughty.begin(); it != mNaughty.end();) {
- delete (*it);
it = mNaughty.erase(it);
}
}
-int PruneList::init(char *str) {
+int PruneList::init(const char *str) {
mWorstUidEnabled = true;
PruneCollection::iterator it;
for (it = mNice.begin(); it != mNice.end();) {
- delete (*it);
it = mNice.erase(it);
}
for (it = mNaughty.begin(); it != mNaughty.end();) {
- delete (*it);
it = mNaughty.erase(it);
}
@@ -142,28 +136,28 @@
// insert sequentially into list
PruneCollection::iterator it = list->begin();
while (it != list->end()) {
- Prune *p = *it;
- int m = uid - p->mUid;
+ Prune &p = *it;
+ int m = uid - p.mUid;
if (m == 0) {
- if (p->mPid == p->pid_all) {
+ if (p.mPid == p.pid_all) {
break;
}
- if ((pid == p->pid_all) && (p->mPid != p->pid_all)) {
+ if ((pid == p.pid_all) && (p.mPid != p.pid_all)) {
it = list->erase(it);
continue;
}
- m = pid - p->mPid;
+ m = pid - p.mPid;
}
if (m <= 0) {
if (m < 0) {
- list->insert(it, new Prune(uid,pid));
+ list->insert(it, Prune(uid,pid));
}
break;
}
++it;
}
if (it == list->end()) {
- list->push_back(new Prune(uid,pid));
+ list->push_back(Prune(uid,pid));
}
if (!*str) {
break;
@@ -173,47 +167,32 @@
return 0;
}
-void PruneList::format(char **strp) {
- if (*strp) {
- free(*strp);
- *strp = NULL;
- }
-
+std::string PruneList::format() {
static const char nice_format[] = " %s";
const char *fmt = nice_format + 1;
- android::String8 string;
+ std::string string;
if (mWorstUidEnabled) {
- string.setTo("~!");
+ string = "~!";
fmt = nice_format;
}
PruneCollection::iterator it;
for (it = mNice.begin(); it != mNice.end(); ++it) {
- char *a = NULL;
- (*it)->format(&a);
-
- string.appendFormat(fmt, a);
+ string += android::base::StringPrintf(fmt, (*it).format().c_str());
fmt = nice_format;
-
- free(a);
}
static const char naughty_format[] = " ~%s";
fmt = naughty_format + (*fmt != ' ');
for (it = mNaughty.begin(); it != mNaughty.end(); ++it) {
- char *a = NULL;
- (*it)->format(&a);
-
- string.appendFormat(fmt, a);
+ string += android::base::StringPrintf(fmt, (*it).format().c_str());
fmt = naughty_format;
-
- free(a);
}
- *strp = strdup(string.string());
+ return string;
}
// ToDo: Lists are in sorted order, Prune->cmp() returns + or -
@@ -223,7 +202,7 @@
bool PruneList::naughty(LogBufferElement *element) {
PruneCollection::iterator it;
for (it = mNaughty.begin(); it != mNaughty.end(); ++it) {
- if (!(*it)->cmp(element)) {
+ if (!(*it).cmp(element)) {
return true;
}
}
@@ -233,7 +212,7 @@
bool PruneList::nice(LogBufferElement *element) {
PruneCollection::iterator it;
for (it = mNice.begin(); it != mNice.end(); ++it) {
- if (!(*it)->cmp(element)) {
+ if (!(*it).cmp(element)) {
return true;
}
}
diff --git a/logd/LogWhiteBlackList.h b/logd/LogWhiteBlackList.h
index 5f60801..00e1cad 100644
--- a/logd/LogWhiteBlackList.h
+++ b/logd/LogWhiteBlackList.h
@@ -19,7 +19,8 @@
#include <sys/types.h>
-#include <utils/List.h>
+#include <list>
+#include <string.h>
#include <LogBufferElement.h>
@@ -43,11 +44,10 @@
int cmp(LogBufferElement *e) const { return cmp(e->getUid(), e->getPid()); }
- // *strp is malloc'd, use free to release
- void format(char **strp);
+ std::string format();
};
-typedef android::List<Prune *> PruneCollection;
+typedef std::list<Prune> PruneCollection;
class PruneList {
PruneCollection mNaughty;
@@ -58,7 +58,7 @@
PruneList();
~PruneList();
- int init(char *str);
+ int init(const char *str);
bool naughty(LogBufferElement *element);
bool naughty(void) { return !mNaughty.empty(); }
@@ -66,8 +66,7 @@
bool nice(void) { return !mNice.empty(); }
bool worstUidEnabled() const { return mWorstUidEnabled; }
- // *strp is malloc'd, use free to release
- void format(char **strp);
+ std::string format();
};
#endif // _LOGD_LOG_WHITE_BLACK_LIST_H__
diff --git a/logd/logd.rc b/logd/logd.rc
new file mode 100644
index 0000000..498baec
--- /dev/null
+++ b/logd/logd.rc
@@ -0,0 +1,9 @@
+service logd /system/bin/logd
+ class core
+ socket logd stream 0666 logd logd
+ socket logdr seqpacket 0666 logd logd
+ socket logdw dgram 0222 logd logd
+
+service logd-reinit /system/bin/logd --reinit
+ oneshot
+ disabled
diff --git a/logwrapper/Android.mk b/logwrapper/Android.mk
index 61b4659..ad45b2c 100644
--- a/logwrapper/Android.mk
+++ b/logwrapper/Android.mk
@@ -11,7 +11,7 @@
LOCAL_SHARED_LIBRARIES := libcutils liblog
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_CFLAGS := -Werror
+LOCAL_CFLAGS := -Werror -std=gnu99
include $(BUILD_STATIC_LIBRARY)
# ========================================================
@@ -23,7 +23,7 @@
LOCAL_WHOLE_STATIC_LIBRARIES := liblogwrap
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_CFLAGS := -Werror
+LOCAL_CFLAGS := -Werror -std=gnu99
include $(BUILD_SHARED_LIBRARY)
# ========================================================
@@ -33,5 +33,5 @@
LOCAL_SRC_FILES:= logwrapper.c
LOCAL_MODULE := logwrapper
LOCAL_STATIC_LIBRARIES := liblog liblogwrap libcutils
-LOCAL_CFLAGS := -Werror
+LOCAL_CFLAGS := -Werror -std=gnu99
include $(BUILD_EXECUTABLE)
diff --git a/logwrapper/include/logwrap/logwrap.h b/logwrapper/include/logwrap/logwrap.h
index 4307a30..89a8fdd 100644
--- a/logwrapper/include/logwrap/logwrap.h
+++ b/logwrapper/include/logwrap/logwrap.h
@@ -19,6 +19,7 @@
#define __LIBS_LOGWRAP_H
#include <stdbool.h>
+#include <stdint.h>
__BEGIN_DECLS
@@ -53,6 +54,9 @@
* the specified log until the child has exited.
* file_path: if log_target has the LOG_FILE bit set, then this parameter
* must be set to the pathname of the file to log to.
+ * opts: set to non-NULL if you want to use one or more of the
+ * FORK_EXECVP_OPTION_* features.
+ * opts_len: the length of the opts array. When opts is NULL, pass 0.
*
* Return value:
* 0 when logwrap successfully run the child process and captured its status
@@ -68,8 +72,30 @@
#define LOG_KLOG 2
#define LOG_FILE 4
+/* Write data to child's stdin. */
+#define FORK_EXECVP_OPTION_INPUT 0
+/* Capture data from child's stdout and stderr. */
+#define FORK_EXECVP_OPTION_CAPTURE_OUTPUT 1
+
+struct AndroidForkExecvpOption {
+ int opt_type;
+ union {
+ struct {
+ const uint8_t* input;
+ size_t input_len;
+ } opt_input;
+ struct {
+ void (*on_output)(const uint8_t* /*output*/,
+ size_t /*output_len*/,
+ void* /* user_pointer */);
+ void* user_pointer;
+ } opt_capture_output;
+ };
+};
+
int android_fork_execvp_ext(int argc, char* argv[], int *status, bool ignore_int_quit,
- int log_target, bool abbreviated, char *file_path);
+ int log_target, bool abbreviated, char *file_path,
+ const struct AndroidForkExecvpOption* opts, size_t opts_len);
/* Similar to above, except abbreviated logging is not available, and if logwrap
* is true, logging is to the Android system log, and if false, there is no
@@ -79,7 +105,8 @@
bool ignore_int_quit, bool logwrap)
{
return android_fork_execvp_ext(argc, argv, status, ignore_int_quit,
- (logwrap ? LOG_ALOG : LOG_NONE), false, NULL);
+ (logwrap ? LOG_ALOG : LOG_NONE), false, NULL,
+ NULL, 0);
}
__END_DECLS
diff --git a/logwrapper/logwrap.c b/logwrapper/logwrap.c
index 777dafe..39bc8fd 100644
--- a/logwrapper/logwrap.c
+++ b/logwrapper/logwrap.c
@@ -291,7 +291,8 @@
}
static int parent(const char *tag, int parent_read, pid_t pid,
- int *chld_sts, int log_target, bool abbreviated, char *file_path) {
+ int *chld_sts, int log_target, bool abbreviated, char *file_path,
+ const struct AndroidForkExecvpOption* opts, size_t opts_len) {
int status = 0;
char buffer[4096];
struct pollfd poll_fds[] = {
@@ -358,6 +359,13 @@
sz = TEMP_FAILURE_RETRY(
read(parent_read, &buffer[b], sizeof(buffer) - 1 - b));
+ for (size_t i = 0; sz > 0 && i < opts_len; ++i) {
+ if (opts[i].opt_type == FORK_EXECVP_OPTION_CAPTURE_OUTPUT) {
+ opts[i].opt_capture_output.on_output(
+ (uint8_t*)&buffer[b], sz, opts[i].opt_capture_output.user_pointer);
+ }
+ }
+
sz += b;
// Log one line at a time
for (b = 0; b < sz; b++) {
@@ -474,7 +482,8 @@
}
int android_fork_execvp_ext(int argc, char* argv[], int *status, bool ignore_int_quit,
- int log_target, bool abbreviated, char *file_path) {
+ int log_target, bool abbreviated, char *file_path,
+ const struct AndroidForkExecvpOption* opts, size_t opts_len) {
pid_t pid;
int parent_ptty;
int child_ptty;
@@ -529,7 +538,13 @@
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
close(parent_ptty);
- // redirect stdout and stderr
+ // redirect stdin, stdout and stderr
+ for (size_t i = 0; i < opts_len; ++i) {
+ if (opts[i].opt_type == FORK_EXECVP_OPTION_INPUT) {
+ dup2(child_ptty, 0);
+ break;
+ }
+ }
dup2(child_ptty, 1);
dup2(child_ptty, 2);
close(child_ptty);
@@ -546,8 +561,24 @@
sigaction(SIGQUIT, &ignact, &quitact);
}
+ for (size_t i = 0; i < opts_len; ++i) {
+ if (opts[i].opt_type == FORK_EXECVP_OPTION_INPUT) {
+ size_t left = opts[i].opt_input.input_len;
+ const uint8_t* input = opts[i].opt_input.input;
+ while (left > 0) {
+ ssize_t res =
+ TEMP_FAILURE_RETRY(write(parent_ptty, input, left));
+ if (res < 0) {
+ break;
+ }
+ left -= res;
+ input += res;
+ }
+ }
+ }
+
rc = parent(argv[0], parent_ptty, pid, status, log_target,
- abbreviated, file_path);
+ abbreviated, file_path, opts, opts_len);
}
if (ignore_int_quit) {
diff --git a/logwrapper/logwrapper.c b/logwrapper/logwrapper.c
index 9e0385d..55b71c7 100644
--- a/logwrapper/logwrapper.c
+++ b/logwrapper/logwrapper.c
@@ -81,7 +81,7 @@
}
rc = android_fork_execvp_ext(argc, &argv[0], &status, true,
- log_target, abbreviated, NULL);
+ log_target, abbreviated, NULL, NULL, 0);
if (!rc) {
if (WIFEXITED(status))
rc = WEXITSTATUS(status);
diff --git a/metricsd/Android.mk b/metricsd/Android.mk
index 9edba6e..89fa222 100644
--- a/metricsd/Android.mk
+++ b/metricsd/Android.mk
@@ -16,6 +16,8 @@
ifeq ($(HOST_OS),linux)
+LOCAL_INIT_SERVICE := metrics_daemon
+
metrics_cpp_extension := .cc
libmetrics_sources := \
c_metrics_library.cc \
@@ -40,7 +42,6 @@
serialization/serialization_utils.cc
metrics_CFLAGS := -Wall \
- -D__BRILLO__ \
-Wno-char-subscripts \
-Wno-missing-field-initializers \
-Wno-unused-function \
@@ -96,21 +97,32 @@
# metrics daemon.
# ========================================================
include $(CLEAR_VARS)
-LOCAL_MODULE := metrics_daemon
+LOCAL_MODULE := $(LOCAL_INIT_SERVICE)
LOCAL_C_INCLUDES := $(metrics_includes) \
external/libchromeos
LOCAL_CFLAGS := $(metrics_CFLAGS)
LOCAL_CPP_EXTENSION := $(metrics_cpp_extension)
LOCAL_CPPFLAGS := $(metrics_CPPFLAGS)
+LOCAL_REQUIRED_MODULES := init.$(LOCAL_INIT_SERVICE).rc
LOCAL_RTTI_FLAG := -frtti
LOCAL_SHARED_LIBRARIES := $(metrics_shared_libraries) \
libmetrics \
libprotobuf-cpp-lite \
libchromeos-http \
libchromeos-dbus \
+ libcutils \
libdbus
LOCAL_SRC_FILES := $(metrics_daemon_sources)
LOCAL_STATIC_LIBRARIES := metrics_daemon_protos
include $(BUILD_EXECUTABLE)
+ifdef INITRC_TEMPLATE
+include $(CLEAR_VARS)
+LOCAL_MODULE := init.$(LOCAL_INIT_SERVICE).rc
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(PRODUCT_OUT)/$(TARGET_COPY_OUT_INITRCD)
+LOCAL_SRC_FILES := init.$(LOCAL_INIT_SERVICE).rc
+include $(BUILD_PREBUILT)
+endif # INITRC_TEMPLATE
+
endif # HOST_OS == linux
diff --git a/metricsd/constants.h b/metricsd/constants.h
index d65e0e0..15c15d9 100644
--- a/metricsd/constants.h
+++ b/metricsd/constants.h
@@ -21,9 +21,14 @@
static const char kMetricsDirectory[] = "/data/misc/metrics/";
static const char kMetricsEventsFilePath[] = "/data/misc/metrics/uma-events";
static const char kMetricsGUIDFilePath[] = "/data/misc/metrics/Sysinfo.GUID";
-static const char kMetricsServer[] = "http://clients4.google.com/uma/v2";
+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/init.metrics_daemon.rc b/metricsd/init.metrics_daemon.rc
new file mode 100644
index 0000000..73ce673
--- /dev/null
+++ b/metricsd/init.metrics_daemon.rc
@@ -0,0 +1,8 @@
+on boot
+ mkdir /data/misc/metrics 0770 system system
+
+service metrics_daemon /system/bin/metrics_daemon --uploader -nodaemon
+ class late_start
+ user system
+ group system dbus inet
+ seclabel u:r:brillo:s0
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/metrics_log.cc b/metricsd/uploader/metrics_log.cc
index 5f4c599..1f16ca1 100644
--- a/metricsd/uploader/metrics_log.cc
+++ b/metricsd/uploader/metrics_log.cc
@@ -48,6 +48,6 @@
stability->set_unclean_system_shutdown_count(current + 1);
}
-void MetricsLog::PopulateSystemProfile(SystemProfileSetter* profile_setter) {
- profile_setter->Populate(uma_proto());
+bool MetricsLog::PopulateSystemProfile(SystemProfileSetter* profile_setter) {
+ return profile_setter->Populate(uma_proto());
}
diff --git a/metricsd/uploader/metrics_log.h b/metricsd/uploader/metrics_log.h
index 50fed89..5e09070 100644
--- a/metricsd/uploader/metrics_log.h
+++ b/metricsd/uploader/metrics_log.h
@@ -39,7 +39,7 @@
void IncrementUncleanShutdownCount();
// Populate the system profile with system information using setter.
- void PopulateSystemProfile(SystemProfileSetter* setter);
+ bool PopulateSystemProfile(SystemProfileSetter* setter);
private:
FRIEND_TEST(UploadServiceTest, LogContainsAggregatedValues);
diff --git a/metricsd/uploader/system_profile_cache.cc b/metricsd/uploader/system_profile_cache.cc
index 35910d7..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) << "Could not initialize system profile.";
+ 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" :
@@ -109,11 +116,12 @@
return initialized_ || Initialize();
}
-void SystemProfileCache::Populate(
+bool SystemProfileCache::Populate(
metrics::ChromeUserMetricsExtension* metrics_proto) {
CHECK(metrics_proto);
- CHECK(InitializeOrCheck())
- << "failed to initialize system information.";
+ if (not InitializeOrCheck()) {
+ return false;
+ }
// The client id is hashed before being sent.
metrics_proto->set_client_id(
@@ -132,6 +140,8 @@
metrics::SystemProfileProto_BrilloDeviceData* device_data =
profile_proto->mutable_brillo();
device_data->set_build_target_id(profile_.build_target_id);
+
+ return true;
}
std::string SystemProfileCache::GetPersistentGUID(
diff --git a/metricsd/uploader/system_profile_cache.h b/metricsd/uploader/system_profile_cache.h
index c53a18e..ac80b47 100644
--- a/metricsd/uploader/system_profile_cache.h
+++ b/metricsd/uploader/system_profile_cache.h
@@ -52,7 +52,7 @@
SystemProfileCache(bool testing, const std::string& config_root);
// Populates the ProfileSystem protobuf with system information.
- void Populate(metrics::ChromeUserMetricsExtension* metrics_proto) override;
+ bool Populate(metrics::ChromeUserMetricsExtension* metrics_proto) override;
// Converts a string representation of the channel to a
// SystemProfileProto_Channel
diff --git a/metricsd/uploader/system_profile_setter.h b/metricsd/uploader/system_profile_setter.h
index cd311a4..bd3ff42 100644
--- a/metricsd/uploader/system_profile_setter.h
+++ b/metricsd/uploader/system_profile_setter.h
@@ -27,7 +27,7 @@
public:
virtual ~SystemProfileSetter() {}
// Populates the protobuf with system informations.
- virtual void Populate(metrics::ChromeUserMetricsExtension* profile_proto) = 0;
+ virtual bool Populate(metrics::ChromeUserMetricsExtension* profile_proto) = 0;
};
#endif // METRICS_UPLOADER_SYSTEM_PROFILE_SETTER_H_
diff --git a/metricsd/uploader/upload_service.cc b/metricsd/uploader/upload_service.cc
index 63b5789..2335630 100644
--- a/metricsd/uploader/upload_service.cc
+++ b/metricsd/uploader/upload_service.cc
@@ -73,7 +73,6 @@
CHECK(!staged_log_) << "the staged log should be discarded before starting "
"a new metrics log";
MetricsLog* log = new MetricsLog();
- log->PopulateSystemProfile(system_profile_setter_.get());
current_log_.reset(log);
}
@@ -97,13 +96,12 @@
// Previous upload successful, reading metrics sample from the file.
ReadMetrics();
GatherHistograms();
-
- // No samples found. Exit to avoid sending an empty log.
- if (!current_log_)
- return;
-
StageCurrentLog();
- SendStagedLog();
+
+ // If a log is available for upload, upload it.
+ if (staged_log_) {
+ SendStagedLog();
+ }
}
void UploadService::SendStagedLog() {
@@ -225,6 +223,11 @@
staged_log_.swap(current_log_);
staged_log_->CloseLog();
+ if (!staged_log_->PopulateSystemProfile(system_profile_setter_.get())) {
+ LOG(WARNING) << "Error while adding metadata to the log. Discarding the "
+ << "log.";
+ staged_log_.reset();
+ }
failed_upload_count_ = 0;
}
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index e1ba2e9..f853fac 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -2,8 +2,6 @@
#######################################
# init.rc
-# Only copy init.rc if the target doesn't have its own.
-ifneq ($(TARGET_PROVIDES_INIT_RC),true)
include $(CLEAR_VARS)
LOCAL_MODULE := init.rc
@@ -12,7 +10,6 @@
LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT)
include $(BUILD_PREBUILT)
-endif
#######################################
# asan.options
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 12999bd..cf16f01 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -235,7 +235,6 @@
# create basic filesystem structure
mkdir /data/misc 01771 system misc
- mkdir /data/misc/adb 02750 system shell
mkdir /data/misc/bluedroid 0770 bluetooth net_bt_stack
mkdir /data/misc/bluetooth 0770 system system
mkdir /data/misc/keystore 0700 keystore keystore
@@ -292,7 +291,6 @@
# the following directory.
mkdir /data/mediadrm 0770 mediadrm mediadrm
- mkdir /data/adb 0700 root root
mkdir /data/anr 0775 system system
# symlink to bugreport storage location
@@ -477,16 +475,6 @@
critical
seclabel u:r:ueventd:s0
-service logd /system/bin/logd
- class core
- socket logd stream 0666 logd logd
- socket logdr seqpacket 0666 logd logd
- socket logdw dgram 0222 logd logd
-
-service logd-reinit /system/bin/logd --reinit
- oneshot
- disabled
-
service healthd /sbin/healthd
class core
critical
@@ -503,139 +491,10 @@
on property:ro.debuggable=1
start console
-# adbd is controlled via property triggers in init.<platform>.usb.rc
-service adbd /sbin/adbd --root_seclabel=u:r:su:s0
- class core
- socket adbd stream 660 system system
- disabled
- seclabel u:r:adbd:s0
-
-# adbd on at boot in emulator
-on property:ro.kernel.qemu=1
- start adbd
-
-service lmkd /system/bin/lmkd
- class core
- critical
- socket lmkd seqpacket 0660 system system
-
-service servicemanager /system/bin/servicemanager
- class core
- user system
- group system
- critical
- onrestart restart healthd
- onrestart restart zygote
- onrestart restart media
- onrestart restart surfaceflinger
- onrestart restart drm
-
-service vold /system/bin/vold
- class core
- socket vold stream 0660 root mount
- ioprio be 2
-
-service netd /system/bin/netd
- class main
- socket netd stream 0660 root system
- socket dnsproxyd stream 0660 root inet
- socket mdns stream 0660 root system
- socket fwmarkd stream 0660 root inet
-
-service debuggerd /system/bin/debuggerd
- class main
-
-service debuggerd64 /system/bin/debuggerd64
- class main
-
-service ril-daemon /system/bin/rild
- class main
- socket rild stream 660 root radio
- socket rild-debug stream 660 radio system
- user root
- group radio cache inet misc audio log
-
-service surfaceflinger /system/bin/surfaceflinger
- class core
- user system
- group graphics drmrpc
- onrestart restart zygote
-
-service drm /system/bin/drmserver
- class main
- user drm
- group drm system inet drmrpc
-
-service media /system/bin/mediaserver
- class main
- user media
- group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm
- ioprio rt 4
-
-# One shot invocation to deal with encrypted volume.
-service defaultcrypto /system/bin/vdc --wait cryptfs mountdefaultencrypted
- disabled
- oneshot
- # vold will set vold.decrypt to trigger_restart_framework (default
- # encryption) or trigger_restart_min_framework (other encryption)
-
-# One shot invocation to encrypt unencrypted volumes
-service encrypt /system/bin/vdc --wait cryptfs enablecrypto inplace default
- disabled
- oneshot
- # vold will set vold.decrypt to trigger_restart_framework (default
- # encryption)
-
-service bootanim /system/bin/bootanimation
- class core
- user graphics
- group graphics audio
- disabled
- oneshot
-
-service installd /system/bin/installd
- class main
- socket installd stream 600 system system
-
service flash_recovery /system/bin/install-recovery.sh
class main
oneshot
-service racoon /system/bin/racoon
- class main
- socket racoon stream 600 system system
- # IKE uses UDP port 500. Racoon will setuid to vpn after binding the port.
- group vpn net_admin inet
- disabled
- oneshot
-
-service mtpd /system/bin/mtpd
- class main
- socket mtpd stream 600 system system
- user vpn
- group vpn net_admin inet net_raw
- disabled
- oneshot
-
-service keystore /system/bin/keystore /data/misc/keystore
- class main
- user keystore
- group keystore drmrpc
-
-service dumpstate /system/bin/dumpstate -s
- class main
- socket dumpstate stream 0660 shell log
- disabled
- oneshot
-
-service mdnsd /system/bin/mdnsd
- class main
- user mdnsr
- group inet net_raw
- socket mdnsd stream 0660 mdnsr inet
- disabled
- oneshot
-
service uncrypt /system/bin/uncrypt
class main
disabled
@@ -645,22 +504,3 @@
class main
disabled
oneshot
-
-service perfprofd /system/xbin/perfprofd
- class late_start
- user root
- oneshot
-
-on property:persist.logd.logpersistd=logcatd
- # all exec/services are called with umask(077), so no gain beyond 0700
- mkdir /data/misc/logd 0700 logd log
- # logd for write to /data/misc/logd, log group for read from pstore (-L)
- exec - logd log -- /system/bin/logcat -L -b all -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 64 -n 256
- start logcatd
-
-service logcatd /system/bin/logcat -b all -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r 64 -n 256
- class late_start
- disabled
- # logd for write to /data/misc/logd, log group for read from log daemon
- user logd
- group log
diff --git a/toolbox/lsof.c b/toolbox/lsof.c
index 982f5aa..198ca52 100644
--- a/toolbox/lsof.c
+++ b/toolbox/lsof.c
@@ -29,6 +29,7 @@
* SUCH DAMAGE.
*/
+#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
@@ -57,7 +58,7 @@
static void print_header()
{
- printf("%-9s %5s %10s %4s %9s %18s %9s %10s %s\n",
+ printf("%-9s %5s %10s %4s %9s %18s %9s %10s %s\n",
"COMMAND",
"PID",
"USER",
@@ -69,12 +70,12 @@
"NAME");
}
-static void print_type(char *type, struct pid_info_t* info)
+static void print_symlink(const char* name, const char* path, struct pid_info_t* info)
{
static ssize_t link_dest_size;
static char link_dest[PATH_MAX];
- strlcat(info->path, type, sizeof(info->path));
+ strlcat(info->path, path, sizeof(info->path));
if ((link_dest_size = readlink(info->path, link_dest, sizeof(link_dest)-1)) < 0) {
if (errno == ENOENT)
goto out;
@@ -88,9 +89,53 @@
if (!strcmp(link_dest, "/"))
goto out;
- printf("%-9s %5d %10s %4s %9s %18s %9s %10s %s\n",
- info->cmdline, info->pid, info->user, type,
- "???", "???", "???", "???", link_dest);
+ const char* fd = name;
+ char rw = ' ';
+ char locks = ' '; // TODO: read /proc/locks
+
+ const char* type = "unknown";
+ char device[32] = "?";
+ char size_off[32] = "?";
+ char node[32] = "?";
+
+ struct stat sb;
+ if (lstat(link_dest, &sb) != -1) {
+ switch ((sb.st_mode & S_IFMT)) {
+ case S_IFSOCK: type = "sock"; break; // TODO: what domain?
+ case S_IFLNK: type = "LINK"; break;
+ case S_IFREG: type = "REG"; break;
+ case S_IFBLK: type = "BLK"; break;
+ case S_IFDIR: type = "DIR"; break;
+ case S_IFCHR: type = "CHR"; break;
+ case S_IFIFO: type = "FIFO"; break;
+ }
+ snprintf(device, sizeof(device), "%d,%d", (int) sb.st_dev, (int) sb.st_rdev);
+ snprintf(node, sizeof(node), "%d", (int) sb.st_ino);
+ snprintf(size_off, sizeof(size_off), "%d", (int) sb.st_size);
+ }
+
+ if (!name) {
+ // We're looking at an fd, so read its flags.
+ fd = path;
+ char fdinfo_path[PATH_MAX];
+ snprintf(fdinfo_path, sizeof(fdinfo_path), "/proc/%d/fdinfo/%s", info->pid, path);
+ FILE* fp = fopen(fdinfo_path, "r");
+ if (fp != NULL) {
+ int pos;
+ unsigned flags;
+
+ if (fscanf(fp, "pos: %d flags: %o", &pos, &flags) == 2) {
+ flags &= O_ACCMODE;
+ if (flags == O_RDONLY) rw = 'r';
+ else if (flags == O_WRONLY) rw = 'w';
+ else rw = 'u';
+ }
+ fclose(fp);
+ }
+ }
+
+ printf("%-9s %5d %10s %4s%c%c %9s %18s %9s %10s %s\n",
+ info->cmdline, info->pid, info->user, fd, rw, locks, type, device, size_off, node, link_dest);
out:
info->path[info->parent_length] = '\0';
@@ -111,15 +156,14 @@
if (!maps)
goto out;
- while (fscanf(maps, "%*x-%*x %*s %zx %s %ld %s\n", &offset, device, &inode,
- file) == 4) {
+ while (fscanf(maps, "%*x-%*x %*s %zx %s %ld %s\n", &offset, device, &inode, file) == 4) {
// We don't care about non-file maps
if (inode == 0 || !strcmp(device, "00:00"))
continue;
- printf("%-9s %5d %10s %4s %9s %18s %9zd %10ld %s\n",
+ printf("%-9s %5d %10s %4s %9s %18s %9zd %10ld %s\n",
info->cmdline, info->pid, info->user, "mem",
- "???", device, offset, inode, file);
+ "REG", device, offset, inode, file);
}
fclose(maps);
@@ -141,7 +185,7 @@
if (dir == NULL) {
char msg[BUF_MAX];
snprintf(msg, sizeof(msg), "%s (opendir: %s)", info->path, strerror(errno));
- printf("%-9s %5d %10s %4s %9s %18s %9s %10s %s\n",
+ printf("%-9s %5d %10s %4s %9s %18s %9s %10s %s\n",
info->cmdline, info->pid, info->user, "FDS",
"", "", "", "", msg);
goto out;
@@ -152,7 +196,7 @@
if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
continue;
- print_type(de->d_name, info);
+ print_symlink(NULL, de->d_name, info);
}
closedir(dir);
@@ -207,10 +251,9 @@
strlcpy(info.cmdline, basename(cmdline), sizeof(info.cmdline));
// Read each of these symlinks
- print_type("cwd", &info);
- print_type("exe", &info);
- print_type("root", &info);
-
+ print_symlink("cwd", "cwd", &info);
+ print_symlink("txt", "exe", &info);
+ print_symlink("rtd", "root", &info);
print_fds(&info);
print_maps(&info);
}