Merge "libutils: Add UNEXPECTED_NULL status_t"
diff --git a/adb/adb.h b/adb/adb.h
index c284c8c..491fff3 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -50,7 +50,7 @@
std::string adb_version();
// Increment this when we want to force users to start a new adb server.
-#define ADB_SERVER_VERSION 34
+#define ADB_SERVER_VERSION 35
class atransport;
struct usb_handle;
diff --git a/adb/adb_trace.cpp b/adb/adb_trace.cpp
index 9586f7c..cf99df7 100644
--- a/adb/adb_trace.cpp
+++ b/adb/adb_trace.cpp
@@ -163,7 +163,7 @@
}
#endif
- android::base::InitLogging(argv, AdbLogger);
+ android::base::InitLogging(argv, &AdbLogger);
setup_trace_mask();
VLOG(ADB) << adb_version();
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index fd61bda..42f1c7d 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -182,11 +182,8 @@
line.push_back(' ');
for (size_t i = 0; i < byte_count; ++i) {
- int c = p[i];
- if (c < 32 || c > 127) {
- c = '.';
- }
- line.push_back(c);
+ int ch = p[i];
+ line.push_back(isprint(ch) ? ch : '.');
}
return line;
diff --git a/adb/commandline.cpp b/adb/commandline.cpp
index 785fef3..6e4c4e8 100644
--- a/adb/commandline.cpp
+++ b/adb/commandline.cpp
@@ -59,6 +59,8 @@
static int install_app(TransportType t, const char* serial, int argc, const char** argv);
static int install_multiple_app(TransportType t, const char* serial, int argc, const char** argv);
static int uninstall_app(TransportType t, const char* serial, int argc, const char** argv);
+static int install_app_legacy(TransportType t, const char* serial, int argc, const char** argv);
+static int uninstall_app_legacy(TransportType t, const char* serial, int argc, const char** argv);
static std::string gProductOutPath;
extern int gListenAll;
@@ -110,11 +112,12 @@
" (-a preserves file timestamp and mode)\n"
" adb sync [ <directory> ] - copy host->device only if changed\n"
" (-l means list but don't copy)\n"
- " adb shell [-Ttx] - run remote shell interactively\n"
- " adb shell [-Ttx] <command> - run remote shell command\n"
- " (-T disables PTY allocation)\n"
- " (-t forces PTY allocation)\n"
- " (-x disables remote exit codes and stdout/stderr separation)\n"
+ " adb shell [-e escape] [-Tt] [-x] [command]\n"
+ " - run remote shell command (interactive shell if no command given)\n"
+ " (-e: choose escape character, or \"none\"; default '~')\n"
+ " (-T: disable PTY allocation)\n"
+ " (-t: force PTY allocation)\n"
+ " (-x: disable remote exit codes and stdout/stderr separation)\n"
" adb emu <command> - run emulator console command\n"
" adb logcat [ <filter-spec> ] - View device log\n"
" adb forward --list - list all forward socket connections.\n"
@@ -465,6 +468,7 @@
int stdin_fd, write_fd;
bool raw_stdin;
std::unique_ptr<ShellProtocol> protocol;
+ char escape_char;
};
// Loops to read from stdin and push the data to the given FD.
@@ -472,7 +476,6 @@
// will take ownership of the object and delete it when finished.
static void* stdin_read_thread_loop(void* x) {
std::unique_ptr<StdinReadArgs> args(reinterpret_cast<StdinReadArgs*>(x));
- int state = 0;
#if !defined(_WIN32)
// Mask SIGTTIN in case we're in a backgrounded process.
@@ -494,7 +497,7 @@
// Set up the initial window size.
send_window_size_change(args->stdin_fd, args->protocol);
- char raw_buffer[1024];
+ char raw_buffer[BUFSIZ];
char* buffer_ptr = raw_buffer;
size_t buffer_size = sizeof(raw_buffer);
if (args->protocol != nullptr) {
@@ -502,6 +505,14 @@
buffer_size = args->protocol->data_capacity();
}
+ // If we need to parse escape sequences, make life easy.
+ if (args->raw_stdin && args->escape_char != '\0') {
+ buffer_size = 1;
+ }
+
+ enum EscapeState { kMidFlow, kStartOfLine, kInEscape };
+ EscapeState state = kStartOfLine;
+
while (true) {
// Use unix_read() rather than adb_read() for stdin.
D("stdin_read_thread_loop(): pre unix_read(fdi=%d,...)", args->stdin_fd);
@@ -527,36 +538,36 @@
}
break;
}
- // If we made stdin raw, check input for the "~." escape sequence. In
+ // If we made stdin raw, check input for escape sequences. In
// this situation signals like Ctrl+C are sent remotely rather than
// interpreted locally so this provides an emergency out if the remote
// process starts ignoring the signal. SSH also does this, see the
// "escape characters" section on the ssh man page for more info.
- if (args->raw_stdin) {
- for (int n = 0; n < r; n++) {
- switch (buffer_ptr[n]) {
- case '\n':
- state = 1;
- break;
- case '\r':
- state = 1;
- break;
- case '~':
- if (state == 1) {
- state++;
- } else {
- state = 0;
- }
- break;
- case '.':
- if (state == 2) {
- fprintf(stderr,"\r\n* disconnect *\r\n");
+ if (args->raw_stdin && args->escape_char != '\0') {
+ char ch = buffer_ptr[0];
+ if (ch == args->escape_char) {
+ if (state == kStartOfLine) {
+ state = kInEscape;
+ // Swallow the escape character.
+ continue;
+ } else {
+ state = kMidFlow;
+ }
+ } else {
+ if (state == kInEscape) {
+ if (ch == '.') {
+ fprintf(stderr,"\r\n[ disconnected ]\r\n");
stdin_raw_restore();
exit(0);
+ } else {
+ // We swallowed an escape character that wasn't part of
+ // a valid escape sequence; time to cough it up.
+ buffer_ptr[0] = args->escape_char;
+ buffer_ptr[1] = ch;
+ ++r;
}
- default:
- state = 0;
}
+ state = (ch == '\n' || ch == '\r') ? kStartOfLine : kMidFlow;
}
}
if (args->protocol) {
@@ -601,6 +612,7 @@
// On success returns the remote exit code if |use_shell_protocol| is true,
// 0 otherwise. On failure returns 1.
static int RemoteShell(bool use_shell_protocol, const std::string& type_arg,
+ char escape_char,
const std::string& command) {
std::string service_string = ShellServiceString(use_shell_protocol,
type_arg, command);
@@ -626,6 +638,7 @@
args->stdin_fd = STDIN_FILENO;
args->write_fd = fd;
args->raw_stdin = raw_stdin;
+ args->escape_char = escape_char;
if (use_shell_protocol) {
args->protocol.reset(new ShellProtocol(args->write_fd));
}
@@ -687,8 +700,17 @@
--argc;
++argv;
int t_arg_count = 0;
+ char escape_char = '~';
while (argc) {
- if (!strcmp(argv[0], "-T") || !strcmp(argv[0], "-t")) {
+ if (!strcmp(argv[0], "-e")) {
+ if (argc < 2 || !(strlen(argv[1]) == 1 || strcmp(argv[1], "none") == 0)) {
+ fprintf(stderr, "error: -e requires a single-character argument or 'none'\n");
+ return 1;
+ }
+ escape_char = (strcmp(argv[1], "none") == 0) ? 0 : argv[1][0];
+ argc -= 2;
+ argv += 2;
+ } else if (!strcmp(argv[0], "-T") || !strcmp(argv[0], "-t")) {
if (!CanUseFeature(features, kFeatureShell2)) {
fprintf(stderr, "error: target doesn't support PTY args -Tt\n");
return 1;
@@ -744,7 +766,7 @@
command = android::base::Join(std::vector<const char*>(argv, argv + argc), ' ');
}
- return RemoteShell(use_shell_protocol, shell_type_arg, command);
+ return RemoteShell(use_shell_protocol, shell_type_arg, escape_char, command);
}
static int adb_download_buffer(const char *service, const char *fn, const void* data, unsigned sz,
@@ -1622,7 +1644,11 @@
}
else if (!strcmp(argv[0], "install")) {
if (argc < 2) return usage();
- return install_app(transport_type, serial, argc, argv);
+ FeatureSet features = GetFeatureSet(transport_type, serial);
+ if (CanUseFeature(features, kFeatureCmd)) {
+ return install_app(transport_type, serial, argc, argv);
+ }
+ return install_app_legacy(transport_type, serial, argc, argv);
}
else if (!strcmp(argv[0], "install-multiple")) {
if (argc < 2) return usage();
@@ -1630,7 +1656,11 @@
}
else if (!strcmp(argv[0], "uninstall")) {
if (argc < 2) return usage();
- return uninstall_app(transport_type, serial, argc, argv);
+ FeatureSet features = GetFeatureSet(transport_type, serial);
+ if (CanUseFeature(features, kFeatureCmd)) {
+ return uninstall_app(transport_type, serial, argc, argv);
+ }
+ return uninstall_app_legacy(transport_type, serial, argc, argv);
}
else if (!strcmp(argv[0], "sync")) {
std::string src;
@@ -1738,86 +1768,83 @@
return 1;
}
-static int pm_command(TransportType transport, const char* serial, int argc, const char** argv) {
- std::string cmd = "pm";
-
+static int uninstall_app(TransportType transport, const char* serial, int argc, const char** argv) {
+ // 'adb uninstall' takes the same arguments as 'cmd package uninstall' on device
+ std::string cmd = "cmd package";
while (argc-- > 0) {
+ // deny the '-k' option until the remaining data/cache can be removed with adb/UI
+ if (strcmp(*argv, "-k") == 0) {
+ printf(
+ "The -k option uninstalls the application while retaining the data/cache.\n"
+ "At the moment, there is no way to remove the remaining data.\n"
+ "You will have to reinstall the application with the same signature, and fully uninstall it.\n"
+ "If you truly wish to continue, execute 'adb shell cmd package uninstall -k'.\n");
+ return EXIT_FAILURE;
+ }
cmd += " " + escape_arg(*argv++);
}
- // TODO(dpursell): add command-line arguments to install/uninstall to
- // manually disable shell protocol if needed.
- return send_shell_command(transport, serial, cmd, false);
-}
-
-static int uninstall_app(TransportType transport, const char* serial, int argc, const char** argv) {
- /* if the user choose the -k option, we refuse to do it until devices are
- out with the option to uninstall the remaining data somehow (adb/ui) */
- if (argc == 3 && strcmp(argv[1], "-k") == 0)
- {
- printf(
- "The -k option uninstalls the application while retaining the data/cache.\n"
- "At the moment, there is no way to remove the remaining data.\n"
- "You will have to reinstall the application with the same signature, and fully uninstall it.\n"
- "If you truly wish to continue, execute 'adb shell pm uninstall -k %s'\n", argv[2]);
- return -1;
- }
-
- /* 'adb uninstall' takes the same arguments as 'pm uninstall' on device */
- return pm_command(transport, serial, argc, argv);
-}
-
-static int delete_file(TransportType transport, const char* serial, const std::string& filename) {
- std::string cmd = "rm -f " + escape_arg(filename);
return send_shell_command(transport, serial, cmd, false);
}
static int install_app(TransportType transport, const char* serial, int argc, const char** argv) {
- static const char *const DATA_DEST = "/data/local/tmp/%s";
- static const char *const SD_DEST = "/sdcard/tmp/%s";
- const char* where = DATA_DEST;
- int i;
+ // The last argument must be the APK file
+ const char* file = argv[argc - 1];
+ const char* dot = strrchr(file, '.');
+ bool found_apk = false;
struct stat sb;
-
- for (i = 1; i < argc; i++) {
- if (!strcmp(argv[i], "-s")) {
- where = SD_DEST;
+ if (dot && !strcasecmp(dot, ".apk")) {
+ if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) {
+ fprintf(stderr, "Invalid APK file: %s\n", file);
+ return EXIT_FAILURE;
}
+ found_apk = true;
}
- // Find last APK argument.
- // All other arguments passed through verbatim.
- int last_apk = -1;
- for (i = argc - 1; i >= 0; i--) {
- const char* file = argv[i];
- const char* dot = strrchr(file, '.');
- if (dot && !strcasecmp(dot, ".apk")) {
- if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) {
- fprintf(stderr, "Invalid APK file: %s\n", file);
- return -1;
- }
-
- last_apk = i;
- break;
- }
- }
-
- if (last_apk == -1) {
+ if (!found_apk) {
fprintf(stderr, "Missing APK file\n");
- return -1;
+ return EXIT_FAILURE;
}
- int result = -1;
- std::vector<const char*> apk_file = {argv[last_apk]};
- std::string apk_dest = android::base::StringPrintf(
- where, adb_basename(argv[last_apk]).c_str());
- if (!do_sync_push(apk_file, apk_dest.c_str())) goto cleanup_apk;
- argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */
- result = pm_command(transport, serial, argc, argv);
+ int localFd = adb_open(file, O_RDONLY);
+ if (localFd < 0) {
+ fprintf(stderr, "Failed to open %s: %s\n", file, strerror(errno));
+ return 1;
+ }
-cleanup_apk:
- delete_file(transport, serial, apk_dest);
- return result;
+ std::string error;
+ std::string cmd = "exec:cmd package";
+
+ // don't copy the APK name, but, copy the rest of the arguments as-is
+ while (argc-- > 1) {
+ cmd += " " + escape_arg(std::string(*argv++));
+ }
+
+ // add size parameter [required for streaming installs]
+ // do last to override any user specified value
+ cmd += " " + android::base::StringPrintf("-S %" PRIu64, static_cast<uint64_t>(sb.st_size));
+
+ int remoteFd = adb_connect(cmd, &error);
+ if (remoteFd < 0) {
+ fprintf(stderr, "Connect error for write: %s\n", error.c_str());
+ adb_close(localFd);
+ return 1;
+ }
+
+ char buf[BUFSIZ];
+ copy_to_file(localFd, remoteFd);
+ read_status_line(remoteFd, buf, sizeof(buf));
+
+ adb_close(localFd);
+ adb_close(remoteFd);
+
+ if (strncmp("Success", buf, 7)) {
+ fprintf(stderr, "Failed to write %s\n", file);
+ fputs(buf, stderr);
+ return 1;
+ }
+ fputs(buf, stderr);
+ return 0;
}
static int install_multiple_app(TransportType transport, const char* serial, int argc,
@@ -1836,7 +1863,7 @@
if (dot && !strcasecmp(dot, ".apk")) {
if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) {
fprintf(stderr, "Invalid APK file: %s\n", file);
- return -1;
+ return EXIT_FAILURE;
}
total_size += sb.st_size;
@@ -1861,7 +1888,7 @@
int fd = adb_connect(cmd, &error);
if (fd < 0) {
fprintf(stderr, "Connect error for create: %s\n", error.c_str());
- return -1;
+ return EXIT_FAILURE;
}
char buf[BUFSIZ];
read_status_line(fd, buf, sizeof(buf));
@@ -1879,7 +1906,7 @@
if (session_id < 0) {
fprintf(stderr, "Failed to create session\n");
fputs(buf, stderr);
- return -1;
+ return EXIT_FAILURE;
}
// Valid session, now stream the APKs
@@ -1934,7 +1961,7 @@
fd = adb_connect(service, &error);
if (fd < 0) {
fprintf(stderr, "Connect error for finalize: %s\n", error.c_str());
- return -1;
+ return EXIT_FAILURE;
}
read_status_line(fd, buf, sizeof(buf));
adb_close(fd);
@@ -1945,6 +1972,88 @@
} else {
fprintf(stderr, "Failed to finalize session\n");
fputs(buf, stderr);
- return -1;
+ return EXIT_FAILURE;
}
}
+
+static int pm_command(TransportType transport, const char* serial, int argc, const char** argv) {
+ std::string cmd = "pm";
+
+ while (argc-- > 0) {
+ cmd += " " + escape_arg(*argv++);
+ }
+
+ return send_shell_command(transport, serial, cmd, false);
+}
+
+static int uninstall_app_legacy(TransportType transport, const char* serial, int argc, const char** argv) {
+ /* if the user choose the -k option, we refuse to do it until devices are
+ out with the option to uninstall the remaining data somehow (adb/ui) */
+ int i;
+ for (i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "-k")) {
+ printf(
+ "The -k option uninstalls the application while retaining the data/cache.\n"
+ "At the moment, there is no way to remove the remaining data.\n"
+ "You will have to reinstall the application with the same signature, and fully uninstall it.\n"
+ "If you truly wish to continue, execute 'adb shell pm uninstall -k'\n.");
+ return EXIT_FAILURE;
+ }
+ }
+
+ /* 'adb uninstall' takes the same arguments as 'pm uninstall' on device */
+ return pm_command(transport, serial, argc, argv);
+}
+
+static int delete_file(TransportType transport, const char* serial, const std::string& filename) {
+ std::string cmd = "rm -f " + escape_arg(filename);
+ return send_shell_command(transport, serial, cmd, false);
+}
+
+static int install_app_legacy(TransportType transport, const char* serial, int argc, const char** argv) {
+ static const char *const DATA_DEST = "/data/local/tmp/%s";
+ static const char *const SD_DEST = "/sdcard/tmp/%s";
+ const char* where = DATA_DEST;
+ int i;
+ struct stat sb;
+
+ for (i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "-s")) {
+ where = SD_DEST;
+ }
+ }
+
+ // Find last APK argument.
+ // All other arguments passed through verbatim.
+ int last_apk = -1;
+ for (i = argc - 1; i >= 0; i--) {
+ const char* file = argv[i];
+ const char* dot = strrchr(file, '.');
+ if (dot && !strcasecmp(dot, ".apk")) {
+ if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) {
+ fprintf(stderr, "Invalid APK file: %s\n", file);
+ return EXIT_FAILURE;
+ }
+
+ last_apk = i;
+ break;
+ }
+ }
+
+ if (last_apk == -1) {
+ fprintf(stderr, "Missing APK file\n");
+ return EXIT_FAILURE;
+ }
+
+ int result = -1;
+ std::vector<const char*> apk_file = {argv[last_apk]};
+ std::string apk_dest = android::base::StringPrintf(
+ where, adb_basename(argv[last_apk]).c_str());
+ if (!do_sync_push(apk_file, apk_dest.c_str())) goto cleanup_apk;
+ argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */
+ result = pm_command(transport, serial, argc, argv);
+
+cleanup_apk:
+ delete_file(transport, serial, apk_dest);
+ return result;
+}
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index 8c3ca63..b8d758f 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -142,9 +142,11 @@
// AID_SDCARD_R to allow reading from the SD card
// AID_SDCARD_RW to allow writing to the SD card
// AID_NET_BW_STATS to read out qtaguid statistics
+ // AID_READPROC for reading /proc entries across UID boundaries
gid_t groups[] = {AID_ADB, AID_LOG, AID_INPUT,
AID_INET, AID_NET_BT, AID_NET_BT_ADMIN,
- AID_SDCARD_R, AID_SDCARD_RW, AID_NET_BW_STATS};
+ AID_SDCARD_R, AID_SDCARD_RW, AID_NET_BW_STATS,
+ AID_READPROC };
if (setgroups(sizeof(groups) / sizeof(groups[0]), groups) != 0) {
PLOG(FATAL) << "Could not set supplental groups";
}
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index d2bc3cd..3322763 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -209,6 +209,17 @@
line_printer_.Print(s, LinePrinter::FULL);
}
+ void Warning(const char* fmt, ...) __attribute__((__format__(ADB_FORMAT_ARCHETYPE, 2, 3))) {
+ std::string s = "adb: warning: ";
+
+ va_list ap;
+ va_start(ap, fmt);
+ android::base::StringAppendV(&s, fmt, ap);
+ va_end(ap);
+
+ line_printer_.Print(s, LinePrinter::FULL);
+ }
+
uint64_t total_bytes;
// TODO: add a char[max] buffer here, to replace syncsendbuf...
@@ -475,12 +486,28 @@
bool skip;
};
-static copyinfo mkcopyinfo(const char* spath, const char* dpath, const char* name, bool isdir) {
+static copyinfo mkcopyinfo(const std::string& spath, const std::string& dpath,
+ const std::string& name, unsigned int mode) {
copyinfo result;
- result.src = android::base::StringPrintf(isdir ? "%s%s/" : "%s%s", spath, name);
- result.dst = android::base::StringPrintf(isdir ? "%s%s/" : "%s%s", dpath, name);
+ result.src = spath;
+ result.dst = dpath;
+ if (result.src.back() != '/') {
+ result.src.push_back('/');
+ }
+ if (result.dst.back() != '/') {
+ result.dst.push_back('/');
+ }
+ result.src.append(name);
+ result.dst.append(name);
+
+ bool isdir = S_ISDIR(mode);
+ if (isdir) {
+ result.src.push_back('/');
+ result.dst.push_back('/');
+ }
+
result.time = 0;
- result.mode = 0;
+ result.mode = mode;
result.size = 0;
result.skip = false;
return result;
@@ -490,89 +517,100 @@
return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
}
-static int local_build_list(SyncConnection& sc, std::vector<copyinfo>* filelist,
- const char* lpath, const char* rpath) {
+static bool local_build_list(SyncConnection& sc, std::vector<copyinfo>* filelist,
+ const std::string& lpath,
+ const std::string& rpath) {
std::vector<copyinfo> dirlist;
- std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(lpath), closedir);
+ std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(lpath.c_str()), closedir);
if (!dir) {
- sc.Error("cannot open '%s': %s", lpath, strerror(errno));
- return -1;
+ sc.Error("cannot open '%s': %s", lpath.c_str(), strerror(errno));
+ return false;
}
+ bool empty_dir = true;
dirent* de;
while ((de = readdir(dir.get()))) {
- if (IsDotOrDotDot(de->d_name)) continue;
-
- char stat_path[PATH_MAX];
- if (strlen(lpath) + strlen(de->d_name) + 1 > sizeof(stat_path)) {
- sc.Error("skipping long path '%s%s'", lpath, de->d_name);
+ if (IsDotOrDotDot(de->d_name)) {
continue;
}
- strcpy(stat_path, lpath);
- strcat(stat_path, de->d_name);
+
+ empty_dir = false;
+ std::string stat_path = lpath + de->d_name;
struct stat st;
- if (!lstat(stat_path, &st)) {
+ if (!lstat(stat_path.c_str(), &st)) {
+ copyinfo ci = mkcopyinfo(lpath, rpath, de->d_name, st.st_mode);
if (S_ISDIR(st.st_mode)) {
- dirlist.push_back(mkcopyinfo(lpath, rpath, de->d_name, 1));
+ dirlist.push_back(ci);
} else {
if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
- sc.Error("skipping special file '%s'", lpath);
+ sc.Warning("skipping special file '%s'", lpath.c_str());
} else {
- copyinfo ci = mkcopyinfo(lpath, rpath, de->d_name, 0);
ci.time = st.st_mtime;
- ci.mode = st.st_mode;
ci.size = st.st_size;
filelist->push_back(ci);
}
}
} else {
- sc.Error("cannot lstat '%s': %s", stat_path, strerror(errno));
+ sc.Error("cannot lstat '%s': %s", stat_path.c_str(),
+ strerror(errno));
}
}
// Close this directory and recurse.
dir.reset();
+
+ // Add the current directory to the list if it was empty, to ensure that
+ // it gets created.
+ if (empty_dir) {
+ // TODO(b/25566053): Make pushing empty directories work.
+ // TODO(b/25457350): We don't preserve permissions on directories.
+ sc.Warning("skipping empty directory '%s'", lpath.c_str());
+ copyinfo ci = mkcopyinfo(adb_dirname(lpath), adb_dirname(rpath),
+ adb_basename(lpath), S_IFDIR);
+ ci.skip = true;
+ filelist->push_back(ci);
+ return true;
+ }
+
for (const copyinfo& ci : dirlist) {
local_build_list(sc, filelist, ci.src.c_str(), ci.dst.c_str());
}
- return 0;
+ return true;
}
-static bool copy_local_dir_remote(SyncConnection& sc, const char* lpath, const char* rpath,
- bool check_timestamps, bool list_only) {
+static bool copy_local_dir_remote(SyncConnection& sc, std::string lpath,
+ std::string rpath, bool check_timestamps,
+ bool list_only) {
+ // Make sure that both directory paths end in a slash.
+ // Both paths are known to exist, so they cannot be empty.
+ if (lpath.back() != '/') {
+ lpath.push_back('/');
+ }
+ if (rpath.back() != '/') {
+ rpath.push_back('/');
+ }
+
+ // Recursively build the list of files to copy.
std::vector<copyinfo> filelist;
int pushed = 0;
int skipped = 0;
-
- if ((lpath[0] == 0) || (rpath[0] == 0)) return false;
- if (lpath[strlen(lpath) - 1] != '/') {
- int tmplen = strlen(lpath)+2;
- char *tmp = reinterpret_cast<char*>(malloc(tmplen));
- if(tmp == 0) return false;
- snprintf(tmp, tmplen, "%s/",lpath);
- lpath = tmp;
- }
- if (rpath[strlen(rpath) - 1] != '/') {
- int tmplen = strlen(rpath)+2;
- char *tmp = reinterpret_cast<char*>(malloc(tmplen));
- if(tmp == 0) return false;
- snprintf(tmp, tmplen, "%s/",rpath);
- rpath = tmp;
- }
-
- if (local_build_list(sc, &filelist, lpath, rpath)) {
+ if (!local_build_list(sc, &filelist, lpath, rpath)) {
return false;
}
if (check_timestamps) {
for (const copyinfo& ci : filelist) {
- if (!sc.SendRequest(ID_STAT, ci.dst.c_str())) return false;
+ if (!sc.SendRequest(ID_STAT, ci.dst.c_str())) {
+ return false;
+ }
}
for (copyinfo& ci : filelist) {
unsigned int timestamp, mode, size;
- if (!sync_finish_stat(sc, ×tamp, &mode, &size)) return false;
+ if (!sync_finish_stat(sc, ×tamp, &mode, &size)) {
+ return false;
+ }
if (size == ci.size) {
/* for links, we cannot update the atime/mtime */
if ((S_ISREG(ci.mode & mode) && timestamp == ci.time) ||
@@ -586,11 +624,12 @@
for (const copyinfo& ci : filelist) {
if (!ci.skip) {
if (list_only) {
- fprintf(stderr, "would push: %s -> %s\n", ci.src.c_str(),
- ci.dst.c_str());
+ sc.Error("would push: %s -> %s", ci.src.c_str(),
+ ci.dst.c_str());
} else {
- if (!sync_send(sc, ci.src.c_str(), ci.dst.c_str(), ci.time, ci.mode)) {
- return false;
+ if (!sync_send(sc, ci.src.c_str(), ci.dst.c_str(), ci.time,
+ ci.mode)) {
+ return false;
}
}
pushed++;
@@ -599,9 +638,9 @@
}
}
- sc.Printf("%s: %d file%s pushed. %d file%s skipped.%s\n", rpath, pushed,
- (pushed == 1) ? "" : "s", skipped, (skipped == 1) ? "" : "s",
- sc.TransferRate().c_str());
+ sc.Printf("%s: %d file%s pushed. %d file%s skipped.%s\n", rpath.c_str(),
+ pushed, (pushed == 1) ? "" : "s", skipped,
+ (skipped == 1) ? "" : "s", sc.TransferRate().c_str());
return true;
}
@@ -658,33 +697,49 @@
static bool remote_build_list(SyncConnection& sc,
std::vector<copyinfo>* filelist,
- const char* rpath, const char* lpath) {
+ const std::string& rpath,
+ const std::string& lpath) {
std::vector<copyinfo> dirlist;
+ bool empty_dir = true;
// Put the files/dirs in rpath on the lists.
auto callback = [&](unsigned mode, unsigned size, unsigned time,
const char* name) {
- if (S_ISDIR(mode)) {
- // Don't try recursing down "." or "..".
- if (IsDotOrDotDot(name)) return;
+ if (IsDotOrDotDot(name)) {
+ return;
+ }
- dirlist.push_back(mkcopyinfo(rpath, lpath, name, 1));
+ // We found a child that isn't '.' or '..'.
+ empty_dir = false;
+
+ copyinfo ci = mkcopyinfo(rpath, lpath, name, mode);
+ if (S_ISDIR(mode)) {
+ dirlist.push_back(ci);
} else if (S_ISREG(mode) || S_ISLNK(mode)) {
- copyinfo ci = mkcopyinfo(rpath, lpath, name, 0);
ci.time = time;
- ci.mode = mode;
ci.size = size;
filelist->push_back(ci);
} else {
- sc.Print(android::base::StringPrintf("skipping special file '%s'\n",
- name));
+ sc.Warning("skipping special file '%s'\n", name);
}
};
- if (!sync_ls(sc, rpath, callback)) {
+ if (!sync_ls(sc, rpath.c_str(), callback)) {
return false;
}
+ // Add the current directory to the list if it was empty, to ensure that
+ // it gets created.
+ if (empty_dir) {
+ auto rdname = adb_dirname(rpath);
+ auto ldname = adb_dirname(lpath);
+ auto rbasename = adb_basename(rpath);
+ auto lbasename = adb_basename(lpath);
+ filelist->push_back(mkcopyinfo(adb_dirname(rpath), adb_dirname(lpath),
+ adb_basename(rpath), S_IFDIR));
+ return true;
+ }
+
// Recurse into each directory we found.
while (!dirlist.empty()) {
copyinfo current = dirlist.back();
@@ -708,23 +763,24 @@
umask(mask);
int r2 = chmod(lpath, mode & ~mask);
- return r1 ? : r2;
+ return r1 ? r1 : r2;
}
-static bool copy_remote_dir_local(SyncConnection& sc, const char* rpath, const char* lpath,
- bool copy_attrs) {
+static bool copy_remote_dir_local(SyncConnection& sc, std::string rpath,
+ std::string lpath, bool copy_attrs) {
// Make sure that both directory paths end in a slash.
- std::string rpath_clean(rpath);
- std::string lpath_clean(lpath);
- if (rpath_clean.empty() || lpath_clean.empty()) return false;
- if (rpath_clean.back() != '/') rpath_clean.push_back('/');
- if (lpath_clean.back() != '/') lpath_clean.push_back('/');
+ // Both paths are known to exist, so they cannot be empty.
+ if (rpath.back() != '/') {
+ rpath.push_back('/');
+ }
+ if (lpath.back() != '/') {
+ lpath.push_back('/');
+ }
// Recursively build the list of files to copy.
sc.Print("pull: building file list...");
std::vector<copyinfo> filelist;
- if (!remote_build_list(sc, &filelist, rpath_clean.c_str(),
- lpath_clean.c_str())) {
+ if (!remote_build_list(sc, &filelist, rpath.c_str(), lpath.c_str())) {
return false;
}
@@ -733,6 +789,19 @@
for (const copyinfo &ci : filelist) {
if (!ci.skip) {
sc.Printf("pull: %s -> %s", ci.src.c_str(), ci.dst.c_str());
+
+ if (S_ISDIR(ci.mode)) {
+ // Entry is for an empty directory, create it and continue.
+ // TODO(b/25457350): We don't preserve permissions on directories.
+ if (!mkdirs(ci.dst)) {
+ sc.Error("failed to create directory '%s': %s",
+ ci.dst.c_str(), strerror(errno));
+ return false;
+ }
+ pulled++;
+ continue;
+ }
+
if (!sync_recv(sc, ci.src.c_str(), ci.dst.c_str())) {
return false;
}
@@ -747,9 +816,9 @@
}
}
- sc.Printf("%s: %d file%s pulled. %d file%s skipped.%s\n", rpath, pulled,
- (pulled == 1) ? "" : "s", skipped, (skipped == 1) ? "" : "s",
- sc.TransferRate().c_str());
+ sc.Printf("%s: %d file%s pulled. %d file%s skipped.%s\n", rpath.c_str(),
+ pulled, (pulled == 1) ? "" : "s", skipped,
+ (skipped == 1) ? "" : "s", sc.TransferRate().c_str());
return true;
}
@@ -793,7 +862,8 @@
continue;
}
- if (S_ISREG(mode) || S_ISLNK(mode) || S_ISCHR(mode) || S_ISBLK(mode)) {
+ if (S_ISREG(mode) || S_ISLNK(mode)) {
+ // TODO(b/25601283): symlinks shouldn't be handled as files.
std::string path_holder;
struct stat st;
if (stat(dst_path, &st) == 0) {
@@ -833,5 +903,5 @@
SyncConnection sc;
if (!sc.IsValid()) return false;
- return copy_local_dir_remote(sc, lpath.c_str(), rpath.c_str(), true, list_only);
+ return copy_local_dir_remote(sc, lpath, rpath, true, list_only);
}
diff --git a/adb/mutex_list.h b/adb/mutex_list.h
index 79c48d8..b59c9f2 100644
--- a/adb/mutex_list.h
+++ b/adb/mutex_list.h
@@ -6,6 +6,7 @@
#ifndef ADB_MUTEX
#error ADB_MUTEX not defined when including this file
#endif
+ADB_MUTEX(basename_lock)
ADB_MUTEX(dirname_lock)
ADB_MUTEX(socket_list_lock)
ADB_MUTEX(transport_lock)
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index f8c2f64..eb0ce85 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -25,6 +25,8 @@
#include <string.h>
#include <unistd.h>
+#include <algorithm>
+
#if !ADB_HOST
#include "cutils/properties.h"
#endif
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 1735627..9f4012a 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -309,7 +309,12 @@
#define closedir adb_closedir
#define rewinddir rewinddir_utf8_not_yet_implemented
#define telldir telldir_utf8_not_yet_implemented
-#define seekdir seekdir_utf8_not_yet_implemented
+// Some compiler's C++ headers have members named seekdir, so we can't do the
+// macro technique and instead cause a link error if seekdir is called.
+inline void seekdir(DIR*, long) {
+ extern int seekdir_utf8_not_yet_implemented;
+ seekdir_utf8_not_yet_implemented = 1;
+}
#define utime adb_utime
#define chmod adb_chmod
diff --git a/adb/transport.cpp b/adb/transport.cpp
index e9e774f..4066889 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -26,6 +26,7 @@
#include <string.h>
#include <unistd.h>
+#include <algorithm>
#include <list>
#include <base/logging.h>
@@ -42,6 +43,9 @@
ADB_MUTEX_DEFINE( transport_lock );
+const char* const kFeatureShell2 = "shell_v2";
+const char* const kFeatureCmd = "cmd";
+
static std::string dump_packet(const char* name, const char* func, apacket* p) {
unsigned command = p->msg.command;
int len = p->msg.data_length;
@@ -780,7 +784,10 @@
const FeatureSet& supported_features() {
// Local static allocation to avoid global non-POD variables.
static const FeatureSet* features = new FeatureSet{
- kFeatureShell2
+ kFeatureShell2,
+ // Internal master has 'cmd'. AOSP master doesn't.
+ // kFeatureCmd
+
// 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).
diff --git a/adb/transport.h b/adb/transport.h
index f41a8d4..d9845b6 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -38,7 +38,9 @@
// Do not use any of [:;=,] in feature strings, they have special meaning
// in the connection banner.
-constexpr char kFeatureShell2[] = "shell_v2";
+extern const char* const kFeatureShell2;
+// The 'cmd' command is available
+extern const char* const kFeatureCmd;
class atransport {
public:
diff --git a/base/logging.cpp b/base/logging.cpp
index 6bfaaec..248cd06 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -212,8 +212,8 @@
gInitialized = true;
// Stash the command line for later use. We can use /proc/self/cmdline on
- // Linux to recover this, but we don't have that luxury on the Mac, and there
- // are a couple of argv[0] variants that are commonly used.
+ // Linux to recover this, but we don't have that luxury on the Mac/Windows,
+ // and there are a couple of argv[0] variants that are commonly used.
if (argv != nullptr) {
gProgramInvocationName.reset(new std::string(basename(argv[0])));
}
@@ -264,11 +264,20 @@
gLogger = std::move(logger);
}
-// We can't use basename(3) because this code runs on the Mac, which doesn't
-// have a non-modifying basename.
static const char* GetFileBasename(const char* file) {
+ // We can't use basename(3) even on Unix because the Mac doesn't
+ // have a non-modifying basename.
const char* last_slash = strrchr(file, '/');
- return (last_slash == nullptr) ? file : last_slash + 1;
+ if (last_slash != nullptr) {
+ return last_slash + 1;
+ }
+#if defined(_WIN32)
+ const char* last_backslash = strrchr(file, '\\');
+ if (last_backslash != nullptr) {
+ return last_backslash + 1;
+ }
+#endif
+ return file;
}
// This indirection greatly reduces the stack impact of having lots of
diff --git a/debuggerd/debuggerd.rc b/debuggerd/debuggerd.rc
index 4be2e5d..e43fe96 100644
--- a/debuggerd/debuggerd.rc
+++ b/debuggerd/debuggerd.rc
@@ -1,3 +1,4 @@
service debuggerd /system/bin/debuggerd
class main
+ group root readproc
writepid /dev/cpuset/system-background/tasks
diff --git a/debuggerd/debuggerd64.rc b/debuggerd/debuggerd64.rc
index c6e7bf2..35b5af3 100644
--- a/debuggerd/debuggerd64.rc
+++ b/debuggerd/debuggerd64.rc
@@ -1,3 +1,4 @@
service debuggerd64 /system/bin/debuggerd64
class main
+ group root readproc
writepid /dev/cpuset/system-background/tasks
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index c7eb34b..e2133e9 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -101,6 +101,7 @@
#define AID_NET_BW_STATS 3006 /* read bandwidth statistics */
#define AID_NET_BW_ACCT 3007 /* change bandwidth statistics accounting */
#define AID_NET_BT_STACK 3008 /* bluetooth: access config files */
+#define AID_READPROC 3009 /* Allow /proc read access */
/* The range 5000-5999 is also reserved for OEM, and must never be used here. */
#define AID_OEM_RESERVED_2_START 5000
@@ -191,6 +192,7 @@
{ "net_bw_stats", AID_NET_BW_STATS, },
{ "net_bw_acct", AID_NET_BW_ACCT, },
{ "net_bt_stack", AID_NET_BT_STACK, },
+ { "readproc", AID_READPROC, },
{ "everybody", AID_EVERYBODY, },
{ "misc", AID_MISC, },
diff --git a/init/init.cpp b/init/init.cpp
index a898b03..86aed9a 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -386,7 +386,7 @@
struct dirent *dp;
while ((dp = readdir(dir.get())) != NULL) {
- if (dp->d_type != DT_REG || !strcmp(dp->d_name, "compatible")) {
+ if (dp->d_type != DT_REG || !strcmp(dp->d_name, "compatible") || !strcmp(dp->d_name, "name")) {
continue;
}
@@ -546,7 +546,8 @@
mkdir("/dev/pts", 0755);
mkdir("/dev/socket", 0755);
mount("devpts", "/dev/pts", "devpts", 0, NULL);
- mount("proc", "/proc", "proc", 0, NULL);
+ #define MAKE_STR(x) __STRING(x)
+ mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC));
mount("sysfs", "/sys", "sysfs", 0, NULL);
}
diff --git a/packagelistparser/Android.mk b/libpackagelistparser/Android.mk
similarity index 100%
rename from packagelistparser/Android.mk
rename to libpackagelistparser/Android.mk
diff --git a/packagelistparser/include/packagelistparser/packagelistparser.h b/libpackagelistparser/include/packagelistparser/packagelistparser.h
similarity index 100%
rename from packagelistparser/include/packagelistparser/packagelistparser.h
rename to libpackagelistparser/include/packagelistparser/packagelistparser.h
diff --git a/packagelistparser/packagelistparser.c b/libpackagelistparser/packagelistparser.c
similarity index 100%
rename from packagelistparser/packagelistparser.c
rename to libpackagelistparser/packagelistparser.c
diff --git a/libpixelflinger/codeflinger/MIPS64Assembler.h b/libpixelflinger/codeflinger/MIPS64Assembler.h
index 3da291a..b43e5da 100644
--- a/libpixelflinger/codeflinger/MIPS64Assembler.h
+++ b/libpixelflinger/codeflinger/MIPS64Assembler.h
@@ -303,32 +303,7 @@
protected:
- // void string_detab(char *s);
- // void string_pad(char *s, int padded_len);
-
ArmToMips64Assembler *mParent;
- sp<Assembly> mAssembly;
- uint32_t* mBase;
- uint32_t* mPC;
- uint32_t* mPrologPC;
- int64_t mDuration;
-#if defined(WITH_LIB_HARDWARE)
- bool mQemuTracing;
-#endif
-
- struct branch_target_t {
- inline branch_target_t() : label(0), pc(0) { }
- inline branch_target_t(const char* l, uint32_t* p)
- : label(l), pc(p) { }
- const char* label;
- uint32_t* pc;
- };
-
- Vector<branch_target_t> mBranchTargets;
- KeyedVector< const char*, uint32_t* > mLabels;
- KeyedVector< uint32_t*, const char* > mLabelsInverseMapping;
- KeyedVector< uint32_t*, const char* > mComments;
-
// opcode field of all instructions
enum opcode_field {
diff --git a/libsync/tests/sync_test.cpp b/libsync/tests/sync_test.cpp
index 55cd687..2c409dc 100644
--- a/libsync/tests/sync_test.cpp
+++ b/libsync/tests/sync_test.cpp
@@ -50,7 +50,7 @@
bool isValid() const {
if (m_fdInitialized) {
int status = fcntl(m_fd, F_GETFD, 0);
- if (status == 0)
+ if (status >= 0)
return true;
else
return false;
@@ -92,7 +92,7 @@
bool isValid() const {
if (m_fdInitialized) {
int status = fcntl(m_fd, F_GETFD, 0);
- if (status == 0)
+ if (status >= 0)
return true;
else
return false;
diff --git a/lmkd/lmkd.rc b/lmkd/lmkd.rc
index 7d6cb11..3bb84ab 100644
--- a/lmkd/lmkd.rc
+++ b/lmkd/lmkd.rc
@@ -1,5 +1,6 @@
service lmkd /system/bin/lmkd
class core
+ group root readproc
critical
socket lmkd seqpacket 0660 system system
writepid /dev/cpuset/system-background/tasks
diff --git a/logd/logd.rc b/logd/logd.rc
index ecd2f0a..10f3553 100644
--- a/logd/logd.rc
+++ b/logd/logd.rc
@@ -3,7 +3,7 @@
socket logd stream 0666 logd logd
socket logdr seqpacket 0666 logd logd
socket logdw dgram 0222 logd logd
- group root system
+ group root system readproc
writepid /dev/cpuset/system-background/tasks
service logd-reinit /system/bin/logd --reinit
diff --git a/logd/main.cpp b/logd/main.cpp
index ad577d2..8e75b37 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -106,7 +106,9 @@
return -1;
}
- if (setgroups(0, NULL) == -1) {
+ gid_t groups[] = { AID_READPROC };
+
+ if (setgroups(sizeof(groups) / sizeof(groups[0]), groups) == -1) {
return -1;
}
diff --git a/metricsd/include/metrics/metrics_library.h b/metricsd/include/metrics/metrics_library.h
index b766194..d2e98c8 100644
--- a/metricsd/include/metrics/metrics_library.h
+++ b/metricsd/include/metrics/metrics_library.h
@@ -34,6 +34,7 @@
virtual bool SendToUMA(const std::string& name, int sample,
int min, int max, int nbuckets) = 0;
virtual bool SendEnumToUMA(const std::string& name, int sample, int max) = 0;
+ virtual bool SendBoolToUMA(const std::string& name, bool sample) = 0;
virtual bool SendSparseToUMA(const std::string& name, int sample) = 0;
virtual bool SendUserActionToUMA(const std::string& action) = 0;
virtual ~MetricsLibraryInterface() {}
@@ -96,6 +97,9 @@
// normal, while 100 is high).
bool SendEnumToUMA(const std::string& name, int sample, int max) override;
+ // Specialization of SendEnumToUMA for boolean values.
+ bool SendBoolToUMA(const std::string& name, bool sample) override;
+
// Sends sparse histogram sample to Chrome for transport to UMA. Returns
// true on success.
//
diff --git a/metricsd/include/metrics/metrics_library_mock.h b/metricsd/include/metrics/metrics_library_mock.h
index 3de87a9..db56f9e 100644
--- a/metricsd/include/metrics/metrics_library_mock.h
+++ b/metricsd/include/metrics/metrics_library_mock.h
@@ -32,6 +32,7 @@
int min, int max, int nbuckets));
MOCK_METHOD3(SendEnumToUMA, bool(const std::string& name, int sample,
int max));
+ MOCK_METHOD2(SendBoolToUMA, bool(const std::string& name, bool sample));
MOCK_METHOD2(SendSparseToUMA, bool(const std::string& name, int sample));
MOCK_METHOD1(SendUserActionToUMA, bool(const std::string& action));
diff --git a/metricsd/metrics_library.cc b/metricsd/metrics_library.cc
index a651b76..735d39f 100644
--- a/metricsd/metrics_library.cc
+++ b/metricsd/metrics_library.cc
@@ -173,6 +173,13 @@
uma_events_file_.value());
}
+bool MetricsLibrary::SendBoolToUMA(const std::string& name, bool sample) {
+ return metrics::SerializationUtils::WriteMetricToFile(
+ *metrics::MetricSample::LinearHistogramSample(name,
+ sample ? 1 : 0, 2).get(),
+ uma_events_file_.value());
+}
+
bool MetricsLibrary::SendSparseToUMA(const std::string& name, int sample) {
return metrics::SerializationUtils::WriteMetricToFile(
*metrics::MetricSample::SparseHistogramSample(name, sample).get(),
diff --git a/rootdir/init.rc b/rootdir/init.rc
index b80c454..17e87da 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -556,7 +556,7 @@
console
disabled
user shell
- group shell log
+ group shell log readproc
seclabel u:r:shell:s0
on property:ro.debuggable=1