Merge "liblp: Move free-region calculation into a separate function."
diff --git a/adb/Android.bp b/adb/Android.bp
index 9f16c40..00e98fe 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -25,6 +25,7 @@
"-Wvla",
],
rtti: true,
+ cpp_std: "gnu++17",
use_version_lib: true,
@@ -314,6 +315,8 @@
"daemon/auth.cpp",
"daemon/jdwp_service.cpp",
"daemon/usb.cpp",
+ "daemon/usb_ffs.cpp",
+ "daemon/usb_legacy.cpp",
],
local_include_dirs: [
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 62e8908..9c0eeca 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -73,39 +73,6 @@
android::base::GetExecutablePath().c_str());
}
-void fatal(const char *fmt, ...) {
- va_list ap;
- va_start(ap, fmt);
- char buf[1024];
- vsnprintf(buf, sizeof(buf), fmt, ap);
-
-#if ADB_HOST
- fprintf(stderr, "error: %s\n", buf);
-#else
- LOG(ERROR) << "error: " << buf;
-#endif
-
- va_end(ap);
- abort();
-}
-
-void fatal_errno(const char* fmt, ...) {
- int err = errno;
- va_list ap;
- va_start(ap, fmt);
- char buf[1024];
- vsnprintf(buf, sizeof(buf), fmt, ap);
-
-#if ADB_HOST
- fprintf(stderr, "error: %s: %s\n", buf, strerror(err));
-#else
- LOG(ERROR) << "error: " << buf << ": " << strerror(err);
-#endif
-
- va_end(ap);
- abort();
-}
-
uint32_t calculate_apacket_checksum(const apacket* p) {
uint32_t sum = 0;
for (size_t i = 0; i < p->msg.data_length; ++i) {
@@ -118,7 +85,7 @@
{
apacket* p = new apacket();
if (p == nullptr) {
- fatal("failed to allocate an apacket");
+ LOG(FATAL) << "failed to allocate an apacket";
}
memset(&p->msg, 0, sizeof(p->msg));
diff --git a/adb/adb.h b/adb/adb.h
index f434e2d..e2911e8 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -124,9 +124,6 @@
void print_packet(const char* label, apacket* p);
-void fatal(const char* fmt, ...) __attribute__((noreturn, format(__printf__, 1, 2)));
-void fatal_errno(const char* fmt, ...) __attribute__((noreturn, format(__printf__, 1, 2)));
-
void handle_packet(apacket* p, atransport* t);
int launch_server(const std::string& socket_spec);
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index 437720e..bc184c5 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -57,11 +57,11 @@
void close_stdin() {
int fd = unix_open(kNullFileName, O_RDONLY);
if (fd == -1) {
- fatal_errno("failed to open %s", kNullFileName);
+ PLOG(FATAL) << "failed to open " << kNullFileName;
}
if (TEMP_FAILURE_RETRY(dup2(fd, STDIN_FILENO)) == -1) {
- fatal_errno("failed to redirect stdin to %s", kNullFileName);
+ PLOG(FATAL) << "failed to redirect stdin to " << kNullFileName;
}
unix_close(fd);
}
@@ -316,18 +316,6 @@
return android_dir;
}
-int syntax_error(const char* fmt, ...) {
- fprintf(stderr, "adb: usage: ");
-
- va_list ap;
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
-
- fprintf(stderr, "\n");
- return 1;
-}
-
std::string GetLogFilePath() {
#if defined(_WIN32)
const char log_name[] = "adb.log";
@@ -337,13 +325,13 @@
DWORD nchars = GetTempPathW(arraysize(temp_path), temp_path);
if (nchars >= arraysize(temp_path) || nchars == 0) {
// If string truncation or some other error.
- fatal("cannot retrieve temporary file path: %s\n",
- android::base::SystemErrorCodeToString(GetLastError()).c_str());
+ LOG(FATAL) << "cannot retrieve temporary file path: "
+ << android::base::SystemErrorCodeToString(GetLastError());
}
std::string temp_path_utf8;
if (!android::base::WideToUTF8(temp_path, &temp_path_utf8)) {
- fatal_errno("cannot convert temporary file path from UTF-16 to UTF-8");
+ PLOG(FATAL) << "cannot convert temporary file path from UTF-16 to UTF-8";
}
return temp_path_utf8 + log_name;
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index ad83302..442ca2b 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -26,8 +26,6 @@
#include "adb.h"
-int syntax_error(const char*, ...) __attribute__((__format__(__printf__, 1, 2)));
-
void close_stdin();
bool getcwd(std::string* cwd);
diff --git a/adb/client/adb_install.cpp b/adb/client/adb_install.cpp
index d69dbef..e1b75b0 100644
--- a/adb/client/adb_install.cpp
+++ b/adb/client/adb_install.cpp
@@ -134,7 +134,7 @@
// The last argument must be the APK file
const char* file = argv[argc - 1];
if (!android::base::EndsWithIgnoreCase(file, ".apk")) {
- return syntax_error("filename doesn't end .apk: %s", file);
+ error(1, 0, "filename doesn't end .apk: %s", file);
}
if (use_fastdeploy == true) {
@@ -224,7 +224,7 @@
}
}
- if (last_apk == -1) return syntax_error("need APK file on command line");
+ if (last_apk == -1) error(1, 0, "need APK file on command line");
int result = -1;
std::vector<const char*> apk_file = {argv[last_apk]};
@@ -311,7 +311,7 @@
}
if (installMode == INSTALL_STREAM && _use_legacy_install() == true) {
- return syntax_error("Attempting to use streaming install on unsupported deivce.");
+ error(1, 0, "Attempting to use streaming install on unsupported device");
}
if (use_fastdeploy == true && is_reinstall == false) {
@@ -370,7 +370,7 @@
}
}
- if (first_apk == -1) return syntax_error("need APK file on command line");
+ if (first_apk == -1) error(1, 0, "need APK file on command line");
std::string install_cmd;
if (_use_legacy_install()) {
diff --git a/adb/client/bugreport.cpp b/adb/client/bugreport.cpp
index fe98737..83eb157 100644
--- a/adb/client/bugreport.cpp
+++ b/adb/client/bugreport.cpp
@@ -197,7 +197,7 @@
};
int Bugreport::DoIt(int argc, const char** argv) {
- if (argc > 2) return syntax_error("adb bugreport [PATH]");
+ if (argc > 2) error(1, 0, "usage: adb bugreport [PATH]");
// Gets bugreportz version.
std::string bugz_stdout, bugz_stderr;
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index 07b5747..0e03201 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -71,8 +71,7 @@
static std::string product_file(const std::string& file) {
const char* ANDROID_PRODUCT_OUT = getenv("ANDROID_PRODUCT_OUT");
if (ANDROID_PRODUCT_OUT == nullptr) {
- fprintf(stderr, "adb: product directory not specified; set $ANDROID_PRODUCT_OUT\n");
- exit(1);
+ error(1, 0, "product directory not specified; set $ANDROID_PRODUCT_OUT");
}
return std::string{ANDROID_PRODUCT_OUT} + OS_PATH_SEPARATOR_STR + file;
}
@@ -318,7 +317,7 @@
#ifdef _WIN32
old_stdin_mode = _setmode(STDIN_FILENO, _O_BINARY);
if (old_stdin_mode == -1) {
- fatal_errno("could not set stdin to binary");
+ PLOG(FATAL) << "could not set stdin to binary";
}
#endif
}
@@ -327,7 +326,7 @@
if (outFd == STDOUT_FILENO) {
old_stdout_mode = _setmode(STDOUT_FILENO, _O_BINARY);
if (old_stdout_mode == -1) {
- fatal_errno("could not set stdout to binary");
+ PLOG(FATAL) << "could not set stdout to binary";
}
}
#endif
@@ -338,7 +337,7 @@
stdin_raw_restore();
#ifdef _WIN32
if (_setmode(STDIN_FILENO, old_stdin_mode) == -1) {
- fatal_errno("could not restore stdin mode");
+ PLOG(FATAL) << "could not restore stdin mode";
}
#endif
}
@@ -346,7 +345,7 @@
#ifdef _WIN32
if (outFd == STDOUT_FILENO) {
if (_setmode(STDOUT_FILENO, old_stdout_mode) == -1) {
- fatal_errno("could not restore stdout mode");
+ PLOG(FATAL) << "could not restore stdout mode";
}
}
#endif
@@ -660,9 +659,9 @@
static int adb_shell(int argc, const char** argv) {
FeatureSet features;
- std::string error;
- if (!adb_get_feature_set(&features, &error)) {
- fprintf(stderr, "error: %s\n", error.c_str());
+ std::string error_message;
+ if (!adb_get_feature_set(&features, &error_message)) {
+ fprintf(stderr, "error: %s\n", error_message.c_str());
return 1;
}
@@ -685,7 +684,7 @@
switch (opt) {
case 'e':
if (!(strlen(optarg) == 1 || strcmp(optarg, "none") == 0)) {
- return syntax_error("-e requires a single-character argument or 'none'");
+ error(1, 0, "-e requires a single-character argument or 'none'");
}
escape_char = (strcmp(optarg, "none") == 0) ? 0 : optarg[0];
break;
@@ -933,31 +932,29 @@
*/
static int ppp(int argc, const char** argv) {
#if defined(_WIN32)
- fprintf(stderr, "error: adb %s not implemented on Win32\n", argv[0]);
- return -1;
+ error(1, 0, "adb %s not implemented on Win32", argv[0]);
+ __builtin_unreachable();
#else
- if (argc < 2) return syntax_error("adb %s <adb service name> [ppp opts]", argv[0]);
+ if (argc < 2) error(1, 0, "usage: adb %s <adb service name> [ppp opts]", argv[0]);
const char* adb_service_name = argv[1];
- std::string error;
- int fd = adb_connect(adb_service_name, &error);
+ std::string error_message;
+ int fd = adb_connect(adb_service_name, &error_message);
if (fd < 0) {
- fprintf(stderr, "adb: could not open adb service %s: %s\n", adb_service_name, error.c_str());
- return 1;
+ error(1, 0, "could not open adb service %s: %s", adb_service_name, error_message.c_str());
}
pid_t pid = fork();
+ if (pid == -1) {
+ error(1, errno, "fork failed");
+ }
- if (pid < 0) {
- perror("from fork()");
- return 1;
- } else if (pid == 0) {
- int err;
+ if (pid == 0) {
+ // child side
int i;
- const char **ppp_args;
// copy args
- ppp_args = (const char **) alloca(sizeof(char *) * argc + 1);
+ const char** ppp_args = (const char**)alloca(sizeof(char*) * argc + 1);
ppp_args[0] = "pppd";
for (i = 2 ; i < argc ; i++) {
//argv[2] and beyond become ppp_args[1] and beyond
@@ -965,25 +962,18 @@
}
ppp_args[i-1] = nullptr;
- // child side
-
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
adb_close(STDERR_FILENO);
adb_close(fd);
- err = execvp("pppd", (char * const *)ppp_args);
-
- if (err < 0) {
- perror("execing pppd");
- }
- exit(-1);
- } else {
- // parent side
-
- adb_close(fd);
- return 0;
+ execvp("pppd", (char* const*)ppp_args);
+ error(1, errno, "exec pppd failed");
}
+
+ // parent side
+ adb_close(fd);
+ return 0;
#endif /* !defined(_WIN32) */
}
@@ -1161,7 +1151,7 @@
/* find, extract, and use any -f argument */
for (int i = 1; i < argc; i++) {
if (!strcmp("-f", argv[i])) {
- if (i == argc - 1) return syntax_error("backup -f passed with no filename");
+ if (i == argc - 1) error(1, 0, "backup -f passed with no filename");
filename = argv[i+1];
for (int j = i+2; j <= argc; ) {
argv[i++] = argv[j++];
@@ -1173,7 +1163,7 @@
// Bare "adb backup" or "adb backup -f filename" are not valid invocations ---
// a list of packages is required.
- if (argc < 2) return syntax_error("backup either needs a list of packages or -all/-shared");
+ if (argc < 2) error(1, 0, "backup either needs a list of packages or -all/-shared");
adb_unlink(filename);
int outFd = adb_creat(filename, 0640);
@@ -1209,7 +1199,7 @@
}
static int restore(int argc, const char** argv) {
- if (argc != 2) return syntax_error("restore requires an argument");
+ if (argc != 2) error(1, 0, "restore requires an argument");
const char* filename = argv[1];
int tarFd = adb_open(filename, O_RDONLY);
@@ -1263,8 +1253,7 @@
} else if (!strcmp(*arg, "--")) {
ignore_flags = true;
} else {
- syntax_error("unrecognized option '%s'", *arg);
- exit(1);
+ error(1, 0, "unrecognized option '%s'", *arg);
}
}
++arg;
@@ -1342,7 +1331,7 @@
/* this is a special flag used only when the ADB client launches the ADB Server */
is_daemon = true;
} else if (!strcmp(argv[0], "--reply-fd")) {
- if (argc < 2) return syntax_error("--reply-fd requires an argument");
+ if (argc < 2) error(1, 0, "--reply-fd requires an argument");
const char* reply_fd_str = argv[1];
argc--;
argv++;
@@ -1355,7 +1344,7 @@
if (isdigit(argv[0][2])) {
serial = argv[0] + 2;
} else {
- if (argc < 2 || argv[0][2] != '\0') return syntax_error("-s requires an argument");
+ if (argc < 2 || argv[0][2] != '\0') error(1, 0, "-s requires an argument");
serial = argv[1];
argc--;
argv++;
@@ -1371,7 +1360,7 @@
}
transport_id = strtoll(id, const_cast<char**>(&id), 10);
if (*id != '\0') {
- return syntax_error("invalid transport id");
+ error(1, 0, "invalid transport id");
}
} else if (!strcmp(argv[0],"-d")) {
transport_type = kTransportUsb;
@@ -1381,7 +1370,7 @@
gListenAll = 1;
} else if (!strncmp(argv[0], "-H", 2)) {
if (argv[0][2] == '\0') {
- if (argc < 2) return syntax_error("-H requires an argument");
+ if (argc < 2) error(1, 0, "-H requires an argument");
server_host_str = argv[1];
argc--;
argv++;
@@ -1390,7 +1379,7 @@
}
} else if (!strncmp(argv[0], "-P", 2)) {
if (argv[0][2] == '\0') {
- if (argc < 2) return syntax_error("-P requires an argument");
+ if (argc < 2) error(1, 0, "-P requires an argument");
server_port_str = argv[1];
argc--;
argv++;
@@ -1398,7 +1387,7 @@
server_port_str = argv[0] + 2;
}
} else if (!strcmp(argv[0], "-L")) {
- if (argc < 2) return syntax_error("-L requires an argument");
+ if (argc < 2) error(1, 0, "-L requires an argument");
server_socket_str = argv[1];
argc--;
argv++;
@@ -1411,7 +1400,7 @@
}
if ((server_host_str || server_port_str) && server_socket_str) {
- return syntax_error("-L is incompatible with -H or -P");
+ error(1, 0, "-L is incompatible with -H or -P");
}
// If -L, -H, or -P are specified, ignore environment variables.
@@ -1428,11 +1417,10 @@
server_port_str = server_port_str ? server_port_str : getenv("ANDROID_ADB_SERVER_PORT");
if (server_port_str && strlen(server_port_str) > 0) {
if (!android::base::ParseInt(server_port_str, &server_port, 1, 65535)) {
- fprintf(stderr,
- "adb: Env var ANDROID_ADB_SERVER_PORT must be a positive"
- " number less than 65535. Got \"%s\"\n",
- server_port_str);
- exit(1);
+ error(1, 0,
+ "$ANDROID_ADB_SERVER_PORT must be a positive number less than 65535: "
+ "got \"%s\"",
+ server_port_str);
}
}
@@ -1444,7 +1432,7 @@
rc = asprintf(&temp, "tcp:%d", server_port);
}
if (rc < 0) {
- fatal("failed to allocate server socket specification");
+ LOG(FATAL) << "failed to allocate server socket specification";
}
server_socket_str = temp;
}
@@ -1506,7 +1494,7 @@
} else if (argc == 2 && !strcmp(argv[1], "-l")) {
listopt = argv[1];
} else {
- return syntax_error("adb devices [-l]");
+ error(1, 0, "adb devices [-l]");
}
std::string query = android::base::StringPrintf("host:%s%s", argv[0], listopt);
@@ -1514,13 +1502,13 @@
return adb_query_command(query);
}
else if (!strcmp(argv[0], "connect")) {
- if (argc != 2) return syntax_error("adb connect <host>[:<port>]");
+ if (argc != 2) error(1, 0, "usage: adb connect <host>[:<port>]");
std::string query = android::base::StringPrintf("host:connect:%s", argv[1]);
return adb_query_command(query);
}
else if (!strcmp(argv[0], "disconnect")) {
- if (argc > 2) return syntax_error("adb disconnect [<host>[:<port>]]");
+ if (argc > 2) error(1, 0, "usage: adb disconnect [<host>[:<port>]]");
std::string query = android::base::StringPrintf("host:disconnect:%s",
(argc == 2) ? argv[1] : "");
@@ -1535,7 +1523,7 @@
else if (!strcmp(argv[0], "exec-in") || !strcmp(argv[0], "exec-out")) {
int exec_in = !strcmp(argv[0], "exec-in");
- if (argc < 2) return syntax_error("adb %s command", argv[0]);
+ if (argc < 2) error(1, 0, "usage: adb %s command", argv[0]);
std::string cmd = "exec:";
cmd += argv[1];
@@ -1565,17 +1553,17 @@
return adb_kill_server() ? 0 : 1;
}
else if (!strcmp(argv[0], "sideload")) {
- if (argc != 2) return syntax_error("sideload requires an argument");
+ if (argc != 2) error(1, 0, "sideload requires an argument");
if (adb_sideload_host(argv[1])) {
return 1;
} else {
return 0;
}
} else if (!strcmp(argv[0], "tcpip")) {
- if (argc != 2) return syntax_error("tcpip requires an argument");
+ if (argc != 2) error(1, 0, "tcpip requires an argument");
int port;
if (!android::base::ParseInt(argv[1], &port, 1, 65535)) {
- return syntax_error("tcpip: invalid port: %s", argv[1]);
+ error(1, 0, "tcpip: invalid port: %s", argv[1]);
}
return adb_connect_command(android::base::StringPrintf("tcpip:%d", port));
}
@@ -1607,7 +1595,7 @@
} else if (!strcmp(argv[0], "forward") || !strcmp(argv[0], "reverse")) {
bool reverse = !strcmp(argv[0], "reverse");
--argc;
- if (argc < 1) return syntax_error("%s requires an argument", argv[0]);
+ if (argc < 1) error(1, 0, "%s requires an argument", argv[0]);
++argv;
// Determine the <host-prefix> for this command.
@@ -1626,46 +1614,44 @@
}
}
- std::string cmd, error;
+ std::string cmd, error_message;
if (strcmp(argv[0], "--list") == 0) {
- if (argc != 1) return syntax_error("--list doesn't take any arguments");
+ if (argc != 1) error(1, 0, "--list doesn't take any arguments");
return adb_query_command(host_prefix + ":list-forward");
} else if (strcmp(argv[0], "--remove-all") == 0) {
- if (argc != 1) return syntax_error("--remove-all doesn't take any arguments");
+ if (argc != 1) error(1, 0, "--remove-all doesn't take any arguments");
cmd = host_prefix + ":killforward-all";
} else if (strcmp(argv[0], "--remove") == 0) {
// forward --remove <local>
- if (argc != 2) return syntax_error("--remove requires an argument");
+ if (argc != 2) error(1, 0, "--remove requires an argument");
cmd = host_prefix + ":killforward:" + argv[1];
} else if (strcmp(argv[0], "--no-rebind") == 0) {
// forward --no-rebind <local> <remote>
- if (argc != 3) return syntax_error("--no-rebind takes two arguments");
- if (forward_targets_are_valid(argv[1], argv[2], &error)) {
+ if (argc != 3) error(1, 0, "--no-rebind takes two arguments");
+ if (forward_targets_are_valid(argv[1], argv[2], &error_message)) {
cmd = host_prefix + ":forward:norebind:" + argv[1] + ";" + argv[2];
}
} else {
// forward <local> <remote>
- if (argc != 2) return syntax_error("forward takes two arguments");
- if (forward_targets_are_valid(argv[0], argv[1], &error)) {
+ if (argc != 2) error(1, 0, "forward takes two arguments");
+ if (forward_targets_are_valid(argv[0], argv[1], &error_message)) {
cmd = host_prefix + ":forward:" + argv[0] + ";" + argv[1];
}
}
- if (!error.empty()) {
- fprintf(stderr, "error: %s\n", error.c_str());
- return 1;
+ if (!error_message.empty()) {
+ error(1, 0, "error: %s", error_message.c_str());
}
- int fd = adb_connect(cmd, &error);
- if (fd < 0 || !adb_status(fd, &error)) {
+ int fd = adb_connect(cmd, &error_message);
+ if (fd < 0 || !adb_status(fd, &error_message)) {
adb_close(fd);
- fprintf(stderr, "error: %s\n", error.c_str());
- return 1;
+ error(1, 0, "error: %s", error_message.c_str());
}
// Server or device may optionally return a resolved TCP port number.
std::string resolved_port;
- if (ReadProtocolString(fd, &resolved_port, &error) && !resolved_port.empty()) {
+ if (ReadProtocolString(fd, &resolved_port, &error_message) && !resolved_port.empty()) {
printf("%s\n", resolved_port.c_str());
}
@@ -1674,7 +1660,7 @@
}
/* do_sync_*() commands */
else if (!strcmp(argv[0], "ls")) {
- if (argc != 2) return syntax_error("ls requires an argument");
+ if (argc != 2) error(1, 0, "ls requires an argument");
return do_sync_ls(argv[1]) ? 0 : 1;
}
else if (!strcmp(argv[0], "push")) {
@@ -1684,7 +1670,7 @@
const char* dst = nullptr;
parse_push_pull_args(&argv[1], argc - 1, &srcs, &dst, ©_attrs, &sync);
- if (srcs.empty() || !dst) return syntax_error("push requires an argument");
+ if (srcs.empty() || !dst) error(1, 0, "push requires an argument");
return do_sync_push(srcs, dst, sync) ? 0 : 1;
}
else if (!strcmp(argv[0], "pull")) {
@@ -1693,19 +1679,19 @@
const char* dst = ".";
parse_push_pull_args(&argv[1], argc - 1, &srcs, &dst, ©_attrs, nullptr);
- if (srcs.empty()) return syntax_error("pull requires an argument");
+ if (srcs.empty()) error(1, 0, "pull requires an argument");
return do_sync_pull(srcs, dst, copy_attrs) ? 0 : 1;
}
else if (!strcmp(argv[0], "install")) {
- if (argc < 2) return syntax_error("install requires an argument");
+ if (argc < 2) error(1, 0, "install requires an argument");
return install_app(argc, argv);
}
else if (!strcmp(argv[0], "install-multiple")) {
- if (argc < 2) return syntax_error("install-multiple requires an argument");
+ if (argc < 2) error(1, 0, "install-multiple requires an argument");
return install_multiple_app(argc, argv);
}
else if (!strcmp(argv[0], "uninstall")) {
- if (argc < 2) return syntax_error("uninstall requires an argument");
+ if (argc < 2) error(1, 0, "uninstall requires an argument");
return uninstall_app(argc, argv);
}
else if (!strcmp(argv[0], "sync")) {
@@ -1719,7 +1705,7 @@
} else if (argc == 2) {
src = argv[1];
} else {
- return syntax_error("adb sync [-l] [PARTITION]");
+ error(1, 0, "usage: adb sync [-l] [PARTITION]");
}
if (src.empty()) src = "all";
@@ -1734,7 +1720,8 @@
if (!do_sync_sync(src_dir, "/" + partition, list_only)) return 1;
}
}
- return found ? 0 : syntax_error("don't know how to sync %s partition", src.c_str());
+ if (!found) error(1, 0, "don't know how to sync %s partition", src.c_str());
+ return 0;
}
/* passthrough commands */
else if (!strcmp(argv[0],"get-state") ||
@@ -1765,7 +1752,7 @@
return restore(argc, argv);
}
else if (!strcmp(argv[0], "keygen")) {
- if (argc != 2) return syntax_error("keygen requires an argument");
+ if (argc != 2) error(1, 0, "keygen requires an argument");
// Always print key generation information for keygen command.
adb_trace_enable(AUTH);
return adb_auth_keygen(argv[1]);
@@ -1780,7 +1767,7 @@
return adb_connect_command("host:track-devices");
} else if (!strcmp(argv[0], "raw")) {
if (argc != 2) {
- return syntax_error("adb raw SERVICE");
+ error(1, 0, "usage: adb raw SERVICE");
}
return adb_connect_command(argv[1]);
}
@@ -1823,11 +1810,11 @@
std::string err;
return adb_query_command("host:reconnect-offline");
} else {
- return syntax_error("adb reconnect [device|offline]");
+ error(1, 0, "usage: adb reconnect [device|offline]");
}
}
}
- syntax_error("unknown command %s", argv[0]);
- return 1;
+ error(1, 0, "unknown command %s", argv[0]);
+ __builtin_unreachable();
}
diff --git a/adb/client/fastdeploy.cpp b/adb/client/fastdeploy.cpp
index 183a1fa..933b913 100644
--- a/adb/client/fastdeploy.cpp
+++ b/adb/client/fastdeploy.cpp
@@ -27,6 +27,7 @@
#include "client/file_sync_client.h"
#include "commandline.h"
#include "fastdeploycallbacks.h"
+#include "sysdeps.h"
#include "utils/String16.h"
static constexpr long kRequiredAgentVersion = 0x00000001;
@@ -72,13 +73,14 @@
static std::string get_agent_component_host_path(const char* local_path, const char* sdk_path) {
std::string adb_dir = android::base::GetExecutableDirectory();
if (adb_dir.empty()) {
- fatal("Could not determine location of adb!");
+ error(1, 0, "Could not determine location of adb!");
}
if (g_use_localagent) {
const char* product_out = getenv("ANDROID_PRODUCT_OUT");
if (product_out == nullptr) {
- fatal("Could not locate %s because $ANDROID_PRODUCT_OUT is not defined", local_path);
+ error(1, 0, "Could not locate %s because $ANDROID_PRODUCT_OUT is not defined",
+ local_path);
}
return android::base::StringPrintf("%s%s", product_out, local_path);
} else {
@@ -103,10 +105,10 @@
android::base::StringPrintf(kChmodCommandPattern, kDeviceAgentPath);
int ret = send_shell_command(chmodCommand);
if (ret != 0) {
- fatal("Error executing %s returncode: %d", chmodCommand.c_str(), ret);
+ error(1, 0, "Error executing %s returncode: %d", chmodCommand.c_str(), ret);
}
} else {
- fatal("Error pushing agent files to device");
+ error(1, 0, "Error pushing agent files to device");
}
return true;
@@ -136,7 +138,7 @@
agent_version = get_agent_version();
if (agent_version != kRequiredAgentVersion) {
- fatal("After update agent version remains incorrect! Expected %ld but version is %ld",
+ error(1, 0, "After update agent version remains incorrect! Expected %ld but version is %ld",
kRequiredAgentVersion, agent_version);
}
}
@@ -153,26 +155,28 @@
}
static std::string get_packagename_from_apk(const char* apkPath) {
+#undef open
std::unique_ptr<android::ZipFileRO> zipFile(android::ZipFileRO::open(apkPath));
+#define open ___xxx_unix_open
if (zipFile == nullptr) {
- fatal("Could not open %s", apkPath);
+ error(1, errno, "Could not open %s", apkPath);
}
android::ZipEntryRO entry = zipFile->findEntryByName("AndroidManifest.xml");
if (entry == nullptr) {
- fatal("Could not find AndroidManifest.xml inside %s", apkPath);
+ error(1, 0, "Could not find AndroidManifest.xml inside %s", apkPath);
}
uint32_t manifest_len = 0;
if (!zipFile->getEntryInfo(entry, NULL, &manifest_len, NULL, NULL, NULL, NULL)) {
- fatal("Could not read AndroidManifest.xml inside %s", apkPath);
+ error(1, 0, "Could not read AndroidManifest.xml inside %s", apkPath);
}
std::vector<char> manifest_data(manifest_len);
if (!zipFile->uncompressEntry(entry, manifest_data.data(), manifest_len)) {
- fatal("Could not uncompress AndroidManifest.xml inside %s", apkPath);
+ error(1, 0, "Could not uncompress AndroidManifest.xml inside %s", apkPath);
}
android::ResXMLTree tree;
android::status_t setto_status = tree.setTo(manifest_data.data(), manifest_len, true);
if (setto_status != android::OK) {
- fatal("Could not parse AndroidManifest.xml inside %s", apkPath);
+ error(1, 0, "Could not parse AndroidManifest.xml inside %s", apkPath);
}
android::ResXMLParser::event_code_t code;
while ((code = tree.next()) != android::ResXMLParser::BAD_DOCUMENT &&
@@ -213,7 +217,8 @@
break;
}
}
- fatal("Could not find package name tag in AndroidManifest.xml inside %s", apkPath);
+ error(1, 0, "Could not find package name tag in AndroidManifest.xml inside %s", apkPath);
+ __builtin_unreachable();
}
void extract_metadata(const char* apkPath, FILE* outputFp) {
@@ -227,7 +232,7 @@
DeployAgentFileCallback cb(outputFp, &extractErrorBuffer, &statusCode);
int returnCode = send_shell_command(extractCommand, false, &cb);
if (returnCode != 0) {
- fatal("Executing %s returned %d\n", extractCommand.c_str(), returnCode);
+ error(1, 0, "Executing %s returned %d", extractCommand.c_str(), returnCode);
}
}
@@ -236,8 +241,9 @@
// This should never happen on a Windows machine
const char* host_out = getenv("ANDROID_HOST_OUT");
if (host_out == nullptr) {
- fatal("Could not locate deploypatchgenerator.jar because $ANDROID_HOST_OUT is not "
- "defined");
+ error(1, 0,
+ "Could not locate deploypatchgenerator.jar because $ANDROID_HOST_OUT "
+ "is not defined");
}
return android::base::StringPrintf("java -jar %s/framework/deploypatchgenerator.jar",
host_out);
@@ -245,7 +251,7 @@
std::string adb_dir = android::base::GetExecutableDirectory();
if (adb_dir.empty()) {
- fatal("Could not locate deploypatchgenerator.jar");
+ error(1, 0, "Could not locate deploypatchgenerator.jar");
}
return android::base::StringPrintf(R"(java -jar "%s/deploypatchgenerator.jar")",
adb_dir.c_str());
@@ -257,7 +263,7 @@
patchPath);
int returnCode = system(generatePatchCommand.c_str());
if (returnCode != 0) {
- fatal("Executing %s returned %d\n", generatePatchCommand.c_str(), returnCode);
+ error(1, 0, "Executing %s returned %d", generatePatchCommand.c_str(), returnCode);
}
}
@@ -276,7 +282,7 @@
std::vector<const char*> srcs = {patchPath};
bool push_ok = do_sync_push(srcs, patchDevicePath.c_str(), false);
if (!push_ok) {
- fatal("Error pushing %s to %s returned\n", patchPath, patchDevicePath.c_str());
+ error(1, 0, "Error pushing %s to %s returned", patchPath, patchDevicePath.c_str());
}
std::string applyPatchCommand =
@@ -285,7 +291,7 @@
int returnCode = send_shell_command(applyPatchCommand);
if (returnCode != 0) {
- fatal("Executing %s returned %d\n", applyPatchCommand.c_str(), returnCode);
+ error(1, 0, "Executing %s returned %d", applyPatchCommand.c_str(), returnCode);
}
}
@@ -299,7 +305,7 @@
std::vector<const char*> srcs{patchPath};
bool push_ok = do_sync_push(srcs, patchDevicePath.c_str(), false);
if (!push_ok) {
- fatal("Error pushing %s to %s returned\n", patchPath, patchDevicePath.c_str());
+ error(1, 0, "Error pushing %s to %s returned", patchPath, patchDevicePath.c_str());
}
std::vector<unsigned char> applyOutputBuffer;
@@ -316,6 +322,6 @@
patchDevicePath.c_str(), argsString.c_str());
int returnCode = send_shell_command(applyPatchCommand);
if (returnCode != 0) {
- fatal("Executing %s returned %d\n", applyPatchCommand.c_str(), returnCode);
+ error(1, 0, "Executing %s returned %d", applyPatchCommand.c_str(), returnCode);
}
}
diff --git a/adb/client/file_sync_client.cpp b/adb/client/file_sync_client.cpp
index cb9bcfa..697d9ea 100644
--- a/adb/client/file_sync_client.cpp
+++ b/adb/client/file_sync_client.cpp
@@ -325,12 +325,12 @@
memset(st, 0, sizeof(*st));
if (have_stat_v2_) {
if (!ReadFdExactly(fd, &msg.stat_v2, sizeof(msg.stat_v2))) {
- fatal_errno("protocol fault: failed to read stat response");
+ PLOG(FATAL) << "protocol fault: failed to read stat response";
}
if (msg.stat_v2.id != ID_LSTAT_V2 && msg.stat_v2.id != ID_STAT_V2) {
- fatal_errno("protocol fault: stat response has wrong message id: %" PRIx32,
- msg.stat_v2.id);
+ PLOG(FATAL) << "protocol fault: stat response has wrong message id: "
+ << msg.stat_v2.id;
}
if (msg.stat_v2.error != 0) {
@@ -351,12 +351,12 @@
return true;
} else {
if (!ReadFdExactly(fd, &msg.stat_v1, sizeof(msg.stat_v1))) {
- fatal_errno("protocol fault: failed to read stat response");
+ PLOG(FATAL) << "protocol fault: failed to read stat response";
}
if (msg.stat_v1.id != ID_LSTAT_V1) {
- fatal_errno("protocol fault: stat response has wrong message id: %" PRIx32,
- msg.stat_v1.id);
+ PLOG(FATAL) << "protocol fault: stat response has wrong message id: "
+ << msg.stat_v1.id;
}
if (msg.stat_v1.mode == 0 && msg.stat_v1.size == 0 && msg.stat_v1.time == 0) {
diff --git a/adb/client/main.cpp b/adb/client/main.cpp
index a7e454d..fb581a6 100644
--- a/adb/client/main.cpp
+++ b/adb/client/main.cpp
@@ -42,13 +42,13 @@
const std::string log_file_path(GetLogFilePath());
int fd = unix_open(log_file_path.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0640);
if (fd == -1) {
- fatal("cannot open '%s': %s", log_file_path.c_str(), strerror(errno));
+ PLOG(FATAL) << "cannot open " << log_file_path;
}
if (dup2(fd, STDOUT_FILENO) == -1) {
- fatal("cannot redirect stdout: %s", strerror(errno));
+ PLOG(FATAL) << "cannot redirect stdout";
}
if (dup2(fd, STDERR_FILENO) == -1) {
- fatal("cannot redirect stderr: %s", strerror(errno));
+ PLOG(FATAL) << "cannot redirect stderr";
}
unix_close(fd);
@@ -81,10 +81,10 @@
// This also keeps stderr unbuffered when it is redirected to adb.log.
if (is_daemon) {
if (setvbuf(stdout, nullptr, _IONBF, 0) == -1) {
- fatal("cannot make stdout unbuffered: %s", strerror(errno));
+ PLOG(FATAL) << "cannot make stdout unbuffered";
}
if (setvbuf(stderr, nullptr, _IONBF, 0) == -1) {
- fatal("cannot make stderr unbuffered: %s", strerror(errno));
+ PLOG(FATAL) << "cannot make stderr unbuffered";
}
}
@@ -137,7 +137,7 @@
while (install_listener(socket_spec, "*smartsocket*", nullptr, 0, nullptr, &error) !=
INSTALL_STATUS_OK) {
if (std::chrono::steady_clock::now() - start > 0.5s) {
- fatal("could not install *smartsocket* listener: %s", error.c_str());
+ LOG(FATAL) << "could not install *smartsocket* listener: " << error;
}
std::this_thread::sleep_for(100ms);
@@ -153,7 +153,7 @@
// setsid will fail with EPERM if it's already been a lead process of new session.
// Ignore such error.
if (setsid() == -1 && errno != EPERM) {
- fatal("setsid() failed: %s", strerror(errno));
+ PLOG(FATAL) << "setsid() failed";
}
#endif
@@ -171,19 +171,19 @@
const DWORD bytes_to_write = arraysize(ack) - 1;
DWORD written = 0;
if (!WriteFile(ack_reply_handle, ack, bytes_to_write, &written, NULL)) {
- fatal("adb: cannot write ACK to handle 0x%p: %s", ack_reply_handle,
- android::base::SystemErrorCodeToString(GetLastError()).c_str());
+ LOG(FATAL) << "cannot write ACK to handle " << ack_reply_handle
+ << android::base::SystemErrorCodeToString(GetLastError());
}
if (written != bytes_to_write) {
- fatal("adb: cannot write %lu bytes of ACK: only wrote %lu bytes", bytes_to_write,
- written);
+ LOG(FATAL) << "cannot write " << bytes_to_write << " bytes of ACK: only wrote "
+ << written << " bytes";
}
CloseHandle(ack_reply_handle);
#else
// TODO(danalbert): Can't use SendOkay because we're sending "OK\n", not
// "OKAY".
if (!android::base::WriteStringToFd("OK\n", ack_reply_fd)) {
- fatal_errno("error writing ACK to fd %d", ack_reply_fd);
+ PLOG(FATAL) << "error writing ACK to fd " << ack_reply_fd;
}
unix_close(ack_reply_fd);
#endif
diff --git a/adb/client/usb_windows.cpp b/adb/client/usb_windows.cpp
index 00aeb9b..cfa5cf4 100644
--- a/adb/client/usb_windows.cpp
+++ b/adb/client/usb_windows.cpp
@@ -212,8 +212,8 @@
const HINSTANCE instance = GetModuleHandleW(nullptr);
if (!instance) {
// This is such a common API call that this should never fail.
- fatal("GetModuleHandleW failed: %s",
- android::base::SystemErrorCodeToString(GetLastError()).c_str());
+ LOG(FATAL) << "GetModuleHandleW failed: "
+ << android::base::SystemErrorCodeToString(GetLastError());
}
WNDCLASSEXW wndclass;
@@ -223,15 +223,15 @@
wndclass.hInstance = instance;
wndclass.lpszClassName = kPowerNotificationWindowClassName;
if (!RegisterClassExW(&wndclass)) {
- fatal("RegisterClassExW failed: %s",
- android::base::SystemErrorCodeToString(GetLastError()).c_str());
+ LOG(FATAL) << "RegisterClassExW failed: "
+ << android::base::SystemErrorCodeToString(GetLastError());
}
if (!CreateWindowExW(WS_EX_NOACTIVATE, kPowerNotificationWindowClassName,
L"ADB Power Notification Window", WS_POPUP, 0, 0, 0, 0, nullptr, nullptr,
instance, nullptr)) {
- fatal("CreateWindowExW failed: %s",
- android::base::SystemErrorCodeToString(GetLastError()).c_str());
+ LOG(FATAL) << "CreateWindowExW failed: "
+ << android::base::SystemErrorCodeToString(GetLastError());
}
MSG msg;
diff --git a/adb/daemon/framebuffer_service.cpp b/adb/daemon/framebuffer_service.cpp
index 8d28c49..586393e 100644
--- a/adb/daemon/framebuffer_service.cpp
+++ b/adb/daemon/framebuffer_service.cpp
@@ -78,7 +78,7 @@
const char* command = "screencap";
const char *args[2] = {command, nullptr};
execvp(command, (char**)args);
- exit(1);
+ error(1, errno, "exec screencap failed");
}
adb_close(fds[1]);
diff --git a/adb/daemon/include/adbd/usb.h b/adb/daemon/include/adbd/usb.h
index 78e4cd5..3213f69 100644
--- a/adb/daemon/include/adbd/usb.h
+++ b/adb/daemon/include/adbd/usb.h
@@ -62,3 +62,5 @@
};
usb_handle *create_usb_handle(unsigned num_bufs, unsigned io_size);
+bool open_functionfs(android::base::unique_fd* control, android::base::unique_fd* bulk_out,
+ android::base::unique_fd* bulk_in);
diff --git a/adb/daemon/jdwp_service.cpp b/adb/daemon/jdwp_service.cpp
index fe79acd..1363976 100644
--- a/adb/daemon/jdwp_service.cpp
+++ b/adb/daemon/jdwp_service.cpp
@@ -136,7 +136,7 @@
this->fde = fdevent_create(socket, jdwp_process_event, this);
if (!this->fde) {
- fatal("could not create fdevent for new JDWP process");
+ LOG(FATAL) << "could not create fdevent for new JDWP process";
}
/* start by waiting for the PID */
@@ -200,7 +200,7 @@
// Message is length-prefixed with 4 hex digits in ASCII.
static constexpr size_t header_len = 4;
if (bufferlen < header_len) {
- fatal("invalid JDWP process list buffer size: %zu", bufferlen);
+ LOG(FATAL) << "invalid JDWP process list buffer size: " << bufferlen;
}
char head[header_len + 1];
@@ -395,7 +395,7 @@
auto proc = std::make_unique<JdwpProcess>(s);
if (!proc) {
- fatal("failed to allocate JdwpProcess");
+ LOG(FATAL) << "failed to allocate JdwpProcess";
}
_jdwp_list.emplace_back(std::move(proc));
@@ -454,7 +454,7 @@
JdwpSocket* s = new JdwpSocket();
if (!s) {
- fatal("failed to allocate JdwpSocket");
+ LOG(FATAL) << "failed to allocate JdwpSocket";
}
install_local_socket(s);
@@ -531,7 +531,7 @@
asocket* create_jdwp_tracker_service_socket(void) {
auto t = std::make_unique<JdwpTracker>();
if (!t) {
- fatal("failed to allocate JdwpTracker");
+ LOG(FATAL) << "failed to allocate JdwpTracker";
}
memset(t.get(), 0, sizeof(asocket));
diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp
index 9d495b0..f603d13 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (C) 2018 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.
@@ -18,528 +18,568 @@
#include "sysdeps.h"
-#include <dirent.h>
#include <errno.h>
-#include <linux/usb/ch9.h>
-#include <linux/usb/functionfs.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
-#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
-#include <algorithm>
-#include <atomic>
-#include <chrono>
-#include <condition_variable>
+#include <linux/usb/functionfs.h>
+#include <sys/eventfd.h>
+
+#include <array>
+#include <future>
+#include <memory>
#include <mutex>
-#include <thread>
+#include <optional>
+#include <vector>
+
+#include <asyncio/AsyncIO.h>
#include <android-base/logging.h>
+#include <android-base/macros.h>
#include <android-base/properties.h>
+#include <android-base/thread_annotations.h>
-#include "adb.h"
-#include "adbd/usb.h"
+#include <adbd/usb.h>
+
+#include "adb_unique_fd.h"
+#include "adb_utils.h"
+#include "sysdeps/chrono.h"
#include "transport.h"
+#include "types.h"
-using namespace std::chrono_literals;
+using android::base::StringPrintf;
-#define MAX_PACKET_SIZE_FS 64
-#define MAX_PACKET_SIZE_HS 512
-#define MAX_PACKET_SIZE_SS 1024
+static constexpr size_t kUsbReadQueueDepth = 16;
+static constexpr size_t kUsbReadSize = 16384;
-#define USB_FFS_BULK_SIZE 16384
+static constexpr size_t kUsbWriteQueueDepth = 16;
-// Number of buffers needed to fit MAX_PAYLOAD, with an extra for ZLPs.
-#define USB_FFS_NUM_BUFS ((4 * MAX_PAYLOAD / USB_FFS_BULK_SIZE) + 1)
-
-#define cpu_to_le16(x) htole16(x)
-#define cpu_to_le32(x) htole32(x)
-
-static unique_fd& dummy_fd = *new unique_fd();
-
-struct func_desc {
- struct usb_interface_descriptor intf;
- struct usb_endpoint_descriptor_no_audio source;
- 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;
- __le32 length;
- __le32 fs_count;
- __le32 hs_count;
- } __attribute__((packed)) header;
- struct func_desc fs_descs, hs_descs;
-} __attribute__((packed));
-
-struct desc_v2 {
- struct usb_functionfs_descs_head_v2 header;
- // The rest of the structure depends on the flags in the header.
- __le32 fs_count;
- __le32 hs_count;
- __le32 ss_count;
- __le32 os_count;
- struct func_desc fs_descs, hs_descs;
- struct ss_func_desc ss_descs;
- struct usb_os_desc_header os_header;
- struct usb_ext_compat_desc os_desc;
-} __attribute__((packed));
-
-static struct func_desc fs_descriptors = {
- .intf = {
- .bLength = sizeof(fs_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(fs_descriptors.source),
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 1 | USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = MAX_PACKET_SIZE_FS,
- },
- .sink = {
- .bLength = sizeof(fs_descriptors.sink),
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 2 | USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = MAX_PACKET_SIZE_FS,
- },
-};
-
-static struct func_desc hs_descriptors = {
- .intf = {
- .bLength = sizeof(hs_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(hs_descriptors.source),
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 1 | USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = MAX_PACKET_SIZE_HS,
- },
- .sink = {
- .bLength = sizeof(hs_descriptors.sink),
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 2 | USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = MAX_PACKET_SIZE_HS,
- },
-};
-
-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,
- .bMaxBurst = 4,
- },
- .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,
- .bMaxBurst = 4,
- },
-};
-
-struct usb_ext_compat_desc os_desc_compat = {
- .bFirstInterfaceNumber = 0,
- .Reserved1 = cpu_to_le32(1),
- .CompatibleID = {0},
- .SubCompatibleID = {0},
- .Reserved2 = {0},
-};
-
-static struct usb_os_desc_header os_desc_header = {
- .interface = cpu_to_le32(1),
- .dwLength = cpu_to_le32(sizeof(os_desc_header) + sizeof(os_desc_compat)),
- .bcdVersion = cpu_to_le32(1),
- .wIndex = cpu_to_le32(4),
- .bCount = cpu_to_le32(1),
- .Reserved = cpu_to_le32(0),
-};
-
-#define STR_INTERFACE_ "ADB Interface"
-
-static const struct {
- struct usb_functionfs_strings_head header;
- struct {
- __le16 code;
- const char str1[sizeof(STR_INTERFACE_)];
- } __attribute__((packed)) lang0;
-} __attribute__((packed)) strings = {
- .header = {
- .magic = cpu_to_le32(FUNCTIONFS_STRINGS_MAGIC),
- .length = cpu_to_le32(sizeof(strings)),
- .str_count = cpu_to_le32(1),
- .lang_count = cpu_to_le32(1),
- },
- .lang0 = {
- cpu_to_le16(0x0409), /* en-us */
- STR_INTERFACE_,
- },
-};
-
-static void aio_block_init(aio_block* aiob, unsigned num_bufs) {
- aiob->iocb.resize(num_bufs);
- aiob->iocbs.resize(num_bufs);
- aiob->events.resize(num_bufs);
- aiob->num_submitted = 0;
- for (unsigned i = 0; i < num_bufs; i++) {
- aiob->iocbs[i] = &aiob->iocb[i];
- }
- memset(&aiob->ctx, 0, sizeof(aiob->ctx));
- if (io_setup(num_bufs, &aiob->ctx)) {
- D("[ aio: got error on io_setup (%d) ]", errno);
+static const char* to_string(enum usb_functionfs_event_type type) {
+ switch (type) {
+ case FUNCTIONFS_BIND:
+ return "FUNCTIONFS_BIND";
+ case FUNCTIONFS_UNBIND:
+ return "FUNCTIONFS_UNBIND";
+ case FUNCTIONFS_ENABLE:
+ return "FUNCTIONFS_ENABLE";
+ case FUNCTIONFS_DISABLE:
+ return "FUNCTIONFS_DISABLE";
+ case FUNCTIONFS_SETUP:
+ return "FUNCTIONFS_SETUP";
+ case FUNCTIONFS_SUSPEND:
+ return "FUNCTIONFS_SUSPEND";
+ case FUNCTIONFS_RESUME:
+ return "FUNCTIONFS_RESUME";
}
}
-static int getMaxPacketSize(int ffs_fd) {
- usb_endpoint_descriptor desc;
- if (ioctl(ffs_fd, FUNCTIONFS_ENDPOINT_DESC, reinterpret_cast<unsigned long>(&desc))) {
- D("[ could not get endpoint descriptor! (%d) ]", errno);
- return MAX_PACKET_SIZE_HS;
- } else {
- return desc.wMaxPacketSize;
+enum class TransferDirection : uint64_t {
+ READ = 0,
+ WRITE = 1,
+};
+
+struct TransferId {
+ TransferDirection direction : 1;
+ uint64_t id : 63;
+
+ TransferId() : TransferId(TransferDirection::READ, 0) {}
+
+ private:
+ TransferId(TransferDirection direction, uint64_t id) : direction(direction), id(id) {}
+
+ public:
+ explicit operator uint64_t() const {
+ uint64_t result;
+ static_assert(sizeof(*this) == sizeof(result));
+ memcpy(&result, this, sizeof(*this));
+ return result;
}
-}
-static bool init_functionfs(struct usb_handle* h) {
- LOG(INFO) << "initializing functionfs";
+ static TransferId read(uint64_t id) { return TransferId(TransferDirection::READ, id); }
+ static TransferId write(uint64_t id) { return TransferId(TransferDirection::WRITE, id); }
- ssize_t ret;
- struct desc_v1 v1_descriptor;
- struct desc_v2 v2_descriptor;
+ static TransferId from_value(uint64_t value) {
+ TransferId result;
+ memcpy(&result, &value, sizeof(value));
+ return result;
+ }
+};
- 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 |
- FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_MS_OS_DESC;
- v2_descriptor.fs_count = 3;
- v2_descriptor.hs_count = 3;
- v2_descriptor.ss_count = 5;
- v2_descriptor.os_count = 1;
- v2_descriptor.fs_descs = fs_descriptors;
- v2_descriptor.hs_descs = hs_descriptors;
- v2_descriptor.ss_descs = ss_descriptors;
- v2_descriptor.os_header = os_desc_header;
- v2_descriptor.os_desc = os_desc_compat;
+struct IoBlock {
+ bool pending;
+ struct iocb control;
+ Block payload;
- if (h->control < 0) { // might have already done this before
- LOG(INFO) << "opening control endpoint " << USB_FFS_ADB_EP0;
- h->control.reset(adb_open(USB_FFS_ADB_EP0, O_WRONLY));
- if (h->control < 0) {
- PLOG(ERROR) << "cannot open control endpoint " << USB_FFS_ADB_EP0;
- goto err;
+ TransferId id() const { return TransferId::from_value(control.aio_data); }
+};
+
+struct ScopedAioContext {
+ ScopedAioContext() = default;
+ ~ScopedAioContext() { reset(); }
+
+ ScopedAioContext(ScopedAioContext&& move) { reset(move.release()); }
+ ScopedAioContext(const ScopedAioContext& copy) = delete;
+
+ ScopedAioContext& operator=(ScopedAioContext&& move) {
+ reset(move.release());
+ return *this;
+ }
+ ScopedAioContext& operator=(const ScopedAioContext& copy) = delete;
+
+ static ScopedAioContext Create(size_t max_events) {
+ aio_context_t ctx = 0;
+ if (io_setup(max_events, &ctx) != 0) {
+ PLOG(FATAL) << "failed to create aio_context_t";
+ }
+ ScopedAioContext result;
+ result.reset(ctx);
+ return result;
+ }
+
+ aio_context_t release() {
+ aio_context_t result = context_;
+ context_ = 0;
+ return result;
+ }
+
+ void reset(aio_context_t new_context = 0) {
+ if (context_ != 0) {
+ io_destroy(context_);
}
- ret = adb_write(h->control.get(), &v2_descriptor, sizeof(v2_descriptor));
- if (ret < 0) {
- v1_descriptor.header.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC);
- v1_descriptor.header.length = cpu_to_le32(sizeof(v1_descriptor));
- v1_descriptor.header.fs_count = 3;
- v1_descriptor.header.hs_count = 3;
- v1_descriptor.fs_descs = fs_descriptors;
- v1_descriptor.hs_descs = hs_descriptors;
- D("[ %s: Switching to V1_descriptor format errno=%d ]", USB_FFS_ADB_EP0, errno);
- ret = adb_write(h->control.get(), &v1_descriptor, sizeof(v1_descriptor));
- if (ret < 0) {
- D("[ %s: write descriptors failed: errno=%d ]", USB_FFS_ADB_EP0, errno);
- goto err;
+ context_ = new_context;
+ }
+
+ aio_context_t get() { return context_; }
+
+ private:
+ aio_context_t context_ = 0;
+};
+
+struct UsbFfsConnection : public Connection {
+ UsbFfsConnection(unique_fd control, unique_fd read, unique_fd write,
+ std::promise<void> destruction_notifier)
+ : stopped_(false),
+ destruction_notifier_(std::move(destruction_notifier)),
+ control_fd_(std::move(control)),
+ read_fd_(std::move(read)),
+ write_fd_(std::move(write)) {
+ LOG(INFO) << "UsbFfsConnection constructed";
+ event_fd_.reset(eventfd(0, EFD_CLOEXEC));
+ if (event_fd_ == -1) {
+ PLOG(FATAL) << "failed to create eventfd";
+ }
+
+ aio_context_ = ScopedAioContext::Create(kUsbReadQueueDepth + kUsbWriteQueueDepth);
+ }
+
+ ~UsbFfsConnection() {
+ LOG(INFO) << "UsbFfsConnection being destroyed";
+ Stop();
+ monitor_thread_.join();
+ destruction_notifier_.set_value();
+ }
+
+ virtual bool Write(std::unique_ptr<apacket> packet) override final {
+ LOG(DEBUG) << "USB write: " << dump_header(&packet->msg);
+ Block header(sizeof(packet->msg));
+ memcpy(header.data(), &packet->msg, sizeof(packet->msg));
+
+ std::lock_guard<std::mutex> lock(write_mutex_);
+ write_requests_.push_back(CreateWriteBlock(std::move(header), next_write_id_++));
+ if (!packet->payload.empty()) {
+ write_requests_.push_back(
+ CreateWriteBlock(std::move(packet->payload), next_write_id_++));
+ }
+ SubmitWrites();
+ return true;
+ }
+
+ virtual void Start() override final { StartMonitor(); }
+
+ virtual void Stop() override final {
+ if (stopped_.exchange(true)) {
+ return;
+ }
+ stopped_ = true;
+ uint64_t notify = 1;
+ ssize_t rc = adb_write(event_fd_.get(), ¬ify, sizeof(notify));
+ if (rc < 0) {
+ PLOG(FATAL) << "failed to notify eventfd to stop UsbFfsConnection";
+ }
+ CHECK_EQ(static_cast<size_t>(rc), sizeof(notify));
+ }
+
+ private:
+ void StartMonitor() {
+ // This is a bit of a mess.
+ // It's possible for io_submit to end up blocking, if we call it as the endpoint
+ // becomes disabled. Work around this by having a monitor thread to listen for functionfs
+ // lifecycle events. If we notice an error condition (either we've become disabled, or we
+ // were never enabled in the first place), we send interruption signals to the worker thread
+ // until it dies, and then report failure to the transport via HandleError, which will
+ // eventually result in the transport being destroyed, which will result in UsbFfsConnection
+ // being destroyed, which unblocks the open thread and restarts this entire process.
+ static constexpr int kInterruptionSignal = SIGUSR1;
+ static std::once_flag handler_once;
+ std::call_once(handler_once, []() { signal(kInterruptionSignal, [](int) {}); });
+
+ monitor_thread_ = std::thread([this]() {
+ adb_thread_setname("UsbFfs-monitor");
+
+ bool bound = false;
+ bool started = false;
+ bool running = true;
+ while (running) {
+ if (!bound || !started) {
+ adb_pollfd pfd = {.fd = control_fd_.get(), .events = POLLIN, .revents = 0};
+ int rc = TEMP_FAILURE_RETRY(adb_poll(&pfd, 1, 5000 /*ms*/));
+ if (rc == -1) {
+ PLOG(FATAL) << "poll on USB control fd failed";
+ } else if (rc == 0) {
+ // Something in the kernel presumably went wrong.
+ // Close our endpoints, wait for a bit, and then try again.
+ aio_context_.reset();
+ read_fd_.reset();
+ write_fd_.reset();
+ control_fd_.reset();
+ std::this_thread::sleep_for(5s);
+ HandleError("didn't receive FUNCTIONFS_ENABLE, retrying");
+ return;
+ }
+ }
+
+ struct usb_functionfs_event event;
+ if (TEMP_FAILURE_RETRY(adb_read(control_fd_.get(), &event, sizeof(event))) !=
+ sizeof(event)) {
+ PLOG(FATAL) << "failed to read functionfs event";
+ }
+
+ LOG(INFO) << "USB event: "
+ << to_string(static_cast<usb_functionfs_event_type>(event.type));
+
+ switch (event.type) {
+ case FUNCTIONFS_BIND:
+ CHECK(!started) << "received FUNCTIONFS_ENABLE while already bound?";
+ bound = true;
+ break;
+
+ case FUNCTIONFS_ENABLE:
+ CHECK(!started) << "received FUNCTIONFS_ENABLE while already running?";
+ started = true;
+ StartWorker();
+ break;
+
+ case FUNCTIONFS_DISABLE:
+ running = false;
+ break;
+ }
+ }
+
+ pthread_t worker_thread_handle = worker_thread_.native_handle();
+ while (true) {
+ int rc = pthread_kill(worker_thread_handle, kInterruptionSignal);
+ if (rc != 0) {
+ LOG(ERROR) << "failed to send interruption signal to worker: " << strerror(rc);
+ break;
+ }
+
+ std::this_thread::sleep_for(100ms);
+
+ rc = pthread_kill(worker_thread_handle, 0);
+ if (rc == 0) {
+ continue;
+ } else if (rc == ESRCH) {
+ break;
+ } else {
+ LOG(ERROR) << "failed to send interruption signal to worker: " << strerror(rc);
+ }
+ }
+
+ worker_thread_.join();
+
+ aio_context_.reset();
+ read_fd_.reset();
+ write_fd_.reset();
+ });
+ }
+
+ void StartWorker() {
+ worker_thread_ = std::thread([this]() {
+ adb_thread_setname("UsbFfs-worker");
+ for (size_t i = 0; i < kUsbReadQueueDepth; ++i) {
+ read_requests_[i] = CreateReadBlock(next_read_id_++);
+ SubmitRead(&read_requests_[i]);
+ }
+
+ while (!stopped_) {
+ uint64_t dummy;
+ ssize_t rc = adb_read(event_fd_.get(), &dummy, sizeof(dummy));
+ if (rc == -1) {
+ PLOG(FATAL) << "failed to read from eventfd";
+ } else if (rc == 0) {
+ LOG(FATAL) << "hit EOF on eventfd";
+ }
+
+ WaitForEvents();
+ }
+ });
+ }
+
+ void PrepareReadBlock(IoBlock* block, uint64_t id) {
+ block->pending = false;
+ block->payload.resize(kUsbReadSize);
+ block->control.aio_data = static_cast<uint64_t>(TransferId::read(id));
+ block->control.aio_buf = reinterpret_cast<uintptr_t>(block->payload.data());
+ block->control.aio_nbytes = block->payload.size();
+ }
+
+ IoBlock CreateReadBlock(uint64_t id) {
+ IoBlock block;
+ PrepareReadBlock(&block, id);
+ block.control.aio_rw_flags = 0;
+ block.control.aio_lio_opcode = IOCB_CMD_PREAD;
+ block.control.aio_reqprio = 0;
+ block.control.aio_fildes = read_fd_.get();
+ block.control.aio_offset = 0;
+ block.control.aio_flags = IOCB_FLAG_RESFD;
+ block.control.aio_resfd = event_fd_.get();
+ return block;
+ }
+
+ void WaitForEvents() {
+ static constexpr size_t kMaxEvents = kUsbReadQueueDepth + kUsbWriteQueueDepth;
+ struct io_event events[kMaxEvents];
+ struct timespec timeout = {.tv_sec = 0, .tv_nsec = 0};
+ int rc = io_getevents(aio_context_.get(), 0, kMaxEvents, events, &timeout);
+ if (rc == -1) {
+ HandleError(StringPrintf("io_getevents failed while reading: %s", strerror(errno)));
+ return;
+ }
+
+ for (int event_idx = 0; event_idx < rc; ++event_idx) {
+ auto& event = events[event_idx];
+ TransferId id = TransferId::from_value(event.data);
+
+ if (event.res < 0) {
+ std::string error =
+ StringPrintf("%s %" PRIu64 " failed with error %s",
+ id.direction == TransferDirection::READ ? "read" : "write",
+ id.id, strerror(-event.res));
+ HandleError(error);
+ return;
+ }
+
+ if (id.direction == TransferDirection::READ) {
+ HandleRead(id, event.res);
+ } else {
+ HandleWrite(id);
+ }
+ }
+ }
+
+ void HandleRead(TransferId id, int64_t size) {
+ uint64_t read_idx = id.id % kUsbReadQueueDepth;
+ IoBlock* block = &read_requests_[read_idx];
+ block->pending = false;
+ block->payload.resize(size);
+
+ // Notification for completed reads can be received out of order.
+ if (block->id().id != needed_read_id_) {
+ LOG(VERBOSE) << "read " << block->id().id << " completed while waiting for "
+ << needed_read_id_;
+ return;
+ }
+
+ for (uint64_t id = needed_read_id_;; ++id) {
+ size_t read_idx = id % kUsbReadQueueDepth;
+ IoBlock* current_block = &read_requests_[read_idx];
+ if (current_block->pending) {
+ break;
+ }
+ ProcessRead(current_block);
+ ++needed_read_id_;
+ }
+ }
+
+ void ProcessRead(IoBlock* block) {
+ if (!block->payload.empty()) {
+ if (!incoming_header_.has_value()) {
+ CHECK_EQ(sizeof(amessage), block->payload.size());
+ amessage msg;
+ memcpy(&msg, block->payload.data(), sizeof(amessage));
+ LOG(DEBUG) << "USB read:" << dump_header(&msg);
+ incoming_header_ = msg;
+ } else {
+ size_t bytes_left = incoming_header_->data_length - incoming_payload_.size();
+ Block payload = std::move(block->payload);
+ CHECK_LE(payload.size(), bytes_left);
+ incoming_payload_.append(std::make_unique<Block>(std::move(payload)));
+ }
+
+ if (incoming_header_->data_length == incoming_payload_.size()) {
+ auto packet = std::make_unique<apacket>();
+ packet->msg = *incoming_header_;
+
+ // TODO: Make apacket contain an IOVector so we don't have to coalesce.
+ packet->payload = incoming_payload_.coalesce();
+ read_callback_(this, std::move(packet));
+
+ incoming_header_.reset();
+ incoming_payload_.clear();
}
}
- ret = adb_write(h->control.get(), &strings, sizeof(strings));
- if (ret < 0) {
- D("[ %s: writing strings failed: errno=%d]", USB_FFS_ADB_EP0, errno);
- goto err;
+ PrepareReadBlock(block, block->id().id + kUsbReadQueueDepth);
+ SubmitRead(block);
+ }
+
+ void SubmitRead(IoBlock* block) {
+ block->pending = true;
+ struct iocb* iocb = &block->control;
+ if (io_submit(aio_context_.get(), 1, &iocb) != 1) {
+ HandleError(StringPrintf("failed to submit read: %s", strerror(errno)));
+ return;
}
- //Signal only when writing the descriptors to ffs
- android::base::SetProperty("sys.usb.ffs.ready", "1");
}
- h->bulk_out.reset(adb_open(USB_FFS_ADB_OUT, O_RDONLY));
- if (h->bulk_out < 0) {
- PLOG(ERROR) << "cannot open bulk-out endpoint " << USB_FFS_ADB_OUT;
- goto err;
+ void HandleWrite(TransferId id) {
+ std::lock_guard<std::mutex> lock(write_mutex_);
+ auto it =
+ std::find_if(write_requests_.begin(), write_requests_.end(), [id](const auto& req) {
+ return static_cast<uint64_t>(req->id()) == static_cast<uint64_t>(id);
+ });
+ CHECK(it != write_requests_.end());
+
+ write_requests_.erase(it);
+ size_t outstanding_writes = --writes_submitted_;
+ LOG(DEBUG) << "USB write: reaped, down to " << outstanding_writes;
+
+ SubmitWrites();
}
- h->bulk_in.reset(adb_open(USB_FFS_ADB_IN, O_WRONLY));
- if (h->bulk_in < 0) {
- PLOG(ERROR) << "cannot open bulk-in endpoint " << USB_FFS_ADB_IN;
- goto err;
+ std::unique_ptr<IoBlock> CreateWriteBlock(Block payload, uint64_t id) {
+ auto block = std::make_unique<IoBlock>();
+ block->payload = std::move(payload);
+ block->control.aio_data = static_cast<uint64_t>(TransferId::write(id));
+ block->control.aio_rw_flags = 0;
+ block->control.aio_lio_opcode = IOCB_CMD_PWRITE;
+ block->control.aio_reqprio = 0;
+ block->control.aio_fildes = write_fd_.get();
+ block->control.aio_buf = reinterpret_cast<uintptr_t>(block->payload.data());
+ block->control.aio_nbytes = block->payload.size();
+ block->control.aio_offset = 0;
+ block->control.aio_flags = IOCB_FLAG_RESFD;
+ block->control.aio_resfd = event_fd_.get();
+ return block;
}
- h->read_aiob.fd = h->bulk_out;
- h->write_aiob.fd = h->bulk_in;
- h->reads_zero_packets = true;
- return true;
+ void SubmitWrites() REQUIRES(write_mutex_) {
+ if (writes_submitted_ == kUsbWriteQueueDepth) {
+ return;
+ }
-err:
- h->bulk_in.reset();
- h->bulk_out.reset();
- h->control.reset();
- return false;
-}
+ ssize_t writes_to_submit = std::min(kUsbWriteQueueDepth - writes_submitted_,
+ write_requests_.size() - writes_submitted_);
+ CHECK_GE(writes_to_submit, 0);
+ if (writes_to_submit == 0) {
+ return;
+ }
-static void usb_ffs_open_thread(usb_handle *usb) {
+ struct iocb* iocbs[kUsbWriteQueueDepth];
+ for (int i = 0; i < writes_to_submit; ++i) {
+ CHECK(!write_requests_[writes_submitted_ + i]->pending);
+ write_requests_[writes_submitted_ + i]->pending = true;
+ iocbs[i] = &write_requests_[writes_submitted_ + i]->control;
+ LOG(VERBOSE) << "submitting write_request " << static_cast<void*>(iocbs[i]);
+ }
+
+ int rc = io_submit(aio_context_.get(), writes_to_submit, iocbs);
+ if (rc == -1) {
+ HandleError(StringPrintf("failed to submit write requests: %s", strerror(errno)));
+ return;
+ } else if (rc != writes_to_submit) {
+ LOG(FATAL) << "failed to submit all writes: wanted to submit " << writes_to_submit
+ << ", actually submitted " << rc;
+ }
+
+ writes_submitted_ += rc;
+ }
+
+ void HandleError(const std::string& error) {
+ std::call_once(error_flag_, [&]() {
+ error_callback_(this, error);
+ if (!stopped_) {
+ Stop();
+ }
+ });
+ }
+
+ std::thread monitor_thread_;
+ std::thread worker_thread_;
+
+ std::atomic<bool> stopped_;
+ std::promise<void> destruction_notifier_;
+ std::once_flag error_flag_;
+
+ unique_fd event_fd_;
+
+ ScopedAioContext aio_context_;
+ unique_fd control_fd_;
+ unique_fd read_fd_;
+ unique_fd write_fd_;
+
+ std::optional<amessage> incoming_header_;
+ IOVector incoming_payload_;
+
+ std::array<IoBlock, kUsbReadQueueDepth> read_requests_;
+ IOVector read_data_;
+
+ // ID of the next request that we're going to send out.
+ size_t next_read_id_ = 0;
+
+ // ID of the next packet we're waiting for.
+ size_t needed_read_id_ = 0;
+
+ std::mutex write_mutex_;
+ std::deque<std::unique_ptr<IoBlock>> write_requests_ GUARDED_BY(write_mutex_);
+ size_t next_write_id_ GUARDED_BY(write_mutex_) = 0;
+ size_t writes_submitted_ GUARDED_BY(write_mutex_) = 0;
+};
+
+static void usb_ffs_open_thread() {
adb_thread_setname("usb ffs open");
while (true) {
- // wait until the USB device needs opening
- std::unique_lock<std::mutex> lock(usb->lock);
- while (!usb->open_new_connection) {
- usb->notify.wait(lock);
- }
- usb->open_new_connection = false;
- lock.unlock();
-
- while (true) {
- if (init_functionfs(usb)) {
- LOG(INFO) << "functionfs successfully initialized";
- break;
- }
+ unique_fd control;
+ unique_fd bulk_out;
+ unique_fd bulk_in;
+ if (!open_functionfs(&control, &bulk_out, &bulk_in)) {
std::this_thread::sleep_for(1s);
- }
-
- LOG(INFO) << "registering usb transport";
- register_usb_transport(usb, nullptr, nullptr, 1);
- }
-
- // never gets here
- abort();
-}
-
-static int usb_ffs_write(usb_handle* h, const void* data, int len) {
- D("about to write (fd=%d, len=%d)", h->bulk_in.get(), len);
-
- const char* buf = static_cast<const char*>(data);
- int orig_len = len;
- while (len > 0) {
- int write_len = std::min(USB_FFS_BULK_SIZE, len);
- int n = adb_write(h->bulk_in, buf, write_len);
- if (n < 0) {
- D("ERROR: fd = %d, n = %d: %s", h->bulk_in.get(), n, strerror(errno));
- return -1;
- }
- buf += n;
- len -= n;
- }
-
- D("[ done fd=%d ]", h->bulk_in.get());
- return orig_len;
-}
-
-static int usb_ffs_read(usb_handle* h, void* data, int len) {
- D("about to read (fd=%d, len=%d)", h->bulk_out.get(), len);
-
- char* buf = static_cast<char*>(data);
- int orig_len = len;
- while (len > 0) {
- int read_len = std::min(USB_FFS_BULK_SIZE, len);
- int n = adb_read(h->bulk_out, buf, read_len);
- if (n < 0) {
- D("ERROR: fd = %d, n = %d: %s", h->bulk_out.get(), n, strerror(errno));
- return -1;
- }
- buf += n;
- len -= n;
- }
-
- D("[ done fd=%d ]", h->bulk_out.get());
- return orig_len;
-}
-
-static int usb_ffs_do_aio(usb_handle* h, const void* data, int len, bool read) {
- aio_block* aiob = read ? &h->read_aiob : &h->write_aiob;
- bool zero_packet = false;
-
- int num_bufs = len / h->io_size + (len % h->io_size == 0 ? 0 : 1);
- const char* cur_data = reinterpret_cast<const char*>(data);
- int packet_size = getMaxPacketSize(aiob->fd);
-
- if (posix_madvise(const_cast<void*>(data), len, POSIX_MADV_SEQUENTIAL | POSIX_MADV_WILLNEED) <
- 0) {
- D("[ Failed to madvise: %d ]", errno);
- }
-
- for (int i = 0; i < num_bufs; i++) {
- int buf_len = std::min(len, static_cast<int>(h->io_size));
- io_prep(&aiob->iocb[i], aiob->fd, cur_data, buf_len, 0, read);
-
- len -= buf_len;
- cur_data += buf_len;
-
- if (len == 0 && buf_len % packet_size == 0 && read) {
- // adb does not expect the device to send a zero packet after data transfer,
- // but the host *does* send a zero packet for the device to read.
- zero_packet = h->reads_zero_packets;
- }
- }
- if (zero_packet) {
- io_prep(&aiob->iocb[num_bufs], aiob->fd, reinterpret_cast<const void*>(cur_data),
- packet_size, 0, read);
- num_bufs += 1;
- }
-
- while (true) {
- if (TEMP_FAILURE_RETRY(io_submit(aiob->ctx, num_bufs, aiob->iocbs.data())) < num_bufs) {
- PLOG(ERROR) << "aio: got error submitting " << (read ? "read" : "write");
- return -1;
- }
- if (TEMP_FAILURE_RETRY(io_getevents(aiob->ctx, num_bufs, num_bufs, aiob->events.data(),
- nullptr)) < num_bufs) {
- PLOG(ERROR) << "aio: got error waiting " << (read ? "read" : "write");
- return -1;
- }
- if (num_bufs == 1 && aiob->events[0].res == -EINTR) {
continue;
}
- int ret = 0;
- for (int i = 0; i < num_bufs; i++) {
- if (aiob->events[i].res < 0) {
- errno = -aiob->events[i].res;
- PLOG(ERROR) << "aio: got error event on " << (read ? "read" : "write")
- << " total bufs " << num_bufs;
- return -1;
- }
- ret += aiob->events[i].res;
- }
- return ret;
+
+ atransport* transport = new atransport();
+ transport->serial = "UsbFfs";
+ std::promise<void> destruction_notifier;
+ std::future<void> future = destruction_notifier.get_future();
+ transport->SetConnection(std::make_unique<UsbFfsConnection>(
+ std::move(control), std::move(bulk_out), std::move(bulk_in),
+ std::move(destruction_notifier)));
+ register_transport(transport);
+ future.wait();
}
}
-static int usb_ffs_aio_read(usb_handle* h, void* data, int len) {
- return usb_ffs_do_aio(h, data, len, true);
-}
-
-static int usb_ffs_aio_write(usb_handle* h, const void* data, int len) {
- return usb_ffs_do_aio(h, data, len, false);
-}
-
-static void usb_ffs_kick(usb_handle* h) {
- int err;
-
- err = ioctl(h->bulk_in.get(), FUNCTIONFS_CLEAR_HALT);
- if (err < 0) {
- D("[ kick: source (fd=%d) clear halt failed (%d) ]", h->bulk_in.get(), errno);
- }
-
- err = ioctl(h->bulk_out.get(), FUNCTIONFS_CLEAR_HALT);
- if (err < 0) {
- D("[ kick: sink (fd=%d) clear halt failed (%d) ]", h->bulk_out.get(), errno);
- }
-
- // don't close ep0 here, since we may not need to reinitialize it with
- // the same descriptors again. if however ep1/ep2 fail to re-open in
- // init_functionfs, only then would we close and open ep0 again.
- // Ditto the comment in usb_adb_kick.
- h->kicked = true;
- TEMP_FAILURE_RETRY(dup2(dummy_fd.get(), h->bulk_out.get()));
- TEMP_FAILURE_RETRY(dup2(dummy_fd.get(), h->bulk_in.get()));
-}
-
-static void usb_ffs_close(usb_handle* h) {
- LOG(INFO) << "closing functionfs transport";
-
- h->kicked = false;
- h->bulk_out.reset();
- h->bulk_in.reset();
-
- // Notify usb_adb_open_thread to open a new connection.
- h->lock.lock();
- h->open_new_connection = true;
- h->lock.unlock();
- h->notify.notify_one();
-}
-
-usb_handle *create_usb_handle(unsigned num_bufs, unsigned io_size) {
- usb_handle* h = new usb_handle();
-
- if (android::base::GetBoolProperty("sys.usb.ffs.aio_compat", false)) {
- // Devices on older kernels (< 3.18) will not have aio support for ffs
- // unless backported. Fall back on the non-aio functions instead.
- h->write = usb_ffs_write;
- h->read = usb_ffs_read;
- } else {
- h->write = usb_ffs_aio_write;
- h->read = usb_ffs_aio_read;
- aio_block_init(&h->read_aiob, num_bufs);
- aio_block_init(&h->write_aiob, num_bufs);
- }
- h->io_size = io_size;
- h->kick = usb_ffs_kick;
- h->close = usb_ffs_close;
- return h;
-}
-
+void usb_init_legacy();
void usb_init() {
- D("[ usb_init - using FunctionFS ]");
- dummy_fd.reset(adb_open("/dev/null", O_WRONLY | O_CLOEXEC));
- CHECK_NE(-1, dummy_fd.get());
-
- std::thread(usb_ffs_open_thread, create_usb_handle(USB_FFS_NUM_BUFS, USB_FFS_BULK_SIZE)).detach();
-}
-
-int usb_write(usb_handle* h, const void* data, int len) {
- return h->write(h, data, len);
-}
-
-int usb_read(usb_handle* h, void* data, int len) {
- return h->read(h, data, len);
-}
-
-int usb_close(usb_handle* h) {
- h->close(h);
- return 0;
-}
-
-void usb_kick(usb_handle* h) {
- h->kick(h);
+ if (!android::base::GetBoolProperty("persist.adb.nonblocking_ffs", false)) {
+ usb_init_legacy();
+ } else {
+ std::thread(usb_ffs_open_thread).detach();
+ }
}
diff --git a/adb/daemon/usb_ffs.cpp b/adb/daemon/usb_ffs.cpp
new file mode 100644
index 0000000..07b4ba8
--- /dev/null
+++ b/adb/daemon/usb_ffs.cpp
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#define TRACE_TAG USB
+
+#include "sysdeps.h"
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/functionfs.h>
+
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/unique_fd.h>
+
+#include "adb.h"
+#include "adbd/usb.h"
+
+#define MAX_PACKET_SIZE_FS 64
+#define MAX_PACKET_SIZE_HS 512
+#define MAX_PACKET_SIZE_SS 1024
+
+#define USB_FFS_BULK_SIZE 16384
+
+// Number of buffers needed to fit MAX_PAYLOAD, with an extra for ZLPs.
+#define USB_FFS_NUM_BUFS ((4 * MAX_PAYLOAD / USB_FFS_BULK_SIZE) + 1)
+
+#define cpu_to_le16(x) htole16(x)
+#define cpu_to_le32(x) htole32(x)
+
+struct func_desc {
+ struct usb_interface_descriptor intf;
+ struct usb_endpoint_descriptor_no_audio source;
+ 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;
+ __le32 length;
+ __le32 fs_count;
+ __le32 hs_count;
+ } __attribute__((packed)) header;
+ struct func_desc fs_descs, hs_descs;
+} __attribute__((packed));
+
+struct desc_v2 {
+ struct usb_functionfs_descs_head_v2 header;
+ // The rest of the structure depends on the flags in the header.
+ __le32 fs_count;
+ __le32 hs_count;
+ __le32 ss_count;
+ __le32 os_count;
+ struct func_desc fs_descs, hs_descs;
+ struct ss_func_desc ss_descs;
+ struct usb_os_desc_header os_header;
+ struct usb_ext_compat_desc os_desc;
+} __attribute__((packed));
+
+// clang-format off
+static struct func_desc fs_descriptors = {
+ .intf = {
+ .bLength = sizeof(fs_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(fs_descriptors.source),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = MAX_PACKET_SIZE_FS,
+ },
+ .sink = {
+ .bLength = sizeof(fs_descriptors.sink),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 2 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = MAX_PACKET_SIZE_FS,
+ },
+};
+
+static struct func_desc hs_descriptors = {
+ .intf = {
+ .bLength = sizeof(hs_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(hs_descriptors.source),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = MAX_PACKET_SIZE_HS,
+ },
+ .sink = {
+ .bLength = sizeof(hs_descriptors.sink),
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 2 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = MAX_PACKET_SIZE_HS,
+ },
+};
+
+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,
+ .bMaxBurst = 4,
+ },
+ .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,
+ .bMaxBurst = 4,
+ },
+};
+
+struct usb_ext_compat_desc os_desc_compat = {
+ .bFirstInterfaceNumber = 0,
+ .Reserved1 = cpu_to_le32(1),
+ .CompatibleID = {0},
+ .SubCompatibleID = {0},
+ .Reserved2 = {0},
+};
+
+static struct usb_os_desc_header os_desc_header = {
+ .interface = cpu_to_le32(1),
+ .dwLength = cpu_to_le32(sizeof(os_desc_header) + sizeof(os_desc_compat)),
+ .bcdVersion = cpu_to_le32(1),
+ .wIndex = cpu_to_le32(4),
+ .bCount = cpu_to_le32(1),
+ .Reserved = cpu_to_le32(0),
+};
+
+#define STR_INTERFACE_ "ADB Interface"
+
+static const struct {
+ struct usb_functionfs_strings_head header;
+ struct {
+ __le16 code;
+ const char str1[sizeof(STR_INTERFACE_)];
+ } __attribute__((packed)) lang0;
+} __attribute__((packed)) strings = {
+ .header = {
+ .magic = cpu_to_le32(FUNCTIONFS_STRINGS_MAGIC),
+ .length = cpu_to_le32(sizeof(strings)),
+ .str_count = cpu_to_le32(1),
+ .lang_count = cpu_to_le32(1),
+ },
+ .lang0 = {
+ cpu_to_le16(0x0409), /* en-us */
+ STR_INTERFACE_,
+ },
+};
+// clang-format on
+
+bool open_functionfs(android::base::unique_fd* out_control, android::base::unique_fd* out_bulk_out,
+ android::base::unique_fd* out_bulk_in) {
+ unique_fd control, bulk_out, bulk_in;
+ struct desc_v1 v1_descriptor = {};
+ struct desc_v2 v2_descriptor = {};
+
+ 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 |
+ FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_MS_OS_DESC;
+ v2_descriptor.fs_count = 3;
+ v2_descriptor.hs_count = 3;
+ v2_descriptor.ss_count = 5;
+ v2_descriptor.os_count = 1;
+ v2_descriptor.fs_descs = fs_descriptors;
+ v2_descriptor.hs_descs = hs_descriptors;
+ v2_descriptor.ss_descs = ss_descriptors;
+ v2_descriptor.os_header = os_desc_header;
+ v2_descriptor.os_desc = os_desc_compat;
+
+ if (out_control->get() < 0) { // might have already done this before
+ LOG(INFO) << "opening control endpoint " << USB_FFS_ADB_EP0;
+ control.reset(adb_open(USB_FFS_ADB_EP0, O_RDWR));
+ if (control < 0) {
+ PLOG(ERROR) << "cannot open control endpoint " << USB_FFS_ADB_EP0;
+ return false;
+ }
+
+ if (adb_write(control.get(), &v2_descriptor, sizeof(v2_descriptor)) < 0) {
+ D("[ %s: Switching to V1_descriptor format errno=%s ]", USB_FFS_ADB_EP0,
+ strerror(errno));
+ v1_descriptor.header.magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC);
+ v1_descriptor.header.length = cpu_to_le32(sizeof(v1_descriptor));
+ v1_descriptor.header.fs_count = 3;
+ v1_descriptor.header.hs_count = 3;
+ v1_descriptor.fs_descs = fs_descriptors;
+ v1_descriptor.hs_descs = hs_descriptors;
+ if (adb_write(control.get(), &v1_descriptor, sizeof(v1_descriptor)) < 0) {
+ PLOG(ERROR) << "failed to write USB descriptors";
+ return false;
+ }
+ }
+
+ if (adb_write(control.get(), &strings, sizeof(strings)) < 0) {
+ PLOG(ERROR) << "failed to write USB strings";
+ return false;
+ }
+ // Signal only when writing the descriptors to ffs
+ android::base::SetProperty("sys.usb.ffs.ready", "1");
+ }
+
+ bulk_out.reset(adb_open(USB_FFS_ADB_OUT, O_RDONLY));
+ if (bulk_out < 0) {
+ PLOG(ERROR) << "cannot open bulk-out endpoint " << USB_FFS_ADB_OUT;
+ return false;
+ }
+
+ bulk_in.reset(adb_open(USB_FFS_ADB_IN, O_WRONLY));
+ if (bulk_in < 0) {
+ PLOG(ERROR) << "cannot open bulk-in endpoint " << USB_FFS_ADB_IN;
+ return false;
+ }
+
+ *out_control = std::move(control);
+ *out_bulk_in = std::move(bulk_in);
+ *out_bulk_out = std::move(bulk_out);
+ return true;
+}
diff --git a/adb/daemon/usb_legacy.cpp b/adb/daemon/usb_legacy.cpp
new file mode 100644
index 0000000..7ace59d
--- /dev/null
+++ b/adb/daemon/usb_legacy.cpp
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#define TRACE_TAG USB
+
+#include "sysdeps.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/functionfs.h>
+
+#include <algorithm>
+#include <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+#include <thread>
+
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+
+#include "adb.h"
+#include "adbd/usb.h"
+#include "transport.h"
+
+using namespace std::chrono_literals;
+
+#define MAX_PACKET_SIZE_FS 64
+#define MAX_PACKET_SIZE_HS 512
+#define MAX_PACKET_SIZE_SS 1024
+
+#define USB_FFS_BULK_SIZE 16384
+
+// Number of buffers needed to fit MAX_PAYLOAD, with an extra for ZLPs.
+#define USB_FFS_NUM_BUFS ((4 * MAX_PAYLOAD / USB_FFS_BULK_SIZE) + 1)
+
+static unique_fd& dummy_fd = *new unique_fd();
+
+static void aio_block_init(aio_block* aiob, unsigned num_bufs) {
+ aiob->iocb.resize(num_bufs);
+ aiob->iocbs.resize(num_bufs);
+ aiob->events.resize(num_bufs);
+ aiob->num_submitted = 0;
+ for (unsigned i = 0; i < num_bufs; i++) {
+ aiob->iocbs[i] = &aiob->iocb[i];
+ }
+ memset(&aiob->ctx, 0, sizeof(aiob->ctx));
+ if (io_setup(num_bufs, &aiob->ctx)) {
+ D("[ aio: got error on io_setup (%d) ]", errno);
+ }
+}
+
+static int getMaxPacketSize(int ffs_fd) {
+ usb_endpoint_descriptor desc;
+ if (ioctl(ffs_fd, FUNCTIONFS_ENDPOINT_DESC, reinterpret_cast<unsigned long>(&desc))) {
+ D("[ could not get endpoint descriptor! (%d) ]", errno);
+ return MAX_PACKET_SIZE_HS;
+ } else {
+ return desc.wMaxPacketSize;
+ }
+}
+
+static bool init_functionfs(struct usb_handle* h) {
+ LOG(INFO) << "initializing functionfs";
+ if (!open_functionfs(&h->control, &h->bulk_out, &h->bulk_in)) {
+ return false;
+ }
+
+ h->read_aiob.fd = h->bulk_out.get();
+ h->write_aiob.fd = h->bulk_in.get();
+ h->reads_zero_packets = true;
+ return true;
+}
+
+static void usb_legacy_ffs_open_thread(usb_handle* usb) {
+ adb_thread_setname("usb legacy ffs open");
+
+ while (true) {
+ // wait until the USB device needs opening
+ std::unique_lock<std::mutex> lock(usb->lock);
+ while (!usb->open_new_connection) {
+ usb->notify.wait(lock);
+ }
+ usb->open_new_connection = false;
+ lock.unlock();
+
+ while (true) {
+ if (init_functionfs(usb)) {
+ LOG(INFO) << "functionfs successfully initialized";
+ break;
+ }
+ std::this_thread::sleep_for(1s);
+ }
+
+ LOG(INFO) << "registering usb transport";
+ register_usb_transport(usb, nullptr, nullptr, 1);
+ }
+
+ // never gets here
+ abort();
+}
+
+static int usb_ffs_write(usb_handle* h, const void* data, int len) {
+ D("about to write (fd=%d, len=%d)", h->bulk_in.get(), len);
+
+ const char* buf = static_cast<const char*>(data);
+ int orig_len = len;
+ while (len > 0) {
+ int write_len = std::min(USB_FFS_BULK_SIZE, len);
+ int n = adb_write(h->bulk_in, buf, write_len);
+ if (n < 0) {
+ D("ERROR: fd = %d, n = %d: %s", h->bulk_in.get(), n, strerror(errno));
+ return -1;
+ }
+ buf += n;
+ len -= n;
+ }
+
+ D("[ done fd=%d ]", h->bulk_in.get());
+ return orig_len;
+}
+
+static int usb_ffs_read(usb_handle* h, void* data, int len) {
+ D("about to read (fd=%d, len=%d)", h->bulk_out.get(), len);
+
+ char* buf = static_cast<char*>(data);
+ int orig_len = len;
+ while (len > 0) {
+ int read_len = std::min(USB_FFS_BULK_SIZE, len);
+ int n = adb_read(h->bulk_out, buf, read_len);
+ if (n < 0) {
+ D("ERROR: fd = %d, n = %d: %s", h->bulk_out.get(), n, strerror(errno));
+ return -1;
+ }
+ buf += n;
+ len -= n;
+ }
+
+ D("[ done fd=%d ]", h->bulk_out.get());
+ return orig_len;
+}
+
+static int usb_ffs_do_aio(usb_handle* h, const void* data, int len, bool read) {
+ aio_block* aiob = read ? &h->read_aiob : &h->write_aiob;
+ bool zero_packet = false;
+
+ int num_bufs = len / h->io_size + (len % h->io_size == 0 ? 0 : 1);
+ const char* cur_data = reinterpret_cast<const char*>(data);
+ int packet_size = getMaxPacketSize(aiob->fd);
+
+ if (posix_madvise(const_cast<void*>(data), len, POSIX_MADV_SEQUENTIAL | POSIX_MADV_WILLNEED) <
+ 0) {
+ D("[ Failed to madvise: %d ]", errno);
+ }
+
+ for (int i = 0; i < num_bufs; i++) {
+ int buf_len = std::min(len, static_cast<int>(h->io_size));
+ io_prep(&aiob->iocb[i], aiob->fd, cur_data, buf_len, 0, read);
+
+ len -= buf_len;
+ cur_data += buf_len;
+
+ if (len == 0 && buf_len % packet_size == 0 && read) {
+ // adb does not expect the device to send a zero packet after data transfer,
+ // but the host *does* send a zero packet for the device to read.
+ zero_packet = h->reads_zero_packets;
+ }
+ }
+ if (zero_packet) {
+ io_prep(&aiob->iocb[num_bufs], aiob->fd, reinterpret_cast<const void*>(cur_data),
+ packet_size, 0, read);
+ num_bufs += 1;
+ }
+
+ while (true) {
+ if (TEMP_FAILURE_RETRY(io_submit(aiob->ctx, num_bufs, aiob->iocbs.data())) < num_bufs) {
+ PLOG(ERROR) << "aio: got error submitting " << (read ? "read" : "write");
+ return -1;
+ }
+ if (TEMP_FAILURE_RETRY(io_getevents(aiob->ctx, num_bufs, num_bufs, aiob->events.data(),
+ nullptr)) < num_bufs) {
+ PLOG(ERROR) << "aio: got error waiting " << (read ? "read" : "write");
+ return -1;
+ }
+ if (num_bufs == 1 && aiob->events[0].res == -EINTR) {
+ continue;
+ }
+ int ret = 0;
+ for (int i = 0; i < num_bufs; i++) {
+ if (aiob->events[i].res < 0) {
+ errno = -aiob->events[i].res;
+ PLOG(ERROR) << "aio: got error event on " << (read ? "read" : "write")
+ << " total bufs " << num_bufs;
+ return -1;
+ }
+ ret += aiob->events[i].res;
+ }
+ return ret;
+ }
+}
+
+static int usb_ffs_aio_read(usb_handle* h, void* data, int len) {
+ return usb_ffs_do_aio(h, data, len, true);
+}
+
+static int usb_ffs_aio_write(usb_handle* h, const void* data, int len) {
+ return usb_ffs_do_aio(h, data, len, false);
+}
+
+static void usb_ffs_kick(usb_handle* h) {
+ int err;
+
+ err = ioctl(h->bulk_in.get(), FUNCTIONFS_CLEAR_HALT);
+ if (err < 0) {
+ D("[ kick: source (fd=%d) clear halt failed (%d) ]", h->bulk_in.get(), errno);
+ }
+
+ err = ioctl(h->bulk_out.get(), FUNCTIONFS_CLEAR_HALT);
+ if (err < 0) {
+ D("[ kick: sink (fd=%d) clear halt failed (%d) ]", h->bulk_out.get(), errno);
+ }
+
+ // don't close ep0 here, since we may not need to reinitialize it with
+ // the same descriptors again. if however ep1/ep2 fail to re-open in
+ // init_functionfs, only then would we close and open ep0 again.
+ // Ditto the comment in usb_adb_kick.
+ h->kicked = true;
+ TEMP_FAILURE_RETRY(dup2(dummy_fd.get(), h->bulk_out.get()));
+ TEMP_FAILURE_RETRY(dup2(dummy_fd.get(), h->bulk_in.get()));
+}
+
+static void usb_ffs_close(usb_handle* h) {
+ LOG(INFO) << "closing functionfs transport";
+
+ h->kicked = false;
+ h->bulk_out.reset();
+ h->bulk_in.reset();
+
+ // Notify usb_adb_open_thread to open a new connection.
+ h->lock.lock();
+ h->open_new_connection = true;
+ h->lock.unlock();
+ h->notify.notify_one();
+}
+
+usb_handle* create_usb_handle(unsigned num_bufs, unsigned io_size) {
+ usb_handle* h = new usb_handle();
+
+ if (android::base::GetBoolProperty("sys.usb.ffs.aio_compat", false)) {
+ // Devices on older kernels (< 3.18) will not have aio support for ffs
+ // unless backported. Fall back on the non-aio functions instead.
+ h->write = usb_ffs_write;
+ h->read = usb_ffs_read;
+ } else {
+ h->write = usb_ffs_aio_write;
+ h->read = usb_ffs_aio_read;
+ aio_block_init(&h->read_aiob, num_bufs);
+ aio_block_init(&h->write_aiob, num_bufs);
+ }
+ h->io_size = io_size;
+ h->kick = usb_ffs_kick;
+ h->close = usb_ffs_close;
+ return h;
+}
+
+void usb_init_legacy() {
+ D("[ usb_init - using legacy FunctionFS ]");
+ dummy_fd.reset(adb_open("/dev/null", O_WRONLY | O_CLOEXEC));
+ CHECK_NE(-1, dummy_fd.get());
+
+ std::thread(usb_legacy_ffs_open_thread, create_usb_handle(USB_FFS_NUM_BUFS, USB_FFS_BULK_SIZE))
+ .detach();
+}
+
+int usb_write(usb_handle* h, const void* data, int len) {
+ return h->write(h, data, len);
+}
+
+int usb_read(usb_handle* h, void* data, int len) {
+ return h->read(h, data, len);
+}
+
+int usb_close(usb_handle* h) {
+ h->close(h);
+ return 0;
+}
+
+void usb_kick(usb_handle* h) {
+ h->kick(h);
+}
diff --git a/adb/fdevent_test.h b/adb/fdevent_test.h
index 5a417e0..8d853c3 100644
--- a/adb/fdevent_test.h
+++ b/adb/fdevent_test.h
@@ -20,6 +20,7 @@
#include <mutex>
#include <thread>
+#include "adb_io.h"
#include "socket.h"
#include "sysdeps.h"
#include "sysdeps/chrono.h"
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index 1534792..8b07f74 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -78,7 +78,7 @@
// Socket ids should never be 0.
if (local_socket_next_id == 0) {
- fatal("local socket id overflow");
+ LOG(FATAL) << "local socket id overflow";
}
local_socket_list.push_back(s);
@@ -451,7 +451,7 @@
// Returns a new non-NULL asocket handle.
asocket* create_remote_socket(unsigned id, atransport* t) {
if (id == 0) {
- fatal("invalid remote socket id (0)");
+ LOG(FATAL) << "invalid remote socket id (0)";
}
asocket* s = new asocket();
s->id = id;
@@ -477,9 +477,7 @@
p->payload.assign(destination, destination + strlen(destination) + 1);
p->msg.data_length = p->payload.size();
- if (p->msg.data_length > s->get_max_payload()) {
- fatal("destination oversized");
- }
+ CHECK_LE(p->msg.data_length, s->get_max_payload());
send_packet(p, s->transport);
}
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index b8d7e06..bebf4e6 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -25,6 +25,7 @@
#endif
#include <errno.h>
+#include <error.h>
#include <string>
#include <vector>
@@ -69,6 +70,8 @@
#define OS_PATH_SEPARATOR_STR "\\"
#define ENV_PATH_SEPARATOR_STR ";"
+void error(int status, int error, const char* fmt, ...) __attribute__((__format__(printf, 3, 4)));
+
static __inline__ bool adb_is_separator(char c) {
return c == '\\' || c == '/';
}
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index 0a08fbb..af15241 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -35,6 +35,7 @@
#include <cutils/sockets.h>
#include <android-base/errors.h>
+#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/macros.h>
#include <android-base/stringprintf.h>
@@ -46,8 +47,6 @@
#include "sysdeps/uio.h"
-extern void fatal(const char *fmt, ...);
-
/* forward declarations */
typedef const struct FHClassRec_* FHClass;
@@ -98,11 +97,6 @@
#undef assert
#endif
-#define assert(cond) \
- do { \
- if (!(cond)) fatal("assertion failed '%s' on %s:%d\n", #cond, __FILE__, __LINE__); \
- } while (0)
-
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.
@@ -730,8 +724,8 @@
WSADATA wsaData;
int rc = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (rc != 0) {
- fatal("adb: could not initialize Winsock: %s",
- android::base::SystemErrorCodeToString(rc).c_str());
+ LOG(FATAL) << "could not initialize Winsock: "
+ << android::base::SystemErrorCodeToString(rc);
}
// Note that we do not call atexit() to register WSACleanup to be called
@@ -1287,11 +1281,11 @@
}
if (read_count == 0) { // should be impossible
- fatal("ReadConsoleInputA returned 0");
+ LOG(FATAL) << "ReadConsoleInputA returned 0";
}
if (read_count != 1) { // should be impossible
- fatal("ReadConsoleInputA did not return one input record");
+ LOG(FATAL) << "ReadConsoleInputA did not return one input record";
}
// If the console window is resized, emulate SIGWINCH by breaking out
@@ -1309,8 +1303,7 @@
if ((input_record->EventType == KEY_EVENT) &&
(input_record->Event.KeyEvent.bKeyDown)) {
if (input_record->Event.KeyEvent.wRepeatCount == 0) {
- fatal("ReadConsoleInputA returned a key event with zero repeat"
- " count");
+ LOG(FATAL) << "ReadConsoleInputA returned a key event with zero repeat count";
}
// Got an interesting INPUT_RECORD, so return
@@ -2193,7 +2186,7 @@
for (int i = 0; i < argc; ++i) {
std::string arg_narrow;
if (!android::base::WideToUTF8(argv[i], &arg_narrow)) {
- fatal_errno("cannot convert argument from UTF-16 to UTF-8");
+ PLOG(FATAL) << "cannot convert argument from UTF-16 to UTF-8";
}
narrow_args[i] = strdup(arg_narrow.c_str());
}
@@ -2644,7 +2637,7 @@
// If _wenviron is null, then -municode probably wasn't used. That
// linker flag will cause the entry point to setup _wenviron. It will
// also require an implementation of wmain() (which we provide above).
- fatal("_wenviron is not set, did you link with -municode?");
+ LOG(FATAL) << "_wenviron is not set, did you link with -municode?";
}
// Read name/value pairs from UTF-16 _wenviron and write new name/value
@@ -2763,3 +2756,24 @@
return 0;
}
+
+void error(int status, int error, const char* fmt, ...) {
+ fflush(stdout);
+ fprintf(stderr, "%s: ", android::base::Basename(android::base::GetExecutablePath()).c_str());
+
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+
+ if (error != 0) {
+ fprintf(stderr, ": %s", strerror(error));
+ }
+
+ putc('\n', stderr);
+ fflush(stderr);
+
+ if (status != 0) {
+ exit(status);
+ }
+}
diff --git a/adb/transport.cpp b/adb/transport.cpp
index d41f9c8..0fbeec6 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -52,7 +52,6 @@
#include "fdevent.h"
#include "sysdeps/chrono.h"
-static void register_transport(atransport* transport);
static void remove_transport(atransport* transport);
static void transport_unref(atransport* transport);
@@ -420,7 +419,7 @@
VLOG(TRANSPORT) << dump_packet(t->serial.c_str(), "to remote", p);
if (t == nullptr) {
- fatal("Transport is null");
+ LOG(FATAL) << "Transport is null";
}
if (t->Write(p) != 0) {
@@ -526,7 +525,7 @@
asocket* create_device_tracker(bool long_output) {
device_tracker* tracker = new device_tracker();
- if (tracker == nullptr) fatal("cannot allocate device tracker");
+ if (tracker == nullptr) LOG(FATAL) << "cannot allocate device tracker";
D("device tracker %p created", tracker);
@@ -632,7 +631,7 @@
}
if (transport_read_action(_fd, &m)) {
- fatal_errno("cannot read transport registration socket");
+ PLOG(FATAL) << "cannot read transport registration socket";
}
t = m.transport;
@@ -671,7 +670,7 @@
return true;
});
t->connection()->SetErrorCallback([t](Connection*, const std::string& error) {
- D("%s: connection terminated: %s", t->serial.c_str(), error.c_str());
+ LOG(INFO) << t->serial_name() << ": connection terminated: " << error;
fdevent_run_on_main_thread([t]() {
handle_offline(t);
transport_unref(t);
@@ -706,7 +705,7 @@
int s[2];
if (adb_socketpair(s)) {
- fatal_errno("cannot open transport registration socketpair");
+ PLOG(FATAL) << "cannot open transport registration socketpair";
}
D("socketpair: (%d,%d)", s[0], s[1]);
@@ -730,13 +729,13 @@
}
/* the fdevent select pump is single threaded */
-static void register_transport(atransport* transport) {
+void register_transport(atransport* transport) {
tmsg m;
m.transport = transport;
m.action = 1;
D("transport: %s registered", transport->serial.c_str());
if (transport_write_action(transport_registration_send, &m)) {
- fatal_errno("cannot write transport registration socket\n");
+ PLOG(FATAL) << "cannot write transport registration socket";
}
}
@@ -746,7 +745,7 @@
m.action = 0;
D("transport: %s removed", transport->serial.c_str());
if (transport_write_action(transport_registration_send, &m)) {
- fatal_errno("cannot write transport registration socket\n");
+ PLOG(FATAL) << "cannot write transport registration socket";
}
}
@@ -758,6 +757,7 @@
CHECK_GT(t->ref_count, 0u);
t->ref_count--;
if (t->ref_count == 0) {
+ LOG(INFO) << "destroying transport " << t->serial_name();
t->connection()->Stop();
#if ADB_HOST
if (t->IsTcpDevice() && !t->kicked()) {
@@ -1293,6 +1293,7 @@
register_transport(t);
}
+#if ADB_HOST
// This should only be used for transports with connection_state == kCsNoPerm.
void unregister_usb_transport(usb_handle* usb) {
std::lock_guard<std::recursive_mutex> lock(transport_lock);
@@ -1304,6 +1305,7 @@
return false;
});
}
+#endif
bool check_header(apacket* p, atransport* t) {
if (p->msg.magic != (p->msg.command ^ 0xffffffff)) {
diff --git a/adb/transport.h b/adb/transport.h
index f854ce5..1350e63 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -362,6 +362,7 @@
void kick_all_tcp_devices();
void kick_all_transports();
+void register_transport(atransport* transport);
void register_usb_transport(usb_handle* h, const char* serial,
const char* devpath, unsigned writeable);
diff --git a/adb/transport_test.cpp b/adb/transport_test.cpp
index 8c628d8..b66f8fa 100644
--- a/adb/transport_test.cpp
+++ b/adb/transport_test.cpp
@@ -19,13 +19,16 @@
#include <gtest/gtest.h>
#include "adb.h"
+#include "fdevent_test.h"
+
+struct TransportTest : public FdeventTest {};
static void DisconnectFunc(void* arg, atransport*) {
int* count = reinterpret_cast<int*>(arg);
++*count;
}
-TEST(transport, RunDisconnects) {
+TEST_F(TransportTest, RunDisconnects) {
atransport t;
// RunDisconnects() can be called with an empty atransport.
t.RunDisconnects();
@@ -49,7 +52,7 @@
ASSERT_EQ(0, count);
}
-TEST(transport, SetFeatures) {
+TEST_F(TransportTest, SetFeatures) {
atransport t;
ASSERT_EQ(0U, t.features().size());
@@ -77,8 +80,7 @@
ASSERT_EQ(0U, t.features().size());
}
-TEST(transport, parse_banner_no_features) {
- set_main_thread();
+TEST_F(TransportTest, parse_banner_no_features) {
atransport t;
parse_banner("host::", &t);
@@ -91,7 +93,7 @@
ASSERT_EQ(std::string(), t.device);
}
-TEST(transport, parse_banner_product_features) {
+TEST_F(TransportTest, parse_banner_product_features) {
atransport t;
const char banner[] =
@@ -107,9 +109,8 @@
ASSERT_EQ(std::string("baz"), t.device);
}
-TEST(transport, parse_banner_features) {
+TEST_F(TransportTest, parse_banner_features) {
atransport t;
-
const char banner[] =
"host::ro.product.name=foo;ro.product.model=bar;ro.product.device=baz;"
"features=woodly,doodly";
@@ -126,7 +127,7 @@
ASSERT_EQ(std::string("baz"), t.device);
}
-TEST(transport, test_matches_target) {
+TEST_F(TransportTest, test_matches_target) {
std::string serial = "foo";
std::string devpath = "/path/to/bar";
std::string product = "test_product";
@@ -157,7 +158,7 @@
}
}
-TEST(transport, test_matches_target_local) {
+TEST_F(TransportTest, test_matches_target_local) {
std::string serial = "100.100.100.100:5555";
atransport t;
diff --git a/base/logging.cpp b/base/logging.cpp
index d60d91d..bd09069 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -53,6 +53,7 @@
#include <unistd.h>
#endif
+#include <android-base/file.h>
#include <android-base/macros.h>
#include <android-base/parseint.h>
#include <android-base/strings.h>
@@ -71,14 +72,8 @@
static char progname[MAX_PATH] = {};
if (first) {
- CHAR longname[MAX_PATH];
- DWORD nchars = GetModuleFileNameA(nullptr, longname, arraysize(longname));
- if ((nchars >= arraysize(longname)) || (nchars == 0)) {
- // String truncation or some other error.
- strcpy(progname, "<unknown>");
- } else {
- strcpy(progname, basename(longname));
- }
+ snprintf(progname, sizeof(progname), "%s",
+ android::base::Basename(android::base::GetExecutablePath()).c_str());
first = false;
}
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
new file mode 100755
index 0000000..d4ca574
--- /dev/null
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -0,0 +1,264 @@
+#! /bin/bash
+#
+# adb remount tests (overlayfs focus)
+#
+# Conditions:
+# - Must be a userdebug build.
+# - Must be in adb mode.
+# - Kernel must have overlayfs enabled and patched to support override_creds.
+# - Must have either squashfs, ext4-dedupe or right-sized partitions.
+# - Minimum expectation system and vender are overlayfs covered partitions.
+#
+
+# Helper Variables
+
+SPACE=" "
+# A _real_ embedded tab character
+TAB="`echo | tr '\n' '\t'`"
+# A _real_ embedded escape character
+ESCAPE="`echo | tr '\n' '\033'`"
+GREEN="${ESCAPE}[38;5;40m"
+RED="${ESCAPE}[38;5;196m"
+ORANGE="${ESCAPE}[38;5;255:165:0m"
+NORMAL="${ESCAPE}[0m"
+
+# Helper functions
+
+[ "USAGE: inFastboot
+
+Returns: true if device is in fastboot mode" ]
+inFastboot() {
+ fastboot devices | grep "^${ANDROID_SERIAL}[${SPACE}${TAB}]" > /dev/null
+}
+
+[ "USAGE: inAdb
+
+Returns: true if device is in adb mode" ]
+inAdb() {
+ adb devices | grep -v 'List of devices attached' | grep "^${ANDROID_SERIAL}[${SPACE}${TAB}]" > /dev/null
+}
+
+[ "USAGE: adb_sh <commands>
+
+Returns: true if the command succeeded" ]
+adb_sh() {
+ adb shell "${@}"
+}
+
+[ "USAGE: get_property <prop>
+
+Returns the property value" ]
+get_property() {
+ adb_sh getprop ${1} 2>&1 </dev/null
+}
+
+[ "USAGE: isDebuggable
+
+Returns: true if device is (likely) a debug build" ]
+isDebuggable() {
+ if inAdb && [ 1 -ne `get_property ro.debuggable` ]; then
+ false
+ fi
+}
+
+[ "USAGE: adb_su <commands>
+
+Returns: true if the command running as root succeeded" ]
+adb_su() {
+ adb_sh su root "${@}"
+}
+
+[ "USAGE: adb_cat <file> >stdout
+
+Returns: content of file to stdout with carriage returns skipped,
+ true of the file exists" ]
+adb_cat() {
+ OUTPUT="`adb_sh cat ${1} </dev/null 2>&1`"
+ retval=${?}
+ echo "${OUTPUT}" | tr -d '\r'
+ return ${retval}
+}
+
+[ "USAGE: adb_reboot
+
+Returns: true if the reboot command succeeded" ]
+adb_reboot() {
+ adb reboot remount-test
+}
+
+[ "USAGE: adb_wait
+
+Returns: waits until the device has returned" ]
+adb_wait() {
+ adb wait-for-device
+}
+
+[ "USAGE: adb_root
+
+Returns: true if device in root state" ]
+adb_root() {
+ adb root >/dev/null </dev/null 2>&1 &&
+ sleep 1 &&
+ adb_wait &&
+ sleep 1
+}
+
+die() {
+ echo "${RED}[ FAILED ]${NORMAL} ${@}" >&2
+ exit 1
+}
+
+[ "USAGE: EXPECT_EQ <lval> <rval> [message]
+
+Returns true if (regex) lval matches rval" ]
+EXPECT_EQ() {
+ lval="${1}"
+ rval="${2}"
+ shift 2
+ if ! ( echo X"${rval}" | grep '^X'"${lval}"'$' >/dev/null 2>/dev/null ); then
+ if [ `echo ${lval}${rval}${*} | wc -c` -gt 50 -o "${rval}" != "${rval%
+*}" ]; then
+ echo "ERROR: expected \"${lval}\"" >&2
+ echo " got \"${rval}\"" |
+ sed ': again
+ N
+ s/\(\n\)\([^ ]\)/\1 \2/
+ t again' >&2
+ if [ -n "${*}" ] ; then
+ echo " ${*}" >&2
+ fi
+ else
+ echo "ERROR: expected \"${lval}\" got \"${rval}\" ${*}" >&2
+ fi
+ return 1
+ fi
+ if [ -n "${*}" ] ; then
+ if [ X"${lval}" != X"${rval}" ]; then
+ if [ `echo ${lval}${rval}${*} | wc -c` -gt 60 -o "${rval}" != "${rval% *}" ]; then
+ echo "INFO: ok \"${lval}\"" >&2
+ echo " = \"${rval}\"" |
+ sed ': again
+ N
+ s/\(\n\)\([^ ]\)/\1 \2/
+ t again' >&2
+ if [ -n "${*}" ] ; then
+ echo " ${*}" >&2
+ fi
+ else
+ echo "INFO: ok \"${lval}\" = \"${rval}\" ${*}" >&2
+ fi
+ else
+ echo "INFO: ok \"${lval}\" ${*}" >&2
+ fi
+ fi
+ return 0
+}
+
+[ "USAGE: check_eq <lval> <rval> [message]
+
+Exits if (regex) lval mismatches rval" ]
+check_eq() {
+ left="${1}"
+ right="${2}"
+ shift 2
+ EXPECT_EQ "${left}" "${right}" ||
+ die "${@}"
+}
+
+[ "USAGE: skip_administrative_mounts
+
+Filters out all administrative (eg: sysfs) mounts" ]
+skip_administrative_mounts() {
+ grep -v -e "^\(overlay\|tmpfs\|none\|sysfs\|proc\|selinuxfs\|debugfs\|bpf\|cg2_bpf\|pstore\|tracefs\|adb\|mtp\|ptp\|devpts\|/data/media\) " -e " /\(cache\|mnt/scratch\|mnt/vendor/persist\|metadata\|data\) "
+}
+
+if [ X"-s" = X"${1}" -a -n "${2}" ]; then
+ export ANDROID_SERIAL="${2}"
+ shift 2
+fi
+
+inFastboot && die "device in fastboot mode"
+inAdb || die "device not in adb mode"
+isDebuggable || die "device not a debug build"
+
+# Do something
+adb_wait || die "wait for device failed"
+adb_sh ls -d /sys/module/overlay </dev/null || die "overlay module not present"
+adb_su ls /sys/module/overlay/parameters/override_creds </dev/null ||
+ die "overlay module can not be used on ANDROID"
+adb_root &&
+ adb_wait &&
+ D=`adb disable-verity 2>&1` ||
+ die "setup for overlay"
+echo "${D}"
+if [ X"${D}" != X"${D##*using overlayfs}" ]; then
+ echo "${GREEN}[ OK ]${NORMAL} using overlayfs" >&2
+fi
+if adb_sh ls -d /data/overlay </dev/null >/dev/null 2>&1; then
+ echo "/data/overlay setup, clearing out" >&2
+ adb_sh rm -rf /data/overlay </dev/null ||
+ die "/data/overlay removal"
+fi
+adb_sh ls -d /cache/overlay </dev/null >/dev/null 2>&1 ||
+ adb_sh ls -d /mnt/scratch/overlay </dev/null >/dev/null 2>&1 ||
+ die "overlay directory setup"
+adb_reboot &&
+ adb_wait &&
+ adb_sh df -k </dev/null | head -1 &&
+ adb_sh df -k </dev/null | grep "^overlay " &&
+ adb_sh df -k </dev/null | grep "^overlay .* /system\$" >/dev/null ||
+ echo "${ORANGE}[ WARNING ]${NORMAL} overlay takeover before remount not complete" >&2
+
+adb_root &&
+ adb_wait &&
+ adb remount &&
+ adb_sh df -k </dev/null | head -1 &&
+ adb_sh df -k </dev/null | grep "^overlay " &&
+ adb_sh df -k </dev/null | grep "^overlay .* /system\$" >/dev/null ||
+ die "overlay takeover after remount"
+!(adb_sh grep "^overlay " /proc/mounts </dev/null | grep " overlay ro,") &&
+ !(adb_sh grep " rw," /proc/mounts </dev/null |
+ skip_administrative_mounts) ||
+ die "remount overlayfs missed a spot"
+
+adb_su "sed -n '1,/overlay \\/system/p' /proc/mounts" </dev/null |
+ skip_administrative_mounts |
+ grep -v ' \(squashfs\|ext4\|f2fs\) ' &&
+ echo "${ORANGE}[ WARNING ]${NORMAL} overlay takeover after first stage init" >&2 ||
+ echo "${GREEN}[ OK ]${NORMAL} overlay takeover in first stage init" >&2
+
+# Check something
+A="Hello World! $(date)"
+echo "${A}" | adb_sh "cat - > /system/hello"
+echo "${A}" | adb_sh "cat - > /vendor/hello"
+B="`adb_cat /system/hello`" ||
+ die "sytem hello"
+check_eq "${A}" "${B}" system before reboot
+B="`adb_cat /vendor/hello`" ||
+ die "vendor hello"
+check_eq "${A}" "${B}" vendor before reboot
+adb_reboot &&
+ adb_wait &&
+ B="`adb_cat /system/hello`" ||
+ die "re-read system hello after reboot"
+check_eq "${A}" "${B}" system after reboot
+# Only root can read vendor if sepolicy permissions are as expected
+B="`adb_cat /vendor/hello`" &&
+ die "re-read vendor hello after reboot w/o root"
+check_eq "cat: /vendor/hello: Permission denied" "${B}" vendor after reboot w/o root
+adb_root &&
+ adb_wait &&
+ B="`adb_cat /vendor/hello`" ||
+ die "re-read vendor hello after reboot"
+check_eq "${A}" "${B}" vendor after reboot
+adb remount &&
+ adb_sh rm /system/hello /vendor/hello </dev/null ||
+ die "cleanup hello"
+B="`adb_cat /system/hello`" &&
+ die "re-read system hello after rm"
+check_eq "cat: /system/hello: No such file or directory" "${B}" after flash rm
+B="`adb_cat /vendor/hello`" &&
+ die "re-read vendor hello after rm"
+check_eq "cat: /vendor/hello: No such file or directory" "${B}" after flash rm
+
+echo "${GREEN}[ PASSED ]${NORMAL} adb remount" >&2
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 115b1a3..87bc6ae 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -478,10 +478,10 @@
" -G <size>, --buffer-size=<size>\n"
" Set size of log ring buffer, may suffix with K or M.\n"
" -L, --last Dump logs from prior to last reboot\n"
- // Leave security (Device Owner only installations) and
- // kernel (userdebug and eng) buffers undocumented.
" -b <buffer>, --buffer=<buffer> Request alternate ring buffer, 'main',\n"
" 'system', 'radio', 'events', 'crash', 'default' or 'all'.\n"
+ " Additionally, 'kernel' for userdebug and eng builds, and\n"
+ " 'security' for Device Owner installations.\n"
" Multiple -b parameters or comma separated list of buffers are\n"
" allowed. Buffers interleaved. Default -b main,system,crash.\n"
" -B, --binary Output the log in binary.\n"