Merge "Create Service and ServiceManager classes"
diff --git a/adb/Android.mk b/adb/Android.mk
index 7fcb5ed..e2d0bb1 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -22,6 +22,15 @@
-Wno-missing-field-initializers \
-DADB_REVISION='"$(adb_version)"' \
+# Define windows.h and tchar.h Unicode preprocessor symbols so that
+# CreateFile(), _tfopen(), etc. map to versions that take wchar_t*, breaking the
+# build if you accidentally pass char*. Fix by calling like:
+# CreateFileW(widen(utf8).c_str()).
+ADB_COMMON_windows_CFLAGS := \
+ -DUNICODE=1 -D_UNICODE=1 \
+
+ADB_COMMON_CFLAGS += $(ADB_COMMON_$(HOST_OS)_CFLAGS)
+
# libadb
# =========================================================
@@ -123,7 +132,9 @@
LOCAL_SHARED_LIBRARIES := liblog libbase libcutils
include $(BUILD_NATIVE_TEST)
-ifneq ($(HOST_OS),windows)
+# adb_test
+# =========================================================
+
include $(CLEAR_VARS)
LOCAL_CLANG := $(adb_host_clang)
LOCAL_MODULE := adb_test
@@ -144,9 +155,13 @@
LOCAL_LDLIBS += -framework CoreFoundation -framework IOKit
endif
-include $(BUILD_HOST_NATIVE_TEST)
+ifeq ($(HOST_OS),windows)
+ LOCAL_LDLIBS += -lws2_32 -luserenv
+ LOCAL_STATIC_LIBRARIES += AdbWinApi
endif
+include $(BUILD_HOST_NATIVE_TEST)
+
# adb device tracker (used by ddms) test tool
# =========================================================
diff --git a/adb/adb.cpp b/adb/adb.cpp
index c5ab7b0..dd6c555 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -580,8 +580,8 @@
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) failure, error %ld\n",
- GetLastError());
+ fprintf(stderr, "CreateFileW(nul, GENERIC_READ) failed: %s\n",
+ SystemErrorCodeToString(GetLastError()).c_str());
return -1;
}
@@ -589,8 +589,8 @@
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) failure, error %ld\n",
- GetLastError());
+ fprintf(stderr, "CreateFileW(nul, GENERIC_WRITE) failed: %s\n",
+ SystemErrorCodeToString(GetLastError()).c_str());
CloseHandle(nul_read);
return -1;
}
@@ -598,7 +598,8 @@
/* create pipe, and ensure its read handle isn't inheritable */
ret = CreatePipe( &pipe_read, &pipe_write, &sa, 0 );
if (!ret) {
- fprintf(stderr, "CreatePipe() failure, error %ld\n", GetLastError() );
+ fprintf(stderr, "CreatePipe() failed: %s\n",
+ SystemErrorCodeToString(GetLastError()).c_str());
CloseHandle(nul_read);
CloseHandle(nul_write);
return -1;
@@ -640,8 +641,8 @@
arraysize(program_path));
if ((module_result == arraysize(program_path)) || (module_result == 0)) {
// String truncation or some other error.
- fprintf(stderr, "GetModuleFileNameW() failure, error %ld\n",
- GetLastError());
+ fprintf(stderr, "GetModuleFileNameW() failed: %s\n",
+ SystemErrorCodeToString(GetLastError()).c_str());
return -1;
}
WCHAR args[64];
@@ -666,7 +667,8 @@
CloseHandle( pipe_write );
if (!ret) {
- fprintf(stderr, "CreateProcess failure, error %ld\n", GetLastError() );
+ fprintf(stderr, "CreateProcess failed: %s\n",
+ SystemErrorCodeToString(GetLastError()).c_str());
CloseHandle( pipe_read );
return -1;
}
@@ -682,7 +684,8 @@
ret = ReadFile( pipe_read, temp, 3, &count, NULL );
CloseHandle( pipe_read );
if ( !ret ) {
- fprintf(stderr, "could not read ok from ADB Server, error = %ld\n", GetLastError() );
+ fprintf(stderr, "could not read ok from ADB Server, error: %s\n",
+ SystemErrorCodeToString(GetLastError()).c_str());
return -1;
}
if (count != 3 || temp[0] != 'O' || temp[1] != 'K' || temp[2] != '\n') {
@@ -695,7 +698,7 @@
int fd[2];
// set up a pipe so the child can tell us when it is ready.
- // fd[0] will be parent's end, and fd[1] will get mapped to stderr in the child.
+ // fd[0] will be parent's end, and the child will write on fd[1]
if (pipe(fd)) {
fprintf(stderr, "pipe failed in launch_server, errno: %d\n", errno);
return -1;
@@ -707,16 +710,14 @@
if (pid == 0) {
// child side of the fork
- // redirect stderr to the pipe
- // we use stderr instead of stdout due to stdout's buffering behavior.
adb_close(fd[0]);
- dup2(fd[1], STDERR_FILENO);
- adb_close(fd[1]);
char str_port[30];
- snprintf(str_port, sizeof(str_port), "%d", server_port);
+ snprintf(str_port, sizeof(str_port), "%d", server_port);
+ char reply_fd[30];
+ snprintf(reply_fd, sizeof(reply_fd), "%d", fd[1]);
// child process
- int result = execl(path, "adb", "-P", str_port, "fork-server", "server", NULL);
+ int result = execl(path, "adb", "-P", str_port, "fork-server", "server", "--reply-fd", reply_fd, NULL);
// this should not return
fprintf(stderr, "OOPS! execl returned %d, errno: %d\n", result, errno);
} else {
diff --git a/adb/adb.h b/adb/adb.h
index 309b0e9..b0e53f0 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -299,7 +299,7 @@
void get_my_path(char *s, size_t maxLen);
int launch_server(int server_port);
-int adb_main(int is_daemon, int server_port);
+int adb_main(int is_daemon, int server_port, int ack_reply_fd);
/* initialize a transport object's func pointers and state */
#if ADB_HOST
diff --git a/adb/adb_auth_host.cpp b/adb/adb_auth_host.cpp
index 966e61d..e7f82a9 100644
--- a/adb/adb_auth_host.cpp
+++ b/adb/adb_auth_host.cpp
@@ -305,7 +305,10 @@
home = getenv("ANDROID_SDK_HOME");
if (!home) {
WCHAR path[MAX_PATH];
- if (FAILED(SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, path))) {
+ const HRESULT hr = SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, path);
+ if (FAILED(hr)) {
+ D("SHGetFolderPathW failed: %s\n",
+ SystemErrorCodeToString(hr).c_str());
return -1;
}
home_str = narrow(path);
diff --git a/adb/adb_client.cpp b/adb/adb_client.cpp
index 6d75966..afff2ef 100644
--- a/adb/adb_client.cpp
+++ b/adb/adb_client.cpp
@@ -229,8 +229,9 @@
}
} else {
// if fd is -1, then check for "unknown host service",
- // which would indicate a version of adb that does not support the version command
- if (*error == "unknown host service") {
+ // which would indicate a version of adb that does not support the
+ // version command, in which case we should fall-through to kill it.
+ if (*error != "unknown host service") {
return fd;
}
}
diff --git a/adb/adb_io_test.cpp b/adb/adb_io_test.cpp
index 0ae21db..f637073 100644
--- a/adb/adb_io_test.cpp
+++ b/adb/adb_io_test.cpp
@@ -30,6 +30,12 @@
#include "base/file.h"
#include "base/test_utils.h"
+// All of these tests fail on Windows because they use the C Runtime open(),
+// but the adb_io APIs expect file descriptors from adb_open(). Also, the
+// android::base file APIs use the C Runtime which uses CR/LF translation by
+// default (changeable with _setmode()), but the adb_io APIs use adb_read()
+// and adb_write() which do no translation.
+
TEST(io, ReadFdExactly_whole) {
const char expected[] = "Foobar";
TemporaryFile tf;
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index 12208cd..ca843bd 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -18,6 +18,7 @@
#include "adb_utils.h"
+#include <libgen.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -32,6 +33,8 @@
#include "adb_trace.h"
#include "sysdeps.h"
+ADB_MUTEX_DEFINE(dirname_lock);
+
bool getcwd(std::string* s) {
char* cwd = getcwd(nullptr, 0);
if (cwd != nullptr) *s = cwd;
@@ -66,35 +69,86 @@
}
std::string adb_basename(const std::string& path) {
- size_t base = path.find_last_of(OS_PATH_SEPARATORS);
- return (base != std::string::npos) ? path.substr(base + 1) : path;
+ size_t base = path.find_last_of(OS_PATH_SEPARATORS);
+ return (base != std::string::npos) ? path.substr(base + 1) : path;
}
-static bool real_mkdirs(const std::string& path) {
- std::vector<std::string> path_components = android::base::Split(path, OS_PATH_SEPARATOR_STR);
- // TODO: all the callers do unlink && mkdirs && adb_creat ---
- // that's probably the operation we should expose.
- path_components.pop_back();
- std::string partial_path;
- for (const auto& path_component : path_components) {
- if (partial_path.back() != OS_PATH_SEPARATOR) partial_path += OS_PATH_SEPARATOR;
- partial_path += path_component;
- if (adb_mkdir(partial_path.c_str(), 0775) == -1 && errno != EEXIST) {
- return false;
- }
- }
- return true;
+std::string adb_dirname(const std::string& path) {
+ // Copy path because dirname may modify the string passed in.
+ std::string parent_storage(path);
+
+ // Use lock because dirname() may write to a process global and return a
+ // pointer to that. Note that this locking strategy only works if all other
+ // callers to dirname in the process also grab this same lock.
+ adb_mutex_lock(&dirname_lock);
+
+ // Note that if std::string uses copy-on-write strings, &str[0] will cause
+ // the copy to be made, so there is no chance of us accidentally writing to
+ // the storage for 'path'.
+ char* parent = dirname(&parent_storage[0]);
+
+ // In case dirname returned a pointer to a process global, copy that string
+ // before leaving the lock.
+ const std::string result(parent);
+
+ adb_mutex_unlock(&dirname_lock);
+
+ return result;
}
+// Given a relative or absolute filepath, create the parent directory hierarchy
+// as needed. Returns true if the hierarchy is/was setup.
bool mkdirs(const std::string& path) {
-#if defined(_WIN32)
- // Replace '/' with '\\' so we can share the code.
- std::string clean_path = path;
- std::replace(clean_path.begin(), clean_path.end(), '/', '\\');
- return real_mkdirs(clean_path);
-#else
- return real_mkdirs(path);
-#endif
+ // TODO: all the callers do unlink && mkdirs && adb_creat ---
+ // that's probably the operation we should expose.
+
+ // Implementation Notes:
+ //
+ // Pros:
+ // - Uses dirname, so does not need to deal with OS_PATH_SEPARATOR.
+ // - On Windows, uses mingw dirname which accepts '/' and '\\', drive letters
+ // (C:\foo), UNC paths (\\server\share\dir\dir\file), and Unicode (when
+ // combined with our adb_mkdir() which takes UTF-8).
+ // - Is optimistic wrt thinking that a deep directory hierarchy will exist.
+ // So it does as few stat()s as possible before doing mkdir()s.
+ // Cons:
+ // - Recursive, so it uses stack space relative to number of directory
+ // components.
+
+ const std::string parent(adb_dirname(path));
+
+ if (directory_exists(parent)) {
+ return true;
+ }
+
+ // If dirname returned the same path as what we passed in, don't go recursive.
+ // This can happen on Windows when walking up the directory hierarchy and not
+ // finding anything that already exists (unlike POSIX that will eventually
+ // find . or /).
+ if (parent == path) {
+ errno = ENOENT;
+ return false;
+ }
+
+ // Recursively make parent directories of 'parent'.
+ if (!mkdirs(parent)) {
+ return false;
+ }
+
+ // Now that the parent directory hierarchy of 'parent' has been ensured,
+ // create parent itself.
+ if (adb_mkdir(parent, 0775) == -1) {
+ // Can't just check for errno == EEXIST because it might be a file that
+ // exists.
+ const int saved_errno = errno;
+ if (directory_exists(parent)) {
+ return true;
+ }
+ errno = saved_errno;
+ return false;
+ }
+
+ return true;
}
void dump_hex(const void* data, size_t byte_count) {
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index 8c5208c..739efcc 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -21,7 +21,11 @@
bool getcwd(std::string* cwd);
bool directory_exists(const std::string& path);
+
+// Like the regular basename and dirname, but thread-safe on all
+// platforms and capable of correctly handling exotic Windows paths.
std::string adb_basename(const std::string& path);
+std::string adb_dirname(const std::string& path);
bool mkdirs(const std::string& path);
diff --git a/adb/adb_utils_test.cpp b/adb/adb_utils_test.cpp
index 309ac02..17c8d0a 100644
--- a/adb/adb_utils_test.cpp
+++ b/adb/adb_utils_test.cpp
@@ -16,6 +16,13 @@
#include "adb_utils.h"
+#ifdef _WIN32
+#include <windows.h>
+#include <userenv.h>
+#endif
+
+#include <string>
+
#include <gtest/gtest.h>
#include <stdlib.h>
@@ -23,12 +30,46 @@
#include "sysdeps.h"
+#include <base/macros.h>
#include <base/test_utils.h>
+#ifdef _WIN32
+static std::string subdir(const char* parent, const char* child) {
+ std::string str(parent);
+ str += OS_PATH_SEPARATOR;
+ str += child;
+ return str;
+}
+#endif
+
TEST(adb_utils, directory_exists) {
+#ifdef _WIN32
+ char profiles_dir[MAX_PATH];
+ DWORD cch = arraysize(profiles_dir);
+
+ // On typical Windows 7, returns C:\Users
+ ASSERT_TRUE(GetProfilesDirectoryA(profiles_dir, &cch));
+
+ ASSERT_TRUE(directory_exists(profiles_dir));
+
+ // On modern (English?) Windows, this is a directory symbolic link to
+ // C:\ProgramData. Symbolic links are rare on Windows and the user requires
+ // a special permission (by default granted to Administrative users) to
+ // create symbolic links.
+ ASSERT_FALSE(directory_exists(subdir(profiles_dir, "All Users")));
+
+ // On modern (English?) Windows, this is a directory junction to
+ // C:\Users\Default. Junctions are used throughout user profile directories
+ // for backwards compatibility and they don't require any special permissions
+ // to create.
+ ASSERT_FALSE(directory_exists(subdir(profiles_dir, "Default User")));
+
+ ASSERT_FALSE(directory_exists(subdir(profiles_dir, "does-not-exist")));
+#else
ASSERT_TRUE(directory_exists("/proc"));
ASSERT_FALSE(directory_exists("/proc/self")); // Symbolic link.
ASSERT_FALSE(directory_exists("/proc/does-not-exist"));
+#endif
}
TEST(adb_utils, escape_arg) {
@@ -145,10 +186,19 @@
EXPECT_FALSE(parse_host_and_port("1.2.3.4:65536", &canonical_address, &host, &port, &error));
}
+void test_mkdirs(const std::string basepath) {
+ EXPECT_TRUE(mkdirs(basepath));
+ EXPECT_NE(-1, adb_creat(basepath.c_str(), 0600));
+ EXPECT_FALSE(mkdirs(basepath + "/subdir/"));
+}
+
TEST(adb_utils, mkdirs) {
TemporaryDir td;
- std::string path = std::string(td.path) + "/dir/subdir/file";
- EXPECT_TRUE(mkdirs(path));
- EXPECT_NE(-1, adb_creat(path.c_str(), 0600));
- EXPECT_FALSE(mkdirs(path + "/subdir/"));
+
+ // Absolute paths.
+ test_mkdirs(std::string(td.path) + "/dir/subdir/file");
+
+ // Relative paths.
+ ASSERT_EQ(0, chdir(td.path)) << strerror(errno);
+ test_mkdirs(std::string("relative/subrel/file"));
}
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index 6b48621..af3a6a1 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -132,7 +132,7 @@
fprintf(stderr, "--- adb starting (pid %d) ---\n", getpid());
}
-int adb_main(int is_daemon, int server_port) {
+int adb_main(int is_daemon, int server_port, int ack_reply_fd) {
HOST = 1;
#if defined(_WIN32)
@@ -157,29 +157,20 @@
LOG(FATAL) << "Could not install *smartsocket* listener: " << error;
}
+ // Inform our parent that we are up and running.
if (is_daemon) {
- // Inform our parent that we are up and running.
- // TODO(danalbert): Can't use SendOkay because we're sending "OK\n", not
- // "OKAY".
- // TODO(danalbert): Why do we use stdout for Windows? There is a
- // comment in launch_server() that suggests that non-Windows uses
- // stderr because it is non-buffered. So perhaps the history is that
- // stdout was preferred for all platforms, but it was discovered that
- // non-Windows needed a non-buffered fd, so stderr was used there.
- // Note that using stderr on unix means that if you do
- // `ADB_TRACE=all adb start-server`, it will say "ADB server didn't ACK"
- // and "* failed to start daemon *" because the adb server will write
- // logging to stderr, obscuring the OK\n output that is sent to stderr.
#if defined(_WIN32)
- int reply_fd = STDOUT_FILENO;
// Change stdout mode to binary so \n => \r\n translation does not
// occur. In a moment stdout will be reopened to the daemon log file
// anyway.
- _setmode(reply_fd, _O_BINARY);
-#else
- int reply_fd = STDERR_FILENO;
+ _setmode(ack_reply_fd, _O_BINARY);
#endif
- android::base::WriteStringToFd("OK\n", reply_fd);
+ // TODO(danalbert): Can't use SendOkay because we're sending "OK\n", not
+ // "OKAY".
+ android::base::WriteStringToFd("OK\n", ack_reply_fd);
+#if !defined(_WIN32)
+ adb_close(ack_reply_fd);
+#endif
close_stdin();
setup_daemon_logging();
}
@@ -204,7 +195,6 @@
adb_sysdeps_init();
adb_trace_init(argv);
- D("Handling commandline()\n");
return adb_commandline(argc - 1, const_cast<const char**>(argv + 1));
}
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index d7a0c8d..2e182e8 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -954,6 +954,14 @@
int r;
TransportType transport_type = kTransportAny;
+#if defined(_WIN32)
+ // TODO(compareandswap): Windows should use a separate reply fd too.
+ int ack_reply_fd = STDOUT_FILENO;
+#else
+ int ack_reply_fd = -1;
+#endif
+
+
// If defined, this should be an absolute path to
// the directory containing all of the various system images
// for a particular product. If not defined, and the adb
@@ -971,7 +979,7 @@
const char* server_port_str = getenv("ANDROID_ADB_SERVER_PORT");
int server_port = DEFAULT_ADB_PORT;
if (server_port_str && strlen(server_port_str) > 0) {
- server_port = (int) strtol(server_port_str, NULL, 0);
+ server_port = strtol(server_port_str, nullptr, 0);
if (server_port <= 0 || server_port > 65535) {
fprintf(stderr,
"adb: Env var ANDROID_ADB_SERVER_PORT must be a positive number less than 65535. Got \"%s\"\n",
@@ -989,6 +997,16 @@
} else if (!strcmp(argv[0], "fork-server")) {
/* this is a special flag used only when the ADB client launches the ADB Server */
is_daemon = 1;
+ } else if (!strcmp(argv[0], "--reply-fd")) {
+ if (argc < 2) return usage();
+ const char* reply_fd_str = argv[1];
+ argc--;
+ argv++;
+ ack_reply_fd = strtol(reply_fd_str, nullptr, 10);
+ if (ack_reply_fd <= 2) { // Disallow stdin, stdout, and stderr.
+ fprintf(stderr, "adb: invalid reply fd \"%s\"\n", reply_fd_str);
+ return usage();
+ }
} else if (!strncmp(argv[0], "-p", 2)) {
const char* product = nullptr;
if (argv[0][2] == '\0') {
@@ -1066,7 +1084,11 @@
if (is_server) {
if (no_daemon || is_daemon) {
- r = adb_main(is_daemon, server_port);
+ if (ack_reply_fd == -1) {
+ fprintf(stderr, "reply fd for adb server to client communication not specified.\n");
+ return usage();
+ }
+ r = adb_main(is_daemon, server_port, ack_reply_fd);
} else {
r = launch_server(server_port);
}
diff --git a/adb/device.py b/adb/device.py
index b6eaad6..a15675b 100644
--- a/adb/device.py
+++ b/adb/device.py
@@ -170,8 +170,12 @@
out, _ = p.communicate()
return self._parse_shell_output(out)
- def install(self, filename):
- return self._simple_call(['install', filename])
+ def install(self, filename, replace=False):
+ cmd = ['install']
+ if replace:
+ cmd.append('-r')
+ cmd.append(filename)
+ return self._simple_call(cmd)
def push(self, local, remote):
return self._simple_call(['push', local, remote])
diff --git a/adb/mutex_list.h b/adb/mutex_list.h
index ff72751..9003361 100644
--- a/adb/mutex_list.h
+++ b/adb/mutex_list.h
@@ -6,6 +6,7 @@
#ifndef ADB_MUTEX
#error ADB_MUTEX not defined when including this file
#endif
+ADB_MUTEX(dirname_lock)
ADB_MUTEX(socket_list_lock)
ADB_MUTEX(transport_lock)
#if ADB_HOST
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index 08f267b..db552a2 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -90,9 +90,9 @@
std::string SystemErrorCodeToString(const DWORD error_code) {
const int kErrorMessageBufferSize = 256;
- char msgbuf[kErrorMessageBufferSize];
+ WCHAR msgbuf[kErrorMessageBufferSize];
DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
- DWORD len = FormatMessageA(flags, nullptr, error_code, 0, msgbuf,
+ DWORD len = FormatMessageW(flags, nullptr, error_code, 0, msgbuf,
arraysize(msgbuf), nullptr);
if (len == 0) {
return android::base::StringPrintf(
@@ -100,7 +100,8 @@
error_code);
}
- std::string msg(msgbuf);
+ // Convert UTF-16 to UTF-8.
+ std::string msg(narrow(msgbuf));
// Messages returned by the system end with line breaks.
msg = android::base::Trim(msg);
// There are many Windows error messages compared to POSIX, so include the
@@ -202,7 +203,7 @@
static adb_mutex_t _win32_lock;
static FHRec _win32_fhs[ WIN32_MAX_FHS ];
-static int _win32_fh_count;
+static int _win32_fh_next; // where to start search for free FHRec
static FH
_fh_from_int( int fd, const char* func )
@@ -211,7 +212,7 @@
fd -= WIN32_FH_BASE;
- if (fd < 0 || fd >= _win32_fh_count) {
+ if (fd < 0 || fd >= WIN32_MAX_FHS) {
D( "_fh_from_int: invalid fd %d passed to %s\n", fd + WIN32_FH_BASE,
func );
errno = EBADF;
@@ -243,28 +244,32 @@
static FH
_fh_alloc( FHClass clazz )
{
- int nn;
FH f = NULL;
adb_mutex_lock( &_win32_lock );
- if (_win32_fh_count < WIN32_MAX_FHS) {
- f = &_win32_fhs[ _win32_fh_count++ ];
- goto Exit;
- }
-
- for (nn = 0; nn < WIN32_MAX_FHS; nn++) {
- if ( _win32_fhs[nn].clazz == NULL) {
- f = &_win32_fhs[nn];
+ // Search entire array, starting from _win32_fh_next.
+ for (int nn = 0; nn < WIN32_MAX_FHS; nn++) {
+ // Keep incrementing _win32_fh_next to avoid giving out an index that
+ // was recently closed, to try to avoid use-after-free.
+ const int index = _win32_fh_next++;
+ // Handle wrap-around of _win32_fh_next.
+ if (_win32_fh_next == WIN32_MAX_FHS) {
+ _win32_fh_next = 0;
+ }
+ if (_win32_fhs[index].clazz == NULL) {
+ f = &_win32_fhs[index];
goto Exit;
}
}
D( "_fh_alloc: no more free file descriptors\n" );
+ errno = EMFILE; // Too many open files
Exit:
if (f) {
- f->clazz = clazz;
- f->used = 1;
- f->eof = 0;
+ f->clazz = clazz;
+ f->used = 1;
+ f->eof = 0;
+ f->name[0] = '\0';
clazz->_fh_init(f);
}
adb_mutex_unlock( &_win32_lock );
@@ -275,12 +280,17 @@
static int
_fh_close( FH f )
{
- if ( f->used ) {
+ // Use lock so that closing only happens once and so that _fh_alloc can't
+ // allocate a FH that we're in the middle of closing.
+ adb_mutex_lock(&_win32_lock);
+ if (f->used) {
f->clazz->_fh_close( f );
- f->used = 0;
- f->eof = 0;
- f->clazz = NULL;
+ f->name[0] = '\0';
+ f->eof = 0;
+ f->used = 0;
+ f->clazz = NULL;
}
+ adb_mutex_unlock(&_win32_lock);
return 0;
}
@@ -403,7 +413,6 @@
f = _fh_alloc( &_fh_file_class );
if ( !f ) {
- errno = ENOMEM;
return -1;
}
@@ -426,7 +435,8 @@
return -1;
default:
- D( "unknown error: %ld\n", err );
+ D( "unknown error: %s\n",
+ SystemErrorCodeToString( err ).c_str() );
errno = ENOENT;
return -1;
}
@@ -444,7 +454,6 @@
f = _fh_alloc( &_fh_file_class );
if ( !f ) {
- errno = ENOMEM;
return -1;
}
@@ -469,7 +478,8 @@
return -1;
default:
- D( "unknown error: %ld\n", err );
+ D( "unknown error: %s\n",
+ SystemErrorCodeToString( err ).c_str() );
errno = ENOENT;
return -1;
}
@@ -803,6 +813,14 @@
snprintf(port_str, sizeof(port_str), "%d", port);
struct addrinfo* addrinfo_ptr = nullptr;
+
+#if (NTDDI_VERSION >= NTDDI_WINXPSP2) || (_WIN32_WINNT >= _WIN32_WINNT_WS03)
+ // TODO: When the Android SDK tools increases the Windows system
+ // requirements >= WinXP SP2, switch to GetAddrInfoW(widen(host).c_str()).
+#else
+ // Otherwise, keep using getaddrinfo(), or do runtime API detection
+ // with GetProcAddress("GetAddrInfoW").
+#endif
if (getaddrinfo(host.c_str(), port_str, &hints, &addrinfo_ptr) != 0) {
*error = SystemErrorCodeToString(WSAGetLastError());
D("could not resolve host '%s' and port %s: %s\n", host.c_str(),
@@ -2315,7 +2333,7 @@
memset(input_record, 0, sizeof(*input_record));
if (!ReadConsoleInputA(console, input_record, 1, &read_count)) {
D("_get_interesting_input_record_uncached: ReadConsoleInputA() "
- "failure, error %ld\n", GetLastError());
+ "failed: %s\n", SystemErrorCodeToString(GetLastError()).c_str());
errno = EIO;
return false;
}
@@ -3129,8 +3147,8 @@
if (!SetConsoleMode(in, _old_console_mode & ~(ENABLE_PROCESSED_INPUT |
ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT))) {
// This really should not fail.
- D("stdin_raw_init: SetConsoleMode() failure, error %ld\n",
- GetLastError());
+ D("stdin_raw_init: SetConsoleMode() failed: %s\n",
+ SystemErrorCodeToString(GetLastError()).c_str());
}
// Once this is set, it means that stdin has been configured for
@@ -3151,8 +3169,8 @@
if (!SetConsoleMode(in, _old_console_mode)) {
// This really should not fail.
- D("stdin_raw_restore: SetConsoleMode() failure, error %ld\n",
- GetLastError());
+ D("stdin_raw_restore: SetConsoleMode() failed: %s\n",
+ SystemErrorCodeToString(GetLastError()).c_str());
}
}
}
@@ -3237,9 +3255,10 @@
//
// The way to output Unicode to a Win32 console window is to call
// WriteConsoleW() with UTF-16 text. (The user must also choose a proper font
-// such as Lucida Console or Consolas, and in the case of Chinese, must go to
-// the Control Panel and change the "system locale" to Chinese, which allows
-// a Chinese font to be used in console windows.)
+// such as Lucida Console or Consolas, and in the case of East Asian languages
+// (such as Chinese, Japanese, Korean), the user must go to the Control Panel
+// and change the "system locale" to Chinese, etc., which allows a Chinese, etc.
+// font to be used in console windows.)
//
// The problem is getting the C Runtime to make fprintf and related APIs call
// WriteConsoleW() under the covers. The C Runtime API, _setmode() sounds
@@ -3294,6 +3313,10 @@
// any NULL terminator (if you're passing an explicit size, you probably don't
// have a NULL terminated string in the first place).
std::wstring widen(const char* utf8, const int size) {
+ // Note: Do not call SystemErrorCodeToString() from widen() because
+ // SystemErrorCodeToString() calls narrow() which may call fatal() which
+ // calls adb_vfprintf() which calls widen(), potentially causing infinite
+ // recursion.
const int chars_to_convert = MultiByteToWideChar(CP_UTF8, 0, utf8, size,
NULL, 0);
if (chars_to_convert <= 0) {
@@ -3349,11 +3372,14 @@
// Convert from UTF-16 to UTF-8.
std::string narrow(const wchar_t* utf16) {
+ // Note: Do not call SystemErrorCodeToString() from narrow() because
+ // SystemErrorCodeToString() calls narrow() and we don't want potential
+ // infinite recursion.
const int chars_required = WideCharToMultiByte(CP_UTF8, 0, utf16, -1, NULL,
0, NULL, NULL);
if (chars_required <= 0) {
// UTF-16 to UTF-8 should be lossless, so we don't expect this to fail.
- fatal("WideCharToMultiByte failed counting: %d, GetLastError: %d",
+ fatal("WideCharToMultiByte failed counting: %d, GetLastError: %lu",
chars_required, GetLastError());
}
@@ -3371,7 +3397,7 @@
chars_required, NULL, NULL);
if (result != chars_required) {
// UTF-16 to UTF-8 should be lossless, so we don't expect this to fail.
- fatal("WideCharToMultiByte failed conversion: %d, GetLastError: %d",
+ fatal("WideCharToMultiByte failed conversion: %d, GetLastError: %lu",
result, GetLastError());
}
@@ -3707,7 +3733,9 @@
// Shadow UTF-8 environment variable name/value pairs that are created from
// _wenviron the first time that adb_getenv() is called. Note that this is not
-// currently updated if putenv, setenv, unsetenv are called.
+// currently updated if putenv, setenv, unsetenv are called. Note that no
+// thread synchronization is done, but we're called early enough in
+// single-threaded startup that things work ok.
static std::unordered_map<std::string, char*> g_environ_utf8;
// Make sure that shadow UTF-8 environment variables are setup.
@@ -3744,8 +3772,7 @@
char* adb_getenv(const char* name) {
_ensure_env_setup();
- std::unordered_map<std::string, char*>::const_iterator it =
- g_environ_utf8.find(std::string(name));
+ const auto it = g_environ_utf8.find(std::string(name));
if (it == g_environ_utf8.end()) {
return nullptr;
}
diff --git a/adb/test_device.py b/adb/test_device.py
index 81c4a94..48a3f6c 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -333,107 +333,96 @@
def _test_push(self, local_file, checksum):
self.device.shell(['rm', '-rf', self.DEVICE_TEMP_FILE])
- try:
- self.device.push(
- local=local_file, remote=self.DEVICE_TEMP_FILE)
- dev_md5, _ = self.device.shell(
- [get_md5_prog(self.device), self.DEVICE_TEMP_FILE]).split()
- self.assertEqual(checksum, dev_md5)
- finally:
- self.device.shell(['rm', '-f', self.DEVICE_TEMP_FILE])
+ self.device.push(local=local_file, remote=self.DEVICE_TEMP_FILE)
+ dev_md5, _ = self.device.shell([get_md5_prog(self.device),
+ self.DEVICE_TEMP_FILE]).split()
+ self.assertEqual(checksum, dev_md5)
+ self.device.shell(['rm', '-f', self.DEVICE_TEMP_FILE])
def test_push(self):
"""Push a randomly generated file to specified device."""
kbytes = 512
tmp = tempfile.NamedTemporaryFile(mode='wb', delete=False)
- try:
- rand_str = os.urandom(1024 * kbytes)
- tmp.write(rand_str)
- tmp.close()
- self._test_push(tmp.name, compute_md5(rand_str))
- finally:
- os.remove(tmp.name)
+ rand_str = os.urandom(1024 * kbytes)
+ tmp.write(rand_str)
+ tmp.close()
+ self._test_push(tmp.name, compute_md5(rand_str))
+ os.remove(tmp.name)
# TODO: write push directory test.
def _test_pull(self, remote_file, checksum):
tmp_write = tempfile.NamedTemporaryFile(mode='wb', delete=False)
- try:
- tmp_write.close()
- self.device.pull(remote=remote_file, local=tmp_write.name)
- with open(tmp_write.name, 'rb') as tmp_read:
- host_contents = tmp_read.read()
- host_md5 = compute_md5(host_contents)
- self.assertEqual(checksum, host_md5)
- finally:
- os.remove(tmp_write.name)
+ tmp_write.close()
+ self.device.pull(remote=remote_file, local=tmp_write.name)
+ with open(tmp_write.name, 'rb') as tmp_read:
+ host_contents = tmp_read.read()
+ host_md5 = compute_md5(host_contents)
+ self.assertEqual(checksum, host_md5)
+ os.remove(tmp_write.name)
def test_pull(self):
"""Pull a randomly generated file from specified device."""
kbytes = 512
self.device.shell(['rm', '-rf', self.DEVICE_TEMP_FILE])
- try:
- cmd = ['dd', 'if=/dev/urandom',
- 'of={}'.format(self.DEVICE_TEMP_FILE), 'bs=1024',
- 'count={}'.format(kbytes)]
- self.device.shell(cmd)
- dev_md5, _ = self.device.shell(
- [get_md5_prog(self.device), self.DEVICE_TEMP_FILE]).split()
- self._test_pull(self.DEVICE_TEMP_FILE, dev_md5)
- finally:
- self.device.shell_nocheck(['rm', self.DEVICE_TEMP_FILE])
+ cmd = ['dd', 'if=/dev/urandom',
+ 'of={}'.format(self.DEVICE_TEMP_FILE), 'bs=1024',
+ 'count={}'.format(kbytes)]
+ self.device.shell(cmd)
+ dev_md5, _ = self.device.shell(
+ [get_md5_prog(self.device), self.DEVICE_TEMP_FILE]).split()
+ self._test_pull(self.DEVICE_TEMP_FILE, dev_md5)
+ self.device.shell_nocheck(['rm', self.DEVICE_TEMP_FILE])
def test_pull_dir(self):
"""Pull a randomly generated directory of files from the device."""
host_dir = tempfile.mkdtemp()
- try:
- self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
- self.device.shell(['mkdir', '-p', self.DEVICE_TEMP_DIR])
+ self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+ self.device.shell(['mkdir', '-p', self.DEVICE_TEMP_DIR])
- # Populate device directory with random files.
- temp_files = make_random_device_files(
- self.device, in_dir=self.DEVICE_TEMP_DIR, num_files=32)
+ # Populate device directory with random files.
+ temp_files = make_random_device_files(
+ self.device, in_dir=self.DEVICE_TEMP_DIR, num_files=32)
- self.device.pull(remote=self.DEVICE_TEMP_DIR, local=host_dir)
+ self.device.pull(remote=self.DEVICE_TEMP_DIR, local=host_dir)
- for temp_file in temp_files:
- host_path = os.path.join(host_dir, temp_file.base_name)
- with open(host_path, 'rb') as host_file:
- host_md5 = compute_md5(host_file.read())
- self.assertEqual(host_md5, temp_file.checksum)
- finally:
- self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
- if host_dir is not None:
- shutil.rmtree(host_dir)
+ for temp_file in temp_files:
+ host_path = os.path.join(host_dir, temp_file.base_name)
+ with open(host_path, 'rb') as host_file:
+ host_md5 = compute_md5(host_file.read())
+ self.assertEqual(host_md5, temp_file.checksum)
+
+ self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+ if host_dir is not None:
+ shutil.rmtree(host_dir)
def test_sync(self):
"""Sync a randomly generated directory of files to specified device."""
base_dir = tempfile.mkdtemp()
- try:
- # Create mirror device directory hierarchy within base_dir.
- full_dir_path = base_dir + self.DEVICE_TEMP_DIR
- os.makedirs(full_dir_path)
- # Create 32 random files within the host mirror.
- temp_files = make_random_host_files(in_dir=full_dir_path,
- num_files=32)
+ # Create mirror device directory hierarchy within base_dir.
+ full_dir_path = base_dir + self.DEVICE_TEMP_DIR
+ os.makedirs(full_dir_path)
- # Clean up any trash on the device.
- device = adb.get_device(product=base_dir)
- device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+ # Create 32 random files within the host mirror.
+ temp_files = make_random_host_files(in_dir=full_dir_path, num_files=32)
- device.sync('data')
+ # Clean up any trash on the device.
+ device = adb.get_device(product=base_dir)
+ device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
- # Confirm that every file on the device mirrors that on the host.
- for temp_file in temp_files:
- device_full_path = posixpath.join(
- self.DEVICE_TEMP_DIR, temp_file.base_name)
- dev_md5, _ = device.shell(
- [get_md5_prog(self.device), device_full_path]).split()
- self.assertEqual(temp_file.checksum, dev_md5)
- finally:
- self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
- shutil.rmtree(base_dir + self.DEVICE_TEMP_DIR)
+ device.sync('data')
+
+ # Confirm that every file on the device mirrors that on the host.
+ for temp_file in temp_files:
+ device_full_path = posixpath.join(self.DEVICE_TEMP_DIR,
+ temp_file.base_name)
+ dev_md5, _ = device.shell(
+ [get_md5_prog(self.device), device_full_path]).split()
+ self.assertEqual(temp_file.checksum, dev_md5)
+
+ self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+ shutil.rmtree(base_dir + self.DEVICE_TEMP_DIR)
def test_unicode_paths(self):
"""Ensure that we can support non-ASCII paths, even on Windows."""
diff --git a/adb/transport_test.cpp b/adb/transport_test.cpp
index 4b74adf..49deb73 100644
--- a/adb/transport_test.cpp
+++ b/adb/transport_test.cpp
@@ -63,6 +63,27 @@
}
};
+class TransportSetup {
+public:
+ TransportSetup() {
+#ifdef _WIN32
+ // Use extern instead of including sysdeps.h which brings in various macros
+ // that conflict with APIs used in this file.
+ extern void adb_sysdeps_init(void);
+ adb_sysdeps_init();
+#else
+ // adb_sysdeps_init() is an inline function that we cannot link against.
+#endif
+ }
+};
+
+// Static initializer will call adb_sysdeps_init() before main() to initialize
+// the transport mutex before it is used in the tests. Alternatives would be to
+// use __attribute__((constructor)) here or to use that or a static initializer
+// for adb_sysdeps_init() itself in sysdeps_win32.cpp (caveats of unclear
+// init order), or to use a test fixture whose SetUp() could do the init once.
+static TransportSetup g_TransportSetup;
+
TEST(transport, kick_transport) {
TestTransport t;
diff --git a/adb/usb_osx.cpp b/adb/usb_osx.cpp
index af65130..939f319 100644
--- a/adb/usb_osx.cpp
+++ b/adb/usb_osx.cpp
@@ -34,6 +34,10 @@
#define DBG D
+// There's no strerror equivalent for the errors returned by IOKit.
+// https://developer.apple.com/library/mac/documentation/DeviceDrivers/Conceptual/AccessingHardware/AH_Handling_Errors/AH_Handling_Errors.html
+// Search the web for "IOReturn.h" to find a complete up to date list.
+
static IONotificationPortRef notificationPort = 0;
static io_iterator_t notificationIterator;
@@ -362,7 +366,7 @@
handle->zero_mask = maxPacketSize - 1;
} else {
- DBG("ERR: FindDeviceInterface - could not get pipe properties\n");
+ DBG("ERR: FindDeviceInterface - could not get pipe properties (%08x)\n", kr);
goto err_get_pipe_props;
}
}
diff --git a/base/file_test.cpp b/base/file_test.cpp
index 4056684..77b9268 100644
--- a/base/file_test.cpp
+++ b/base/file_test.cpp
@@ -34,17 +34,7 @@
EXPECT_EQ("", s); // s was cleared.
}
-TEST(file, ReadFileToString_success) {
- std::string s("hello");
- ASSERT_TRUE(android::base::ReadFileToString("/proc/version", &s))
- << strerror(errno);
- EXPECT_GT(s.length(), 6U);
- EXPECT_EQ('\n', s[s.length() - 1]);
- s[5] = 0;
- EXPECT_STREQ("Linux", s.c_str());
-}
-
-TEST(file, WriteStringToFile) {
+TEST(file, ReadFileToString_WriteStringToFile) {
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
ASSERT_TRUE(android::base::WriteStringToFile("abc", tf.path))
@@ -88,28 +78,21 @@
EXPECT_EQ("abc", s);
}
-TEST(file, ReadFully) {
- int fd = open("/proc/version", O_RDONLY);
- ASSERT_NE(-1, fd) << strerror(errno);
-
- char buf[1024];
- memset(buf, 0, sizeof(buf));
- ASSERT_TRUE(android::base::ReadFully(fd, buf, 5));
- ASSERT_STREQ("Linux", buf);
-
- ASSERT_EQ(0, lseek(fd, 0, SEEK_SET)) << strerror(errno);
-
- ASSERT_FALSE(android::base::ReadFully(fd, buf, sizeof(buf)));
-
- close(fd);
-}
-
TEST(file, WriteFully) {
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
ASSERT_TRUE(android::base::WriteFully(tf.fd, "abc", 3));
+
+ ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
+
std::string s;
- ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s))
+ s.resize(3);
+ ASSERT_TRUE(android::base::ReadFully(tf.fd, &s[0], s.size()))
<< strerror(errno);
EXPECT_EQ("abc", s);
+
+ ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
+
+ s.resize(1024);
+ ASSERT_FALSE(android::base::ReadFully(tf.fd, &s[0], s.size()));
}
diff --git a/base/include/base/test_utils.h b/base/include/base/test_utils.h
index 83f0f1c..402e0a5 100644
--- a/base/include/base/test_utils.h
+++ b/base/include/base/test_utils.h
@@ -35,7 +35,6 @@
DISALLOW_COPY_AND_ASSIGN(TemporaryFile);
};
-#if !defined(_WIN32)
class TemporaryDir {
public:
TemporaryDir();
@@ -48,6 +47,5 @@
DISALLOW_COPY_AND_ASSIGN(TemporaryDir);
};
-#endif
#endif // TEST_UTILS_H
diff --git a/base/stringprintf_test.cpp b/base/stringprintf_test.cpp
index 54b2b6c..5cc2086 100644
--- a/base/stringprintf_test.cpp
+++ b/base/stringprintf_test.cpp
@@ -20,14 +20,11 @@
#include <string>
-// The z size sepcifier isn't supported on Windows, so this test isn't useful.
-#if !defined(_WIN32)
TEST(StringPrintfTest, HexSizeT) {
size_t size = 0x00107e59;
EXPECT_EQ("00107e59", android::base::StringPrintf("%08zx", size));
EXPECT_EQ("0x00107e59", android::base::StringPrintf("0x%08zx", size));
}
-#endif
TEST(StringPrintfTest, StringAppendF) {
std::string s("a");
diff --git a/base/test_utils.cpp b/base/test_utils.cpp
index dceb8b7..b0c5a12 100644
--- a/base/test_utils.cpp
+++ b/base/test_utils.cpp
@@ -14,7 +14,9 @@
* limitations under the License.
*/
+#include "base/logging.h"
#include "base/test_utils.h"
+#include "utils/Compat.h" // For OS_PATH_SEPARATOR.
#include <fcntl.h>
#include <stdio.h>
@@ -24,17 +26,47 @@
#if defined(_WIN32)
#include <windows.h>
+#include <direct.h>
#endif
#include <string>
+#ifdef _WIN32
+int mkstemp(char* template_name) {
+ if (_mktemp(template_name) == nullptr) {
+ return -1;
+ }
+ // Use open() to match the close() that TemporaryFile's destructor does.
+ // Note that on Windows, this does CR/LF translation and _setmode() should
+ // be used to change that if appropriate.
+ return open(template_name, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR);
+}
+
+char* mkdtemp(char* template_name) {
+ if (_mktemp(template_name) == nullptr) {
+ return nullptr;
+ }
+ if (_mkdir(template_name) == -1) {
+ return nullptr;
+ }
+ return template_name;
+}
+#endif
+
static std::string GetSystemTempDir() {
#if defined(__ANDROID__)
return "/data/local/tmp";
#elif defined(_WIN32)
- char wd[MAX_PATH] = {};
- _getcwd(wd, sizeof(wd));
- return wd;
+ char tmp_dir[MAX_PATH];
+ DWORD result = GetTempPathA(sizeof(tmp_dir), tmp_dir);
+ CHECK_NE(result, 0ul) << "GetTempPathA failed, error: " << GetLastError();
+ CHECK_LT(result, sizeof(tmp_dir)) << "path truncated to: " << result;
+
+ // GetTempPath() returns a path with a trailing slash, but init()
+ // does not expect that, so remove it.
+ CHECK_EQ(tmp_dir[result - 1], '\\');
+ tmp_dir[result - 1] = '\0';
+ return tmp_dir;
#else
return "/tmp";
#endif
@@ -50,21 +82,11 @@
}
void TemporaryFile::init(const std::string& tmp_dir) {
- snprintf(path, sizeof(path), "%s/TemporaryFile-XXXXXX", tmp_dir.c_str());
-#if !defined(_WIN32)
+ snprintf(path, sizeof(path), "%s%cTemporaryFile-XXXXXX", tmp_dir.c_str(),
+ OS_PATH_SEPARATOR);
fd = mkstemp(path);
-#else
- // Windows doesn't have mkstemp, and tmpfile creates the file in the root
- // directory, requiring root (?!) permissions. We have to settle for mktemp.
- if (mktemp(path) == nullptr) {
- abort();
- }
-
- fd = open(path, O_RDWR | O_NOINHERIT | O_CREAT, _S_IREAD | _S_IWRITE);
-#endif
}
-#if !defined(_WIN32)
TemporaryDir::TemporaryDir() {
init(GetSystemTempDir());
}
@@ -74,7 +96,7 @@
}
bool TemporaryDir::init(const std::string& tmp_dir) {
- snprintf(path, sizeof(path), "%s/TemporaryDir-XXXXXX", tmp_dir.c_str());
+ snprintf(path, sizeof(path), "%s%cTemporaryDir-XXXXXX", tmp_dir.c_str(),
+ OS_PATH_SEPARATOR);
return (mkdtemp(path) != nullptr);
}
-#endif
diff --git a/fastboot/usb_osx.cpp b/fastboot/usb_osx.cpp
index a959566..abd6eb9 100644
--- a/fastboot/usb_osx.cpp
+++ b/fastboot/usb_osx.cpp
@@ -75,7 +75,6 @@
HRESULT result;
SInt32 score;
UInt8 interfaceNumEndpoints;
- UInt8 endpoint;
UInt8 configuration;
// Placing the constant KIOUSBFindInterfaceDontCare into the following
@@ -182,7 +181,7 @@
// Iterate over the endpoints for this interface and see if there
// are any that do bulk in/out.
- for (endpoint = 0; endpoint <= interfaceNumEndpoints; endpoint++) {
+ for (UInt8 endpoint = 0; endpoint <= interfaceNumEndpoints; endpoint++) {
UInt8 transferType;
UInt16 maxPacketSize;
UInt8 interval;
@@ -210,7 +209,7 @@
handle->zero_mask = maxPacketSize - 1;
}
} else {
- ERR("could not get pipe properties\n");
+ ERR("could not get pipe properties for endpoint %u (%08x)\n", endpoint, kr);
}
if (handle->info.has_bulk_in && handle->info.has_bulk_out) {
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c
index f467f81..459daec 100644
--- a/fs_mgr/fs_mgr.c
+++ b/fs_mgr/fs_mgr.c
@@ -524,6 +524,14 @@
continue;
}
+ /* Skip mounting the root partition, as it will already have been mounted */
+ if (!strcmp(fstab->recs[i].mount_point, "/")) {
+ if ((fstab->recs[i].fs_mgr_flags & MS_RDONLY) != 0) {
+ fs_mgr_set_blk_ro(fstab->recs[i].blk_device);
+ }
+ continue;
+ }
+
/* Translate LABEL= file system labels into block devices */
if (!strcmp(fstab->recs[i].fs_type, "ext2") ||
!strcmp(fstab->recs[i].fs_type, "ext3") ||
diff --git a/include/utils/Errors.h b/include/utils/Errors.h
index 46173db..9402614 100644
--- a/include/utils/Errors.h
+++ b/include/utils/Errors.h
@@ -58,7 +58,6 @@
ALREADY_EXISTS = -EEXIST,
DEAD_OBJECT = -EPIPE,
FAILED_TRANSACTION = (UNKNOWN_ERROR + 2),
- JPARKS_BROKE_IT = -EPIPE,
#if !defined(HAVE_MS_C_RUNTIME)
BAD_INDEX = -EOVERFLOW,
NOT_ENOUGH_DATA = -ENODATA,
diff --git a/init/perfboot.py b/init/perfboot.py
index 2cd4699..b0efb11 100755
--- a/init/perfboot.py
+++ b/init/perfboot.py
@@ -40,6 +40,7 @@
import argparse
import atexit
import cStringIO
+import glob
import inspect
import logging
import math
@@ -66,6 +67,8 @@
'boot_progress_pms_ready',
'boot_progress_ams_ready',
'boot_progress_enable_screen',
+ 'sf_stop_bootanim',
+ 'wm_boot_animation_done',
]
@@ -139,6 +142,7 @@
def notify_timeout():
self._timedout = True
self._timer = threading.Timer(timeout, notify_timeout)
+ self._timer.daemon = True
self._timer.start()
def is_timedout(self):
@@ -200,11 +204,21 @@
output_results(output, record_list, tags)
if original_dropbox_max_files is not None:
restore_dropbox(device, original_dropbox_max_files)
- except subprocess.CalledProcessError, RuntimeError:
+ except (subprocess.CalledProcessError, RuntimeError):
pass
atexit.register(cleanup)
+def check_dm_verity_settings(device):
+ device.wait()
+ for partition in ['system', 'vendor']:
+ verity_mode = device.get_prop('partition.%s.verified' % partition)
+ if verity_mode is None:
+ logging.warning('dm-verity is not enabled for /%s. Did you run '
+ 'adb disable-verity? That may skew the result.',
+ partition)
+
+
def read_event_tags(tags_file):
"""Reads event tags from |tags_file|."""
if not tags_file:
@@ -226,6 +240,23 @@
'|'.join(tags))
+def filter_event_tags(tags, device):
+ """Drop unknown tags not listed in device's event-log-tags file."""
+ device.wait()
+ supported_tags = set()
+ for l in device.shell(['cat', '/system/etc/event-log-tags']).splitlines():
+ tokens = l.split(' ')
+ if len(tokens) >= 2:
+ supported_tags.add(tokens[1])
+ filtered = []
+ for tag in tags:
+ if tag in supported_tags:
+ filtered.append(tag)
+ else:
+ logging.warning('Unknown tag \'%s\'. Ignoring...', tag)
+ return filtered
+
+
def get_values(record, tag):
"""Gets values that matches |tag| from |record|."""
keys = [key for key in record.keys() if key[0] == tag]
@@ -378,9 +409,17 @@
'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.')
+ parser.add_argument('--apk-dir', help='Specify the directory which contains '
+ 'APK files to be installed before measuring boot time.')
return parser.parse_args()
+def install_apks(device, apk_dir):
+ for apk in glob.glob(os.path.join(apk_dir, '*.apk')):
+ print 'Installing: ' + apk
+ device.install(apk, replace=True)
+
+
def main():
args = parse_args()
if args.verbose:
@@ -393,9 +432,13 @@
args.output = 'perf-%s-%s.tsv' % (
device.get_prop('ro.build.flavor'),
device.get_prop('ro.build.version.incremental'))
+ check_dm_verity_settings(device)
+
+ if args.apk_dir:
+ install_apks(device, args.apk_dir)
record_list = []
- event_tags = read_event_tags(args.tags)
+ event_tags = filter_event_tags(read_event_tags(args.tags), device)
init_perf(device, args.output, record_list, event_tags)
interval_adjuster = IntervalAdjuster(args.interval, device)
event_tags_re = make_event_tags_re(event_tags)
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index d6dad2d..30a2851 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -24,9 +24,18 @@
# Put it here instead of in init.rc module definition,
# because init.rc is conditionally included.
#
-# create some directories (some are mount points)
-LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
- sbin dev proc sys system data oem acct cache config storage mnt root)
+# create some directories (some are mount points) and symlinks
+local_post_install_cmd_base := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
+ sbin dev proc sys system data oem acct cache config storage mnt root); \
+ ln -sf /system/etc $(TARGET_ROOT_OUT)/etc; \
+ ln -sf /sys/kernel/debug $(TARGET_ROOT_OUT)/d; \
+ ln -sf /storage/self/primary $(TARGET_ROOT_OUT)/sdcard
+ifdef BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE
+ LOCAL_POST_INSTALL_CMD := $(local_post_install_cmd_base); mkdir -p $(TARGET_ROOT_OUT)/vendor
+else
+ LOCAL_POST_INSTALL_CMD := $(local_post_install_cmd_base)
+endif
+local_post_install_cmd_base :=
include $(BUILD_SYSTEM)/base_rules.mk