Merge "Add adbd_test to presubmit test mapping"
diff --git a/adb/Android.bp b/adb/Android.bp
index 2a88de5..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,
@@ -41,7 +42,10 @@
target: {
android: {
- cflags: ["-DADB_HOST=0"],
+ cflags: [
+ "-DADB_HOST=0",
+ "-Wthread-safety",
+ ],
},
host: {
@@ -311,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 35017f0..ad77064 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);
}
@@ -186,6 +186,48 @@
return line;
}
+std::string dump_header(const amessage* msg) {
+ unsigned command = msg->command;
+ int len = msg->data_length;
+ char cmd[9];
+ char arg0[12], arg1[12];
+ int n;
+
+ for (n = 0; n < 4; n++) {
+ int b = (command >> (n * 8)) & 255;
+ if (b < 32 || b >= 127) break;
+ cmd[n] = (char)b;
+ }
+ if (n == 4) {
+ cmd[4] = 0;
+ } else {
+ // There is some non-ASCII name in the command, so dump the hexadecimal value instead
+ snprintf(cmd, sizeof cmd, "%08x", command);
+ }
+
+ if (msg->arg0 < 256U)
+ snprintf(arg0, sizeof arg0, "%d", msg->arg0);
+ else
+ snprintf(arg0, sizeof arg0, "0x%x", msg->arg0);
+
+ if (msg->arg1 < 256U)
+ snprintf(arg1, sizeof arg1, "%d", msg->arg1);
+ else
+ snprintf(arg1, sizeof arg1, "0x%x", msg->arg1);
+
+ return android::base::StringPrintf("[%s] arg0=%s arg1=%s (len=%d) ", cmd, arg0, arg1, len);
+}
+
+std::string dump_packet(const char* name, const char* func, const apacket* p) {
+ std::string result = name;
+ result += ": ";
+ result += func;
+ result += ": ";
+ result += dump_header(&p->msg);
+ result += dump_hex(p->payload.data(), p->payload.size());
+ return result;
+}
+
std::string perror_str(const char* msg) {
return android::base::StringPrintf("%s: %s", msg, strerror(errno));
}
@@ -274,18 +316,6 @@
return android_dir;
}
-int syntax_error(const char* fmt, ...) {
- fprintf(stderr, "adb: usage: ");
-
- va_list ap;
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
-
- fprintf(stderr, "\n");
- return 1;
-}
-
std::string GetLogFilePath() {
#if defined(_WIN32)
const char log_name[] = "adb.log";
@@ -295,13 +325,13 @@
DWORD nchars = GetTempPathW(arraysize(temp_path), temp_path);
if (nchars >= arraysize(temp_path) || nchars == 0) {
// If string truncation or some other error.
- fatal("cannot retrieve temporary file path: %s\n",
- android::base::SystemErrorCodeToString(GetLastError()).c_str());
+ LOG(FATAL) << "cannot retrieve temporary file path: "
+ << android::base::SystemErrorCodeToString(GetLastError());
}
std::string temp_path_utf8;
if (!android::base::WideToUTF8(temp_path, &temp_path_utf8)) {
- fatal_errno("cannot convert temporary file path from UTF-16 to UTF-8");
+ PLOG(FATAL) << "cannot convert temporary file path from UTF-16 to UTF-8";
}
return temp_path_utf8 + log_name;
@@ -311,3 +341,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 f6ce8e2..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>
@@ -24,7 +23,7 @@
#include <android-base/macros.h>
-int syntax_error(const char*, ...) __attribute__((__format__(__printf__, 1, 2)));
+#include "adb.h"
void close_stdin();
@@ -42,12 +41,17 @@
std::string escape_arg(const std::string& s);
std::string dump_hex(const void* ptr, size_t byte_count);
+std::string dump_header(const amessage* msg);
+std::string dump_packet(const char* name, const char* func, const apacket* p);
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.
@@ -90,5 +94,3 @@
};
std::string GetLogFilePath();
-
-#endif
diff --git a/adb/benchmark_device.py b/adb/benchmark_device.py
index 00c2315..e56ef5a 100755
--- a/adb/benchmark_device.py
+++ b/adb/benchmark_device.py
@@ -60,8 +60,6 @@
if device == None:
device = adb.get_device()
- lock_max(device)
-
remote_path = "/dev/null"
local_path = "/tmp/adb_benchmark_temp"
@@ -69,7 +67,7 @@
f.truncate(file_size_mb * 1024 * 1024)
speeds = list()
- for _ in range(0, 5):
+ for _ in range(0, 10):
begin = time.time()
device.push(local=local_path, remote=remote_path)
end = time.time()
@@ -81,15 +79,13 @@
if device == None:
device = adb.get_device()
- lock_max(device)
-
remote_path = "/data/local/tmp/adb_benchmark_temp"
local_path = "/tmp/adb_benchmark_temp"
device.shell(["dd", "if=/dev/zero", "of=" + remote_path, "bs=1m",
"count=" + str(file_size_mb)])
speeds = list()
- for _ in range(0, 5):
+ for _ in range(0, 10):
begin = time.time()
device.pull(remote=remote_path, local=local_path)
end = time.time()
@@ -101,10 +97,8 @@
if device == None:
device = adb.get_device()
- lock_max(device)
-
speeds = list()
- for _ in range(0, 5):
+ for _ in range(0, 10):
begin = time.time()
device.shell(["dd", "if=/dev/zero", "bs=1m",
"count=" + str(file_size_mb)])
@@ -114,7 +108,10 @@
analyze("shell %dMiB" % file_size_mb, speeds)
def main():
- benchmark_pull()
+ device = adb.get_device()
+ unlock(device)
+ benchmark_push(device)
+ benchmark_pull(device)
if __name__ == "__main__":
main()
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..3124852 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;
}
@@ -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 cabd279..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 {
@@ -408,42 +409,6 @@
fd_.reset();
}
-static std::string dump_packet(const char* name, const char* func, apacket* p) {
- unsigned command = p->msg.command;
- int len = p->msg.data_length;
- char cmd[9];
- char arg0[12], arg1[12];
- int n;
-
- for (n = 0; n < 4; n++) {
- int b = (command >> (n * 8)) & 255;
- if (b < 32 || b >= 127) break;
- cmd[n] = (char)b;
- }
- if (n == 4) {
- cmd[4] = 0;
- } else {
- /* There is some non-ASCII name in the command, so dump
- * the hexadecimal value instead */
- snprintf(cmd, sizeof cmd, "%08x", command);
- }
-
- if (p->msg.arg0 < 256U)
- snprintf(arg0, sizeof arg0, "%d", p->msg.arg0);
- else
- snprintf(arg0, sizeof arg0, "0x%x", p->msg.arg0);
-
- if (p->msg.arg1 < 256U)
- snprintf(arg1, sizeof arg1, "%d", p->msg.arg1);
- else
- snprintf(arg1, sizeof arg1, "0x%x", p->msg.arg1);
-
- std::string result = android::base::StringPrintf("%s: %s: [%s] arg0=%s arg1=%s (len=%d) ", name,
- func, cmd, arg0, arg1, len);
- result += dump_hex(p->payload.data(), p->payload.size());
- return result;
-}
-
void send_packet(apacket* p, atransport* t) {
p->msg.magic = p->msg.command ^ 0xffffffff;
// compute a checksum for connection/auth packets for compatibility reasons
@@ -456,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) {
@@ -562,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);
@@ -668,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;
@@ -707,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);
@@ -742,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]);
@@ -766,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";
}
}
@@ -782,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";
}
}
@@ -794,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()) {
@@ -1043,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).
@@ -1329,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);
@@ -1340,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/logging.cpp b/base/logging.cpp
index d60d91d..bd09069 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -53,6 +53,7 @@
#include <unistd.h>
#endif
+#include <android-base/file.h>
#include <android-base/macros.h>
#include <android-base/parseint.h>
#include <android-base/strings.h>
@@ -71,14 +72,8 @@
static char progname[MAX_PATH] = {};
if (first) {
- CHAR longname[MAX_PATH];
- DWORD nchars = GetModuleFileNameA(nullptr, longname, arraysize(longname));
- if ((nchars >= arraysize(longname)) || (nchars == 0)) {
- // String truncation or some other error.
- strcpy(progname, "<unknown>");
- } else {
- strcpy(progname, basename(longname));
- }
+ snprintf(progname, sizeof(progname), "%s",
+ android::base::Basename(android::base::GetExecutablePath()).c_str());
first = false;
}
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index bca2337..64e9fb4 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -446,11 +446,13 @@
bool* change) {
const auto top = overlay + kOverlayTopDir;
- if (!fs_mgr_access(top)) return false;
+ if (!fs_mgr_access(top)) return fs_mgr_overlayfs_teardown_scratch(overlay, change);
auto cleanup_all = mount_point.empty();
- const auto oldpath = top + (cleanup_all ? "" : ("/" + mount_point));
- const auto newpath = oldpath + ".teardown";
+ const auto partition_name = android::base::Basename(mount_point);
+ const auto oldpath = top + (cleanup_all ? "" : ("/" + partition_name));
+ const auto newpath = cleanup_all ? overlay + "/." + kOverlayTopDir.substr(1) + ".teardown"
+ : top + "/." + partition_name + ".teardown";
auto ret = fs_mgr_rm_all(newpath);
auto save_errno = errno;
if (!rename(oldpath.c_str(), newpath.c_str())) {
@@ -476,12 +478,28 @@
if (!rmdir(top.c_str())) {
if (change) *change = true;
cleanup_all = true;
- } else if ((errno != ENOENT) && (errno != ENOTEMPTY)) {
+ } else if (errno == ENOTEMPTY) {
+ cleanup_all = true;
+ // cleanup all if the content is all hidden (leading .)
+ std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(top.c_str()), closedir);
+ if (!dir) {
+ PERROR << "opendir " << top;
+ } else {
+ dirent* entry;
+ while ((entry = readdir(dir.get()))) {
+ if (entry->d_name[0] != '.') {
+ cleanup_all = false;
+ break;
+ }
+ }
+ }
+ errno = save_errno;
+ } else if (errno == ENOENT) {
+ cleanup_all = true;
+ errno = save_errno;
+ } else {
ret = false;
PERROR << "rmdir " << top;
- } else {
- errno = save_errno;
- cleanup_all = true;
}
}
if (cleanup_all) ret &= fs_mgr_overlayfs_teardown_scratch(overlay, change);
@@ -589,8 +607,18 @@
fsrec->fs_type = strdup(mnt_type.c_str());
fsrec->flags = MS_RELATIME;
fsrec->fs_options = strdup("");
- auto mounted = fs_mgr_do_mount_one(fsrec) == 0;
auto save_errno = errno;
+ auto mounted = fs_mgr_do_mount_one(fsrec) == 0;
+ if (!mounted) {
+ free(fsrec->fs_type);
+ if (mnt_type == "f2fs") {
+ fsrec->fs_type = strdup("ext4");
+ } else {
+ fsrec->fs_type = strdup("f2fs");
+ }
+ mounted = fs_mgr_do_mount_one(fsrec) == 0;
+ if (!mounted) save_errno = errno;
+ }
setfscreatecon(nullptr);
if (!mounted) rmdir(kScratchMountPoint.c_str());
errno = save_errno;
@@ -600,6 +628,7 @@
const std::string kMkF2fs("/system/bin/make_f2fs");
const std::string kMkExt4("/system/bin/mke2fs");
+// Only a suggestion for _first_ try during mounting
std::string fs_mgr_overlayfs_scratch_mount_type() {
if (!access(kMkF2fs.c_str(), X_OK)) return "f2fs";
if (!access(kMkExt4.c_str(), X_OK)) return "ext4";
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 03fd5f9..2c57a35 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -261,15 +261,20 @@
// we store a backup copy of everything.
uint64_t reserved =
LP_METADATA_GEOMETRY_SIZE + (uint64_t(metadata_max_size) * metadata_slot_count);
- uint64_t total_reserved = reserved * 2;
+ uint64_t total_reserved = LP_PARTITION_RESERVED_BYTES + reserved * 2;
if (device_info.size < total_reserved) {
LERROR << "Attempting to create metadata on a block device that is too small.";
return false;
}
// Compute the first free sector, factoring in alignment.
- uint64_t free_area_start =
- AlignTo(total_reserved, device_info.alignment, device_info.alignment_offset);
+ uint64_t free_area_start = total_reserved;
+ if (device_info.alignment || device_info.alignment_offset) {
+ free_area_start =
+ AlignTo(free_area_start, device_info.alignment, device_info.alignment_offset);
+ } else {
+ free_area_start = AlignTo(free_area_start, device_info.logical_block_size);
+ }
uint64_t first_sector = free_area_start / LP_SECTOR_SIZE;
// There must be one logical block of free space remaining (enough for one partition).
@@ -334,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();
@@ -363,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);
@@ -384,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);
@@ -561,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;
@@ -620,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 eb65f89..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);
@@ -48,8 +51,11 @@
LinearExtent* extent = system->extents()[0]->AsLinearExtent();
ASSERT_NE(extent, nullptr);
EXPECT_EQ(extent->num_sectors(), 65536 / LP_SECTOR_SIZE);
- // The first logical sector will be (8192+1024*4)/512 = 12.
- EXPECT_EQ(extent->physical_sector(), 24);
+ // The first logical sector will be:
+ // (LP_PARTITION_RESERVED_BYTES + 4096*2 + 1024*4) / 512
+ // Or, in terms of sectors (reserved + geometry + metadata):
+ // (8 + 16 + 8) = 32
+ EXPECT_EQ(extent->physical_sector(), 32);
// Test resizing to the same size.
EXPECT_EQ(builder->ResizePartition(system, 65536), true);
@@ -78,7 +84,7 @@
extent = system->extents()[0]->AsLinearExtent();
ASSERT_NE(extent, nullptr);
EXPECT_EQ(extent->num_sectors(), 32768 / LP_SECTOR_SIZE);
- EXPECT_EQ(extent->physical_sector(), 24);
+ EXPECT_EQ(extent->physical_sector(), 32);
// Test shrinking to 0.
builder->ResizePartition(system, 0);
@@ -148,7 +154,7 @@
ASSERT_NE(builder, nullptr);
exported = builder->Export();
ASSERT_NE(exported, nullptr);
- EXPECT_EQ(exported->geometry.first_logical_sector, 150);
+ EXPECT_EQ(exported->geometry.first_logical_sector, 174);
// Test a small alignment with no alignment offset.
device_info.alignment = 11 * 1024;
@@ -202,7 +208,8 @@
// maximum size of a metadata blob. Then, we double that space since
// we store a backup copy of everything.
static constexpr uint64_t geometry = 4 * 1024;
- static constexpr uint64_t allocatable = total - (metadata * slots + geometry) * 2;
+ static constexpr uint64_t allocatable =
+ total - (metadata * slots + geometry) * 2 - LP_PARTITION_RESERVED_BYTES;
EXPECT_EQ(builder->AllocatableSpace(), allocatable);
EXPECT_EQ(builder->UsedSpace(), 0);
@@ -243,11 +250,11 @@
ASSERT_NE(system2, nullptr);
ASSERT_NE(vendor1, nullptr);
EXPECT_EQ(system1->num_sectors(), 65536 / LP_SECTOR_SIZE);
- EXPECT_EQ(system1->physical_sector(), 24);
+ EXPECT_EQ(system1->physical_sector(), 32);
EXPECT_EQ(system2->num_sectors(), 32768 / LP_SECTOR_SIZE);
- EXPECT_EQ(system2->physical_sector(), 216);
+ EXPECT_EQ(system2->physical_sector(), 224);
EXPECT_EQ(vendor1->num_sectors(), 32768 / LP_SECTOR_SIZE);
- EXPECT_EQ(vendor1->physical_sector(), 152);
+ EXPECT_EQ(vendor1->physical_sector(), 160);
EXPECT_EQ(system1->physical_sector() + system1->num_sectors(), vendor1->physical_sector());
EXPECT_EQ(vendor1->physical_sector() + vendor1->num_sectors(), system2->physical_sector());
}
@@ -293,7 +300,7 @@
EXPECT_EQ(geometry.struct_size, sizeof(geometry));
EXPECT_EQ(geometry.metadata_max_size, 1024);
EXPECT_EQ(geometry.metadata_slot_count, 2);
- EXPECT_EQ(geometry.first_logical_sector, 24);
+ EXPECT_EQ(geometry.first_logical_sector, 32);
static const size_t kMetadataSpace =
((kMetadataSize * kMetadataSlots) + LP_METADATA_GEOMETRY_SIZE) * 2;
@@ -354,9 +361,9 @@
LinearExtent* system2 = system->extents()[1]->AsLinearExtent();
LinearExtent* vendor1 = vendor->extents()[0]->AsLinearExtent();
EXPECT_EQ(system1->num_sectors(), 65536 / LP_SECTOR_SIZE);
- EXPECT_EQ(system1->physical_sector(), 24);
+ EXPECT_EQ(system1->physical_sector(), 32);
EXPECT_EQ(system2->num_sectors(), 32768 / LP_SECTOR_SIZE);
- EXPECT_EQ(system2->physical_sector(), 216);
+ EXPECT_EQ(system2->physical_sector(), 224);
EXPECT_EQ(vendor1->num_sectors(), 32768 / LP_SECTOR_SIZE);
}
@@ -381,7 +388,7 @@
EXPECT_EQ(builder, nullptr);
// No space to store metadata + geometry + one free sector.
- device_info.size += LP_METADATA_GEOMETRY_SIZE * 2;
+ device_info.size += LP_PARTITION_RESERVED_BYTES + (LP_METADATA_GEOMETRY_SIZE * 2);
builder = MetadataBuilder::New(device_info, kMetadataSize, 1);
EXPECT_EQ(builder, nullptr);
@@ -511,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/images.cpp b/fs_mgr/liblp/images.cpp
index 8716988..dfa37fe 100644
--- a/fs_mgr/liblp/images.cpp
+++ b/fs_mgr/liblp/images.cpp
@@ -28,12 +28,17 @@
namespace fs_mgr {
std::unique_ptr<LpMetadata> ReadFromImageFile(int fd) {
- LpMetadataGeometry geometry;
- if (!ReadLogicalPartitionGeometry(fd, &geometry)) {
+ std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(LP_METADATA_GEOMETRY_SIZE);
+ if (SeekFile64(fd, 0, SEEK_SET) < 0) {
+ PERROR << __PRETTY_FUNCTION__ << " lseek failed";
return nullptr;
}
- if (SeekFile64(fd, LP_METADATA_GEOMETRY_SIZE, SEEK_SET) < 0) {
- PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << LP_METADATA_GEOMETRY_SIZE;
+ if (!android::base::ReadFully(fd, buffer.get(), LP_METADATA_GEOMETRY_SIZE)) {
+ PERROR << __PRETTY_FUNCTION__ << " read failed";
+ return nullptr;
+ }
+ LpMetadataGeometry geometry;
+ if (!ParseGeometry(buffer.get(), &geometry)) {
return nullptr;
}
return ParseMetadata(geometry, fd);
@@ -59,7 +64,7 @@
std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file) {
android::base::unique_fd fd(open(file, O_RDONLY));
if (fd < 0) {
- PERROR << __PRETTY_FUNCTION__ << "open failed: " << file;
+ PERROR << __PRETTY_FUNCTION__ << " open failed: " << file;
return nullptr;
}
return ReadFromImageFile(fd);
@@ -72,7 +77,7 @@
std::string everything = geometry + metadata;
if (!android::base::WriteFully(fd, everything.data(), everything.size())) {
- PERROR << __PRETTY_FUNCTION__ << "write " << everything.size() << " bytes failed";
+ PERROR << __PRETTY_FUNCTION__ << " write " << everything.size() << " bytes failed";
return false;
}
return true;
@@ -81,7 +86,7 @@
bool WriteToImageFile(const char* file, const LpMetadata& input) {
android::base::unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC, 0644));
if (fd < 0) {
- PERROR << __PRETTY_FUNCTION__ << "open failed: " << file;
+ PERROR << __PRETTY_FUNCTION__ << " open failed: " << file;
return false;
}
return WriteToImageFile(fd, input);
@@ -106,6 +111,14 @@
LERROR << "Metadata max size must be a multiple of the block size, " << block_size;
return;
}
+ if (LP_METADATA_GEOMETRY_SIZE % block_size != 0) {
+ LERROR << "Geometry size is not a multiple of the block size, " << block_size;
+ return;
+ }
+ if (LP_PARTITION_RESERVED_BYTES % block_size != 0) {
+ LERROR << "Reserved size is not a multiple of the block size, " << block_size;
+ return;
+ }
uint64_t num_blocks = metadata.geometry.block_device_size % block_size;
if (num_blocks >= UINT_MAX) {
@@ -163,6 +176,11 @@
}
bool SparseBuilder::Build() {
+ if (sparse_file_add_fill(file_.get(), 0, LP_PARTITION_RESERVED_BYTES, 0) < 0) {
+ LERROR << "Could not add initial sparse block for reserved zeroes";
+ return false;
+ }
+
std::string geometry_blob = SerializeGeometry(geometry_);
std::string metadata_blob = SerializeMetadata(metadata_);
metadata_blob.resize(geometry_.metadata_max_size);
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/fs_mgr/liblp/include/liblp/metadata_format.h b/fs_mgr/liblp/include/liblp/metadata_format.h
index 711ff95..89b219c 100644
--- a/fs_mgr/liblp/include/liblp/metadata_format.h
+++ b/fs_mgr/liblp/include/liblp/metadata_format.h
@@ -38,7 +38,7 @@
#define LP_METADATA_HEADER_MAGIC 0x414C5030
/* Current metadata version. */
-#define LP_METADATA_MAJOR_VERSION 5
+#define LP_METADATA_MAJOR_VERSION 6
#define LP_METADATA_MINOR_VERSION 0
/* Attributes for the LpMetadataPartition::attributes field.
@@ -72,6 +72,11 @@
/* Size of a sector is always 512 bytes for compatibility with the Linux kernel. */
#define LP_SECTOR_SIZE 512
+/* Amount of space reserved at the start of every super partition to avoid
+ * creating an accidental boot sector.
+ */
+#define LP_PARTITION_RESERVED_BYTES 4096
+
/* This structure is stored at block 0 in the first 4096 bytes of the
* partition, and again in the following block. It is never modified and
* describes how logical partition information can be located.
diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp
index 92696f5..2aa41f3 100644
--- a/fs_mgr/liblp/io_test.cpp
+++ b/fs_mgr/liblp/io_test.cpp
@@ -376,6 +376,7 @@
ASSERT_NE(builder, nullptr);
ASSERT_TRUE(AddDefaultPartitions(builder.get()));
unique_ptr<LpMetadata> exported = builder->Export();
+ ASSERT_NE(exported, nullptr);
unique_fd fd(syscall(__NR_memfd_create, "image_file", 0));
ASSERT_GE(fd, 0);
diff --git a/fs_mgr/liblp/reader.cpp b/fs_mgr/liblp/reader.cpp
index 835df9b..43d8076 100644
--- a/fs_mgr/liblp/reader.cpp
+++ b/fs_mgr/liblp/reader.cpp
@@ -123,11 +123,11 @@
bool ReadPrimaryGeometry(int fd, LpMetadataGeometry* geometry) {
std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(LP_METADATA_GEOMETRY_SIZE);
if (SeekFile64(fd, GetPrimaryGeometryOffset(), SEEK_SET) < 0) {
- PERROR << __PRETTY_FUNCTION__ << "lseek failed";
+ PERROR << __PRETTY_FUNCTION__ << " lseek failed";
return false;
}
if (!android::base::ReadFully(fd, buffer.get(), LP_METADATA_GEOMETRY_SIZE)) {
- PERROR << __PRETTY_FUNCTION__ << "read " << LP_METADATA_GEOMETRY_SIZE << " bytes failed";
+ PERROR << __PRETTY_FUNCTION__ << " read " << LP_METADATA_GEOMETRY_SIZE << " bytes failed";
return false;
}
return ParseGeometry(buffer.get(), geometry);
@@ -136,11 +136,11 @@
bool ReadBackupGeometry(int fd, LpMetadataGeometry* geometry) {
std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(LP_METADATA_GEOMETRY_SIZE);
if (SeekFile64(fd, GetBackupGeometryOffset(), SEEK_SET) < 0) {
- PERROR << __PRETTY_FUNCTION__ << "lseek failed, offset " << -LP_METADATA_GEOMETRY_SIZE;
+ PERROR << __PRETTY_FUNCTION__ << " lseek failed";
return false;
}
if (!android::base::ReadFully(fd, buffer.get(), LP_METADATA_GEOMETRY_SIZE)) {
- PERROR << __PRETTY_FUNCTION__ << "backup read " << LP_METADATA_GEOMETRY_SIZE
+ PERROR << __PRETTY_FUNCTION__ << " backup read " << LP_METADATA_GEOMETRY_SIZE
<< " bytes failed";
return false;
}
@@ -223,7 +223,7 @@
// First read and validate the header.
std::unique_ptr<LpMetadata> metadata = std::make_unique<LpMetadata>();
if (!reader->ReadFully(&metadata->header, sizeof(metadata->header))) {
- PERROR << __PRETTY_FUNCTION__ << "read " << sizeof(metadata->header) << "bytes failed";
+ PERROR << __PRETTY_FUNCTION__ << " read " << sizeof(metadata->header) << "bytes failed";
return nullptr;
}
if (!ValidateMetadataHeader(metadata->header)) {
@@ -241,7 +241,7 @@
return nullptr;
}
if (!reader->ReadFully(buffer.get(), header.tables_size)) {
- PERROR << __PRETTY_FUNCTION__ << "read " << header.tables_size << "bytes failed";
+ PERROR << __PRETTY_FUNCTION__ << " read " << header.tables_size << "bytes failed";
return nullptr;
}
@@ -312,7 +312,7 @@
uint32_t slot_number) {
int64_t offset = GetPrimaryMetadataOffset(geometry, slot_number);
if (SeekFile64(fd, offset, SEEK_SET) < 0) {
- PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << offset;
+ PERROR << __PRETTY_FUNCTION__ << " lseek failed: offset " << offset;
return nullptr;
}
return ParseMetadata(geometry, fd);
@@ -322,7 +322,7 @@
uint32_t slot_number) {
int64_t offset = GetBackupMetadataOffset(geometry, slot_number);
if (SeekFile64(fd, offset, SEEK_SET) < 0) {
- PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << offset;
+ PERROR << __PRETTY_FUNCTION__ << " lseek failed: offset " << offset;
return nullptr;
}
return ParseMetadata(geometry, fd);
@@ -335,7 +335,7 @@
}
if (slot_number >= geometry.metadata_slot_count) {
- LERROR << __PRETTY_FUNCTION__ << "invalid metadata slot number";
+ LERROR << __PRETTY_FUNCTION__ << " invalid metadata slot number";
return nullptr;
}
@@ -350,7 +350,7 @@
std::unique_ptr<LpMetadata> ReadMetadata(const char* block_device, uint32_t slot_number) {
android::base::unique_fd fd(open(block_device, O_RDONLY));
if (fd < 0) {
- PERROR << __PRETTY_FUNCTION__ << "open failed: " << block_device;
+ PERROR << __PRETTY_FUNCTION__ << " open failed: " << block_device;
return nullptr;
}
return ReadMetadata(fd, slot_number);
diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp
index 2f7692f..0556833 100644
--- a/fs_mgr/liblp/utility.cpp
+++ b/fs_mgr/liblp/utility.cpp
@@ -57,17 +57,18 @@
}
int64_t GetPrimaryGeometryOffset() {
- return 0;
+ return LP_PARTITION_RESERVED_BYTES;
}
int64_t GetBackupGeometryOffset() {
- return LP_METADATA_GEOMETRY_SIZE;
+ return GetPrimaryGeometryOffset() + LP_METADATA_GEOMETRY_SIZE;
}
int64_t GetPrimaryMetadataOffset(const LpMetadataGeometry& geometry, uint32_t slot_number) {
CHECK(slot_number < geometry.metadata_slot_count);
- int64_t offset = (LP_METADATA_GEOMETRY_SIZE * 2) + geometry.metadata_max_size * slot_number;
+ int64_t offset = LP_PARTITION_RESERVED_BYTES + (LP_METADATA_GEOMETRY_SIZE * 2) +
+ geometry.metadata_max_size * slot_number;
CHECK(offset + geometry.metadata_max_size <=
int64_t(geometry.first_logical_sector * LP_SECTOR_SIZE));
return offset;
@@ -75,7 +76,7 @@
int64_t GetBackupMetadataOffset(const LpMetadataGeometry& geometry, uint32_t slot_number) {
CHECK(slot_number < geometry.metadata_slot_count);
- int64_t start = LP_METADATA_GEOMETRY_SIZE * 2 +
+ int64_t start = LP_PARTITION_RESERVED_BYTES + (LP_METADATA_GEOMETRY_SIZE * 2) +
int64_t(geometry.metadata_max_size) * geometry.metadata_slot_count;
return start + int64_t(geometry.metadata_max_size * slot_number);
}
diff --git a/fs_mgr/liblp/utility_test.cpp b/fs_mgr/liblp/utility_test.cpp
index 46ed2e6..8baf9e7 100644
--- a/fs_mgr/liblp/utility_test.cpp
+++ b/fs_mgr/liblp/utility_test.cpp
@@ -41,13 +41,13 @@
0,
1024 * 1024,
4096};
- EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 0), 8192);
- EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 1), 8192 + 16384);
- EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 2), 8192 + 16384 * 2);
- EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 3), 8192 + 16384 * 3);
+ static const uint64_t start = LP_PARTITION_RESERVED_BYTES;
+ EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 0), start + 8192);
+ EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 1), start + 8192 + 16384);
+ EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 2), start + 8192 + 16384 * 2);
+ EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 3), start + 8192 + 16384 * 3);
- static const uint64_t backup_start = 8192 + 16384 * 4;
-
+ static const uint64_t backup_start = start + 8192 + 16384 * 4;
EXPECT_EQ(GetBackupMetadataOffset(geometry, 3), backup_start + 16384 * 3);
EXPECT_EQ(GetBackupMetadataOffset(geometry, 2), backup_start + 16384 * 2);
EXPECT_EQ(GetBackupMetadataOffset(geometry, 1), backup_start + 16384 * 1);
diff --git a/fs_mgr/liblp/writer.cpp b/fs_mgr/liblp/writer.cpp
index 5cf1a2c..f857d8c 100644
--- a/fs_mgr/liblp/writer.cpp
+++ b/fs_mgr/liblp/writer.cpp
@@ -144,11 +144,11 @@
const std::function<bool(int, const std::string&)>& writer) {
int64_t primary_offset = GetPrimaryMetadataOffset(geometry, slot_number);
if (SeekFile64(fd, primary_offset, SEEK_SET) < 0) {
- PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << primary_offset;
+ PERROR << __PRETTY_FUNCTION__ << " lseek failed: offset " << primary_offset;
return false;
}
if (!writer(fd, blob)) {
- PERROR << __PRETTY_FUNCTION__ << "write " << blob.size() << " bytes failed";
+ PERROR << __PRETTY_FUNCTION__ << " write " << blob.size() << " bytes failed";
return false;
}
return true;
@@ -160,16 +160,16 @@
int64_t backup_offset = GetBackupMetadataOffset(geometry, slot_number);
int64_t abs_offset = SeekFile64(fd, backup_offset, SEEK_SET);
if (abs_offset == (int64_t)-1) {
- PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << backup_offset;
+ PERROR << __PRETTY_FUNCTION__ << " lseek failed: offset " << backup_offset;
return false;
}
if (abs_offset >= int64_t(geometry.first_logical_sector) * LP_SECTOR_SIZE) {
- PERROR << __PRETTY_FUNCTION__ << "backup offset " << abs_offset
+ PERROR << __PRETTY_FUNCTION__ << " backup offset " << abs_offset
<< " is within logical partition bounds, sector " << geometry.first_logical_sector;
return false;
}
if (!writer(fd, blob)) {
- PERROR << __PRETTY_FUNCTION__ << "backup write " << blob.size() << " bytes failed";
+ PERROR << __PRETTY_FUNCTION__ << " backup write " << blob.size() << " bytes failed";
return false;
}
return true;
@@ -205,22 +205,33 @@
return false;
}
- // Write geometry to the first and last 4096 bytes of the device.
+ // Write zeroes to the first block.
+ std::string zeroes(LP_PARTITION_RESERVED_BYTES, 0);
+ if (SeekFile64(fd, 0, SEEK_SET) < 0) {
+ PERROR << __PRETTY_FUNCTION__ << " lseek failed: offset 0";
+ return false;
+ }
+ if (!android::base::WriteFully(fd, zeroes.data(), zeroes.size())) {
+ PERROR << __PRETTY_FUNCTION__ << " write " << zeroes.size() << " bytes failed";
+ return false;
+ }
+
+ // Write geometry to the primary and backup locations.
std::string blob = SerializeGeometry(metadata.geometry);
if (SeekFile64(fd, GetPrimaryGeometryOffset(), SEEK_SET) < 0) {
- PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset 0";
+ PERROR << __PRETTY_FUNCTION__ << " lseek failed: primary geometry";
return false;
}
if (!android::base::WriteFully(fd, blob.data(), blob.size())) {
- PERROR << __PRETTY_FUNCTION__ << "write " << blob.size() << " bytes failed";
+ PERROR << __PRETTY_FUNCTION__ << " write " << blob.size() << " bytes failed";
return false;
}
if (SeekFile64(fd, GetBackupGeometryOffset(), SEEK_SET) < 0) {
- PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << -LP_METADATA_GEOMETRY_SIZE;
+ PERROR << __PRETTY_FUNCTION__ << " lseek failed: backup geometry";
return false;
}
if (!android::base::WriteFully(fd, blob.data(), blob.size())) {
- PERROR << __PRETTY_FUNCTION__ << "backup write " << blob.size() << " bytes failed";
+ PERROR << __PRETTY_FUNCTION__ << " backup write " << blob.size() << " bytes failed";
return false;
}
@@ -303,7 +314,7 @@
bool FlashPartitionTable(const std::string& block_device, const LpMetadata& metadata) {
android::base::unique_fd fd(open(block_device.c_str(), O_RDWR | O_SYNC));
if (fd < 0) {
- PERROR << __PRETTY_FUNCTION__ << "open failed: " << block_device;
+ PERROR << __PRETTY_FUNCTION__ << " open failed: " << block_device;
return false;
}
if (!FlashPartitionTable(fd, metadata)) {
@@ -317,7 +328,7 @@
uint32_t slot_number) {
android::base::unique_fd fd(open(block_device.c_str(), O_RDWR | O_SYNC));
if (fd < 0) {
- PERROR << __PRETTY_FUNCTION__ << "open failed: " << block_device;
+ PERROR << __PRETTY_FUNCTION__ << " open failed: " << block_device;
return false;
}
if (!UpdatePartitionTable(fd, metadata, slot_number)) {
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
new file mode 100755
index 0000000..d4ca574
--- /dev/null
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -0,0 +1,264 @@
+#! /bin/bash
+#
+# adb remount tests (overlayfs focus)
+#
+# Conditions:
+# - Must be a userdebug build.
+# - Must be in adb mode.
+# - Kernel must have overlayfs enabled and patched to support override_creds.
+# - Must have either squashfs, ext4-dedupe or right-sized partitions.
+# - Minimum expectation system and vender are overlayfs covered partitions.
+#
+
+# Helper Variables
+
+SPACE=" "
+# A _real_ embedded tab character
+TAB="`echo | tr '\n' '\t'`"
+# A _real_ embedded escape character
+ESCAPE="`echo | tr '\n' '\033'`"
+GREEN="${ESCAPE}[38;5;40m"
+RED="${ESCAPE}[38;5;196m"
+ORANGE="${ESCAPE}[38;5;255:165:0m"
+NORMAL="${ESCAPE}[0m"
+
+# Helper functions
+
+[ "USAGE: inFastboot
+
+Returns: true if device is in fastboot mode" ]
+inFastboot() {
+ fastboot devices | grep "^${ANDROID_SERIAL}[${SPACE}${TAB}]" > /dev/null
+}
+
+[ "USAGE: inAdb
+
+Returns: true if device is in adb mode" ]
+inAdb() {
+ adb devices | grep -v 'List of devices attached' | grep "^${ANDROID_SERIAL}[${SPACE}${TAB}]" > /dev/null
+}
+
+[ "USAGE: adb_sh <commands>
+
+Returns: true if the command succeeded" ]
+adb_sh() {
+ adb shell "${@}"
+}
+
+[ "USAGE: get_property <prop>
+
+Returns the property value" ]
+get_property() {
+ adb_sh getprop ${1} 2>&1 </dev/null
+}
+
+[ "USAGE: isDebuggable
+
+Returns: true if device is (likely) a debug build" ]
+isDebuggable() {
+ if inAdb && [ 1 -ne `get_property ro.debuggable` ]; then
+ false
+ fi
+}
+
+[ "USAGE: adb_su <commands>
+
+Returns: true if the command running as root succeeded" ]
+adb_su() {
+ adb_sh su root "${@}"
+}
+
+[ "USAGE: adb_cat <file> >stdout
+
+Returns: content of file to stdout with carriage returns skipped,
+ true of the file exists" ]
+adb_cat() {
+ OUTPUT="`adb_sh cat ${1} </dev/null 2>&1`"
+ retval=${?}
+ echo "${OUTPUT}" | tr -d '\r'
+ return ${retval}
+}
+
+[ "USAGE: adb_reboot
+
+Returns: true if the reboot command succeeded" ]
+adb_reboot() {
+ adb reboot remount-test
+}
+
+[ "USAGE: adb_wait
+
+Returns: waits until the device has returned" ]
+adb_wait() {
+ adb wait-for-device
+}
+
+[ "USAGE: adb_root
+
+Returns: true if device in root state" ]
+adb_root() {
+ adb root >/dev/null </dev/null 2>&1 &&
+ sleep 1 &&
+ adb_wait &&
+ sleep 1
+}
+
+die() {
+ echo "${RED}[ FAILED ]${NORMAL} ${@}" >&2
+ exit 1
+}
+
+[ "USAGE: EXPECT_EQ <lval> <rval> [message]
+
+Returns true if (regex) lval matches rval" ]
+EXPECT_EQ() {
+ lval="${1}"
+ rval="${2}"
+ shift 2
+ if ! ( echo X"${rval}" | grep '^X'"${lval}"'$' >/dev/null 2>/dev/null ); then
+ if [ `echo ${lval}${rval}${*} | wc -c` -gt 50 -o "${rval}" != "${rval%
+*}" ]; then
+ echo "ERROR: expected \"${lval}\"" >&2
+ echo " got \"${rval}\"" |
+ sed ': again
+ N
+ s/\(\n\)\([^ ]\)/\1 \2/
+ t again' >&2
+ if [ -n "${*}" ] ; then
+ echo " ${*}" >&2
+ fi
+ else
+ echo "ERROR: expected \"${lval}\" got \"${rval}\" ${*}" >&2
+ fi
+ return 1
+ fi
+ if [ -n "${*}" ] ; then
+ if [ X"${lval}" != X"${rval}" ]; then
+ if [ `echo ${lval}${rval}${*} | wc -c` -gt 60 -o "${rval}" != "${rval% *}" ]; then
+ echo "INFO: ok \"${lval}\"" >&2
+ echo " = \"${rval}\"" |
+ sed ': again
+ N
+ s/\(\n\)\([^ ]\)/\1 \2/
+ t again' >&2
+ if [ -n "${*}" ] ; then
+ echo " ${*}" >&2
+ fi
+ else
+ echo "INFO: ok \"${lval}\" = \"${rval}\" ${*}" >&2
+ fi
+ else
+ echo "INFO: ok \"${lval}\" ${*}" >&2
+ fi
+ fi
+ return 0
+}
+
+[ "USAGE: check_eq <lval> <rval> [message]
+
+Exits if (regex) lval mismatches rval" ]
+check_eq() {
+ left="${1}"
+ right="${2}"
+ shift 2
+ EXPECT_EQ "${left}" "${right}" ||
+ die "${@}"
+}
+
+[ "USAGE: skip_administrative_mounts
+
+Filters out all administrative (eg: sysfs) mounts" ]
+skip_administrative_mounts() {
+ grep -v -e "^\(overlay\|tmpfs\|none\|sysfs\|proc\|selinuxfs\|debugfs\|bpf\|cg2_bpf\|pstore\|tracefs\|adb\|mtp\|ptp\|devpts\|/data/media\) " -e " /\(cache\|mnt/scratch\|mnt/vendor/persist\|metadata\|data\) "
+}
+
+if [ X"-s" = X"${1}" -a -n "${2}" ]; then
+ export ANDROID_SERIAL="${2}"
+ shift 2
+fi
+
+inFastboot && die "device in fastboot mode"
+inAdb || die "device not in adb mode"
+isDebuggable || die "device not a debug build"
+
+# Do something
+adb_wait || die "wait for device failed"
+adb_sh ls -d /sys/module/overlay </dev/null || die "overlay module not present"
+adb_su ls /sys/module/overlay/parameters/override_creds </dev/null ||
+ die "overlay module can not be used on ANDROID"
+adb_root &&
+ adb_wait &&
+ D=`adb disable-verity 2>&1` ||
+ die "setup for overlay"
+echo "${D}"
+if [ X"${D}" != X"${D##*using overlayfs}" ]; then
+ echo "${GREEN}[ OK ]${NORMAL} using overlayfs" >&2
+fi
+if adb_sh ls -d /data/overlay </dev/null >/dev/null 2>&1; then
+ echo "/data/overlay setup, clearing out" >&2
+ adb_sh rm -rf /data/overlay </dev/null ||
+ die "/data/overlay removal"
+fi
+adb_sh ls -d /cache/overlay </dev/null >/dev/null 2>&1 ||
+ adb_sh ls -d /mnt/scratch/overlay </dev/null >/dev/null 2>&1 ||
+ die "overlay directory setup"
+adb_reboot &&
+ adb_wait &&
+ adb_sh df -k </dev/null | head -1 &&
+ adb_sh df -k </dev/null | grep "^overlay " &&
+ adb_sh df -k </dev/null | grep "^overlay .* /system\$" >/dev/null ||
+ echo "${ORANGE}[ WARNING ]${NORMAL} overlay takeover before remount not complete" >&2
+
+adb_root &&
+ adb_wait &&
+ adb remount &&
+ adb_sh df -k </dev/null | head -1 &&
+ adb_sh df -k </dev/null | grep "^overlay " &&
+ adb_sh df -k </dev/null | grep "^overlay .* /system\$" >/dev/null ||
+ die "overlay takeover after remount"
+!(adb_sh grep "^overlay " /proc/mounts </dev/null | grep " overlay ro,") &&
+ !(adb_sh grep " rw," /proc/mounts </dev/null |
+ skip_administrative_mounts) ||
+ die "remount overlayfs missed a spot"
+
+adb_su "sed -n '1,/overlay \\/system/p' /proc/mounts" </dev/null |
+ skip_administrative_mounts |
+ grep -v ' \(squashfs\|ext4\|f2fs\) ' &&
+ echo "${ORANGE}[ WARNING ]${NORMAL} overlay takeover after first stage init" >&2 ||
+ echo "${GREEN}[ OK ]${NORMAL} overlay takeover in first stage init" >&2
+
+# Check something
+A="Hello World! $(date)"
+echo "${A}" | adb_sh "cat - > /system/hello"
+echo "${A}" | adb_sh "cat - > /vendor/hello"
+B="`adb_cat /system/hello`" ||
+ die "sytem hello"
+check_eq "${A}" "${B}" system before reboot
+B="`adb_cat /vendor/hello`" ||
+ die "vendor hello"
+check_eq "${A}" "${B}" vendor before reboot
+adb_reboot &&
+ adb_wait &&
+ B="`adb_cat /system/hello`" ||
+ die "re-read system hello after reboot"
+check_eq "${A}" "${B}" system after reboot
+# Only root can read vendor if sepolicy permissions are as expected
+B="`adb_cat /vendor/hello`" &&
+ die "re-read vendor hello after reboot w/o root"
+check_eq "cat: /vendor/hello: Permission denied" "${B}" vendor after reboot w/o root
+adb_root &&
+ adb_wait &&
+ B="`adb_cat /vendor/hello`" ||
+ die "re-read vendor hello after reboot"
+check_eq "${A}" "${B}" vendor after reboot
+adb remount &&
+ adb_sh rm /system/hello /vendor/hello </dev/null ||
+ die "cleanup hello"
+B="`adb_cat /system/hello`" &&
+ die "re-read system hello after rm"
+check_eq "cat: /system/hello: No such file or directory" "${B}" after flash rm
+B="`adb_cat /vendor/hello`" &&
+ die "re-read vendor hello after rm"
+check_eq "cat: /vendor/hello: No such file or directory" "${B}" after flash rm
+
+echo "${GREEN}[ PASSED ]${NORMAL} adb remount" >&2
diff --git a/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/README.md b/init/README.md
index f938ccc..6c51b37 100644
--- a/init/README.md
+++ b/init/README.md
@@ -226,6 +226,15 @@
keycodes are pressed at once, the service will start. This is typically used to start the
bugreport service.
+> This option may take a property instead of a list of keycodes. In this case, only one option is
+ provided: the property name in the typical property expansion format. The property must contain
+ a comma separated list of keycode values or the text 'none' to indicate that
+ this service does not respond to keycodes.
+
+> For example, `keycodes ${some.property.name:-none}` where some.property.name expands
+ to "123,124,125". Since keycodes are handled very early in init,
+ only PRODUCT_DEFAULT_PROPERTY_OVERRIDES properties can be used.
+
`memcg.limit_in_bytes <value>`
> Sets the child's memory.limit_in_bytes to the specified value (only if memcg is mounted),
which must be equal or greater than 0.
diff --git a/init/action.cpp b/init/action.cpp
index 11335ca..94ccef2 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -44,9 +44,12 @@
return function(builtin_arguments);
}
-Command::Command(BuiltinFunction f, bool execute_in_subcontext,
- const std::vector<std::string>& args, int line)
- : func_(std::move(f)), execute_in_subcontext_(execute_in_subcontext), args_(args), line_(line) {}
+Command::Command(BuiltinFunction f, bool execute_in_subcontext, std::vector<std::string>&& args,
+ int line)
+ : func_(std::move(f)),
+ execute_in_subcontext_(execute_in_subcontext),
+ args_(std::move(args)),
+ line_(line) {}
Result<Success> Command::InvokeFunc(Subcontext* subcontext) const {
if (subcontext) {
@@ -80,7 +83,7 @@
const KeywordFunctionMap* Action::function_map_ = nullptr;
-Result<Success> Action::AddCommand(const std::vector<std::string>& args, int line) {
+Result<Success> Action::AddCommand(std::vector<std::string>&& args, int line) {
if (!function_map_) {
return Error() << "no function map available";
}
@@ -88,12 +91,12 @@
auto function = function_map_->FindFunction(args);
if (!function) return Error() << function.error();
- commands_.emplace_back(function->second, function->first, args, line);
+ commands_.emplace_back(function->second, function->first, std::move(args), line);
return Success();
}
-void Action::AddCommand(BuiltinFunction f, const std::vector<std::string>& args, int line) {
- commands_.emplace_back(f, false, args, line);
+void Action::AddCommand(BuiltinFunction f, std::vector<std::string>&& args, int line) {
+ commands_.emplace_back(f, false, std::move(args), line);
}
std::size_t Action::NumCommands() const {
diff --git a/init/action.h b/init/action.h
index 4f063cc..967c682 100644
--- a/init/action.h
+++ b/init/action.h
@@ -36,7 +36,7 @@
class Command {
public:
- Command(BuiltinFunction f, bool execute_in_subcontext, const std::vector<std::string>& args,
+ Command(BuiltinFunction f, bool execute_in_subcontext, std::vector<std::string>&& args,
int line);
Result<Success> InvokeFunc(Subcontext* subcontext) const;
@@ -61,8 +61,8 @@
const std::string& event_trigger,
const std::map<std::string, std::string>& property_triggers);
- Result<Success> AddCommand(const std::vector<std::string>& args, int line);
- void AddCommand(BuiltinFunction f, const std::vector<std::string>& args, int line);
+ Result<Success> AddCommand(std::vector<std::string>&& args, int line);
+ void AddCommand(BuiltinFunction f, std::vector<std::string>&& args, int line);
std::size_t NumCommands() const;
void ExecuteOneCommand(std::size_t command) const;
void ExecuteAllCommands() const;
diff --git a/init/action_manager.cpp b/init/action_manager.cpp
index 22977bb..9de4085 100644
--- a/init/action_manager.cpp
+++ b/init/action_manager.cpp
@@ -47,9 +47,7 @@
void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name) {
auto action = std::make_unique<Action>(true, nullptr, "<Builtin Action>", 0, name,
std::map<std::string, std::string>{});
- std::vector<std::string> name_vector{name};
-
- action->AddCommand(func, name_vector, 0);
+ action->AddCommand(func, {name}, 0);
event_queue_.emplace(action.get());
actions_.emplace_back(std::move(action));
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/init.cpp b/init/init.cpp
index 42ec88c..b12ba8c 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -61,6 +61,10 @@
#include "ueventd.h"
#include "util.h"
+#if __has_feature(address_sanitizer)
+#include <sanitizer/asan_interface.h>
+#endif
+
using namespace std::chrono_literals;
using namespace std::string_literals;
@@ -74,6 +78,25 @@
namespace android {
namespace init {
+#if __has_feature(address_sanitizer)
+// Load asan.options if it exists since these are not yet in the environment.
+// Always ensure detect_container_overflow=0 as there are false positives with this check.
+// Always ensure abort_on_error=1 to ensure we reboot to bootloader for development builds.
+extern "C" const char* __asan_default_options() {
+ return "include_if_exists=/system/asan.options:detect_container_overflow=0:abort_on_error=1";
+}
+
+__attribute__((no_sanitize("address", "memory", "thread", "undefined"))) extern "C" void
+__sanitizer_report_error_summary(const char* summary) {
+ LOG(ERROR) << "Main stage (error summary): " << summary;
+}
+
+__attribute__((no_sanitize("address", "memory", "thread", "undefined"))) static void
+AsanReportCallback(const char* str) {
+ LOG(ERROR) << "Main stage: " << str;
+}
+#endif
+
static int property_triggers_enabled = 0;
static char qemu[32];
@@ -619,6 +642,10 @@
}
int main(int argc, char** argv) {
+#if __has_feature(address_sanitizer)
+ __asan_set_error_report_callback(AsanReportCallback);
+#endif
+
if (!strcmp(basename(argv[0]), "ueventd")) {
return ueventd_main(argc, argv);
}
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 5c8b92a..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) {
@@ -746,7 +762,7 @@
return;
}
- int fd = open(rec->blk_device, O_RDONLY);
+ int fd = open(rec->blk_device, O_RDONLY | O_CLOEXEC);
if (fd == -1) {
PLOG(ERROR) << "error opening block device " << rec->blk_device;
return;
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/service.cpp b/init/service.cpp
index 0b1425d..7f49423 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -60,6 +60,7 @@
using android::base::GetProperty;
using android::base::Join;
using android::base::ParseInt;
+using android::base::Split;
using android::base::StartsWith;
using android::base::StringPrintf;
using android::base::unique_fd;
@@ -400,7 +401,7 @@
[] (const auto& info) { LOG(INFO) << *info; });
}
-Result<Success> Service::ParseCapabilities(const std::vector<std::string>& args) {
+Result<Success> Service::ParseCapabilities(std::vector<std::string>&& args) {
capabilities_ = 0;
if (!CapAmbientSupported()) {
@@ -429,29 +430,29 @@
return Success();
}
-Result<Success> Service::ParseClass(const std::vector<std::string>& args) {
+Result<Success> Service::ParseClass(std::vector<std::string>&& args) {
classnames_ = std::set<std::string>(args.begin() + 1, args.end());
return Success();
}
-Result<Success> Service::ParseConsole(const std::vector<std::string>& args) {
+Result<Success> Service::ParseConsole(std::vector<std::string>&& args) {
flags_ |= SVC_CONSOLE;
console_ = args.size() > 1 ? "/dev/" + args[1] : "";
return Success();
}
-Result<Success> Service::ParseCritical(const std::vector<std::string>& args) {
+Result<Success> Service::ParseCritical(std::vector<std::string>&& args) {
flags_ |= SVC_CRITICAL;
return Success();
}
-Result<Success> Service::ParseDisabled(const std::vector<std::string>& args) {
+Result<Success> Service::ParseDisabled(std::vector<std::string>&& args) {
flags_ |= SVC_DISABLED;
flags_ |= SVC_RC_DISABLED;
return Success();
}
-Result<Success> Service::ParseEnterNamespace(const std::vector<std::string>& args) {
+Result<Success> Service::ParseEnterNamespace(std::vector<std::string>&& args) {
if (args[1] != "net") {
return Error() << "Init only supports entering network namespaces";
}
@@ -461,11 +462,11 @@
// Network namespaces require that /sys is remounted, otherwise the old adapters will still be
// present. Therefore, they also require mount namespaces.
namespace_flags_ |= CLONE_NEWNS;
- namespaces_to_enter_.emplace_back(CLONE_NEWNET, args[2]);
+ namespaces_to_enter_.emplace_back(CLONE_NEWNET, std::move(args[2]));
return Success();
}
-Result<Success> Service::ParseGroup(const std::vector<std::string>& args) {
+Result<Success> Service::ParseGroup(std::vector<std::string>&& args) {
auto gid = DecodeUid(args[1]);
if (!gid) {
return Error() << "Unable to decode GID for '" << args[1] << "': " << gid.error();
@@ -482,7 +483,7 @@
return Success();
}
-Result<Success> Service::ParsePriority(const std::vector<std::string>& args) {
+Result<Success> Service::ParsePriority(std::vector<std::string>&& args) {
priority_ = 0;
if (!ParseInt(args[1], &priority_,
static_cast<int>(ANDROID_PRIORITY_HIGHEST), // highest is negative
@@ -493,7 +494,7 @@
return Success();
}
-Result<Success> Service::ParseInterface(const std::vector<std::string>& args) {
+Result<Success> Service::ParseInterface(std::vector<std::string>&& args) {
const std::string& interface_name = args[1];
const std::string& instance_name = args[2];
@@ -524,7 +525,7 @@
return Success();
}
-Result<Success> Service::ParseIoprio(const std::vector<std::string>& args) {
+Result<Success> Service::ParseIoprio(std::vector<std::string>&& args) {
if (!ParseInt(args[2], &ioprio_pri_, 0, 7)) {
return Error() << "priority value must be range 0 - 7";
}
@@ -542,36 +543,53 @@
return Success();
}
-Result<Success> Service::ParseKeycodes(const std::vector<std::string>& args) {
- for (std::size_t i = 1; i < args.size(); i++) {
+Result<Success> Service::ParseKeycodes(std::vector<std::string>&& args) {
+ auto it = args.begin() + 1;
+ if (args.size() == 2 && StartsWith(args[1], "$")) {
+ std::string expanded;
+ if (!expand_props(args[1], &expanded)) {
+ return Error() << "Could not expand property '" << args[1] << "'";
+ }
+
+ // If the property is not set, it defaults to none, in which case there are no keycodes
+ // for this service.
+ if (expanded == "none") {
+ return Success();
+ }
+
+ args = Split(expanded, ",");
+ it = args.begin();
+ }
+
+ for (; it != args.end(); ++it) {
int code;
- if (ParseInt(args[i], &code, 0, KEY_MAX)) {
+ if (ParseInt(*it, &code, 0, KEY_MAX)) {
for (auto& key : keycodes_) {
- if (key == code) return Error() << "duplicate keycode: " << args[i];
+ if (key == code) return Error() << "duplicate keycode: " << *it;
}
keycodes_.insert(std::upper_bound(keycodes_.begin(), keycodes_.end(), code), code);
} else {
- return Error() << "invalid keycode: " << args[i];
+ return Error() << "invalid keycode: " << *it;
}
}
return Success();
}
-Result<Success> Service::ParseOneshot(const std::vector<std::string>& args) {
+Result<Success> Service::ParseOneshot(std::vector<std::string>&& args) {
flags_ |= SVC_ONESHOT;
return Success();
}
-Result<Success> Service::ParseOnrestart(const std::vector<std::string>& args) {
- std::vector<std::string> str_args(args.begin() + 1, args.end());
+Result<Success> Service::ParseOnrestart(std::vector<std::string>&& args) {
+ args.erase(args.begin());
int line = onrestart_.NumCommands() + 1;
- if (auto result = onrestart_.AddCommand(str_args, line); !result) {
+ if (auto result = onrestart_.AddCommand(std::move(args), line); !result) {
return Error() << "cannot add Onrestart command: " << result.error();
}
return Success();
}
-Result<Success> Service::ParseNamespace(const std::vector<std::string>& args) {
+Result<Success> Service::ParseNamespace(std::vector<std::string>&& args) {
for (size_t i = 1; i < args.size(); i++) {
if (args[i] == "pid") {
namespace_flags_ |= CLONE_NEWPID;
@@ -586,40 +604,40 @@
return Success();
}
-Result<Success> Service::ParseOomScoreAdjust(const std::vector<std::string>& args) {
+Result<Success> Service::ParseOomScoreAdjust(std::vector<std::string>&& args) {
if (!ParseInt(args[1], &oom_score_adjust_, -1000, 1000)) {
return Error() << "oom_score_adjust value must be in range -1000 - +1000";
}
return Success();
}
-Result<Success> Service::ParseOverride(const std::vector<std::string>& args) {
+Result<Success> Service::ParseOverride(std::vector<std::string>&& args) {
override_ = true;
return Success();
}
-Result<Success> Service::ParseMemcgSwappiness(const std::vector<std::string>& args) {
+Result<Success> Service::ParseMemcgSwappiness(std::vector<std::string>&& args) {
if (!ParseInt(args[1], &swappiness_, 0)) {
return Error() << "swappiness value must be equal or greater than 0";
}
return Success();
}
-Result<Success> Service::ParseMemcgLimitInBytes(const std::vector<std::string>& args) {
+Result<Success> Service::ParseMemcgLimitInBytes(std::vector<std::string>&& args) {
if (!ParseInt(args[1], &limit_in_bytes_, 0)) {
return Error() << "limit_in_bytes value must be equal or greater than 0";
}
return Success();
}
-Result<Success> Service::ParseMemcgSoftLimitInBytes(const std::vector<std::string>& args) {
+Result<Success> Service::ParseMemcgSoftLimitInBytes(std::vector<std::string>&& args) {
if (!ParseInt(args[1], &soft_limit_in_bytes_, 0)) {
return Error() << "soft_limit_in_bytes value must be equal or greater than 0";
}
return Success();
}
-Result<Success> Service::ParseProcessRlimit(const std::vector<std::string>& args) {
+Result<Success> Service::ParseProcessRlimit(std::vector<std::string>&& args) {
auto rlimit = ParseRlimit(args);
if (!rlimit) return rlimit.error();
@@ -627,7 +645,7 @@
return Success();
}
-Result<Success> Service::ParseRestartPeriod(const std::vector<std::string>& args) {
+Result<Success> Service::ParseRestartPeriod(std::vector<std::string>&& args) {
int period;
if (!ParseInt(args[1], &period, 5)) {
return Error() << "restart_period value must be an integer >= 5";
@@ -636,22 +654,22 @@
return Success();
}
-Result<Success> Service::ParseSeclabel(const std::vector<std::string>& args) {
- seclabel_ = args[1];
+Result<Success> Service::ParseSeclabel(std::vector<std::string>&& args) {
+ seclabel_ = std::move(args[1]);
return Success();
}
-Result<Success> Service::ParseSigstop(const std::vector<std::string>& args) {
+Result<Success> Service::ParseSigstop(std::vector<std::string>&& args) {
sigstop_ = true;
return Success();
}
-Result<Success> Service::ParseSetenv(const std::vector<std::string>& args) {
- environment_vars_.emplace_back(args[1], args[2]);
+Result<Success> Service::ParseSetenv(std::vector<std::string>&& args) {
+ environment_vars_.emplace_back(std::move(args[1]), std::move(args[2]));
return Success();
}
-Result<Success> Service::ParseShutdown(const std::vector<std::string>& args) {
+Result<Success> Service::ParseShutdown(std::vector<std::string>&& args) {
if (args[1] == "critical") {
flags_ |= SVC_SHUTDOWN_CRITICAL;
return Success();
@@ -659,7 +677,7 @@
return Error() << "Invalid shutdown option";
}
-Result<Success> Service::ParseTimeoutPeriod(const std::vector<std::string>& args) {
+Result<Success> Service::ParseTimeoutPeriod(std::vector<std::string>&& args) {
int period;
if (!ParseInt(args[1], &period, 1)) {
return Error() << "timeout_period value must be an integer >= 1";
@@ -669,7 +687,7 @@
}
template <typename T>
-Result<Success> Service::AddDescriptor(const std::vector<std::string>& args) {
+Result<Success> Service::AddDescriptor(std::vector<std::string>&& args) {
int perm = args.size() > 3 ? std::strtoul(args[3].c_str(), 0, 8) : -1;
Result<uid_t> uid = 0;
Result<gid_t> gid = 0;
@@ -704,26 +722,26 @@
}
// name type perm [ uid gid context ]
-Result<Success> Service::ParseSocket(const std::vector<std::string>& args) {
+Result<Success> Service::ParseSocket(std::vector<std::string>&& args) {
if (!StartsWith(args[2], "dgram") && !StartsWith(args[2], "stream") &&
!StartsWith(args[2], "seqpacket")) {
return Error() << "socket type must be 'dgram', 'stream' or 'seqpacket'";
}
- return AddDescriptor<SocketInfo>(args);
+ return AddDescriptor<SocketInfo>(std::move(args));
}
// name type perm [ uid gid context ]
-Result<Success> Service::ParseFile(const std::vector<std::string>& args) {
+Result<Success> Service::ParseFile(std::vector<std::string>&& args) {
if (args[2] != "r" && args[2] != "w" && args[2] != "rw") {
return Error() << "file type must be 'r', 'w' or 'rw'";
}
if ((args[1][0] != '/') || (args[1].find("../") != std::string::npos)) {
return Error() << "file name must not be relative";
}
- return AddDescriptor<FileInfo>(args);
+ return AddDescriptor<FileInfo>(std::move(args));
}
-Result<Success> Service::ParseUser(const std::vector<std::string>& args) {
+Result<Success> Service::ParseUser(std::vector<std::string>&& args) {
auto uid = DecodeUid(args[1]);
if (!uid) {
return Error() << "Unable to find UID for '" << args[1] << "': " << uid.error();
@@ -732,8 +750,9 @@
return Success();
}
-Result<Success> Service::ParseWritepid(const std::vector<std::string>& args) {
- writepid_files_.assign(args.begin() + 1, args.end());
+Result<Success> Service::ParseWritepid(std::vector<std::string>&& args) {
+ args.erase(args.begin());
+ writepid_files_ = std::move(args);
return Success();
}
@@ -792,13 +811,13 @@
return option_parsers;
}
-Result<Success> Service::ParseLine(const std::vector<std::string>& args) {
+Result<Success> Service::ParseLine(std::vector<std::string>&& args) {
static const OptionParserMap parser_map;
auto parser = parser_map.FindFunction(args);
if (!parser) return parser.error();
- return std::invoke(*parser, this, args);
+ return std::invoke(*parser, this, std::move(args));
}
Result<Success> Service::ExecStart() {
diff --git a/init/service.h b/init/service.h
index ee53adf..c7beee9 100644
--- a/init/service.h
+++ b/init/service.h
@@ -75,7 +75,7 @@
static std::unique_ptr<Service> MakeTemporaryOneshotService(const std::vector<std::string>& args);
bool IsRunning() { return (flags_ & SVC_RUNNING) != 0; }
- Result<Success> ParseLine(const std::vector<std::string>& args);
+ Result<Success> ParseLine(std::vector<std::string>&& args);
Result<Success> ExecStart();
Result<Success> Start();
Result<Success> StartIfNotDisabled();
@@ -125,7 +125,7 @@
const std::vector<std::string>& args() const { return args_; }
private:
- using OptionParser = Result<Success> (Service::*)(const std::vector<std::string>& args);
+ using OptionParser = Result<Success> (Service::*)(std::vector<std::string>&& args);
class OptionParserMap;
Result<Success> SetUpMountNamespace() const;
@@ -138,39 +138,39 @@
void KillProcessGroup(int signal);
void SetProcessAttributes();
- Result<Success> ParseCapabilities(const std::vector<std::string>& args);
- Result<Success> ParseClass(const std::vector<std::string>& args);
- Result<Success> ParseConsole(const std::vector<std::string>& args);
- Result<Success> ParseCritical(const std::vector<std::string>& args);
- Result<Success> ParseDisabled(const std::vector<std::string>& args);
- Result<Success> ParseEnterNamespace(const std::vector<std::string>& args);
- Result<Success> ParseGroup(const std::vector<std::string>& args);
- Result<Success> ParsePriority(const std::vector<std::string>& args);
- Result<Success> ParseInterface(const std::vector<std::string>& args);
- Result<Success> ParseIoprio(const std::vector<std::string>& args);
- Result<Success> ParseKeycodes(const std::vector<std::string>& args);
- Result<Success> ParseOneshot(const std::vector<std::string>& args);
- Result<Success> ParseOnrestart(const std::vector<std::string>& args);
- Result<Success> ParseOomScoreAdjust(const std::vector<std::string>& args);
- Result<Success> ParseOverride(const std::vector<std::string>& args);
- Result<Success> ParseMemcgLimitInBytes(const std::vector<std::string>& args);
- Result<Success> ParseMemcgSoftLimitInBytes(const std::vector<std::string>& args);
- Result<Success> ParseMemcgSwappiness(const std::vector<std::string>& args);
- Result<Success> ParseNamespace(const std::vector<std::string>& args);
- Result<Success> ParseProcessRlimit(const std::vector<std::string>& args);
- Result<Success> ParseRestartPeriod(const std::vector<std::string>& args);
- Result<Success> ParseSeclabel(const std::vector<std::string>& args);
- Result<Success> ParseSetenv(const std::vector<std::string>& args);
- Result<Success> ParseShutdown(const std::vector<std::string>& args);
- Result<Success> ParseSigstop(const std::vector<std::string>& args);
- Result<Success> ParseSocket(const std::vector<std::string>& args);
- Result<Success> ParseTimeoutPeriod(const std::vector<std::string>& args);
- Result<Success> ParseFile(const std::vector<std::string>& args);
- Result<Success> ParseUser(const std::vector<std::string>& args);
- Result<Success> ParseWritepid(const std::vector<std::string>& args);
+ Result<Success> ParseCapabilities(std::vector<std::string>&& args);
+ Result<Success> ParseClass(std::vector<std::string>&& args);
+ Result<Success> ParseConsole(std::vector<std::string>&& args);
+ Result<Success> ParseCritical(std::vector<std::string>&& args);
+ Result<Success> ParseDisabled(std::vector<std::string>&& args);
+ Result<Success> ParseEnterNamespace(std::vector<std::string>&& args);
+ Result<Success> ParseGroup(std::vector<std::string>&& args);
+ Result<Success> ParsePriority(std::vector<std::string>&& args);
+ Result<Success> ParseInterface(std::vector<std::string>&& args);
+ Result<Success> ParseIoprio(std::vector<std::string>&& args);
+ Result<Success> ParseKeycodes(std::vector<std::string>&& args);
+ Result<Success> ParseOneshot(std::vector<std::string>&& args);
+ Result<Success> ParseOnrestart(std::vector<std::string>&& args);
+ Result<Success> ParseOomScoreAdjust(std::vector<std::string>&& args);
+ Result<Success> ParseOverride(std::vector<std::string>&& args);
+ Result<Success> ParseMemcgLimitInBytes(std::vector<std::string>&& args);
+ Result<Success> ParseMemcgSoftLimitInBytes(std::vector<std::string>&& args);
+ Result<Success> ParseMemcgSwappiness(std::vector<std::string>&& args);
+ Result<Success> ParseNamespace(std::vector<std::string>&& args);
+ Result<Success> ParseProcessRlimit(std::vector<std::string>&& args);
+ Result<Success> ParseRestartPeriod(std::vector<std::string>&& args);
+ Result<Success> ParseSeclabel(std::vector<std::string>&& args);
+ Result<Success> ParseSetenv(std::vector<std::string>&& args);
+ Result<Success> ParseShutdown(std::vector<std::string>&& args);
+ Result<Success> ParseSigstop(std::vector<std::string>&& args);
+ Result<Success> ParseSocket(std::vector<std::string>&& args);
+ Result<Success> ParseTimeoutPeriod(std::vector<std::string>&& args);
+ Result<Success> ParseFile(std::vector<std::string>&& args);
+ Result<Success> ParseUser(std::vector<std::string>&& args);
+ Result<Success> ParseWritepid(std::vector<std::string>&& args);
template <typename T>
- Result<Success> AddDescriptor(const std::vector<std::string>& args);
+ Result<Success> AddDescriptor(std::vector<std::string>&& args);
static unsigned long next_start_order_;
static bool is_exec_service_running_;
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/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/logcat/logcat.cpp b/logcat/logcat.cpp
index 115b1a3..87bc6ae 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -478,10 +478,10 @@
" -G <size>, --buffer-size=<size>\n"
" Set size of log ring buffer, may suffix with K or M.\n"
" -L, --last Dump logs from prior to last reboot\n"
- // Leave security (Device Owner only installations) and
- // kernel (userdebug and eng) buffers undocumented.
" -b <buffer>, --buffer=<buffer> Request alternate ring buffer, 'main',\n"
" 'system', 'radio', 'events', 'crash', 'default' or 'all'.\n"
+ " Additionally, 'kernel' for userdebug and eng builds, and\n"
+ " 'security' for Device Owner installations.\n"
" Multiple -b parameters or comma separated list of buffers are\n"
" allowed. Buffers interleaved. Default -b main,system,crash.\n"
" -B, --binary Output the log in binary.\n"
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index 13c7af3..9db8c00 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -212,6 +212,10 @@
cli->getUid(), cli->getGid(), cli->getPid(), nonBlock ? 'n' : 'b', tail,
logMask, (int)pid, sequence.nsec(), timeout);
+ if (sequence == log_time::EPOCH) {
+ timeout = 0;
+ }
+
LogTimeEntry::wrlock();
auto entry = std::make_unique<LogTimeEntry>(
*this, cli, nonBlock, tail, logMask, pid, sequence, timeout);
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 21d234f..025e3c3 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -275,6 +275,13 @@
chown root root /apex
restorecon /apex
+ # Start logd before any other services run to ensure we capture all of their logs.
+ start logd
+ # Start essential services.
+ start servicemanager
+ start hwservicemanager
+ start vndservicemanager
+
# Healthd can trigger a full boot from charger mode by signaling this
# property when the power button is held.
on property:sys.boot_from_charger_mode=1
@@ -331,11 +338,6 @@
# /vendor/build.prop and
# /factory/factory.prop
load_system_props
- # start essential services
- start logd
- start servicemanager
- start hwservicemanager
- start vndservicemanager
start vold
exec - system system -- /system/bin/vdc checkpoint markBootAttempt
@@ -487,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