Merge "fs_mgr: fs_mgr_overlayfs_teardown access to dynamic partition data"
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 0000000..c47230f
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "adbd_test"
+ }
+ ]
+}
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..8c37c4b 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -59,7 +59,7 @@
std::string adb_version();
// Increment this when we want to force users to start a new adb server.
-#define ADB_SERVER_VERSION 40
+#define ADB_SERVER_VERSION 41
using TransportId = uint64_t;
class atransport;
@@ -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..6960345 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);
}
@@ -293,6 +293,9 @@
struct passwd pwent;
struct passwd* result;
int pwent_max = sysconf(_SC_GETPW_R_SIZE_MAX);
+ if (pwent_max == -1) {
+ pwent_max = 16384;
+ }
std::vector<char> buf(pwent_max);
int rc = getpwuid_r(getuid(), &pwent, buf.data(), buf.size(), &result);
if (rc == 0 && result) {
@@ -316,18 +319,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 +328,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;
@@ -353,3 +344,33 @@
return android::base::StringPrintf("%s/adb.%u.log", tmp_dir, getuid());
#endif
}
+
+[[noreturn]] static void error_exit_va(int error, const char* fmt, va_list va) {
+ fflush(stdout);
+ fprintf(stderr, "%s: ", android::base::Basename(android::base::GetExecutablePath()).c_str());
+
+ vfprintf(stderr, fmt, va);
+
+ if (error != 0) {
+ fprintf(stderr, ": %s", strerror(error));
+ }
+
+ putc('\n', stderr);
+ fflush(stderr);
+
+ exit(EXIT_FAILURE);
+}
+
+void error_exit(const char* fmt, ...) {
+ va_list va;
+ va_start(va, fmt);
+ error_exit_va(0, fmt, va);
+ va_end(va);
+}
+
+void perror_exit(const char* fmt, ...) {
+ va_list va;
+ va_start(va, fmt);
+ error_exit_va(errno, fmt, va);
+ va_end(va);
+}
diff --git a/adb/adb_utils.h b/adb/adb_utils.h
index ad83302..6d12225 100644
--- a/adb/adb_utils.h
+++ b/adb/adb_utils.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef _ADB_UTILS_H_
-#define _ADB_UTILS_H_
+#pragma once
#include <condition_variable>
#include <mutex>
@@ -26,8 +25,6 @@
#include "adb.h"
-int syntax_error(const char*, ...) __attribute__((__format__(__printf__, 1, 2)));
-
void close_stdin();
bool getcwd(std::string* cwd);
@@ -49,9 +46,12 @@
std::string perror_str(const char* msg);
+[[noreturn]] void error_exit(const char* fmt, ...) __attribute__((__format__(__printf__, 1, 2)));
+[[noreturn]] void perror_exit(const char* fmt, ...) __attribute__((__format__(__printf__, 1, 2)));
+
bool set_file_block_mode(int fd, bool block);
-extern int adb_close(int fd);
+int adb_close(int fd);
// Given forward/reverse targets, returns true if they look sane. If an error is found, fills
// |error| and returns false.
@@ -94,5 +94,3 @@
};
std::string GetLogFilePath();
-
-#endif
diff --git a/adb/client/adb_install.cpp b/adb/client/adb_install.cpp
index d69dbef..cf22efa 100644
--- a/adb/client/adb_install.cpp
+++ b/adb/client/adb_install.cpp
@@ -38,14 +38,22 @@
static constexpr int kFastDeployMinApi = 24;
-static bool _use_legacy_install() {
+static bool can_use_feature(const char* feature) {
FeatureSet features;
std::string error;
if (!adb_get_feature_set(&features, &error)) {
fprintf(stderr, "error: %s\n", error.c_str());
return true;
}
- return !CanUseFeature(features, kFeatureCmd);
+ return CanUseFeature(features, feature);
+}
+
+static bool use_legacy_install() {
+ return !can_use_feature(kFeatureCmd);
+}
+
+static bool is_apex_supported() {
+ return can_use_feature(kFeatureApex);
}
static int pm_command(int argc, const char** argv) {
@@ -102,7 +110,7 @@
}
int uninstall_app(int argc, const char** argv) {
- if (_use_legacy_install()) {
+ if (use_legacy_install()) {
return uninstall_app_legacy(argc, argv);
}
return uninstall_app_streamed(argc, argv);
@@ -133,8 +141,21 @@
// 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);
+ if (!android::base::EndsWithIgnoreCase(file, ".apk") &&
+ !android::base::EndsWithIgnoreCase(file, ".apex")) {
+ error_exit("filename doesn't end .apk or .apex: %s", file);
+ }
+
+ bool is_apex = false;
+ if (android::base::EndsWithIgnoreCase(file, ".apex")) {
+ is_apex = true;
+ }
+ if (is_apex && !is_apex_supported()) {
+ error_exit(".apex is not supported on the target device");
+ }
+
+ if (is_apex && use_fastdeploy) {
+ error_exit("--fastdeploy doesn't support .apex files");
}
if (use_fastdeploy == true) {
@@ -177,6 +198,10 @@
// do last to override any user specified value
cmd += " " + android::base::StringPrintf("-S %" PRIu64, static_cast<uint64_t>(sb.st_size));
+ if (is_apex) {
+ cmd += " --apex";
+ }
+
int remoteFd = adb_connect(cmd, &error);
if (remoteFd < 0) {
fprintf(stderr, "adb: connect error for write: %s\n", error.c_str());
@@ -218,13 +243,16 @@
// All other arguments passed through verbatim.
int last_apk = -1;
for (int i = argc - 1; i >= 0; i--) {
+ if (android::base::EndsWithIgnoreCase(argv[i], ".apex")) {
+ error_exit("APEX packages are only compatible with Streamed Install");
+ }
if (android::base::EndsWithIgnoreCase(argv[i], ".apk")) {
last_apk = i;
break;
}
}
- if (last_apk == -1) return syntax_error("need APK file on command line");
+ if (last_apk == -1) error_exit("need APK file on command line");
int result = -1;
std::vector<const char*> apk_file = {argv[last_apk]};
@@ -303,15 +331,15 @@
}
if (installMode == INSTALL_DEFAULT) {
- if (_use_legacy_install()) {
+ if (use_legacy_install()) {
installMode = INSTALL_PUSH;
} else {
installMode = INSTALL_STREAM;
}
}
- if (installMode == INSTALL_STREAM && _use_legacy_install() == true) {
- return syntax_error("Attempting to use streaming install on unsupported deivce.");
+ if (installMode == INSTALL_STREAM && use_legacy_install() == true) {
+ error_exit("Attempting to use streaming install on unsupported device");
}
if (use_fastdeploy == true && is_reinstall == false) {
@@ -359,6 +387,9 @@
uint64_t total_size = 0;
for (int i = argc - 1; i >= 0; i--) {
const char* file = argv[i];
+ if (android::base::EndsWithIgnoreCase(argv[i], ".apex")) {
+ error_exit("APEX packages are not compatible with install-multiple");
+ }
if (android::base::EndsWithIgnoreCase(file, ".apk") ||
android::base::EndsWithIgnoreCase(file, ".dm")) {
@@ -370,10 +401,10 @@
}
}
- if (first_apk == -1) return syntax_error("need APK file on command line");
+ if (first_apk == -1) error_exit("need APK file on command line");
std::string install_cmd;
- if (_use_legacy_install()) {
+ if (use_legacy_install()) {
install_cmd = "exec:pm";
} else {
install_cmd = "exec:cmd package";
diff --git a/adb/client/bugreport.cpp b/adb/client/bugreport.cpp
index fe98737..8ca44e8 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_exit("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..b5bed28 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_exit("product directory not specified; set $ANDROID_PRODUCT_OUT");
}
return std::string{ANDROID_PRODUCT_OUT} + OS_PATH_SEPARATOR_STR + file;
}
@@ -205,8 +204,8 @@
" sideload OTAPACKAGE sideload the given full OTA package\n"
" root restart adbd with root permissions\n"
" unroot restart adbd without root permissions\n"
- " usb restart adb server listening on USB\n"
- " tcpip PORT restart adb server listening on TCP on PORT\n"
+ " usb restart adbd listening on USB\n"
+ " tcpip PORT restart adbd listening on TCP on PORT\n"
"\n"
"internal debugging:\n"
" start-server ensure that there is a server running\n"
@@ -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_exit("-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_exit("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_exit("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_exit("could not open adb service %s: %s", adb_service_name, error_message.c_str());
}
pid_t pid = fork();
+ if (pid == -1) {
+ perror_exit("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);
+ perror_exit("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_exit("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_exit("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_exit("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_exit("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_exit("--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_exit("-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_exit("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_exit("-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_exit("-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_exit("-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_exit("-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",
+ error_exit(
+ "$ANDROID_ADB_SERVER_PORT must be a positive number less than 65535: "
+ "got \"%s\"",
server_port_str);
- exit(1);
}
}
@@ -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_exit("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_exit("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_exit("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_exit("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_exit("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_exit("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_exit("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_exit("%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_exit("--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_exit("--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_exit("--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_exit("--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_exit("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_exit("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_exit("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_exit("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_exit("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_exit("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_exit("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_exit("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_exit("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_exit("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_exit("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_exit("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_exit("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_exit("usage: adb reconnect [device|offline]");
}
}
}
- syntax_error("unknown command %s", argv[0]);
- return 1;
+ error_exit("unknown command %s", argv[0]);
+ __builtin_unreachable();
}
diff --git a/adb/client/fastdeploy.cpp b/adb/client/fastdeploy.cpp
index 183a1fa..45f3cca 100644
--- a/adb/client/fastdeploy.cpp
+++ b/adb/client/fastdeploy.cpp
@@ -27,7 +27,9 @@
#include "client/file_sync_client.h"
#include "commandline.h"
#include "fastdeploycallbacks.h"
-#include "utils/String16.h"
+#include "sysdeps.h"
+
+#include "adb_utils.h"
static constexpr long kRequiredAgentVersion = 0x00000001;
@@ -72,13 +74,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_exit("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_exit("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 +106,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_exit("Error executing %s returncode: %d", chmodCommand.c_str(), ret);
}
} else {
- fatal("Error pushing agent files to device");
+ error_exit("Error pushing agent files to device");
}
return true;
@@ -136,8 +139,8 @@
agent_version = get_agent_version();
if (agent_version != kRequiredAgentVersion) {
- fatal("After update agent version remains incorrect! Expected %ld but version is %ld",
- kRequiredAgentVersion, agent_version);
+ error_exit("After update agent version remains incorrect! Expected %ld but version is %ld",
+ kRequiredAgentVersion, agent_version);
}
}
@@ -153,26 +156,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);
+ perror_exit("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_exit("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_exit("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_exit("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_exit("Could not parse AndroidManifest.xml inside %s", apkPath);
}
android::ResXMLParser::event_code_t code;
while ((code = tree.next()) != android::ResXMLParser::BAD_DOCUMENT &&
@@ -213,7 +218,7 @@
break;
}
}
- fatal("Could not find package name tag in AndroidManifest.xml inside %s", apkPath);
+ error_exit("Could not find package name tag in AndroidManifest.xml inside %s", apkPath);
}
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_exit("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_exit(
+ "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_exit("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_exit("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_exit("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_exit("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_exit("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_exit("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..f0f9a80 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) {
@@ -894,7 +894,8 @@
//
// TODO(b/25457350): We don't preserve permissions on directories.
// TODO: Find all of the leaves and `mkdir -p` them instead?
- if (CanUseFeature(sc.Features(), kFeatureShell2)) {
+ if (!CanUseFeature(sc.Features(), kFeatureFixedPushMkdir) &&
+ CanUseFeature(sc.Features(), kFeatureShell2)) {
SilentStandardStreamsCallbackInterface cb;
std::string cmd = "mkdir";
for (const auto& dir : directory_list) {
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..2a6418a 100644
--- a/adb/daemon/framebuffer_service.cpp
+++ b/adb/daemon/framebuffer_service.cpp
@@ -32,6 +32,7 @@
#include "adb.h"
#include "adb_io.h"
+#include "adb_utils.h"
#include "fdevent.h"
/* TODO:
@@ -78,7 +79,7 @@
const char* command = "screencap";
const char *args[2] = {command, nullptr};
execvp(command, (char**)args);
- exit(1);
+ perror_exit("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_win32.cpp b/adb/sysdeps_win32.cpp
index 0a08fbb..8a6541d 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
diff --git a/adb/test_device.py b/adb/test_device.py
index c3166ff..34f8fd9 100755
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -750,7 +750,7 @@
if host_dir is not None:
shutil.rmtree(host_dir)
- def test_push_empty(self):
+ def disabled_test_push_empty(self):
"""Push an empty directory to the device."""
self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
self.device.shell(['mkdir', self.DEVICE_TEMP_DIR])
diff --git a/adb/transport.cpp b/adb/transport.cpp
index d41f9c8..03a9f30 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);
@@ -67,6 +66,8 @@
const char* const kFeatureStat2 = "stat_v2";
const char* const kFeatureLibusb = "libusb";
const char* const kFeaturePushSync = "push_sync";
+const char* const kFeatureApex = "apex";
+const char* const kFeatureFixedPushMkdir = "fixed_push_mkdir";
namespace {
@@ -420,7 +421,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 +527,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 +633,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 +672,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 +707,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 +731,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 +747,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 +759,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()) {
@@ -1007,7 +1009,10 @@
const FeatureSet& supported_features() {
// Local static allocation to avoid global non-POD variables.
static const FeatureSet* features = new FeatureSet{
- kFeatureShell2, kFeatureCmd, kFeatureStat2,
+ kFeatureShell2, kFeatureCmd, kFeatureStat2, kFeatureFixedPushMkdir,
+#if ADB_HOST
+ kFeatureApex
+#endif
// Increment ADB_SERVER_VERSION whenever the feature list changes to
// make sure that the adb client and server features stay in sync
// (http://b/24370690).
@@ -1293,6 +1298,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 +1310,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..9894bdf 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -57,8 +57,12 @@
extern const char* const kFeatureStat2;
// The server is running with libusb enabled.
extern const char* const kFeatureLibusb;
-// The server supports `push --sync`.
+// adbd supports `push --sync`.
extern const char* const kFeaturePushSync;
+// adbd supports installing .apex packages.
+extern const char* const kFeatureApex;
+// adbd has b/110953234 fixed.
+extern const char* const kFeatureFixedPushMkdir;
TransportId NextTransportId();
@@ -362,6 +366,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/Android.bp b/base/Android.bp
index daa820a..741664b 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -47,6 +47,7 @@
"chrono_utils.cpp",
"file.cpp",
"logging.cpp",
+ "mapped_file.cpp",
"parsenetaddress.cpp",
"properties.cpp",
"quick_exit.cpp",
@@ -124,6 +125,7 @@
"file_test.cpp",
"logging_test.cpp",
"macros_test.cpp",
+ "mapped_file_test.cpp",
"parsedouble_test.cpp",
"parseint_test.cpp",
"parsenetaddress_test.cpp",
diff --git a/base/include/android-base/macros.h b/base/include/android-base/macros.h
index 1748665..5abf514 100644
--- a/base/include/android-base/macros.h
+++ b/base/include/android-base/macros.h
@@ -75,46 +75,6 @@
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
-// ARRAYSIZE_UNSAFE performs essentially the same calculation as arraysize,
-// but can be used on anonymous types or types defined inside
-// functions. It's less safe than arraysize as it accepts some
-// (although not all) pointers. Therefore, you should use arraysize
-// whenever possible.
-//
-// The expression ARRAYSIZE_UNSAFE(a) is a compile-time constant of type
-// size_t.
-//
-// ARRAYSIZE_UNSAFE catches a few type errors. If you see a compiler error
-//
-// "warning: division by zero in ..."
-//
-// when using ARRAYSIZE_UNSAFE, you are (wrongfully) giving it a pointer.
-// You should only use ARRAYSIZE_UNSAFE on statically allocated arrays.
-//
-// The following comments are on the implementation details, and can
-// be ignored by the users.
-//
-// ARRAYSIZE_UNSAFE(arr) works by inspecting sizeof(arr) (the # of bytes in
-// the array) and sizeof(*(arr)) (the # of bytes in one array
-// element). If the former is divisible by the latter, perhaps arr is
-// indeed an array, in which case the division result is the # of
-// elements in the array. Otherwise, arr cannot possibly be an array,
-// and we generate a compiler error to prevent the code from
-// compiling.
-//
-// Since the size of bool is implementation-defined, we need to cast
-// !(sizeof(a) & sizeof(*(a))) to size_t in order to ensure the final
-// result has type size_t.
-//
-// This macro is not perfect as it wrongfully accepts certain
-// pointers, namely where the pointer size is divisible by the pointee
-// size. Since all our code has to go through a 32-bit compiler,
-// where a pointer is 4 bytes, this means all pointers to a type whose
-// size is 3 or greater than 4 will be (righteously) rejected.
-#define ARRAYSIZE_UNSAFE(a) \
- ((sizeof(a) / sizeof(*(a))) / \
- static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
-
#define SIZEOF_MEMBER(t, f) sizeof(std::declval<t>().f)
// Changing this definition will cause you a lot of pain. A majority of
@@ -153,23 +113,23 @@
// case 42:
// ...
//
-// As shown in the example above, the FALLTHROUGH_INTENDED macro should be
-// followed by a semicolon. It is designed to mimic control-flow statements
-// like 'break;', so it can be placed in most places where 'break;' can, but
-// only if there are no statements on the execution path between it and the
-// next switch label.
+// As shown in the example above, the FALLTHROUGH_INTENDED macro should be
+// followed by a semicolon. It is designed to mimic control-flow statements
+// like 'break;', so it can be placed in most places where 'break;' can, but
+// only if there are no statements on the execution path between it and the
+// next switch label.
//
-// When compiled with clang, the FALLTHROUGH_INTENDED macro is expanded to
-// [[clang::fallthrough]] attribute, which is analysed when performing switch
-// labels fall-through diagnostic ('-Wimplicit-fallthrough'). See clang
-// documentation on language extensions for details:
-// http://clang.llvm.org/docs/LanguageExtensions.html#clang__fallthrough
+// When compiled with clang, the FALLTHROUGH_INTENDED macro is expanded to
+// [[clang::fallthrough]] attribute, which is analysed when performing switch
+// labels fall-through diagnostic ('-Wimplicit-fallthrough'). See clang
+// documentation on language extensions for details:
+// http://clang.llvm.org/docs/LanguageExtensions.html#clang__fallthrough
//
-// When used with unsupported compilers, the FALLTHROUGH_INTENDED macro has no
-// effect on diagnostics.
+// When used with unsupported compilers, the FALLTHROUGH_INTENDED macro has no
+// effect on diagnostics.
//
-// In either case this macro has no effect on runtime behavior and performance
-// of code.
+// In either case this macro has no effect on runtime behavior and performance
+// of code.
#ifndef FALLTHROUGH_INTENDED
#define FALLTHROUGH_INTENDED [[clang::fallthrough]] // NOLINT
#endif
diff --git a/base/include/android-base/mapped_file.h b/base/include/android-base/mapped_file.h
new file mode 100644
index 0000000..52d11ed
--- /dev/null
+++ b/base/include/android-base/mapped_file.h
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "android-base/macros.h"
+
+#include <sys/types.h>
+
+#include <memory>
+
+#if defined(_WIN32)
+#include <windows.h>
+#define PROT_READ 1
+#define PROT_WRITE 2
+#else
+#include <sys/mman.h>
+#endif
+
+namespace android {
+namespace base {
+
+/**
+ * A region of a file mapped into memory.
+ */
+class MappedFile {
+ public:
+ /**
+ * Creates a new mapping of the file pointed to by `fd`. Unlike the underlying OS primitives,
+ * `offset` does not need to be page-aligned. If `PROT_WRITE` is set in `prot`, the mapping
+ * will be writable, otherwise it will be read-only. Mappings are always `MAP_SHARED`.
+ */
+ static std::unique_ptr<MappedFile> FromFd(int fd, off64_t offset, size_t length, int prot);
+
+ /**
+ * Removes the mapping.
+ */
+ ~MappedFile();
+
+ char* data() { return base_ + offset_; }
+ size_t size() { return size_; }
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(MappedFile);
+
+ char* base_;
+ size_t size_;
+
+ size_t offset_;
+
+#if defined(_WIN32)
+ MappedFile(char* base, size_t size, size_t offset, HANDLE handle)
+ : base_(base), size_(size), offset_(offset), handle_(handle) {}
+ HANDLE handle_;
+#else
+ MappedFile(char* base, size_t size, size_t offset) : base_(base), size_(size), offset_(offset) {}
+#endif
+};
+
+} // namespace base
+} // namespace android
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/base/mapped_file.cpp b/base/mapped_file.cpp
new file mode 100644
index 0000000..f7901af
--- /dev/null
+++ b/base/mapped_file.cpp
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+#include "android-base/mapped_file.h"
+
+namespace android {
+namespace base {
+
+static off64_t InitPageSize() {
+#if defined(_WIN32)
+ SYSTEM_INFO si;
+ GetSystemInfo(&si);
+ return si.dwAllocationGranularity;
+#else
+ return sysconf(_SC_PAGE_SIZE);
+#endif
+}
+
+std::unique_ptr<MappedFile> MappedFile::FromFd(int fd, off64_t offset, size_t length, int prot) {
+ static off64_t page_size = InitPageSize();
+ size_t slop = offset % page_size;
+ off64_t file_offset = offset - slop;
+ off64_t file_length = length + slop;
+
+#if defined(_WIN32)
+ HANDLE handle =
+ CreateFileMapping(reinterpret_cast<HANDLE>(_get_osfhandle(fd)), nullptr,
+ (prot & PROT_WRITE) ? PAGE_READWRITE : PAGE_READONLY, 0, 0, nullptr);
+ if (handle == nullptr) return nullptr;
+ void* base = MapViewOfFile(handle, (prot & PROT_WRITE) ? FILE_MAP_ALL_ACCESS : FILE_MAP_READ, 0,
+ file_offset, file_length);
+ if (base == nullptr) {
+ CloseHandle(handle);
+ return nullptr;
+ }
+ return std::unique_ptr<MappedFile>(
+ new MappedFile{static_cast<char*>(base), length, slop, handle});
+#else
+ void* base = mmap(nullptr, file_length, prot, MAP_SHARED, fd, file_offset);
+ if (base == MAP_FAILED) return nullptr;
+ return std::unique_ptr<MappedFile>(new MappedFile{static_cast<char*>(base), length, slop});
+#endif
+}
+
+MappedFile::~MappedFile() {
+#if defined(_WIN32)
+ if (base_ != nullptr) UnmapViewOfFile(base_);
+ if (handle_ != nullptr) CloseHandle(handle_);
+#else
+ if (base_ != nullptr) munmap(base_, size_);
+#endif
+
+ base_ = nullptr;
+ offset_ = size_ = 0;
+}
+
+} // namespace base
+} // namespace android
diff --git a/base/mapped_file_test.cpp b/base/mapped_file_test.cpp
new file mode 100644
index 0000000..57fde6f
--- /dev/null
+++ b/base/mapped_file_test.cpp
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+#include "android-base/mapped_file.h"
+
+#include <gtest/gtest.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <string>
+
+#include "android-base/file.h"
+#include "android-base/test_utils.h"
+#include "android-base/unique_fd.h"
+
+TEST(mapped_file, smoke) {
+ TemporaryFile tf;
+ ASSERT_TRUE(tf.fd != -1);
+ ASSERT_TRUE(android::base::WriteStringToFd("hello world", tf.fd));
+
+ auto m = android::base::MappedFile::FromFd(tf.fd, 3, 2, PROT_READ);
+ ASSERT_EQ(2u, m->size());
+ ASSERT_EQ('l', m->data()[0]);
+ ASSERT_EQ('o', m->data()[1]);
+}
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 6b6e659..925cac4 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -79,8 +79,8 @@
using android::base::Trim;
using android::base::unique_fd;
-#ifndef O_BINARY
-#define O_BINARY 0
+#if defined(_WIN32)
+#define O_CLOEXEC O_NOINHERIT
#endif
static const char* serial = nullptr;
diff --git a/fastboot/fastboot_driver.cpp b/fastboot/fastboot_driver.cpp
index b1f3bc9..65a5247 100644
--- a/fastboot/fastboot_driver.cpp
+++ b/fastboot/fastboot_driver.cpp
@@ -41,10 +41,10 @@
#include <vector>
#include <android-base/file.h>
+#include <android-base/mapped_file.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
-#include <utils/FileMap.h>
#include "constants.h"
#include "transport.h"
@@ -467,15 +467,14 @@
while (remaining) {
// Memory map the file
- android::FileMap filemap;
size_t len = std::min(remaining, MAX_MAP_SIZE);
-
- if (!filemap.create(NULL, fd, offset, len, true)) {
+ auto mapping{android::base::MappedFile::FromFd(fd, offset, len, PROT_READ)};
+ if (!mapping) {
error_ = "Creating filemap failed";
return IO_ERROR;
}
- if ((ret = SendBuffer(filemap.getDataPtr(), len))) {
+ if ((ret = SendBuffer(mapping->data(), mapping->size()))) {
return ret;
}
diff --git a/fs_mgr/liblp/Android.bp b/fs_mgr/liblp/Android.bp
index bbdec5b..4953655 100644
--- a/fs_mgr/liblp/Android.bp
+++ b/fs_mgr/liblp/Android.bp
@@ -47,6 +47,9 @@
cppflags: [
"-Wno-unused-parameter",
],
+ static_libs: [
+ "libgmock",
+ ],
shared_libs: [
"liblp",
"libbase",
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index 80257fe..2c57a35 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -339,7 +339,7 @@
return nullptr;
}
-PartitionGroup* MetadataBuilder::FindGroup(const std::string& group_name) const {
+PartitionGroup* MetadataBuilder::FindGroup(const std::string& group_name) {
for (const auto& group : groups_) {
if (group->name() == group_name) {
return group.get();
@@ -368,6 +368,57 @@
}
}
+void MetadataBuilder::ExtentsToFreeList(const std::vector<Interval>& extents,
+ std::vector<Interval>* free_regions) const {
+ // Convert the extent list into a list of gaps between the extents; i.e.,
+ // the list of ranges that are free on the disk.
+ for (size_t i = 1; i < extents.size(); i++) {
+ const Interval& previous = extents[i - 1];
+ const Interval& current = extents[i];
+
+ uint64_t aligned = AlignSector(previous.end);
+ if (aligned >= current.start) {
+ // There is no gap between these two extents, try the next one.
+ // Note that we check with >= instead of >, since alignment may
+ // bump the ending sector past the beginning of the next extent.
+ continue;
+ }
+
+ // The new interval represents the free space starting at the end of
+ // the previous interval, and ending at the start of the next interval.
+ free_regions->emplace_back(aligned, current.start);
+ }
+}
+
+auto MetadataBuilder::GetFreeRegions() const -> std::vector<Interval> {
+ std::vector<Interval> free_regions;
+
+ // Collect all extents in the partition table, then sort them by starting
+ // sector.
+ std::vector<Interval> extents;
+ for (const auto& partition : partitions_) {
+ for (const auto& extent : partition->extents()) {
+ LinearExtent* linear = extent->AsLinearExtent();
+ if (!linear) {
+ continue;
+ }
+ extents.emplace_back(linear->physical_sector(),
+ linear->physical_sector() + extent->num_sectors());
+ }
+ }
+
+ // Add 0-length intervals for the first and last sectors. This will cause
+ // ExtentsToFreeList() to treat the space in between as available.
+ uint64_t last_sector = geometry_.block_device_size / LP_SECTOR_SIZE;
+ extents.emplace_back(geometry_.first_logical_sector, geometry_.first_logical_sector);
+ extents.emplace_back(last_sector, last_sector);
+
+ std::sort(extents.begin(), extents.end());
+
+ ExtentsToFreeList(extents, &free_regions);
+ return free_regions;
+}
+
bool MetadataBuilder::GrowPartition(Partition* partition, uint64_t aligned_size) {
PartitionGroup* group = FindGroup(partition->group_name());
CHECK(group);
@@ -389,59 +440,7 @@
uint64_t sectors_needed = space_needed / LP_SECTOR_SIZE;
DCHECK(sectors_needed * LP_SECTOR_SIZE == space_needed);
- struct Interval {
- uint64_t start;
- uint64_t end;
-
- Interval(uint64_t start, uint64_t end) : start(start), end(end) {}
- uint64_t length() const { return end - start; }
- bool operator<(const Interval& other) const { return start < other.start; }
- };
-
- // Collect all extents in the partition table, then sort them by starting
- // sector.
- std::vector<Interval> extents;
- for (const auto& partition : partitions_) {
- for (const auto& extent : partition->extents()) {
- LinearExtent* linear = extent->AsLinearExtent();
- if (!linear) {
- continue;
- }
- extents.emplace_back(linear->physical_sector(),
- linear->physical_sector() + extent->num_sectors());
- }
- }
- std::sort(extents.begin(), extents.end());
-
- // Convert the extent list into a list of gaps between the extents; i.e.,
- // the list of ranges that are free on the disk.
- std::vector<Interval> free_regions;
- for (size_t i = 1; i < extents.size(); i++) {
- const Interval& previous = extents[i - 1];
- const Interval& current = extents[i];
-
- uint64_t aligned = AlignSector(previous.end);
- if (aligned >= current.start) {
- // There is no gap between these two extents, try the next one.
- // Note that we check with >= instead of >, since alignment may
- // bump the ending sector past the beginning of the next extent.
- continue;
- }
-
- // The new interval represents the free space starting at the end of
- // the previous interval, and ending at the start of the next interval.
- free_regions.emplace_back(aligned, current.start);
- }
-
- // Add a final interval representing the remainder of the free space.
- uint64_t last_free_extent_start =
- extents.empty() ? geometry_.first_logical_sector : extents.back().end;
- last_free_extent_start = AlignSector(last_free_extent_start);
-
- uint64_t last_sector = geometry_.block_device_size / LP_SECTOR_SIZE;
- if (last_free_extent_start < last_sector) {
- free_regions.emplace_back(last_free_extent_start, last_sector);
- }
+ std::vector<Interval> free_regions = GetFreeRegions();
const uint64_t sectors_per_block = geometry_.logical_block_size / LP_SECTOR_SIZE;
CHECK_NE(sectors_per_block, 0);
@@ -566,7 +565,7 @@
return size;
}
-uint64_t MetadataBuilder::AlignSector(uint64_t sector) {
+uint64_t MetadataBuilder::AlignSector(uint64_t sector) const {
// Note: when reading alignment info from the Kernel, we don't assume it
// is aligned to the sector size, so we round up to the nearest sector.
uint64_t lba = sector * LP_SECTOR_SIZE;
@@ -625,5 +624,36 @@
return true;
}
+std::vector<std::string> MetadataBuilder::ListGroups() const {
+ std::vector<std::string> names;
+ for (const auto& group : groups_) {
+ names.emplace_back(group->name());
+ }
+ return names;
+}
+
+void MetadataBuilder::RemoveGroupAndPartitions(const std::string& group_name) {
+ if (group_name == "default") {
+ // Cannot remove the default group.
+ return;
+ }
+ std::vector<std::string> partition_names;
+ for (const auto& partition : partitions_) {
+ if (partition->group_name() == group_name) {
+ partition_names.emplace_back(partition->name());
+ }
+ }
+
+ for (const auto& partition_name : partition_names) {
+ RemovePartition(partition_name);
+ }
+ for (auto iter = groups_.begin(); iter != groups_.end(); iter++) {
+ if ((*iter)->name() == group_name) {
+ groups_.erase(iter);
+ break;
+ }
+ }
+}
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index f5d39a8..27ad250 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -14,13 +14,16 @@
* limitations under the License.
*/
+#include <fs_mgr.h>
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <liblp/builder.h>
-#include "fs_mgr.h"
+
#include "utility.h"
using namespace std;
using namespace android::fs_mgr;
+using ::testing::ElementsAre;
TEST(liblp, BuildBasic) {
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
@@ -515,3 +518,57 @@
EXPECT_FALSE(builder->ResizePartition(partition, 32768));
EXPECT_EQ(partition->size(), 16384);
}
+
+constexpr unsigned long long operator"" _GiB(unsigned long long x) { // NOLINT
+ return x << 30;
+}
+
+TEST(liblp, RemoveAndAddFirstPartition) {
+ auto builder = MetadataBuilder::New(10_GiB, 65536, 2);
+ ASSERT_NE(nullptr, builder);
+ ASSERT_TRUE(builder->AddGroup("foo_a", 5_GiB));
+ ASSERT_TRUE(builder->AddGroup("foo_b", 5_GiB));
+ android::fs_mgr::Partition* p;
+ p = builder->AddPartition("system_a", "foo_a", 0);
+ ASSERT_TRUE(p && builder->ResizePartition(p, 2_GiB));
+ p = builder->AddPartition("vendor_a", "foo_a", 0);
+ ASSERT_TRUE(p && builder->ResizePartition(p, 1_GiB));
+ p = builder->AddPartition("system_b", "foo_b", 0);
+ ASSERT_TRUE(p && builder->ResizePartition(p, 2_GiB));
+ p = builder->AddPartition("vendor_b", "foo_b", 0);
+ ASSERT_TRUE(p && builder->ResizePartition(p, 1_GiB));
+
+ builder->RemovePartition("system_a");
+ builder->RemovePartition("vendor_a");
+ p = builder->AddPartition("system_a", "foo_a", 0);
+ ASSERT_TRUE(p && builder->ResizePartition(p, 3_GiB));
+ p = builder->AddPartition("vendor_a", "foo_a", 0);
+ ASSERT_TRUE(p && builder->ResizePartition(p, 1_GiB));
+}
+
+TEST(liblp, ListGroups) {
+ BlockDeviceInfo device_info(1024 * 1024, 0, 0, 4096);
+ unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
+ ASSERT_NE(builder, nullptr);
+ ASSERT_TRUE(builder->AddGroup("example", 0));
+
+ std::vector<std::string> groups = builder->ListGroups();
+ ASSERT_THAT(groups, ElementsAre("default", "example"));
+}
+
+TEST(liblp, RemoveGroupAndPartitions) {
+ BlockDeviceInfo device_info(1024 * 1024, 0, 0, 4096);
+ unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
+ ASSERT_NE(builder, nullptr);
+ ASSERT_TRUE(builder->AddGroup("example", 0));
+ ASSERT_NE(builder->AddPartition("system", "default", 0), nullptr);
+ ASSERT_NE(builder->AddPartition("vendor", "example", 0), nullptr);
+
+ builder->RemoveGroupAndPartitions("example");
+ ASSERT_NE(builder->FindPartition("system"), nullptr);
+ ASSERT_EQ(builder->FindPartition("vendor"), nullptr);
+ ASSERT_THAT(builder->ListGroups(), ElementsAre("default"));
+
+ builder->RemoveGroupAndPartitions("default");
+ ASSERT_NE(builder->FindPartition("system"), nullptr);
+}
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index 8dbba84..7e07df4 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -199,6 +199,9 @@
// Find a partition by name. If no partition is found, nullptr is returned.
Partition* FindPartition(const std::string& name);
+ // Find a group by name. If no group is found, nullptr is returned.
+ PartitionGroup* FindGroup(const std::string& name);
+
// Grow or shrink a partition to the requested size. This size will be
// rounded UP to the nearest block (512 bytes).
//
@@ -215,6 +218,12 @@
uint64_t AllocatableSpace() const;
uint64_t UsedSpace() const;
+ // Return a list of all group names.
+ std::vector<std::string> ListGroups() const;
+
+ // Remove all partitions belonging to a group, then remove the group.
+ void RemoveGroupAndPartitions(const std::string& group_name);
+
bool GetBlockDeviceInfo(BlockDeviceInfo* info) const;
bool UpdateBlockDeviceInfo(const BlockDeviceInfo& info);
@@ -228,10 +237,23 @@
bool Init(const LpMetadata& metadata);
bool GrowPartition(Partition* partition, uint64_t aligned_size);
void ShrinkPartition(Partition* partition, uint64_t aligned_size);
- uint64_t AlignSector(uint64_t sector);
- PartitionGroup* FindGroup(const std::string& group_name) const;
+ uint64_t AlignSector(uint64_t sector) const;
uint64_t TotalSizeOfGroup(PartitionGroup* group) const;
+ struct Interval {
+ uint64_t start;
+ uint64_t end;
+
+ Interval(uint64_t start, uint64_t end) : start(start), end(end) {}
+ uint64_t length() const { return end - start; }
+ bool operator<(const Interval& other) const {
+ return (start == other.start) ? end < other.end : start < other.start;
+ }
+ };
+ std::vector<Interval> GetFreeRegions() const;
+ void ExtentsToFreeList(const std::vector<Interval>& extents,
+ std::vector<Interval>* free_regions) const;
+
LpMetadataGeometry geometry_;
LpMetadataHeader header_;
std::vector<std::unique_ptr<Partition>> partitions_;
diff --git a/healthd/animation.h b/healthd/animation.h
index 562b689..f59fb38 100644
--- a/healthd/animation.h
+++ b/healthd/animation.h
@@ -20,7 +20,7 @@
#include <inttypes.h>
#include <string>
-struct GRSurface;
+class GRSurface;
struct GRFont;
namespace android {
diff --git a/init/action_parser.cpp b/init/action_parser.cpp
index 1481162..2d497b3 100644
--- a/init/action_parser.cpp
+++ b/init/action_parser.cpp
@@ -19,7 +19,11 @@
#include <android-base/properties.h>
#include <android-base/strings.h>
-#include "stable_properties.h"
+#if defined(__ANDROID__)
+#include "property_service.h"
+#else
+#include "host_init_stubs.h"
+#endif
using android::base::GetBoolProperty;
using android::base::StartsWith;
@@ -36,15 +40,7 @@
return true;
}
- if (kExportedActionableProperties.count(prop_name) == 1) {
- return true;
- }
- for (const auto& prefix : kPartnerPrefixes) {
- if (android::base::StartsWith(prop_name, prefix)) {
- return true;
- }
- }
- return false;
+ return CanReadProperty(subcontext->context(), prop_name);
}
Result<Success> ParsePropertyTrigger(const std::string& trigger, Subcontext* subcontext,
diff --git a/init/host_init_stubs.cpp b/init/host_init_stubs.cpp
index 8866bdc..b85e54a 100644
--- a/init/host_init_stubs.cpp
+++ b/init/host_init_stubs.cpp
@@ -30,6 +30,9 @@
std::string default_console = "/dev/console";
// property_service.h
+bool CanReadProperty(const std::string& source_context, const std::string& name) {
+ return true;
+}
uint32_t SetProperty(const std::string& key, const std::string& value) {
android::base::SetProperty(key, value);
return 0;
diff --git a/init/host_init_stubs.h b/init/host_init_stubs.h
index 0af11f6..63ceead 100644
--- a/init/host_init_stubs.h
+++ b/init/host_init_stubs.h
@@ -39,6 +39,7 @@
extern std::string default_console;
// property_service.h
+bool CanReadProperty(const std::string& source_context, const std::string& name);
extern uint32_t (*property_set)(const std::string& name, const std::string& value);
uint32_t HandlePropertySet(const std::string& name, const std::string& value,
const std::string& source_context, const ucred& cr, std::string* error);
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 6aed0a3..5328869 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -111,6 +111,22 @@
LOG(FATAL) << "Failed to load serialized property info file";
}
}
+
+bool CanReadProperty(const std::string& source_context, const std::string& name) {
+ const char* target_context = nullptr;
+ property_info_area->GetPropertyInfo(name.c_str(), &target_context, nullptr);
+
+ PropertyAuditData audit_data;
+
+ audit_data.name = name.c_str();
+
+ ucred cr = {.pid = 0, .uid = 0, .gid = 0};
+ audit_data.cr = &cr;
+
+ return selinux_check_access(source_context.c_str(), target_context, "file", "read",
+ &audit_data) == 0;
+}
+
static bool CheckMacPerms(const std::string& name, const char* target_context,
const char* source_context, const ucred& cr) {
if (!target_context || !source_context) {
diff --git a/init/property_service.h b/init/property_service.h
index cacd987..9022f5a 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -26,6 +26,8 @@
namespace android {
namespace init {
+bool CanReadProperty(const std::string& source_context, const std::string& name);
+
extern uint32_t (*property_set)(const std::string& name, const std::string& value);
uint32_t HandlePropertySet(const std::string& name, const std::string& value,
diff --git a/init/stable_properties.h b/init/stable_properties.h
deleted file mode 100644
index baef833..0000000
--- a/init/stable_properties.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _INIT_STABLE_PROPERTIES_H
-#define _INIT_STABLE_PROPERTIES_H
-
-#include <set>
-#include <string>
-
-namespace android {
-namespace init {
-
-static constexpr const char* kPartnerPrefixes[] = {
- "init.svc.vendor.", "ro.vendor.", "persist.vendor.", "vendor.", "init.svc.odm.", "ro.odm.",
- "persist.odm.", "odm.", "ro.boot.",
-};
-
-static const std::set<std::string> kExportedActionableProperties = {
- "dev.bootcomplete",
- "init.svc.console",
- "init.svc.dumpstatez",
- "init.svc.mediadrm",
- "init.svc.surfaceflinger",
- "init.svc.zygote",
- "persist.bluetooth.btsnoopenable",
- "persist.sys.crash_rcu",
- "persist.sys.usb.usbradio.config",
- "persist.sys.zram_enabled",
- "ro.board.platform",
- "ro.bootmode",
- "ro.build.type",
- "ro.crypto.state",
- "ro.crypto.type",
- "ro.debuggable",
- "sys.boot_completed",
- "sys.boot_from_charger_mode",
- "sys.retaildemo.enabled",
- "sys.shutdown.requested",
- "sys.usb.config",
- "sys.usb.configfs",
- "sys.usb.ffs.mtp.ready",
- "sys.usb.ffs.ready",
- "sys.user.0.ce_available",
- "sys.vdso",
- "vold.decrypt",
- "vold.post_fs_data_done",
- "vts.native_server.on",
- "wlan.driver.status",
-};
-
-} // namespace init
-} // namespace android
-
-#endif
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
index d2d6ab8..52dd441 100644
--- a/libbacktrace/UnwindStackMap.cpp
+++ b/libbacktrace/UnwindStackMap.cpp
@@ -106,7 +106,7 @@
return "";
}
- unwindstack::Elf* elf = map_info->GetElf(process_memory(), true);
+ unwindstack::Elf* elf = map_info->GetElf(process_memory());
std::string name;
uint64_t func_offset;
diff --git a/libnativebridge/Android.bp b/libnativebridge/Android.bp
index 6e63b74..92fd2a2 100644
--- a/libnativebridge/Android.bp
+++ b/libnativebridge/Android.bp
@@ -10,9 +10,11 @@
host_supported: true,
srcs: ["native_bridge.cc"],
+ header_libs: [
+ "libbase_headers",
+ ],
shared_libs: [
"liblog",
- "libbase",
],
export_include_dirs: ["include"],
diff --git a/libnativebridge/tests/Android.mk b/libnativebridge/tests/Android.mk
index 5b9ba1c..4ed6e20 100644
--- a/libnativebridge/tests/Android.mk
+++ b/libnativebridge/tests/Android.mk
@@ -29,10 +29,12 @@
shared_libraries := \
liblog \
- libbase \
libnativebridge \
libnativebridge-dummy
+header_libraries := \
+ libbase_headers
+
libnativebridge_tests_common_cflags := \
-Wall \
-Werror \
@@ -40,6 +42,7 @@
$(foreach file,$(test_src_files), \
$(eval include $(CLEAR_VARS)) \
$(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
+ $(eval LOCAL_HEADER_LIBRARIES := $(header_libraries)) \
$(eval LOCAL_SRC_FILES := $(file)) \
$(eval LOCAL_CFLAGS := $(libnativebridge_tests_common_cflags)) \
$(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
@@ -49,6 +52,7 @@
$(foreach file,$(test_src_files), \
$(eval include $(CLEAR_VARS)) \
$(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
+ $(eval LOCAL_HEADER_LIBRARIES := $(header_libraries)) \
$(eval LOCAL_SRC_FILES := $(file)) \
$(eval LOCAL_CFLAGS := $(libnativebridge_tests_common_cflags)) \
$(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index 56a0679..60ef796 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -40,7 +40,7 @@
std::unordered_map<std::string, std::pair<std::shared_ptr<Elf>, bool>>* Elf::cache_;
std::mutex* Elf::cache_lock_;
-bool Elf::Init(bool init_gnu_debugdata) {
+bool Elf::Init() {
load_bias_ = 0;
if (!memory_) {
return false;
@@ -54,11 +54,7 @@
valid_ = interface_->Init(&load_bias_);
if (valid_) {
interface_->InitHeaders(load_bias_);
- if (init_gnu_debugdata) {
- InitGnuDebugdata();
- } else {
- gnu_debugdata_interface_.reset(nullptr);
- }
+ InitGnuDebugdata();
} else {
interface_.reset(nullptr);
}
diff --git a/libunwindstack/Global.cpp b/libunwindstack/Global.cpp
index b449c7e..f0ad2b6 100644
--- a/libunwindstack/Global.cpp
+++ b/libunwindstack/Global.cpp
@@ -46,7 +46,7 @@
}
}
- Elf* elf = info->GetElf(memory_, true);
+ Elf* elf = info->GetElf(memory_);
uint64_t ptr;
// Find first non-empty list (libraries might be loaded multiple times).
if (elf->GetGlobalVariable(variable, &ptr) && ptr != 0) {
diff --git a/libunwindstack/JitDebug.cpp b/libunwindstack/JitDebug.cpp
index fe680d7..d6af49e 100644
--- a/libunwindstack/JitDebug.cpp
+++ b/libunwindstack/JitDebug.cpp
@@ -201,7 +201,7 @@
entry_addr_ = (this->*read_entry_func_)(&start, &size);
Elf* elf = new Elf(new MemoryRange(memory_, start, size, 0));
- elf->Init(true);
+ elf->Init();
if (!elf->valid()) {
// The data is not formatted in a way we understand, do not attempt
// to process any other entries.
diff --git a/libunwindstack/LocalUnwinder.cpp b/libunwindstack/LocalUnwinder.cpp
index 952b332..31337a9 100644
--- a/libunwindstack/LocalUnwinder.cpp
+++ b/libunwindstack/LocalUnwinder.cpp
@@ -100,7 +100,7 @@
break;
}
- Elf* elf = map_info->GetElf(process_memory_, true);
+ Elf* elf = map_info->GetElf(process_memory_);
uint64_t rel_pc = elf->GetRelPc(cur_pc, map_info);
uint64_t step_pc = rel_pc;
uint64_t pc_adjustment;
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
index 52b7535..8527797 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -146,7 +146,7 @@
return nullptr;
}
-Elf* MapInfo::GetElf(const std::shared_ptr<Memory>& process_memory, bool init_gnu_debugdata) {
+Elf* MapInfo::GetElf(const std::shared_ptr<Memory>& process_memory) {
// Make sure no other thread is trying to add the elf to this map.
std::lock_guard<std::mutex> guard(mutex_);
@@ -175,7 +175,7 @@
elf.reset(new Elf(memory));
// If the init fails, keep the elf around as an invalid object so we
// don't try to reinit the object.
- elf->Init(init_gnu_debugdata);
+ elf->Init();
if (locked) {
Elf::CacheAdd(this);
diff --git a/libunwindstack/RegsInfo.h b/libunwindstack/RegsInfo.h
index e6dd33c..e445a91 100644
--- a/libunwindstack/RegsInfo.h
+++ b/libunwindstack/RegsInfo.h
@@ -41,7 +41,7 @@
}
inline AddressType* Save(uint32_t reg) {
- if (reg > MAX_REGISTERS) {
+ if (reg >= MAX_REGISTERS) {
// This should never happen since all currently supported
// architectures have < 64 total registers.
abort();
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index ee1cd1a..b8b0ac6 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -155,7 +155,7 @@
if (ShouldStop(map_suffixes_to_ignore, map_info->name)) {
break;
}
- elf = map_info->GetElf(process_memory_, true);
+ elf = map_info->GetElf(process_memory_);
step_pc = regs_->pc();
rel_pc = elf->GetRelPc(step_pc, map_info);
// Everyone except elf data in gdb jit debug maps uses the relative pc.
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index 9af859d..24cabf2 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -53,7 +53,7 @@
Elf(Memory* memory) : memory_(memory) {}
virtual ~Elf() = default;
- bool Init(bool init_gnu_debugdata);
+ bool Init();
void InitGnuDebugdata();
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
index 9755c48..ff634f2 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -72,7 +72,7 @@
std::atomic_uint64_t load_bias;
// This function guarantees it will never return nullptr.
- Elf* GetElf(const std::shared_ptr<Memory>& process_memory, bool init_gnu_debugdata = false);
+ Elf* GetElf(const std::shared_ptr<Memory>& process_memory);
uint64_t GetLoadBias(const std::shared_ptr<Memory>& process_memory);
diff --git a/libunwindstack/tests/ElfCacheTest.cpp b/libunwindstack/tests/ElfCacheTest.cpp
index 1afd4ef..8ed697c 100644
--- a/libunwindstack/tests/ElfCacheTest.cpp
+++ b/libunwindstack/tests/ElfCacheTest.cpp
@@ -82,9 +82,9 @@
MapInfo info1(nullptr, start, end, 0, 0x5, tf.path);
MapInfo info2(nullptr, start, end, 0, 0x5, tf.path);
- Elf* elf1 = info1.GetElf(memory_, true);
+ Elf* elf1 = info1.GetElf(memory_);
ASSERT_TRUE(elf1->valid());
- Elf* elf2 = info2.GetElf(memory_, true);
+ Elf* elf2 = info2.GetElf(memory_);
ASSERT_TRUE(elf2->valid());
if (cache_enabled) {
@@ -132,10 +132,10 @@
MapInfo info300_1(nullptr, start, end, 0x300, 0x5, tf.path);
MapInfo info300_2(nullptr, start, end, 0x300, 0x5, tf.path);
- Elf* elf0_1 = info0_1.GetElf(memory_, true);
+ Elf* elf0_1 = info0_1.GetElf(memory_);
ASSERT_TRUE(elf0_1->valid());
EXPECT_EQ(ARCH_ARM, elf0_1->arch());
- Elf* elf0_2 = info0_2.GetElf(memory_, true);
+ Elf* elf0_2 = info0_2.GetElf(memory_);
ASSERT_TRUE(elf0_2->valid());
EXPECT_EQ(ARCH_ARM, elf0_2->arch());
EXPECT_EQ(0U, info0_1.elf_offset);
@@ -146,10 +146,10 @@
EXPECT_NE(elf0_1, elf0_2);
}
- Elf* elf100_1 = info100_1.GetElf(memory_, true);
+ Elf* elf100_1 = info100_1.GetElf(memory_);
ASSERT_TRUE(elf100_1->valid());
EXPECT_EQ(ARCH_X86, elf100_1->arch());
- Elf* elf100_2 = info100_2.GetElf(memory_, true);
+ Elf* elf100_2 = info100_2.GetElf(memory_);
ASSERT_TRUE(elf100_2->valid());
EXPECT_EQ(ARCH_X86, elf100_2->arch());
EXPECT_EQ(0U, info100_1.elf_offset);
@@ -160,10 +160,10 @@
EXPECT_NE(elf100_1, elf100_2);
}
- Elf* elf200_1 = info200_1.GetElf(memory_, true);
+ Elf* elf200_1 = info200_1.GetElf(memory_);
ASSERT_TRUE(elf200_1->valid());
EXPECT_EQ(ARCH_X86_64, elf200_1->arch());
- Elf* elf200_2 = info200_2.GetElf(memory_, true);
+ Elf* elf200_2 = info200_2.GetElf(memory_);
ASSERT_TRUE(elf200_2->valid());
EXPECT_EQ(ARCH_X86_64, elf200_2->arch());
EXPECT_EQ(0U, info200_1.elf_offset);
@@ -174,10 +174,10 @@
EXPECT_NE(elf200_1, elf200_2);
}
- Elf* elf300_1 = info300_1.GetElf(memory_, true);
+ Elf* elf300_1 = info300_1.GetElf(memory_);
ASSERT_TRUE(elf300_1->valid());
EXPECT_EQ(ARCH_ARM, elf300_1->arch());
- Elf* elf300_2 = info300_2.GetElf(memory_, true);
+ Elf* elf300_2 = info300_2.GetElf(memory_);
ASSERT_TRUE(elf300_2->valid());
EXPECT_EQ(ARCH_ARM, elf300_2->arch());
EXPECT_EQ(0x300U, info300_1.elf_offset);
@@ -222,10 +222,10 @@
MapInfo info400_1(nullptr, start, end, 0x400, 0x5, tf.path);
MapInfo info400_2(nullptr, start, end, 0x400, 0x5, tf.path);
- Elf* elf300_1 = info300_1.GetElf(memory_, true);
+ Elf* elf300_1 = info300_1.GetElf(memory_);
ASSERT_TRUE(elf300_1->valid());
EXPECT_EQ(ARCH_ARM, elf300_1->arch());
- Elf* elf300_2 = info300_2.GetElf(memory_, true);
+ Elf* elf300_2 = info300_2.GetElf(memory_);
ASSERT_TRUE(elf300_2->valid());
EXPECT_EQ(ARCH_ARM, elf300_2->arch());
EXPECT_EQ(0x300U, info300_1.elf_offset);
@@ -236,10 +236,10 @@
EXPECT_NE(elf300_1, elf300_2);
}
- Elf* elf400_1 = info400_1.GetElf(memory_, true);
+ Elf* elf400_1 = info400_1.GetElf(memory_);
ASSERT_TRUE(elf400_1->valid());
EXPECT_EQ(ARCH_ARM, elf400_1->arch());
- Elf* elf400_2 = info400_2.GetElf(memory_, true);
+ Elf* elf400_2 = info400_2.GetElf(memory_);
ASSERT_TRUE(elf400_2->valid());
EXPECT_EQ(ARCH_ARM, elf400_2->arch());
EXPECT_EQ(0x400U, info400_1.elf_offset);
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
index 9a117b2..ccf8927 100644
--- a/libunwindstack/tests/ElfTest.cpp
+++ b/libunwindstack/tests/ElfTest.cpp
@@ -110,7 +110,7 @@
TEST_F(ElfTest, invalid_memory) {
Elf elf(memory_);
- ASSERT_FALSE(elf.Init(false));
+ ASSERT_FALSE(elf.Init());
ASSERT_FALSE(elf.valid());
}
@@ -122,7 +122,7 @@
// Corrupt the ELF signature.
memory_->SetData32(0, 0x7f000000);
- ASSERT_FALSE(elf.Init(false));
+ ASSERT_FALSE(elf.Init());
ASSERT_FALSE(elf.valid());
ASSERT_TRUE(elf.interface() == nullptr);
@@ -142,7 +142,7 @@
InitElf32(EM_PPC);
ResetLogs();
- ASSERT_FALSE(elf.Init(false));
+ ASSERT_FALSE(elf.Init());
ASSERT_EQ("", GetFakeLogBuf());
ASSERT_EQ("4 unwind 32 bit elf that is neither arm nor x86 nor mips: e_machine = 20\n\n",
@@ -155,7 +155,7 @@
InitElf64(EM_PPC64);
ResetLogs();
- ASSERT_FALSE(elf.Init(false));
+ ASSERT_FALSE(elf.Init());
ASSERT_EQ("", GetFakeLogBuf());
ASSERT_EQ("4 unwind 64 bit elf that is neither aarch64 nor x86_64 nor mips64: e_machine = 21\n\n",
@@ -167,7 +167,7 @@
InitElf32(EM_ARM);
- ASSERT_TRUE(elf.Init(false));
+ ASSERT_TRUE(elf.Init());
ASSERT_TRUE(elf.valid());
ASSERT_EQ(static_cast<uint32_t>(EM_ARM), elf.machine_type());
ASSERT_EQ(ELFCLASS32, elf.class_type());
@@ -179,7 +179,7 @@
InitElf32(EM_MIPS);
- ASSERT_TRUE(elf.Init(false));
+ ASSERT_TRUE(elf.Init());
ASSERT_TRUE(elf.valid());
ASSERT_EQ(static_cast<uint32_t>(EM_MIPS), elf.machine_type());
ASSERT_EQ(ELFCLASS32, elf.class_type());
@@ -191,7 +191,7 @@
InitElf32(EM_386);
- ASSERT_TRUE(elf.Init(false));
+ ASSERT_TRUE(elf.Init());
ASSERT_TRUE(elf.valid());
ASSERT_EQ(static_cast<uint32_t>(EM_386), elf.machine_type());
ASSERT_EQ(ELFCLASS32, elf.class_type());
@@ -203,7 +203,7 @@
InitElf64(EM_AARCH64);
- ASSERT_TRUE(elf.Init(false));
+ ASSERT_TRUE(elf.Init());
ASSERT_TRUE(elf.valid());
ASSERT_EQ(static_cast<uint32_t>(EM_AARCH64), elf.machine_type());
ASSERT_EQ(ELFCLASS64, elf.class_type());
@@ -215,7 +215,7 @@
InitElf64(EM_X86_64);
- ASSERT_TRUE(elf.Init(false));
+ ASSERT_TRUE(elf.Init());
ASSERT_TRUE(elf.valid());
ASSERT_EQ(static_cast<uint32_t>(EM_X86_64), elf.machine_type());
ASSERT_EQ(ELFCLASS64, elf.class_type());
@@ -227,41 +227,13 @@
InitElf64(EM_MIPS);
- ASSERT_TRUE(elf.Init(false));
+ ASSERT_TRUE(elf.Init());
ASSERT_TRUE(elf.valid());
ASSERT_EQ(static_cast<uint32_t>(EM_MIPS), elf.machine_type());
ASSERT_EQ(ELFCLASS64, elf.class_type());
ASSERT_TRUE(elf.interface() != nullptr);
}
-TEST_F(ElfTest, gnu_debugdata_init_fail32) {
- TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, false,
- [&](uint64_t offset, const void* ptr, size_t size) {
- memory_->SetMemory(offset, ptr, size);
- });
-
- Elf elf(memory_);
- ASSERT_TRUE(elf.Init(false));
- ASSERT_TRUE(elf.interface() != nullptr);
- ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
- EXPECT_EQ(0x1acU, elf.interface()->gnu_debugdata_offset());
- EXPECT_EQ(0x100U, elf.interface()->gnu_debugdata_size());
-}
-
-TEST_F(ElfTest, gnu_debugdata_init_fail64) {
- TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, false,
- [&](uint64_t offset, const void* ptr, size_t size) {
- memory_->SetMemory(offset, ptr, size);
- });
-
- Elf elf(memory_);
- ASSERT_TRUE(elf.Init(false));
- ASSERT_TRUE(elf.interface() != nullptr);
- ASSERT_TRUE(elf.gnu_debugdata_interface() == nullptr);
- EXPECT_EQ(0x200U, elf.interface()->gnu_debugdata_offset());
- EXPECT_EQ(0x100U, elf.interface()->gnu_debugdata_size());
-}
-
TEST_F(ElfTest, gnu_debugdata_init32) {
TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, true,
[&](uint64_t offset, const void* ptr, size_t size) {
@@ -269,7 +241,7 @@
});
Elf elf(memory_);
- ASSERT_TRUE(elf.Init(true));
+ ASSERT_TRUE(elf.Init());
ASSERT_TRUE(elf.interface() != nullptr);
ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr);
EXPECT_EQ(0x1acU, elf.interface()->gnu_debugdata_offset());
@@ -283,7 +255,7 @@
});
Elf elf(memory_);
- ASSERT_TRUE(elf.Init(true));
+ ASSERT_TRUE(elf.Init());
ASSERT_TRUE(elf.interface() != nullptr);
ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr);
EXPECT_EQ(0x200U, elf.interface()->gnu_debugdata_offset());
diff --git a/libunwindstack/tests/MapInfoGetElfTest.cpp b/libunwindstack/tests/MapInfoGetElfTest.cpp
index 918c028..c6c1c34 100644
--- a/libunwindstack/tests/MapInfoGetElfTest.cpp
+++ b/libunwindstack/tests/MapInfoGetElfTest.cpp
@@ -72,7 +72,7 @@
MapInfo info(nullptr, 0x1000, 0x2000, 0, PROT_READ, "");
// The map is empty, but this should still create an invalid elf object.
- Elf* elf = info.GetElf(process_memory_, false);
+ Elf* elf = info.GetElf(process_memory_);
ASSERT_TRUE(elf != nullptr);
ASSERT_FALSE(elf->valid());
}
@@ -84,7 +84,7 @@
TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
memory_->SetMemory(0x3000, &ehdr, sizeof(ehdr));
- Elf* elf = info.GetElf(process_memory_, false);
+ Elf* elf = info.GetElf(process_memory_);
ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
@@ -98,45 +98,13 @@
TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
memory_->SetMemory(0x8000, &ehdr, sizeof(ehdr));
- Elf* elf = info.GetElf(process_memory_, false);
+ Elf* elf = info.GetElf(process_memory_);
ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
EXPECT_EQ(ELFCLASS64, elf->class_type());
}
-TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init32) {
- MapInfo info(nullptr, 0x4000, 0x8000, 0, PROT_READ, "");
-
- TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, false,
- [&](uint64_t offset, const void* ptr, size_t size) {
- memory_->SetMemory(0x4000 + offset, ptr, size);
- });
-
- Elf* elf = info.GetElf(process_memory_, false);
- ASSERT_TRUE(elf != nullptr);
- ASSERT_TRUE(elf->valid());
- EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
- EXPECT_EQ(ELFCLASS32, elf->class_type());
- EXPECT_TRUE(elf->gnu_debugdata_interface() == nullptr);
-}
-
-TEST_F(MapInfoGetElfTest, gnu_debugdata_do_not_init64) {
- MapInfo info(nullptr, 0x6000, 0x8000, 0, PROT_READ, "");
-
- TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, false,
- [&](uint64_t offset, const void* ptr, size_t size) {
- memory_->SetMemory(0x6000 + offset, ptr, size);
- });
-
- Elf* elf = info.GetElf(process_memory_, false);
- ASSERT_TRUE(elf != nullptr);
- ASSERT_TRUE(elf->valid());
- EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
- EXPECT_EQ(ELFCLASS64, elf->class_type());
- EXPECT_TRUE(elf->gnu_debugdata_interface() == nullptr);
-}
-
TEST_F(MapInfoGetElfTest, gnu_debugdata_init32) {
MapInfo info(nullptr, 0x2000, 0x3000, 0, PROT_READ, "");
@@ -145,7 +113,7 @@
memory_->SetMemory(0x2000 + offset, ptr, size);
});
- Elf* elf = info.GetElf(process_memory_, true);
+ Elf* elf = info.GetElf(process_memory_);
ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
@@ -161,7 +129,7 @@
memory_->SetMemory(0x5000 + offset, ptr, size);
});
- Elf* elf = info.GetElf(process_memory_, true);
+ Elf* elf = info.GetElf(process_memory_);
ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
@@ -176,20 +144,20 @@
TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
ASSERT_TRUE(android::base::WriteFully(elf_.fd, &ehdr, sizeof(ehdr)));
- Elf* elf = info.GetElf(process_memory_, false);
+ Elf* elf = info.GetElf(process_memory_);
ASSERT_TRUE(elf != nullptr);
ASSERT_FALSE(elf->valid());
info.elf.reset();
info.end = 0xfff;
- elf = info.GetElf(process_memory_, false);
+ elf = info.GetElf(process_memory_);
ASSERT_TRUE(elf != nullptr);
ASSERT_FALSE(elf->valid());
// Make sure this test is valid.
info.elf.reset();
info.end = 0x2000;
- elf = info.GetElf(process_memory_, false);
+ elf = info.GetElf(process_memory_);
ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
}
@@ -206,7 +174,7 @@
memcpy(buffer.data(), &ehdr, sizeof(ehdr));
ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
- Elf* elf = info.GetElf(process_memory_, false);
+ Elf* elf = info.GetElf(process_memory_);
ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
ASSERT_TRUE(elf->memory() != nullptr);
@@ -235,7 +203,7 @@
memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
- Elf* elf = info.GetElf(process_memory_, false);
+ Elf* elf = info.GetElf(process_memory_);
ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
ASSERT_TRUE(elf->memory() != nullptr);
@@ -268,7 +236,7 @@
memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
- Elf* elf = info.GetElf(process_memory_, false);
+ Elf* elf = info.GetElf(process_memory_);
ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
ASSERT_TRUE(elf->memory() != nullptr);
@@ -296,7 +264,7 @@
memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
- Elf* elf = info.GetElf(process_memory_, false);
+ Elf* elf = info.GetElf(process_memory_);
ASSERT_TRUE(elf != nullptr);
ASSERT_TRUE(elf->valid());
ASSERT_TRUE(elf->memory() != nullptr);
@@ -322,13 +290,13 @@
ehdr.e_shnum = 0;
memory_->SetMemory(0x9000, &ehdr, sizeof(ehdr));
- Elf* elf = info.GetElf(process_memory_, false);
+ Elf* elf = info.GetElf(process_memory_);
ASSERT_TRUE(elf != nullptr);
ASSERT_FALSE(elf->valid());
info.elf.reset();
info.flags = PROT_READ;
- elf = info.GetElf(process_memory_, false);
+ elf = info.GetElf(process_memory_);
ASSERT_TRUE(elf->valid());
}
@@ -345,20 +313,20 @@
ehdr.e_shnum = 0;
memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr));
- Elf* elf = info.GetElf(process_memory_, false);
+ Elf* elf = info.GetElf(process_memory_);
ASSERT_TRUE(elf != nullptr);
ASSERT_FALSE(elf->valid());
// Set the name to nothing to verify that it still fails.
info.elf.reset();
info.name = "";
- elf = info.GetElf(process_memory_, false);
+ elf = info.GetElf(process_memory_);
ASSERT_FALSE(elf->valid());
// Change the flags and verify the elf is valid now.
info.elf.reset();
info.flags = PROT_READ;
- elf = info.GetElf(process_memory_, false);
+ elf = info.GetElf(process_memory_);
ASSERT_TRUE(elf->valid());
}
@@ -384,7 +352,7 @@
std::thread* thread = new std::thread([i, this, &wait, &info, &elf_in_threads]() {
while (wait)
;
- Elf* elf = info.GetElf(process_memory_, false);
+ Elf* elf = info.GetElf(process_memory_);
elf_in_threads[i] = elf;
});
threads.push_back(thread);
diff --git a/libunwindstack/tests/RegsInfoTest.cpp b/libunwindstack/tests/RegsInfoTest.cpp
index 052b5bf..a6bc2c5 100644
--- a/libunwindstack/tests/RegsInfoTest.cpp
+++ b/libunwindstack/tests/RegsInfoTest.cpp
@@ -82,4 +82,11 @@
}
}
+TEST(RegsInfoTest, invalid_register) {
+ RegsImplFake<uint64_t> regs(64);
+ RegsInfo<uint64_t> info(®s);
+
+ EXPECT_DEATH(info.Save(RegsInfo<uint64_t>::MAX_REGISTERS), "");
+}
+
} // namespace unwindstack
diff --git a/libunwindstack/tools/unwind_info.cpp b/libunwindstack/tools/unwind_info.cpp
index 266a6db..aebeb95 100644
--- a/libunwindstack/tools/unwind_info.cpp
+++ b/libunwindstack/tools/unwind_info.cpp
@@ -113,7 +113,7 @@
}
Elf elf(memory);
- if (!elf.Init(true) || !elf.valid()) {
+ if (!elf.Init() || !elf.valid()) {
printf("%s is not a valid elf file.\n", file);
return 1;
}
diff --git a/libunwindstack/tools/unwind_reg_info.cpp b/libunwindstack/tools/unwind_reg_info.cpp
index 0f01566..4b6f49a 100644
--- a/libunwindstack/tools/unwind_reg_info.cpp
+++ b/libunwindstack/tools/unwind_reg_info.cpp
@@ -173,7 +173,7 @@
}
Elf elf(memory);
- if (!elf.Init(true) || !elf.valid()) {
+ if (!elf.Init() || !elf.valid()) {
printf("%s is not a valid elf file.\n", file);
return 1;
}
diff --git a/libunwindstack/tools/unwind_symbols.cpp b/libunwindstack/tools/unwind_symbols.cpp
index f8e3e92..9128430 100644
--- a/libunwindstack/tools/unwind_symbols.cpp
+++ b/libunwindstack/tools/unwind_symbols.cpp
@@ -66,7 +66,7 @@
}
unwindstack::Elf elf(memory);
- if (!elf.Init(true) || !elf.valid()) {
+ if (!elf.Init() || !elf.valid()) {
printf("%s is not a valid elf file.\n", argv[1]);
return 1;
}
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index 3308adf..608afb7 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -84,14 +84,6 @@
"libz",
],
target: {
- android: {
- shared_libs: [
- "libutils",
- ],
- },
- host: {
- static_libs: ["libutils"],
- },
linux_bionic: {
enabled: true,
},
diff --git a/libziparchive/include/ziparchive/zip_archive.h b/libziparchive/include/ziparchive/zip_archive.h
index 32d7901..3952532 100644
--- a/libziparchive/include/ziparchive/zip_archive.h
+++ b/libziparchive/include/ziparchive/zip_archive.h
@@ -14,17 +14,16 @@
* limitations under the License.
*/
+#pragma once
+
/*
* Read-only access to Zip archives, with minimal heap allocation.
*/
-#ifndef LIBZIPARCHIVE_ZIPARCHIVE_H_
-#define LIBZIPARCHIVE_ZIPARCHIVE_H_
#include <stdint.h>
#include <string.h>
#include <sys/cdefs.h>
#include <sys/types.h>
-#include <utils/Compat.h>
/* Zip compression methods we support */
enum {
@@ -273,5 +272,3 @@
int32_t Inflate(const Reader& reader, const uint32_t compressed_length,
const uint32_t uncompressed_length, Writer* writer, uint64_t* crc_out);
} // namespace zip_archive
-
-#endif // LIBZIPARCHIVE_ZIPARCHIVE_H_
diff --git a/libziparchive/include/ziparchive/zip_writer.h b/libziparchive/include/ziparchive/zip_writer.h
index 0e0caf1..6e4ca62 100644
--- a/libziparchive/include/ziparchive/zip_writer.h
+++ b/libziparchive/include/ziparchive/zip_writer.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef LIBZIPARCHIVE_ZIPWRITER_H_
-#define LIBZIPARCHIVE_ZIPWRITER_H_
+#pragma once
#include <cstdio>
#include <ctime>
@@ -25,7 +24,6 @@
#include <vector>
#include "android-base/macros.h"
-#include "utils/Compat.h"
struct z_stream_s;
typedef struct z_stream_s z_stream;
@@ -183,5 +181,3 @@
std::unique_ptr<z_stream, void (*)(z_stream*)> z_stream_;
std::vector<uint8_t> buffer_;
};
-
-#endif /* LIBZIPARCHIVE_ZIPWRITER_H_ */
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 4221ee7..9d6d919 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -20,7 +20,8 @@
#define LOG_TAG "ziparchive"
-#include <assert.h>
+#include "ziparchive/zip_archive.h"
+
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
@@ -40,12 +41,10 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/macros.h> // TEMP_FAILURE_RETRY may or may not be in unistd
+#include <android-base/mapped_file.h>
#include <android-base/memory.h>
#include <android-base/utf8.h>
#include <log/log.h>
-#include <utils/Compat.h>
-#include <utils/FileMap.h>
-#include "ziparchive/zip_archive.h"
#include "zlib.h"
#include "entry_name_utils-inl.h"
@@ -58,12 +57,6 @@
// specified in the local file header and the central directory.
static const bool kCrcChecksEnabled = false;
-// This is for windows. If we don't open a file in binary mode, weird
-// things will happen.
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
-
// The maximum number of bytes to scan backwards for the EOCD start.
static const uint32_t kMaxEOCDSearch = kMaxCommentLen + sizeof(EocdRecord);
@@ -196,7 +189,7 @@
close_file(assume_ownership),
directory_offset(0),
central_directory(),
- directory_map(new android::FileMap()),
+ directory_map(),
num_entries(0),
hash_table_size(0),
hash_table(nullptr) {
@@ -212,7 +205,7 @@
close_file(false),
directory_offset(0),
central_directory(),
- directory_map(new android::FileMap()),
+ directory_map(),
num_entries(0),
hash_table_size(0),
hash_table(nullptr) {}
@@ -303,8 +296,7 @@
* in archive.
*/
- if (!archive->InitializeCentralDirectory(debug_file_name,
- static_cast<off64_t>(eocd->cd_start_offset),
+ if (!archive->InitializeCentralDirectory(static_cast<off64_t>(eocd->cd_start_offset),
static_cast<size_t>(eocd->cd_size))) {
ALOGE("Zip: failed to intialize central directory.\n");
return kMmapFailed;
@@ -823,7 +815,7 @@
virtual bool Append(uint8_t* buf, size_t buf_size) override {
if (bytes_written_ + buf_size > size_) {
- ALOGW("Zip: Unexpected size " ZD " (declared) vs " ZD " (actual)", size_,
+ ALOGW("Zip: Unexpected size %zu (declared) vs %zu (actual)", size_,
bytes_written_ + buf_size);
return false;
}
@@ -910,7 +902,7 @@
virtual bool Append(uint8_t* buf, size_t buf_size) override {
if (total_bytes_written_ + buf_size > declared_length_) {
- ALOGW("Zip: Unexpected size " ZD " (declared) vs " ZD " (actual)", declared_length_,
+ ALOGW("Zip: Unexpected size %zu (declared) vs %zu (actual)", declared_length_,
total_bytes_written_ + buf_size);
return false;
}
@@ -919,7 +911,7 @@
if (result) {
total_bytes_written_ += buf_size;
} else {
- ALOGW("Zip: unable to write " ZD " bytes to file; %s", buf_size, strerror(errno));
+ ALOGW("Zip: unable to write %zu bytes to file; %s", buf_size, strerror(errno));
}
return result;
@@ -1048,7 +1040,7 @@
}
} while (zerr == Z_OK);
- assert(zerr == Z_STREAM_END); /* other errors should've been caught */
+ CHECK_EQ(zerr, Z_STREAM_END); /* other errors should've been caught */
// NOTE: zstream.adler is always set to 0, because we're using the -MAX_WBITS
// "feature" of zlib to tell it there won't be a zlib file header. zlib
@@ -1255,16 +1247,14 @@
length_ = cd_size;
}
-bool ZipArchive::InitializeCentralDirectory(const char* debug_file_name, off64_t cd_start_offset,
- size_t cd_size) {
+bool ZipArchive::InitializeCentralDirectory(off64_t cd_start_offset, size_t cd_size) {
if (mapped_zip.HasFd()) {
- if (!directory_map->create(debug_file_name, mapped_zip.GetFileDescriptor(), cd_start_offset,
- cd_size, true /* read only */)) {
- return false;
- }
+ directory_map = android::base::MappedFile::FromFd(mapped_zip.GetFileDescriptor(),
+ cd_start_offset, cd_size, PROT_READ);
+ if (!directory_map) return false;
- CHECK_EQ(directory_map->getDataLength(), cd_size);
- central_directory.Initialize(directory_map->getDataPtr(), 0 /*offset*/, cd_size);
+ CHECK_EQ(directory_map->size(), cd_size);
+ central_directory.Initialize(directory_map->data(), 0 /*offset*/, cd_size);
} else {
if (mapped_zip.GetBasePtr() == nullptr) {
ALOGE("Zip: Failed to map central directory, bad mapped_zip base pointer\n");
diff --git a/libziparchive/zip_archive_private.h b/libziparchive/zip_archive_private.h
index 83cb11f..330a02a 100644
--- a/libziparchive/zip_archive_private.h
+++ b/libziparchive/zip_archive_private.h
@@ -14,8 +14,9 @@
* limitations under the License.
*/
-#ifndef LIBZIPARCHIVE_ZIPARCHIVE_PRIVATE_H_
-#define LIBZIPARCHIVE_ZIPARCHIVE_PRIVATE_H_
+#pragma once
+
+#include <ziparchive/zip_archive.h>
#include <stdint.h>
#include <stdlib.h>
@@ -24,9 +25,8 @@
#include <memory>
#include <vector>
-#include <utils/FileMap.h>
-#include <ziparchive/zip_archive.h>
#include "android-base/macros.h"
+#include "android-base/mapped_file.h"
static const char* kErrorMessages[] = {
"Success",
@@ -164,7 +164,7 @@
// mapped central directory area
off64_t directory_offset;
CentralDirectory central_directory;
- std::unique_ptr<android::FileMap> directory_map;
+ std::unique_ptr<android::base::MappedFile> directory_map;
// number of entries in the Zip archive
uint16_t num_entries;
@@ -180,8 +180,5 @@
ZipArchive(void* address, size_t length);
~ZipArchive();
- bool InitializeCentralDirectory(const char* debug_file_name, off64_t cd_start_offset,
- size_t cd_size);
+ bool InitializeCentralDirectory(off64_t cd_start_offset, size_t cd_size);
};
-
-#endif // LIBZIPARCHIVE_ZIPARCHIVE_PRIVATE_H_
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index 23dd5dc..af9f4c8 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -27,10 +27,10 @@
#include <vector>
#include <android-base/file.h>
+#include <android-base/mapped_file.h>
#include <android-base/test_utils.h>
#include <android-base/unique_fd.h>
#include <gtest/gtest.h>
-#include <utils/FileMap.h>
#include <ziparchive/zip_archive.h>
#include <ziparchive/zip_archive_stream_entry.h>
@@ -416,11 +416,10 @@
ASSERT_EQ(0, fstat(fd, &sb));
// Memory map the file first and open the archive from the memory region.
- android::FileMap file_map;
- file_map.create(zip_path.c_str(), fd, 0 /*offset*/, sb.st_size, true);
+ auto file_map{android::base::MappedFile::FromFd(fd, 0, sb.st_size, PROT_READ)};
ZipArchiveHandle handle;
- ASSERT_EQ(0, OpenArchiveFromMemory(file_map.getDataPtr(), file_map.getDataLength(),
- zip_path.c_str(), &handle));
+ ASSERT_EQ(0,
+ OpenArchiveFromMemory(file_map->data(), file_map->size(), zip_path.c_str(), &handle));
// Assert one entry can be found and extracted correctly.
std::string BINARY_PATH("META-INF/com/google/android/update-binary");
diff --git a/libziparchive/zip_writer.cc b/libziparchive/zip_writer.cc
index ed1d135..981df3a 100644
--- a/libziparchive/zip_writer.cc
+++ b/libziparchive/zip_writer.cc
@@ -26,8 +26,6 @@
#include <vector>
#include "android-base/logging.h"
-#include "utils/Compat.h"
-#include "utils/Log.h"
#include "entry_name_utils-inl.h"
#include "zip_archive_common.h"
@@ -303,10 +301,10 @@
if (zerr != Z_OK) {
if (zerr == Z_VERSION_ERROR) {
- ALOGE("Installed zlib is not compatible with linked version (%s)", ZLIB_VERSION);
+ LOG(ERROR) << "Installed zlib is not compatible with linked version (" << ZLIB_VERSION << ")";
return HandleError(kZlibError);
} else {
- ALOGE("deflateInit2 failed (zerr=%d)", zerr);
+ LOG(ERROR) << "deflateInit2 failed (zerr=" << zerr << ")";
return HandleError(kZlibError);
}
}
diff --git a/llkd/include/llkd.h b/llkd/include/llkd.h
index 4d39dd9..2c62fca 100644
--- a/llkd/include/llkd.h
+++ b/llkd/include/llkd.h
@@ -51,13 +51,13 @@
#define LLK_CHECK_STACK_DEFAULT "cma_alloc,__get_user_pages"
#define LLK_BLACKLIST_PROCESS_PROPERTY "ro.llk.blacklist.process"
#define LLK_BLACKLIST_PROCESS_DEFAULT \
- "0,1,2,init,[kthreadd],[khungtaskd],lmkd,lmkd.llkd,llkd,watchdogd,[watchdogd],[watchdogd/0]"
+ "0,1,2,init,[kthreadd],[khungtaskd],lmkd,llkd,watchdogd,[watchdogd],[watchdogd/0]"
#define LLK_BLACKLIST_PARENT_PROPERTY "ro.llk.blacklist.parent"
#define LLK_BLACKLIST_PARENT_DEFAULT "0,2,[kthreadd]"
#define LLK_BLACKLIST_UID_PROPERTY "ro.llk.blacklist.uid"
#define LLK_BLACKLIST_UID_DEFAULT ""
#define LLK_BLACKLIST_STACK_PROPERTY "ro.llk.blacklist.process.stack"
-#define LLK_BLACKLIST_STACK_DEFAULT "init,lmkd.llkd,llkd,keystore,/system/bin/keystore,ueventd,apexd"
+#define LLK_BLACKLIST_STACK_DEFAULT "init,lmkd.llkd,llkd,keystore,ueventd,apexd"
/* clang-format on */
__END_DECLS
diff --git a/llkd/libllkd.cpp b/llkd/libllkd.cpp
index 6840ed0..2727aab 100644
--- a/llkd/libllkd.cpp
+++ b/llkd/libllkd.cpp
@@ -712,6 +712,7 @@
if (llkSkipName(std::to_string(procp->pid), llkBlacklistStack)) return false;
if (llkSkipName(procp->getComm(), llkBlacklistStack)) return false;
if (llkSkipName(procp->getCmdline(), llkBlacklistStack)) return false;
+ if (llkSkipName(android::base::Basename(procp->getCmdline()), llkBlacklistStack)) return false;
auto kernel_stack = ReadFile(piddir + "/stack");
if (kernel_stack.empty()) {
@@ -995,13 +996,18 @@
if (llkSkipName(procp->getCmdline())) {
break;
}
+ if (llkSkipName(android::base::Basename(procp->getCmdline()))) {
+ break;
+ }
auto pprocp = llkTidLookup(ppid);
if (pprocp == nullptr) {
pprocp = llkTidAlloc(ppid, ppid, 0, "", 0, '?');
}
- if ((pprocp != nullptr) && (llkSkipName(pprocp->getComm(), llkBlacklistParent) ||
- llkSkipName(pprocp->getCmdline(), llkBlacklistParent))) {
+ if ((pprocp != nullptr) &&
+ (llkSkipName(pprocp->getComm(), llkBlacklistParent) ||
+ llkSkipName(pprocp->getCmdline(), llkBlacklistParent) ||
+ llkSkipName(android::base::Basename(pprocp->getCmdline()), llkBlacklistParent))) {
break;
}
diff --git a/lmkd/include/lmkd.h b/lmkd/include/lmkd.h
index e8f51da..e72d159 100644
--- a/lmkd/include/lmkd.h
+++ b/lmkd/include/lmkd.h
@@ -31,6 +31,7 @@
LMK_PROCPRIO, /* Register a process and set its oom_adj_score */
LMK_PROCREMOVE, /* Unregister a process */
LMK_PROCPURGE, /* Purge all registered processes */
+ LMK_GETKILLCNT, /* Get number of kills */
};
/*
@@ -152,6 +153,44 @@
return sizeof(int);
}
+/* LMK_GETKILLCNT packet payload */
+struct lmk_getkillcnt {
+ int min_oomadj;
+ int max_oomadj;
+};
+
+/*
+ * For LMK_GETKILLCNT packet get its payload.
+ * Warning: no checks performed, caller should ensure valid parameters.
+ */
+inline void lmkd_pack_get_getkillcnt(LMKD_CTRL_PACKET packet,
+ struct lmk_getkillcnt *params) {
+ params->min_oomadj = ntohl(packet[1]);
+ params->max_oomadj = ntohl(packet[2]);
+}
+
+/*
+ * Prepare LMK_GETKILLCNT packet and return packet size in bytes.
+ * Warning: no checks performed, caller should ensure valid parameters.
+ */
+inline size_t lmkd_pack_set_getkillcnt(LMKD_CTRL_PACKET packet,
+ struct lmk_getkillcnt *params) {
+ packet[0] = htonl(LMK_GETKILLCNT);
+ packet[1] = htonl(params->min_oomadj);
+ packet[2] = htonl(params->max_oomadj);
+ return 3 * sizeof(int);
+}
+
+/*
+ * Prepare LMK_GETKILLCNT reply packet and return packet size in bytes.
+ * Warning: no checks performed, caller should ensure valid parameters.
+ */
+inline size_t lmkd_pack_set_getkillcnt_repl(LMKD_CTRL_PACKET packet, int kill_cnt) {
+ packet[0] = htonl(LMK_GETKILLCNT);
+ packet[1] = htonl(kill_cnt);
+ return 2 * sizeof(int);
+}
+
__END_DECLS
#endif /* _LMKD_H_ */
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 0a469e8..e3c4ccc 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -313,7 +313,20 @@
#define pid_hashfn(x) ((((x) >> 8) ^ (x)) & (PIDHASH_SZ - 1))
#define ADJTOSLOT(adj) ((adj) + -OOM_SCORE_ADJ_MIN)
-static struct adjslot_list procadjslot_list[ADJTOSLOT(OOM_SCORE_ADJ_MAX) + 1];
+#define ADJTOSLOT_COUNT (ADJTOSLOT(OOM_SCORE_ADJ_MAX) + 1)
+static struct adjslot_list procadjslot_list[ADJTOSLOT_COUNT];
+
+#define MAX_DISTINCT_OOM_ADJ 32
+#define KILLCNT_INVALID_IDX 0xFF
+/*
+ * Because killcnt array is sparse a two-level indirection is used
+ * to keep the size small. killcnt_idx stores index of the element in
+ * killcnt array. Index KILLCNT_INVALID_IDX indicates an unused slot.
+ */
+static uint8_t killcnt_idx[ADJTOSLOT_COUNT];
+static uint16_t killcnt[MAX_DISTINCT_OOM_ADJ];
+static int killcnt_free_idx = 0;
+static uint32_t killcnt_total = 0;
/* PAGE_SIZE / 1024 */
static long page_k;
@@ -644,6 +657,67 @@
memset(&pidhash[0], 0, sizeof(pidhash));
}
+static void inc_killcnt(int oomadj) {
+ int slot = ADJTOSLOT(oomadj);
+ uint8_t idx = killcnt_idx[slot];
+
+ if (idx == KILLCNT_INVALID_IDX) {
+ /* index is not assigned for this oomadj */
+ if (killcnt_free_idx < MAX_DISTINCT_OOM_ADJ) {
+ killcnt_idx[slot] = killcnt_free_idx;
+ killcnt[killcnt_free_idx] = 1;
+ killcnt_free_idx++;
+ } else {
+ ALOGW("Number of distinct oomadj levels exceeds %d",
+ MAX_DISTINCT_OOM_ADJ);
+ }
+ } else {
+ /*
+ * wraparound is highly unlikely and is detectable using total
+ * counter because it has to be equal to the sum of all counters
+ */
+ killcnt[idx]++;
+ }
+ /* increment total kill counter */
+ killcnt_total++;
+}
+
+static int get_killcnt(int min_oomadj, int max_oomadj) {
+ int slot;
+ int count = 0;
+
+ if (min_oomadj > max_oomadj)
+ return 0;
+
+ /* special case to get total kill count */
+ if (min_oomadj > OOM_SCORE_ADJ_MAX)
+ return killcnt_total;
+
+ while (min_oomadj <= max_oomadj &&
+ (slot = ADJTOSLOT(min_oomadj)) < ADJTOSLOT_COUNT) {
+ uint8_t idx = killcnt_idx[slot];
+ if (idx != KILLCNT_INVALID_IDX) {
+ count += killcnt[idx];
+ }
+ min_oomadj++;
+ }
+
+ return count;
+}
+
+static int cmd_getkillcnt(LMKD_CTRL_PACKET packet) {
+ struct lmk_getkillcnt params;
+
+ if (use_inkernel_interface) {
+ /* kernel driver does not expose this information */
+ return 0;
+ }
+
+ lmkd_pack_get_getkillcnt(packet, ¶ms);
+
+ return get_killcnt(params.min_oomadj, params.max_oomadj);
+}
+
static void cmd_target(int ntargets, LMKD_CTRL_PACKET packet) {
int i;
struct lmk_target target;
@@ -748,12 +822,28 @@
return ret;
}
+static int ctrl_data_write(int dsock_idx, char *buf, size_t bufsz) {
+ int ret = 0;
+
+ ret = TEMP_FAILURE_RETRY(write(data_sock[dsock_idx].sock, buf, bufsz));
+
+ if (ret == -1) {
+ ALOGE("control data socket write failed; errno=%d", errno);
+ } else if (ret == 0) {
+ ALOGE("Got EOF on control data socket");
+ ret = -1;
+ }
+
+ return ret;
+}
+
static void ctrl_command_handler(int dsock_idx) {
LMKD_CTRL_PACKET packet;
int len;
enum lmk_cmd cmd;
int nargs;
int targets;
+ int kill_cnt;
len = ctrl_data_read(dsock_idx, (char *)packet, CTRL_PACKET_MAX_SIZE);
if (len <= 0)
@@ -791,6 +881,14 @@
goto wronglen;
cmd_procpurge();
break;
+ case LMK_GETKILLCNT:
+ if (nargs != 2)
+ goto wronglen;
+ kill_cnt = cmd_getkillcnt(packet);
+ len = lmkd_pack_set_getkillcnt_repl(packet, kill_cnt);
+ if (ctrl_data_write(dsock_idx, (char *)packet, len) != len)
+ return;
+ break;
default:
ALOGE("Received unknown command code %d", cmd);
return;
@@ -1200,6 +1298,7 @@
/* CAP_KILL required */
r = kill(pid, SIGKILL);
+ inc_killcnt(procp->oomadj);
ALOGI("Kill '%s' (%d), uid %d, oom_adj %d to free %ldkB",
taskname, pid, uid, procp->oomadj, tasksize * page_k);
@@ -1700,6 +1799,8 @@
procadjslot_list[i].prev = &procadjslot_list[i];
}
+ memset(killcnt_idx, KILLCNT_INVALID_IDX, sizeof(killcnt_idx));
+
return 0;
}
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 393e204..aad00ad 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -146,13 +146,7 @@
include $(BUILD_SYSTEM)/base_rules.mk
-# Regenerate init.environ.rc if PRODUCT_BOOTCLASSPATH has changed.
-bcp_md5 := $(word 1, $(shell echo $(PRODUCT_BOOTCLASSPATH) $(PRODUCT_SYSTEM_SERVER_CLASSPATH) | $(MD5SUM)))
-bcp_dep := $(intermediates)/$(bcp_md5).bcp.dep
-$(bcp_dep) :
- $(hide) mkdir -p $(dir $@) && rm -rf $(dir $@)*.bcp.dep && touch $@
-
-$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/init.environ.rc.in $(bcp_dep)
+$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/init.environ.rc.in
@echo "Generate: $< -> $@"
@mkdir -p $(dir $@)
$(hide) sed -e 's?%BOOTCLASSPATH%?$(PRODUCT_BOOTCLASSPATH)?g' $< >$@
@@ -161,9 +155,6 @@
$(hide) sed -i -e 's?%EXPORT_GLOBAL_GCOV_OPTIONS%?$(EXPORT_GLOBAL_GCOV_OPTIONS)?g' $@
$(hide) sed -i -e 's?%EXPORT_GLOBAL_HWASAN_OPTIONS%?$(EXPORT_GLOBAL_HWASAN_OPTIONS)?g' $@
-bcp_md5 :=
-bcp_dep :=
-
# Append PLATFORM_VNDK_VERSION to base name.
define append_vndk_version
$(strip \
diff --git a/rootdir/init.rc b/rootdir/init.rc
index ea83ef9..025e3c3 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -489,6 +489,8 @@
mkdir /data/misc/profman 0770 system shell
mkdir /data/misc/gcov 0770 root root
+ mkdir /data/preloads 0775 system system
+
mkdir /data/vendor 0771 root root
mkdir /data/vendor_ce 0771 root root
mkdir /data/vendor_de 0771 root root