Merge changes I12d46493,I0ed00441,I55e5dc5a,If61296ff into oc-mr1-dev

* changes:
  adb: add lock to remove_socket.
  Revert "adb: fix deadlock between transport_unref and usb_close."
  adb: allow selection of a specific transport.
  adb: fix deadlock in kick_all_transports.
This commit is contained in:
Josh Gao 2017-09-28 17:51:44 +00:00 committed by Android (Google) Code Review
commit c03127ef5c
14 changed files with 318 additions and 233 deletions

View file

@ -956,8 +956,8 @@ int launch_server(const std::string& socket_spec) {
// Try to handle a network forwarding request. // Try to handle a network forwarding request.
// This returns 1 on success, 0 on failure, and -1 to indicate this is not // This returns 1 on success, 0 on failure, and -1 to indicate this is not
// a forwarding-related request. // a forwarding-related request.
int handle_forward_request(const char* service, TransportType type, const char* serial, int reply_fd) int handle_forward_request(const char* service, TransportType type, const char* serial,
{ TransportId transport_id, int reply_fd) {
if (!strcmp(service, "list-forward")) { if (!strcmp(service, "list-forward")) {
// Create the list of forward redirections. // Create the list of forward redirections.
std::string listeners = format_listeners(); std::string listeners = format_listeners();
@ -1010,7 +1010,8 @@ int handle_forward_request(const char* service, TransportType type, const char*
} }
std::string error_msg; std::string error_msg;
atransport* transport = acquire_one_transport(type, serial, nullptr, &error_msg); atransport* transport =
acquire_one_transport(type, serial, transport_id, nullptr, &error_msg);
if (!transport) { if (!transport) {
SendFail(reply_fd, error_msg); SendFail(reply_fd, error_msg);
return 1; return 1;
@ -1068,8 +1069,8 @@ static int SendOkay(int fd, const std::string& s) {
return 0; return 0;
} }
int handle_host_request(const char* service, TransportType type, int handle_host_request(const char* service, TransportType type, const char* serial,
const char* serial, int reply_fd, asocket* s) { TransportId transport_id, int reply_fd, asocket* s) {
if (strcmp(service, "kill") == 0) { if (strcmp(service, "kill") == 0) {
fprintf(stderr, "adb server killed by remote request\n"); fprintf(stderr, "adb server killed by remote request\n");
fflush(stdout); fflush(stdout);
@ -1089,7 +1090,14 @@ int handle_host_request(const char* service, TransportType type,
if (!strncmp(service, "transport", strlen("transport"))) { if (!strncmp(service, "transport", strlen("transport"))) {
TransportType type = kTransportAny; TransportType type = kTransportAny;
if (!strncmp(service, "transport-usb", strlen("transport-usb"))) { if (!strncmp(service, "transport-id:", strlen("transport-id:"))) {
service += strlen("transport-id:");
transport_id = strtoll(service, const_cast<char**>(&service), 10);
if (*service != '\0') {
SendFail(reply_fd, "invalid transport id");
return 1;
}
} else if (!strncmp(service, "transport-usb", strlen("transport-usb"))) {
type = kTransportUsb; type = kTransportUsb;
} else if (!strncmp(service, "transport-local", strlen("transport-local"))) { } else if (!strncmp(service, "transport-local", strlen("transport-local"))) {
type = kTransportLocal; type = kTransportLocal;
@ -1101,7 +1109,7 @@ int handle_host_request(const char* service, TransportType type,
} }
std::string error; std::string error;
atransport* t = acquire_one_transport(type, serial, nullptr, &error); atransport* t = acquire_one_transport(type, serial, transport_id, nullptr, &error);
if (t != nullptr) { if (t != nullptr) {
s->transport = t; s->transport = t;
SendOkay(reply_fd); SendOkay(reply_fd);
@ -1144,7 +1152,7 @@ int handle_host_request(const char* service, TransportType type,
if (!strcmp(service, "features")) { if (!strcmp(service, "features")) {
std::string error; std::string error;
atransport* t = acquire_one_transport(type, serial, nullptr, &error); atransport* t = acquire_one_transport(type, serial, transport_id, nullptr, &error);
if (t != nullptr) { if (t != nullptr) {
SendOkay(reply_fd, FeatureSetToString(t->features())); SendOkay(reply_fd, FeatureSetToString(t->features()));
} else { } else {
@ -1197,7 +1205,7 @@ int handle_host_request(const char* service, TransportType type,
// These always report "unknown" rather than the actual error, for scripts. // These always report "unknown" rather than the actual error, for scripts.
if (!strcmp(service, "get-serialno")) { if (!strcmp(service, "get-serialno")) {
std::string error; std::string error;
atransport* t = acquire_one_transport(type, serial, nullptr, &error); atransport* t = acquire_one_transport(type, serial, transport_id, nullptr, &error);
if (t) { if (t) {
return SendOkay(reply_fd, t->serial ? t->serial : "unknown"); return SendOkay(reply_fd, t->serial ? t->serial : "unknown");
} else { } else {
@ -1206,7 +1214,7 @@ int handle_host_request(const char* service, TransportType type,
} }
if (!strcmp(service, "get-devpath")) { if (!strcmp(service, "get-devpath")) {
std::string error; std::string error;
atransport* t = acquire_one_transport(type, serial, nullptr, &error); atransport* t = acquire_one_transport(type, serial, transport_id, nullptr, &error);
if (t) { if (t) {
return SendOkay(reply_fd, t->devpath ? t->devpath : "unknown"); return SendOkay(reply_fd, t->devpath ? t->devpath : "unknown");
} else { } else {
@ -1215,7 +1223,7 @@ int handle_host_request(const char* service, TransportType type,
} }
if (!strcmp(service, "get-state")) { if (!strcmp(service, "get-state")) {
std::string error; std::string error;
atransport* t = acquire_one_transport(type, serial, nullptr, &error); atransport* t = acquire_one_transport(type, serial, transport_id, nullptr, &error);
if (t) { if (t) {
return SendOkay(reply_fd, t->connection_state_name()); return SendOkay(reply_fd, t->connection_state_name());
} else { } else {
@ -1233,7 +1241,7 @@ int handle_host_request(const char* service, TransportType type,
if (!strcmp(service, "reconnect")) { if (!strcmp(service, "reconnect")) {
std::string response; std::string response;
atransport* t = acquire_one_transport(type, serial, nullptr, &response, true); atransport* t = acquire_one_transport(type, serial, transport_id, nullptr, &response, true);
if (t != nullptr) { if (t != nullptr) {
kick_transport(t); kick_transport(t);
response = response =
@ -1242,7 +1250,7 @@ int handle_host_request(const char* service, TransportType type,
return SendOkay(reply_fd, response); return SendOkay(reply_fd, response);
} }
int ret = handle_forward_request(service, type, serial, reply_fd); int ret = handle_forward_request(service, type, serial, transport_id, reply_fd);
if (ret >= 0) if (ret >= 0)
return ret - 1; return ret - 1;
return -1; return -1;

View file

@ -56,6 +56,7 @@ std::string adb_version();
// Increment this when we want to force users to start a new adb server. // Increment this when we want to force users to start a new adb server.
#define ADB_SERVER_VERSION 39 #define ADB_SERVER_VERSION 39
using TransportId = uint64_t;
class atransport; class atransport;
struct amessage { struct amessage {
@ -149,7 +150,7 @@ atransport* find_emulator_transport_by_console_port(int console_port);
int service_to_fd(const char* name, const atransport* transport); int service_to_fd(const char* name, const atransport* transport);
#if ADB_HOST #if ADB_HOST
asocket *host_service_to_socket(const char* name, const char *serial); asocket* host_service_to_socket(const char* name, const char* serial, TransportId transport_id);
#endif #endif
#if !ADB_HOST #if !ADB_HOST
@ -159,7 +160,8 @@ asocket* create_jdwp_tracker_service_socket();
int create_jdwp_connection_fd(int jdwp_pid); int create_jdwp_connection_fd(int jdwp_pid);
#endif #endif
int handle_forward_request(const char* service, TransportType type, const char* serial, int reply_fd); int handle_forward_request(const char* service, TransportType type, const char* serial,
TransportId transport_id, int reply_fd);
#if !ADB_HOST #if !ADB_HOST
void framebuffer_service(int fd, void *cookie); void framebuffer_service(int fd, void *cookie);
@ -216,7 +218,8 @@ extern int SHELL_EXIT_NOTIFY_FD;
#define USB_FFS_ADB_IN USB_FFS_ADB_EP(ep2) #define USB_FFS_ADB_IN USB_FFS_ADB_EP(ep2)
#endif #endif
int handle_host_request(const char* service, TransportType type, const char* serial, int reply_fd, asocket *s); int handle_host_request(const char* service, TransportType type, const char* serial,
TransportId transport_id, int reply_fd, asocket* s);
void handle_online(atransport *t); void handle_online(atransport *t);
void handle_offline(atransport *t); void handle_offline(atransport *t);

View file

@ -20,6 +20,7 @@
#include "adb_client.h" #include "adb_client.h"
#include <errno.h> #include <errno.h>
#include <inttypes.h>
#include <limits.h> #include <limits.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
@ -46,12 +47,20 @@
static TransportType __adb_transport = kTransportAny; static TransportType __adb_transport = kTransportAny;
static const char* __adb_serial = NULL; static const char* __adb_serial = NULL;
static TransportId __adb_transport_id = 0;
static const char* __adb_server_socket_spec; static const char* __adb_server_socket_spec;
void adb_set_transport(TransportType type, const char* serial) { void adb_set_transport(TransportType type, const char* serial, TransportId transport_id) {
__adb_transport = type; __adb_transport = type;
__adb_serial = serial; __adb_serial = serial;
__adb_transport_id = transport_id;
}
void adb_get_transport(TransportType* type, const char** serial, TransportId* transport_id) {
if (type) *type = __adb_transport;
if (serial) *serial = __adb_serial;
if (transport_id) *transport_id = __adb_transport_id;
} }
void adb_set_socket_spec(const char* socket_spec) { void adb_set_socket_spec(const char* socket_spec) {
@ -63,7 +72,10 @@ void adb_set_socket_spec(const char* socket_spec) {
static int switch_socket_transport(int fd, std::string* error) { static int switch_socket_transport(int fd, std::string* error) {
std::string service; std::string service;
if (__adb_serial) { if (__adb_transport_id) {
service += "host:transport-id:";
service += std::to_string(__adb_transport_id);
} else if (__adb_serial) {
service += "host:transport:"; service += "host:transport:";
service += __adb_serial; service += __adb_serial;
} else { } else {
@ -292,15 +304,18 @@ bool adb_query(const std::string& service, std::string* result, std::string* err
return true; return true;
} }
std::string format_host_command(const char* command, TransportType type, const char* serial) { std::string format_host_command(const char* command) {
if (serial) { if (__adb_transport_id) {
return android::base::StringPrintf("host-serial:%s:%s", serial, command); return android::base::StringPrintf("host-transport-id:%" PRIu64 ":%s", __adb_transport_id,
command);
} else if (__adb_serial) {
return android::base::StringPrintf("host-serial:%s:%s", __adb_serial, command);
} }
const char* prefix = "host"; const char* prefix = "host";
if (type == kTransportUsb) { if (__adb_transport == kTransportUsb) {
prefix = "host-usb"; prefix = "host-usb";
} else if (type == kTransportLocal) { } else if (__adb_transport == kTransportLocal) {
prefix = "host-local"; prefix = "host-local";
} }
return android::base::StringPrintf("%s:%s", prefix, command); return android::base::StringPrintf("%s:%s", prefix, command);
@ -308,7 +323,7 @@ std::string format_host_command(const char* command, TransportType type, const c
bool adb_get_feature_set(FeatureSet* feature_set, std::string* error) { bool adb_get_feature_set(FeatureSet* feature_set, std::string* error) {
std::string result; std::string result;
if (adb_query(format_host_command("features", __adb_transport, __adb_serial), &result, error)) { if (adb_query(format_host_command("features"), &result, error)) {
*feature_set = StringToFeatureSet(result); *feature_set = StringToFeatureSet(result);
return true; return true;
} }

View file

@ -40,7 +40,9 @@ bool adb_query(const std::string& service, std::string* _Nonnull result,
std::string* _Nonnull error); std::string* _Nonnull error);
// Set the preferred transport to connect to. // Set the preferred transport to connect to.
void adb_set_transport(TransportType type, const char* _Nullable serial); void adb_set_transport(TransportType type, const char* _Nullable serial, TransportId transport_id);
void adb_get_transport(TransportType* _Nullable type, const char* _Nullable* _Nullable serial,
TransportId* _Nullable transport_id);
// Set the socket specification for the adb server. // Set the socket specification for the adb server.
// This function can only be called once, and the argument must live to the end of the process. // This function can only be called once, and the argument must live to the end of the process.
@ -57,8 +59,7 @@ int adb_send_emulator_command(int argc, const char* _Nonnull* _Nonnull argv,
bool adb_status(int fd, std::string* _Nonnull error); bool adb_status(int fd, std::string* _Nonnull error);
// Create a host command corresponding to selected transport type/serial. // Create a host command corresponding to selected transport type/serial.
std::string format_host_command(const char* _Nonnull command, TransportType type, std::string format_host_command(const char* _Nonnull command);
const char* _Nullable serial);
// Get the feature set of the current preferred transport. // Get the feature set of the current preferred transport.
bool adb_get_feature_set(FeatureSet* _Nonnull feature_set, std::string* _Nonnull error); bool adb_get_feature_set(FeatureSet* _Nonnull feature_set, std::string* _Nonnull error);

View file

@ -195,13 +195,13 @@ class BugreportStandardStreamsCallback : public StandardStreamsCallbackInterface
DISALLOW_COPY_AND_ASSIGN(BugreportStandardStreamsCallback); DISALLOW_COPY_AND_ASSIGN(BugreportStandardStreamsCallback);
}; };
int Bugreport::DoIt(TransportType transport_type, const char* serial, int argc, const char** argv) { int Bugreport::DoIt(int argc, const char** argv) {
if (argc > 2) return syntax_error("adb bugreport [PATH]"); if (argc > 2) return syntax_error("adb bugreport [PATH]");
// Gets bugreportz version. // Gets bugreportz version.
std::string bugz_stdout, bugz_stderr; std::string bugz_stdout, bugz_stderr;
DefaultStandardStreamsCallback version_callback(&bugz_stdout, &bugz_stderr); DefaultStandardStreamsCallback version_callback(&bugz_stdout, &bugz_stderr);
int status = SendShellCommand(transport_type, serial, "bugreportz -v", false, &version_callback); int status = SendShellCommand("bugreportz -v", false, &version_callback);
std::string bugz_version = android::base::Trim(bugz_stderr); std::string bugz_version = android::base::Trim(bugz_stderr);
std::string bugz_output = android::base::Trim(bugz_stdout); std::string bugz_output = android::base::Trim(bugz_stdout);
@ -214,7 +214,7 @@ int Bugreport::DoIt(TransportType transport_type, const char* serial, int argc,
fprintf(stderr, fprintf(stderr,
"Failed to get bugreportz version, which is only available on devices " "Failed to get bugreportz version, which is only available on devices "
"running Android 7.0 or later.\nTrying a plain-text bug report instead.\n"); "running Android 7.0 or later.\nTrying a plain-text bug report instead.\n");
return SendShellCommand(transport_type, serial, "bugreport", false); return SendShellCommand("bugreport", false);
} }
// But if user explicitly asked for a zipped bug report, fails instead (otherwise calling // But if user explicitly asked for a zipped bug report, fails instead (otherwise calling
@ -265,7 +265,7 @@ int Bugreport::DoIt(TransportType transport_type, const char* serial, int argc,
bugz_command = "bugreportz"; bugz_command = "bugreportz";
} }
BugreportStandardStreamsCallback bugz_callback(dest_dir, dest_file, show_progress, this); BugreportStandardStreamsCallback bugz_callback(dest_dir, dest_file, show_progress, this);
return SendShellCommand(transport_type, serial, bugz_command, false, &bugz_callback); return SendShellCommand(bugz_command, false, &bugz_callback);
} }
void Bugreport::UpdateProgress(const std::string& message, int progress_percentage) { void Bugreport::UpdateProgress(const std::string& message, int progress_percentage) {
@ -274,10 +274,9 @@ void Bugreport::UpdateProgress(const std::string& message, int progress_percenta
LinePrinter::INFO); LinePrinter::INFO);
} }
int Bugreport::SendShellCommand(TransportType transport_type, const char* serial, int Bugreport::SendShellCommand(const std::string& command, bool disable_shell_protocol,
const std::string& command, bool disable_shell_protocol,
StandardStreamsCallbackInterface* callback) { StandardStreamsCallbackInterface* callback) {
return send_shell_command(transport_type, serial, command, disable_shell_protocol, callback); return send_shell_command(command, disable_shell_protocol, callback);
} }
bool Bugreport::DoSyncPull(const std::vector<const char*>& srcs, const char* dst, bool copy_attrs, bool Bugreport::DoSyncPull(const std::vector<const char*>& srcs, const char* dst, bool copy_attrs,

View file

@ -29,14 +29,13 @@ class Bugreport {
public: public:
Bugreport() : line_printer_() { Bugreport() : line_printer_() {
} }
int DoIt(TransportType transport_type, const char* serial, int argc, const char** argv); int DoIt(int argc, const char** argv);
protected: protected:
// Functions below are abstractions of external functions so they can be // Functions below are abstractions of external functions so they can be
// mocked on tests. // mocked on tests.
virtual int SendShellCommand( virtual int SendShellCommand(
TransportType transport_type, const char* serial, const std::string& command, const std::string& command, bool disable_shell_protocol,
bool disable_shell_protocol,
StandardStreamsCallbackInterface* callback = &DEFAULT_STANDARD_STREAMS_CALLBACK); StandardStreamsCallbackInterface* callback = &DEFAULT_STANDARD_STREAMS_CALLBACK);
virtual bool DoSyncPull(const std::vector<const char*>& srcs, const char* dst, bool copy_attrs, virtual bool DoSyncPull(const std::vector<const char*>& srcs, const char* dst, bool copy_attrs,

View file

@ -51,8 +51,8 @@ bool do_sync_pull(const std::vector<const char*>& srcs, const char* dst, bool co
// Empty functions so tests don't need to be linked against commandline.cpp // Empty functions so tests don't need to be linked against commandline.cpp
DefaultStandardStreamsCallback DEFAULT_STANDARD_STREAMS_CALLBACK(nullptr, nullptr); DefaultStandardStreamsCallback DEFAULT_STANDARD_STREAMS_CALLBACK(nullptr, nullptr);
int send_shell_command(TransportType transport_type, const char* serial, const std::string& command, int send_shell_command(const std::string& command, bool disable_shell_protocol,
bool disable_shell_protocol, StandardStreamsCallbackInterface* callback) { StandardStreamsCallbackInterface* callback) {
ADD_FAILURE() << "send_shell_command() should have been mocked"; ADD_FAILURE() << "send_shell_command() should have been mocked";
return -42; return -42;
} }
@ -62,7 +62,7 @@ enum StreamType {
kStreamStderr, kStreamStderr,
}; };
// gmock black magic to provide a WithArg<4>(WriteOnStdout(output)) matcher // gmock black magic to provide a WithArg<2>(WriteOnStdout(output)) matcher
typedef void OnStandardStreamsCallbackFunction(StandardStreamsCallbackInterface*); typedef void OnStandardStreamsCallbackFunction(StandardStreamsCallbackInterface*);
class OnStandardStreamsCallbackAction : public ActionInterface<OnStandardStreamsCallbackFunction> { class OnStandardStreamsCallbackAction : public ActionInterface<OnStandardStreamsCallbackFunction> {
@ -118,9 +118,8 @@ Action<CallbackDoneFunction> ReturnCallbackDone(int status = -1337) {
class BugreportMock : public Bugreport { class BugreportMock : public Bugreport {
public: public:
MOCK_METHOD5(SendShellCommand, MOCK_METHOD3(SendShellCommand, int(const std::string& command, bool disable_shell_protocol,
int(TransportType transport_type, const char* serial, const std::string& command, StandardStreamsCallbackInterface* callback));
bool disable_shell_protocol, StandardStreamsCallbackInterface* callback));
MOCK_METHOD4(DoSyncPull, bool(const std::vector<const char*>& srcs, const char* dst, MOCK_METHOD4(DoSyncPull, bool(const std::vector<const char*>& srcs, const char* dst,
bool copy_attrs, const char* name)); bool copy_attrs, const char* name));
MOCK_METHOD2(UpdateProgress, void(const std::string&, int)); MOCK_METHOD2(UpdateProgress, void(const std::string&, int));
@ -136,10 +135,9 @@ class BugreportTest : public ::testing::Test {
} }
void ExpectBugreportzVersion(const std::string& version) { void ExpectBugreportzVersion(const std::string& version) {
EXPECT_CALL(br_, EXPECT_CALL(br_, SendShellCommand("bugreportz -v", false, _))
SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -v", false, _)) .WillOnce(DoAll(WithArg<2>(WriteOnStderr(version.c_str())),
.WillOnce(DoAll(WithArg<4>(WriteOnStderr(version.c_str())), WithArg<2>(ReturnCallbackDone(0))));
WithArg<4>(ReturnCallbackDone(0))));
} }
void ExpectProgress(int progress_percentage, const std::string& file = "file.zip") { void ExpectProgress(int progress_percentage, const std::string& file = "file.zip") {
@ -153,26 +151,26 @@ class BugreportTest : public ::testing::Test {
// Tests when called with invalid number of arguments // Tests when called with invalid number of arguments
TEST_F(BugreportTest, InvalidNumberArgs) { TEST_F(BugreportTest, InvalidNumberArgs) {
const char* args[] = {"bugreport", "to", "principal"}; const char* args[] = {"bugreport", "to", "principal"};
ASSERT_EQ(1, br_.DoIt(kTransportLocal, "HannibalLecter", 3, args)); ASSERT_EQ(1, br_.DoIt(3, args));
} }
// Tests the 'adb bugreport' option when the device does not support 'bugreportz' - it falls back // Tests the 'adb bugreport' option when the device does not support 'bugreportz' - it falls back
// to the flat-file format ('bugreport' binary on device) // to the flat-file format ('bugreport' binary on device)
TEST_F(BugreportTest, NoArgumentsPreNDevice) { TEST_F(BugreportTest, NoArgumentsPreNDevice) {
// clang-format off // clang-format off
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -v", false, _)) EXPECT_CALL(br_, SendShellCommand("bugreportz -v", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStderr("")), .WillOnce(DoAll(WithArg<2>(WriteOnStderr("")),
// Write some bogus output on stdout to make sure it's ignored // Write some bogus output on stdout to make sure it's ignored
WithArg<4>(WriteOnStdout("Dude, where is my bugreportz?")), WithArg<2>(WriteOnStdout("Dude, where is my bugreportz?")),
WithArg<4>(ReturnCallbackDone(0)))); WithArg<2>(ReturnCallbackDone(0))));
// clang-format on // clang-format on
std::string bugreport = "Reported the bug was."; std::string bugreport = "Reported the bug was.";
CaptureStdout(); CaptureStdout();
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreport", false, _)) EXPECT_CALL(br_, SendShellCommand("bugreport", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStdout(bugreport)), Return(0))); .WillOnce(DoAll(WithArg<2>(WriteOnStdout(bugreport)), Return(0)));
const char* args[] = {"bugreport"}; const char* args[] = {"bugreport"};
ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 1, args)); ASSERT_EQ(0, br_.DoIt(1, args));
ASSERT_THAT(GetCapturedStdout(), StrEq(bugreport)); ASSERT_THAT(GetCapturedStdout(), StrEq(bugreport));
} }
@ -183,15 +181,15 @@ TEST_F(BugreportTest, NoArgumentsNDevice) {
std::string dest_file = std::string dest_file =
android::base::StringPrintf("%s%cda_bugreport.zip", cwd_.c_str(), OS_PATH_SEPARATOR); android::base::StringPrintf("%s%cda_bugreport.zip", cwd_.c_str(), OS_PATH_SEPARATOR);
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz", false, _)) EXPECT_CALL(br_, SendShellCommand("bugreportz", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device/da_bugreport.zip")), .WillOnce(DoAll(WithArg<2>(WriteOnStdout("OK:/device/da_bugreport.zip")),
WithArg<4>(ReturnCallbackDone()))); WithArg<2>(ReturnCallbackDone())));
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file), EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
true, StrEq("pulling da_bugreport.zip"))) true, StrEq("pulling da_bugreport.zip")))
.WillOnce(Return(true)); .WillOnce(Return(true));
const char* args[] = {"bugreport"}; const char* args[] = {"bugreport"};
ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 1, args)); ASSERT_EQ(0, br_.DoIt(1, args));
} }
// Tests the 'adb bugreport' option when the device supports 'bugreportz' version 1.1 - it will // Tests the 'adb bugreport' option when the device supports 'bugreportz' version 1.1 - it will
@ -201,47 +199,47 @@ TEST_F(BugreportTest, NoArgumentsPostNDevice) {
std::string dest_file = std::string dest_file =
android::base::StringPrintf("%s%cda_bugreport.zip", cwd_.c_str(), OS_PATH_SEPARATOR); android::base::StringPrintf("%s%cda_bugreport.zip", cwd_.c_str(), OS_PATH_SEPARATOR);
ExpectProgress(50, "da_bugreport.zip"); ExpectProgress(50, "da_bugreport.zip");
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _)) EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStdout("BEGIN:/device/da_bugreport.zip\n")), .WillOnce(DoAll(WithArg<2>(WriteOnStdout("BEGIN:/device/da_bugreport.zip\n")),
WithArg<4>(WriteOnStdout("PROGRESS:50/100\n")), WithArg<2>(WriteOnStdout("PROGRESS:50/100\n")),
WithArg<4>(WriteOnStdout("OK:/device/da_bugreport.zip\n")), WithArg<2>(WriteOnStdout("OK:/device/da_bugreport.zip\n")),
WithArg<4>(ReturnCallbackDone()))); WithArg<2>(ReturnCallbackDone())));
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file), EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
true, StrEq("pulling da_bugreport.zip"))) true, StrEq("pulling da_bugreport.zip")))
.WillOnce(Return(true)); .WillOnce(Return(true));
const char* args[] = {"bugreport"}; const char* args[] = {"bugreport"};
ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 1, args)); ASSERT_EQ(0, br_.DoIt(1, args));
} }
// Tests 'adb bugreport file.zip' when it succeeds and device does not support progress. // Tests 'adb bugreport file.zip' when it succeeds and device does not support progress.
TEST_F(BugreportTest, OkNDevice) { TEST_F(BugreportTest, OkNDevice) {
ExpectBugreportzVersion("1.0"); ExpectBugreportzVersion("1.0");
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz", false, _)) EXPECT_CALL(br_, SendShellCommand("bugreportz", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device/bugreport.zip")), .WillOnce(DoAll(WithArg<2>(WriteOnStdout("OK:/device/bugreport.zip")),
WithArg<4>(ReturnCallbackDone()))); WithArg<2>(ReturnCallbackDone())));
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"), EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
true, StrEq("pulling file.zip"))) true, StrEq("pulling file.zip")))
.WillOnce(Return(true)); .WillOnce(Return(true));
const char* args[] = {"bugreport", "file.zip"}; const char* args[] = {"bugreport", "file.zip"};
ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args)); ASSERT_EQ(0, br_.DoIt(2, args));
} }
// Tests 'adb bugreport file.zip' when it succeeds but response was sent in // Tests 'adb bugreport file.zip' when it succeeds but response was sent in
// multiple buffer writers and without progress updates. // multiple buffer writers and without progress updates.
TEST_F(BugreportTest, OkNDeviceSplitBuffer) { TEST_F(BugreportTest, OkNDeviceSplitBuffer) {
ExpectBugreportzVersion("1.0"); ExpectBugreportzVersion("1.0");
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz", false, _)) EXPECT_CALL(br_, SendShellCommand("bugreportz", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device")), .WillOnce(DoAll(WithArg<2>(WriteOnStdout("OK:/device")),
WithArg<4>(WriteOnStdout("/bugreport.zip")), WithArg<2>(WriteOnStdout("/bugreport.zip")),
WithArg<4>(ReturnCallbackDone()))); WithArg<2>(ReturnCallbackDone())));
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"), EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
true, StrEq("pulling file.zip"))) true, StrEq("pulling file.zip")))
.WillOnce(Return(true)); .WillOnce(Return(true));
const char* args[] = {"bugreport", "file.zip"}; const char* args[] = {"bugreport", "file.zip"};
ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args)); ASSERT_EQ(0, br_.DoIt(2, args));
} }
// Tests 'adb bugreport file.zip' when it succeeds and displays progress. // Tests 'adb bugreport file.zip' when it succeeds and displays progress.
@ -252,32 +250,32 @@ TEST_F(BugreportTest, OkProgress) {
ExpectProgress(50); ExpectProgress(50);
ExpectProgress(99); ExpectProgress(99);
// clang-format off // clang-format off
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _)) EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
// NOTE: DoAll accepts at most 10 arguments, and we're almost reached that limit... // NOTE: DoAll accepts at most 10 arguments, and we're almost reached that limit...
.WillOnce(DoAll( .WillOnce(DoAll(
// Name might change on OK, so make sure the right one is picked. // Name might change on OK, so make sure the right one is picked.
WithArg<4>(WriteOnStdout("BEGIN:/device/bugreport___NOT.zip\n")), WithArg<2>(WriteOnStdout("BEGIN:/device/bugreport___NOT.zip\n")),
// Progress line in one write // Progress line in one write
WithArg<4>(WriteOnStdout("PROGRESS:1/100\n")), WithArg<2>(WriteOnStdout("PROGRESS:1/100\n")),
// Add some bogus lines // Add some bogus lines
WithArg<4>(WriteOnStdout("\nDUDE:SWEET\n\nBLA\n\nBLA\nBLA\n\n")), WithArg<2>(WriteOnStdout("\nDUDE:SWEET\n\nBLA\n\nBLA\nBLA\n\n")),
// Multiple progress lines in one write // Multiple progress lines in one write
WithArg<4>(WriteOnStdout("PROGRESS:10/100\nPROGRESS:50/100\n")), WithArg<2>(WriteOnStdout("PROGRESS:10/100\nPROGRESS:50/100\n")),
// Progress line in multiple writes // Progress line in multiple writes
WithArg<4>(WriteOnStdout("PROG")), WithArg<2>(WriteOnStdout("PROG")),
WithArg<4>(WriteOnStdout("RESS:99")), WithArg<2>(WriteOnStdout("RESS:99")),
WithArg<4>(WriteOnStdout("/100\n")), WithArg<2>(WriteOnStdout("/100\n")),
// Split last message as well, just in case // Split last message as well, just in case
WithArg<4>(WriteOnStdout("OK:/device/bugreport")), WithArg<2>(WriteOnStdout("OK:/device/bugreport")),
WithArg<4>(WriteOnStdout(".zip")), WithArg<2>(WriteOnStdout(".zip")),
WithArg<4>(ReturnCallbackDone()))); WithArg<2>(ReturnCallbackDone())));
// clang-format on // clang-format on
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"), EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
true, StrEq("pulling file.zip"))) true, StrEq("pulling file.zip")))
.WillOnce(Return(true)); .WillOnce(Return(true));
const char* args[] = {"bugreport", "file.zip"}; const char* args[] = {"bugreport", "file.zip"};
ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args)); ASSERT_EQ(0, br_.DoIt(2, args));
} }
// Tests 'adb bugreport file.zip' when it succeeds and displays progress, even if progress recedes. // Tests 'adb bugreport file.zip' when it succeeds and displays progress, even if progress recedes.
@ -287,28 +285,28 @@ TEST_F(BugreportTest, OkProgressAlwaysForward) {
ExpectProgress(50); ExpectProgress(50);
ExpectProgress(75); ExpectProgress(75);
// clang-format off // clang-format off
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _)) EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
// NOTE: DoAll accepts at most 10 arguments, and we're almost reached that limit... // NOTE: DoAll accepts at most 10 arguments, and we're almost reached that limit...
.WillOnce(DoAll( .WillOnce(DoAll(
WithArg<4>(WriteOnStdout("BEGIN:/device/bugreport.zip\n")), WithArg<2>(WriteOnStdout("BEGIN:/device/bugreport.zip\n")),
WithArg<4>(WriteOnStdout("PROGRESS:1/100\n")), // 1% WithArg<2>(WriteOnStdout("PROGRESS:1/100\n")), // 1%
WithArg<4>(WriteOnStdout("PROGRESS:50/100\n")), // 50% WithArg<2>(WriteOnStdout("PROGRESS:50/100\n")), // 50%
// 25% should be ignored becaused it receded. // 25% should be ignored becaused it receded.
WithArg<4>(WriteOnStdout("PROGRESS:25/100\n")), // 25% WithArg<2>(WriteOnStdout("PROGRESS:25/100\n")), // 25%
WithArg<4>(WriteOnStdout("PROGRESS:75/100\n")), // 75% WithArg<2>(WriteOnStdout("PROGRESS:75/100\n")), // 75%
// 75% should be ignored becaused it didn't change. // 75% should be ignored becaused it didn't change.
WithArg<4>(WriteOnStdout("PROGRESS:75/100\n")), // 75% WithArg<2>(WriteOnStdout("PROGRESS:75/100\n")), // 75%
// Try a receeding percentage with a different max progress // Try a receeding percentage with a different max progress
WithArg<4>(WriteOnStdout("PROGRESS:700/1000\n")), // 70% WithArg<2>(WriteOnStdout("PROGRESS:700/1000\n")), // 70%
WithArg<4>(WriteOnStdout("OK:/device/bugreport.zip")), WithArg<2>(WriteOnStdout("OK:/device/bugreport.zip")),
WithArg<4>(ReturnCallbackDone()))); WithArg<2>(ReturnCallbackDone())));
// clang-format on // clang-format on
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"), EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
true, StrEq("pulling file.zip"))) true, StrEq("pulling file.zip")))
.WillOnce(Return(true)); .WillOnce(Return(true));
const char* args[] = {"bugreport", "file.zip"}; const char* args[] = {"bugreport", "file.zip"};
ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args)); ASSERT_EQ(0, br_.DoIt(2, args));
} }
// Tests 'adb bugreport file.zip' when it succeeds and displays the initial progress of 0% // Tests 'adb bugreport file.zip' when it succeeds and displays the initial progress of 0%
@ -317,21 +315,21 @@ TEST_F(BugreportTest, OkProgressZeroPercentIsNotIgnored) {
ExpectProgress(0); ExpectProgress(0);
ExpectProgress(1); ExpectProgress(1);
// clang-format off // clang-format off
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _)) EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
// NOTE: DoAll accepts at most 10 arguments, and we're almost reached that limit... // NOTE: DoAll accepts at most 10 arguments, and we're almost reached that limit...
.WillOnce(DoAll( .WillOnce(DoAll(
WithArg<4>(WriteOnStdout("BEGIN:/device/bugreport.zip\n")), WithArg<2>(WriteOnStdout("BEGIN:/device/bugreport.zip\n")),
WithArg<4>(WriteOnStdout("PROGRESS:1/100000\n")), WithArg<2>(WriteOnStdout("PROGRESS:1/100000\n")),
WithArg<4>(WriteOnStdout("PROGRESS:1/100\n")), // 1% WithArg<2>(WriteOnStdout("PROGRESS:1/100\n")), // 1%
WithArg<4>(WriteOnStdout("OK:/device/bugreport.zip")), WithArg<2>(WriteOnStdout("OK:/device/bugreport.zip")),
WithArg<4>(ReturnCallbackDone()))); WithArg<2>(ReturnCallbackDone())));
// clang-format on // clang-format on
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"), EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
true, StrEq("pulling file.zip"))) true, StrEq("pulling file.zip")))
.WillOnce(Return(true)); .WillOnce(Return(true));
const char* args[] = {"bugreport", "file.zip"}; const char* args[] = {"bugreport", "file.zip"};
ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args)); ASSERT_EQ(0, br_.DoIt(2, args));
} }
// Tests 'adb bugreport dir' when it succeeds and destination is a directory. // Tests 'adb bugreport dir' when it succeeds and destination is a directory.
@ -341,30 +339,30 @@ TEST_F(BugreportTest, OkDirectory) {
std::string dest_file = std::string dest_file =
android::base::StringPrintf("%s%cda_bugreport.zip", td.path, OS_PATH_SEPARATOR); android::base::StringPrintf("%s%cda_bugreport.zip", td.path, OS_PATH_SEPARATOR);
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _)) EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStdout("BEGIN:/device/da_bugreport.zip\n")), .WillOnce(DoAll(WithArg<2>(WriteOnStdout("BEGIN:/device/da_bugreport.zip\n")),
WithArg<4>(WriteOnStdout("OK:/device/da_bugreport.zip")), WithArg<2>(WriteOnStdout("OK:/device/da_bugreport.zip")),
WithArg<4>(ReturnCallbackDone()))); WithArg<2>(ReturnCallbackDone())));
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file), EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
true, StrEq("pulling da_bugreport.zip"))) true, StrEq("pulling da_bugreport.zip")))
.WillOnce(Return(true)); .WillOnce(Return(true));
const char* args[] = {"bugreport", td.path}; const char* args[] = {"bugreport", td.path};
ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args)); ASSERT_EQ(0, br_.DoIt(2, args));
} }
// Tests 'adb bugreport file' when it succeeds // Tests 'adb bugreport file' when it succeeds
TEST_F(BugreportTest, OkNoExtension) { TEST_F(BugreportTest, OkNoExtension) {
ExpectBugreportzVersion("1.1"); ExpectBugreportzVersion("1.1");
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _)) EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device/bugreport.zip\n")), .WillOnce(DoAll(WithArg<2>(WriteOnStdout("OK:/device/bugreport.zip\n")),
WithArg<4>(ReturnCallbackDone()))); WithArg<2>(ReturnCallbackDone())));
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"), EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
true, StrEq("pulling file.zip"))) true, StrEq("pulling file.zip")))
.WillOnce(Return(true)); .WillOnce(Return(true));
const char* args[] = {"bugreport", "file"}; const char* args[] = {"bugreport", "file"};
ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args)); ASSERT_EQ(0, br_.DoIt(2, args));
} }
// Tests 'adb bugreport dir' when it succeeds and destination is a directory and device runs N. // Tests 'adb bugreport dir' when it succeeds and destination is a directory and device runs N.
@ -374,28 +372,28 @@ TEST_F(BugreportTest, OkNDeviceDirectory) {
std::string dest_file = std::string dest_file =
android::base::StringPrintf("%s%cda_bugreport.zip", td.path, OS_PATH_SEPARATOR); android::base::StringPrintf("%s%cda_bugreport.zip", td.path, OS_PATH_SEPARATOR);
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz", false, _)) EXPECT_CALL(br_, SendShellCommand("bugreportz", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStdout("BEGIN:/device/da_bugreport.zip\n")), .WillOnce(DoAll(WithArg<2>(WriteOnStdout("BEGIN:/device/da_bugreport.zip\n")),
WithArg<4>(WriteOnStdout("OK:/device/da_bugreport.zip")), WithArg<2>(WriteOnStdout("OK:/device/da_bugreport.zip")),
WithArg<4>(ReturnCallbackDone()))); WithArg<2>(ReturnCallbackDone())));
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file), EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
true, StrEq("pulling da_bugreport.zip"))) true, StrEq("pulling da_bugreport.zip")))
.WillOnce(Return(true)); .WillOnce(Return(true));
const char* args[] = {"bugreport", td.path}; const char* args[] = {"bugreport", td.path};
ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args)); ASSERT_EQ(0, br_.DoIt(2, args));
} }
// Tests 'adb bugreport file.zip' when the bugreport itself failed // Tests 'adb bugreport file.zip' when the bugreport itself failed
TEST_F(BugreportTest, BugreportzReturnedFail) { TEST_F(BugreportTest, BugreportzReturnedFail) {
ExpectBugreportzVersion("1.1"); ExpectBugreportzVersion("1.1");
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _)) EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
.WillOnce( .WillOnce(
DoAll(WithArg<4>(WriteOnStdout("FAIL:D'OH!\n")), WithArg<4>(ReturnCallbackDone()))); DoAll(WithArg<2>(WriteOnStdout("FAIL:D'OH!\n")), WithArg<2>(ReturnCallbackDone())));
CaptureStderr(); CaptureStderr();
const char* args[] = {"bugreport", "file.zip"}; const char* args[] = {"bugreport", "file.zip"};
ASSERT_EQ(-1, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args)); ASSERT_EQ(-1, br_.DoIt(2, args));
ASSERT_THAT(GetCapturedStderr(), HasSubstr("D'OH!")); ASSERT_THAT(GetCapturedStderr(), HasSubstr("D'OH!"));
} }
@ -404,13 +402,13 @@ TEST_F(BugreportTest, BugreportzReturnedFail) {
// multiple buffer writes // multiple buffer writes
TEST_F(BugreportTest, BugreportzReturnedFailSplitBuffer) { TEST_F(BugreportTest, BugreportzReturnedFailSplitBuffer) {
ExpectBugreportzVersion("1.1"); ExpectBugreportzVersion("1.1");
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _)) EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStdout("FAIL")), WithArg<4>(WriteOnStdout(":D'OH!\n")), .WillOnce(DoAll(WithArg<2>(WriteOnStdout("FAIL")), WithArg<2>(WriteOnStdout(":D'OH!\n")),
WithArg<4>(ReturnCallbackDone()))); WithArg<2>(ReturnCallbackDone())));
CaptureStderr(); CaptureStderr();
const char* args[] = {"bugreport", "file.zip"}; const char* args[] = {"bugreport", "file.zip"};
ASSERT_EQ(-1, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args)); ASSERT_EQ(-1, br_.DoIt(2, args));
ASSERT_THAT(GetCapturedStderr(), HasSubstr("D'OH!")); ASSERT_THAT(GetCapturedStderr(), HasSubstr("D'OH!"));
} }
@ -418,23 +416,22 @@ TEST_F(BugreportTest, BugreportzReturnedFailSplitBuffer) {
// response. // response.
TEST_F(BugreportTest, BugreportzReturnedUnsupported) { TEST_F(BugreportTest, BugreportzReturnedUnsupported) {
ExpectBugreportzVersion("1.1"); ExpectBugreportzVersion("1.1");
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _)) EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStdout("bugreportz? What am I, a zombie?")), .WillOnce(DoAll(WithArg<2>(WriteOnStdout("bugreportz? What am I, a zombie?")),
WithArg<4>(ReturnCallbackDone()))); WithArg<2>(ReturnCallbackDone())));
CaptureStderr(); CaptureStderr();
const char* args[] = {"bugreport", "file.zip"}; const char* args[] = {"bugreport", "file.zip"};
ASSERT_EQ(-1, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args)); ASSERT_EQ(-1, br_.DoIt(2, args));
ASSERT_THAT(GetCapturedStderr(), HasSubstr("bugreportz? What am I, a zombie?")); ASSERT_THAT(GetCapturedStderr(), HasSubstr("bugreportz? What am I, a zombie?"));
} }
// Tests 'adb bugreport file.zip' when the bugreportz -v command failed // Tests 'adb bugreport file.zip' when the bugreportz -v command failed
TEST_F(BugreportTest, BugreportzVersionFailed) { TEST_F(BugreportTest, BugreportzVersionFailed) {
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -v", false, _)) EXPECT_CALL(br_, SendShellCommand("bugreportz -v", false, _)).WillOnce(Return(666));
.WillOnce(Return(666));
const char* args[] = {"bugreport", "file.zip"}; const char* args[] = {"bugreport", "file.zip"};
ASSERT_EQ(666, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args)); ASSERT_EQ(666, br_.DoIt(2, args));
} }
// Tests 'adb bugreport file.zip' when the bugreportz -v returns status 0 but with no output. // Tests 'adb bugreport file.zip' when the bugreportz -v returns status 0 but with no output.
@ -442,29 +439,28 @@ TEST_F(BugreportTest, BugreportzVersionEmpty) {
ExpectBugreportzVersion(""); ExpectBugreportzVersion("");
const char* args[] = {"bugreport", "file.zip"}; const char* args[] = {"bugreport", "file.zip"};
ASSERT_EQ(-1, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args)); ASSERT_EQ(-1, br_.DoIt(2, args));
} }
// Tests 'adb bugreport file.zip' when the main bugreportz command failed // Tests 'adb bugreport file.zip' when the main bugreportz command failed
TEST_F(BugreportTest, BugreportzFailed) { TEST_F(BugreportTest, BugreportzFailed) {
ExpectBugreportzVersion("1.1"); ExpectBugreportzVersion("1.1");
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _)) EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _)).WillOnce(Return(666));
.WillOnce(Return(666));
const char* args[] = {"bugreport", "file.zip"}; const char* args[] = {"bugreport", "file.zip"};
ASSERT_EQ(666, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args)); ASSERT_EQ(666, br_.DoIt(2, args));
} }
// Tests 'adb bugreport file.zip' when the bugreport could not be pulled // Tests 'adb bugreport file.zip' when the bugreport could not be pulled
TEST_F(BugreportTest, PullFails) { TEST_F(BugreportTest, PullFails) {
ExpectBugreportzVersion("1.1"); ExpectBugreportzVersion("1.1");
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _)) EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device/bugreport.zip")), .WillOnce(DoAll(WithArg<2>(WriteOnStdout("OK:/device/bugreport.zip")),
WithArg<4>(ReturnCallbackDone()))); WithArg<2>(ReturnCallbackDone())));
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"), EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
true, HasSubstr("file.zip"))) true, HasSubstr("file.zip")))
.WillOnce(Return(false)); .WillOnce(Return(false));
const char* args[] = {"bugreport", "file.zip"}; const char* args[] = {"bugreport", "file.zip"};
ASSERT_EQ(1, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args)); ASSERT_EQ(1, br_.DoIt(2, args));
} }

View file

@ -412,8 +412,13 @@ static void device_disconnected(libusb_device* device) {
if (it != usb_handles.end()) { if (it != usb_handles.end()) {
if (!it->second->device_handle) { if (!it->second->device_handle) {
// If the handle is null, we were never able to open the device. // If the handle is null, we were never able to open the device.
unregister_usb_transport(it->second.get());
// Temporarily release the usb handles mutex to avoid deadlock.
std::unique_ptr<usb_handle> handle = std::move(it->second);
usb_handles.erase(it); usb_handles.erase(it);
lock.unlock();
unregister_usb_transport(handle.get());
lock.lock();
} else { } else {
// Closure of the transport will erase the usb_handle. // Closure of the transport will erase the usb_handle.
} }

View file

@ -62,11 +62,11 @@
#include "shell_service.h" #include "shell_service.h"
#include "sysdeps/chrono.h" #include "sysdeps/chrono.h"
static int install_app(TransportType t, const char* serial, int argc, const char** argv); static int install_app(int argc, const char** argv);
static int install_multiple_app(TransportType t, const char* serial, int argc, const char** argv); static int install_multiple_app(int argc, const char** argv);
static int uninstall_app(TransportType t, const char* serial, int argc, const char** argv); static int uninstall_app(int argc, const char** argv);
static int install_app_legacy(TransportType t, const char* serial, int argc, const char** argv); static int install_app_legacy(int argc, const char** argv);
static int uninstall_app_legacy(TransportType t, const char* serial, int argc, const char** argv); static int uninstall_app_legacy(int argc, const char** argv);
extern int gListenAll; extern int gListenAll;
@ -90,6 +90,7 @@ static void help() {
" -d use USB device (error if multiple devices connected)\n" " -d use USB device (error if multiple devices connected)\n"
" -e use TCP/IP device (error if multiple TCP/IP devices available)\n" " -e use TCP/IP device (error if multiple TCP/IP devices available)\n"
" -s SERIAL use device with given serial (overrides $ANDROID_SERIAL)\n" " -s SERIAL use device with given serial (overrides $ANDROID_SERIAL)\n"
" -t ID use device with given transport id\n"
" -H name of adb server host [default=localhost]\n" " -H name of adb server host [default=localhost]\n"
" -P port of adb server [default=5037]\n" " -P port of adb server [default=5037]\n"
" -L SOCKET listen on given socket for adb server [default=tcp:localhost:5037]\n" " -L SOCKET listen on given socket for adb server [default=tcp:localhost:5037]\n"
@ -986,13 +987,16 @@ static int ppp(int argc, const char** argv) {
#endif /* !defined(_WIN32) */ #endif /* !defined(_WIN32) */
} }
static bool wait_for_device(const char* service, TransportType t, const char* serial) { static bool wait_for_device(const char* service) {
std::vector<std::string> components = android::base::Split(service, "-"); std::vector<std::string> components = android::base::Split(service, "-");
if (components.size() < 3 || components.size() > 4) { if (components.size() < 3 || components.size() > 4) {
fprintf(stderr, "adb: couldn't parse 'wait-for' command: %s\n", service); fprintf(stderr, "adb: couldn't parse 'wait-for' command: %s\n", service);
return false; return false;
} }
TransportType t;
adb_get_transport(&t, nullptr, nullptr);
// Was the caller vague about what they'd like us to wait for? // Was the caller vague about what they'd like us to wait for?
// If so, check they weren't more specific in their choice of transport type. // If so, check they weren't more specific in their choice of transport type.
if (components.size() == 3) { if (components.size() == 3) {
@ -1019,7 +1023,7 @@ static bool wait_for_device(const char* service, TransportType t, const char* se
return false; return false;
} }
std::string cmd = format_host_command(android::base::Join(components, "-").c_str(), t, serial); std::string cmd = format_host_command(android::base::Join(components, "-").c_str());
return adb_command(cmd); return adb_command(cmd);
} }
@ -1065,8 +1069,8 @@ static bool adb_root(const char* command) {
return true; return true;
} }
int send_shell_command(TransportType transport_type, const char* serial, const std::string& command, int send_shell_command(const std::string& command, bool disable_shell_protocol,
bool disable_shell_protocol, StandardStreamsCallbackInterface* callback) { StandardStreamsCallbackInterface* callback) {
int fd; int fd;
bool use_shell_protocol = false; bool use_shell_protocol = false;
@ -1097,7 +1101,7 @@ int send_shell_command(TransportType transport_type, const char* serial, const s
} }
fprintf(stderr, "- waiting for device -\n"); fprintf(stderr, "- waiting for device -\n");
if (!wait_for_device("wait-for-device", transport_type, serial)) { if (!wait_for_device("wait-for-device")) {
return 1; return 1;
} }
} }
@ -1111,7 +1115,7 @@ int send_shell_command(TransportType transport_type, const char* serial, const s
return exit_code; return exit_code;
} }
static int logcat(TransportType transport, const char* serial, int argc, const char** argv) { static int logcat(int argc, const char** argv) {
char* log_tags = getenv("ANDROID_LOG_TAGS"); char* log_tags = getenv("ANDROID_LOG_TAGS");
std::string quoted = escape_arg(log_tags == nullptr ? "" : log_tags); std::string quoted = escape_arg(log_tags == nullptr ? "" : log_tags);
@ -1128,7 +1132,7 @@ static int logcat(TransportType transport, const char* serial, int argc, const c
} }
// No need for shell protocol with logcat, always disable for simplicity. // No need for shell protocol with logcat, always disable for simplicity.
return send_shell_command(transport, serial, cmd, true); return send_shell_command(cmd, true);
} }
static void write_zeros(int bytes, int fd) { static void write_zeros(int bytes, int fd) {
@ -1340,6 +1344,7 @@ int adb_commandline(int argc, const char** argv) {
// We need to check for -d and -e before we look at $ANDROID_SERIAL. // We need to check for -d and -e before we look at $ANDROID_SERIAL.
const char* serial = nullptr; const char* serial = nullptr;
TransportId transport_id = 0;
while (argc > 0) { while (argc > 0) {
if (!strcmp(argv[0],"server")) { if (!strcmp(argv[0],"server")) {
@ -1359,7 +1364,7 @@ int adb_commandline(int argc, const char** argv) {
fprintf(stderr, "adb: invalid reply fd \"%s\"\n", reply_fd_str); fprintf(stderr, "adb: invalid reply fd \"%s\"\n", reply_fd_str);
return 1; return 1;
} }
} else if (argv[0][0]=='-' && argv[0][1]=='s') { } else if (!strncmp(argv[0], "-s", 2)) {
if (isdigit(argv[0][2])) { if (isdigit(argv[0][2])) {
serial = argv[0] + 2; serial = argv[0] + 2;
} else { } else {
@ -1368,6 +1373,19 @@ int adb_commandline(int argc, const char** argv) {
argc--; argc--;
argv++; argv++;
} }
} else if (!strncmp(argv[0], "-t", 2)) {
const char* id;
if (isdigit(argv[0][2])) {
id = argv[0] + 2;
} else {
id = argv[1];
argc--;
argv++;
}
transport_id = strtoll(id, const_cast<char**>(&id), 10);
if (*id != '\0') {
return syntax_error("invalid transport id");
}
} else if (!strcmp(argv[0],"-d")) { } else if (!strcmp(argv[0],"-d")) {
transport_type = kTransportUsb; transport_type = kTransportUsb;
} else if (!strcmp(argv[0],"-e")) { } else if (!strcmp(argv[0],"-e")) {
@ -1451,7 +1469,7 @@ int adb_commandline(int argc, const char** argv) {
serial = getenv("ANDROID_SERIAL"); serial = getenv("ANDROID_SERIAL");
} }
adb_set_transport(transport_type, serial); adb_set_transport(transport_type, serial, transport_id);
if (is_server) { if (is_server) {
if (no_daemon || is_daemon) { if (no_daemon || is_daemon) {
@ -1478,7 +1496,7 @@ int adb_commandline(int argc, const char** argv) {
if (!strncmp(argv[0], "wait-for-", strlen("wait-for-"))) { if (!strncmp(argv[0], "wait-for-", strlen("wait-for-"))) {
const char* service = argv[0]; const char* service = argv[0];
if (!wait_for_device(service, transport_type, serial)) { if (!wait_for_device(service)) {
return 1; return 1;
} }
@ -1589,7 +1607,7 @@ int adb_commandline(int argc, const char** argv) {
return adb_root(argv[0]) ? 0 : 1; return adb_root(argv[0]) ? 0 : 1;
} else if (!strcmp(argv[0], "bugreport")) { } else if (!strcmp(argv[0], "bugreport")) {
Bugreport bugreport; Bugreport bugreport;
return bugreport.DoIt(transport_type, serial, argc, argv); return bugreport.DoIt(argc, argv);
} else if (!strcmp(argv[0], "forward") || !strcmp(argv[0], "reverse")) { } else if (!strcmp(argv[0], "forward") || !strcmp(argv[0], "reverse")) {
bool reverse = !strcmp(argv[0], "reverse"); bool reverse = !strcmp(argv[0], "reverse");
++argv; ++argv;
@ -1685,20 +1703,20 @@ int adb_commandline(int argc, const char** argv) {
else if (!strcmp(argv[0], "install")) { else if (!strcmp(argv[0], "install")) {
if (argc < 2) return syntax_error("install requires an argument"); if (argc < 2) return syntax_error("install requires an argument");
if (_use_legacy_install()) { if (_use_legacy_install()) {
return install_app_legacy(transport_type, serial, argc, argv); return install_app_legacy(argc, argv);
} }
return install_app(transport_type, serial, argc, argv); return install_app(argc, argv);
} }
else if (!strcmp(argv[0], "install-multiple")) { else if (!strcmp(argv[0], "install-multiple")) {
if (argc < 2) return syntax_error("install-multiple requires an argument"); if (argc < 2) return syntax_error("install-multiple requires an argument");
return install_multiple_app(transport_type, serial, argc, argv); return install_multiple_app(argc, argv);
} }
else if (!strcmp(argv[0], "uninstall")) { else if (!strcmp(argv[0], "uninstall")) {
if (argc < 2) return syntax_error("uninstall requires an argument"); if (argc < 2) return syntax_error("uninstall requires an argument");
if (_use_legacy_install()) { if (_use_legacy_install()) {
return uninstall_app_legacy(transport_type, serial, argc, argv); return uninstall_app_legacy(argc, argv);
} }
return uninstall_app(transport_type, serial, argc, argv); return uninstall_app(argc, argv);
} }
else if (!strcmp(argv[0], "sync")) { else if (!strcmp(argv[0], "sync")) {
std::string src; std::string src;
@ -1752,11 +1770,11 @@ int adb_commandline(int argc, const char** argv) {
!strcmp(argv[0],"get-serialno") || !strcmp(argv[0],"get-serialno") ||
!strcmp(argv[0],"get-devpath")) !strcmp(argv[0],"get-devpath"))
{ {
return adb_query_command(format_host_command(argv[0], transport_type, serial)); return adb_query_command(format_host_command(argv[0]));
} }
/* other commands */ /* other commands */
else if (!strcmp(argv[0],"logcat") || !strcmp(argv[0],"lolcat") || !strcmp(argv[0],"longcat")) { else if (!strcmp(argv[0],"logcat") || !strcmp(argv[0],"lolcat") || !strcmp(argv[0],"longcat")) {
return logcat(transport_type, serial, argc, argv); return logcat(argc, argv);
} }
else if (!strcmp(argv[0],"ppp")) { else if (!strcmp(argv[0],"ppp")) {
return ppp(argc, argv); return ppp(argc, argv);
@ -1819,7 +1837,7 @@ int adb_commandline(int argc, const char** argv) {
return adb_query_command("host:host-features"); return adb_query_command("host:host-features");
} else if (!strcmp(argv[0], "reconnect")) { } else if (!strcmp(argv[0], "reconnect")) {
if (argc == 1) { if (argc == 1) {
return adb_query_command(format_host_command(argv[0], transport_type, serial)); return adb_query_command(format_host_command(argv[0]));
} else if (argc == 2) { } else if (argc == 2) {
if (!strcmp(argv[1], "device")) { if (!strcmp(argv[1], "device")) {
std::string err; std::string err;
@ -1838,7 +1856,7 @@ int adb_commandline(int argc, const char** argv) {
return 1; return 1;
} }
static int uninstall_app(TransportType transport, const char* serial, int argc, const char** argv) { static int uninstall_app(int argc, const char** argv) {
// 'adb uninstall' takes the same arguments as 'cmd package uninstall' on device // 'adb uninstall' takes the same arguments as 'cmd package uninstall' on device
std::string cmd = "cmd package"; std::string cmd = "cmd package";
while (argc-- > 0) { while (argc-- > 0) {
@ -1854,10 +1872,10 @@ static int uninstall_app(TransportType transport, const char* serial, int argc,
cmd += " " + escape_arg(*argv++); cmd += " " + escape_arg(*argv++);
} }
return send_shell_command(transport, serial, cmd, false); return send_shell_command(cmd, false);
} }
static int install_app(TransportType transport, const char* serial, int argc, const char** argv) { static int install_app(int argc, const char** argv) {
// The last argument must be the APK file // The last argument must be the APK file
const char* file = argv[argc - 1]; const char* file = argv[argc - 1];
if (!android::base::EndsWithIgnoreCase(file, ".apk")) { if (!android::base::EndsWithIgnoreCase(file, ".apk")) {
@ -1910,9 +1928,7 @@ static int install_app(TransportType transport, const char* serial, int argc, co
return 1; return 1;
} }
static int install_multiple_app(TransportType transport, const char* serial, int argc, static int install_multiple_app(int argc, const char** argv) {
const char** argv)
{
// Find all APK arguments starting at end. // Find all APK arguments starting at end.
// All other arguments passed through verbatim. // All other arguments passed through verbatim.
int first_apk = -1; int first_apk = -1;
@ -2037,17 +2053,17 @@ finalize_session:
return EXIT_FAILURE; return EXIT_FAILURE;
} }
static int pm_command(TransportType transport, const char* serial, int argc, const char** argv) { static int pm_command(int argc, const char** argv) {
std::string cmd = "pm"; std::string cmd = "pm";
while (argc-- > 0) { while (argc-- > 0) {
cmd += " " + escape_arg(*argv++); cmd += " " + escape_arg(*argv++);
} }
return send_shell_command(transport, serial, cmd, false); return send_shell_command(cmd, false);
} }
static int uninstall_app_legacy(TransportType transport, const char* serial, int argc, const char** argv) { static int uninstall_app_legacy(int argc, const char** argv) {
/* if the user choose the -k option, we refuse to do it until devices are /* 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) */ out with the option to uninstall the remaining data somehow (adb/ui) */
int i; int i;
@ -2063,15 +2079,15 @@ static int uninstall_app_legacy(TransportType transport, const char* serial, int
} }
/* 'adb uninstall' takes the same arguments as 'pm uninstall' on device */ /* 'adb uninstall' takes the same arguments as 'pm uninstall' on device */
return pm_command(transport, serial, argc, argv); return pm_command(argc, argv);
} }
static int delete_file(TransportType transport, const char* serial, const std::string& filename) { static int delete_file(const std::string& filename) {
std::string cmd = "rm -f " + escape_arg(filename); std::string cmd = "rm -f " + escape_arg(filename);
return send_shell_command(transport, serial, cmd, false); return send_shell_command(cmd, false);
} }
static int install_app_legacy(TransportType transport, const char* serial, int argc, const char** argv) { static int install_app_legacy(int argc, const char** argv) {
static const char *const DATA_DEST = "/data/local/tmp/%s"; static const char *const DATA_DEST = "/data/local/tmp/%s";
static const char *const SD_DEST = "/sdcard/tmp/%s"; static const char *const SD_DEST = "/sdcard/tmp/%s";
const char* where = DATA_DEST; const char* where = DATA_DEST;
@ -2100,9 +2116,9 @@ static int install_app_legacy(TransportType transport, const char* serial, int a
where, android::base::Basename(argv[last_apk]).c_str()); where, android::base::Basename(argv[last_apk]).c_str());
if (!do_sync_push(apk_file, apk_dest.c_str(), false)) goto cleanup_apk; if (!do_sync_push(apk_file, apk_dest.c_str(), false)) goto cleanup_apk;
argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */ argv[last_apk] = apk_dest.c_str(); /* destination name, not source location */
result = pm_command(transport, serial, argc, argv); result = pm_command(argc, argv);
cleanup_apk: cleanup_apk:
delete_file(transport, serial, apk_dest); delete_file(apk_dest);
return result; return result;
} }

View file

@ -91,8 +91,8 @@ int adb_commandline(int argc, const char** argv);
// Connects to the device "shell" service with |command| and prints the // Connects to the device "shell" service with |command| and prints the
// resulting output. // resulting output.
// if |callback| is non-null, stdout/stderr output will be handled by it. // if |callback| is non-null, stdout/stderr output will be handled by it.
int send_shell_command(TransportType transport_type, const char* serial, const std::string& command, int send_shell_command(
bool disable_shell_protocol, StandardStreamsCallbackInterface* callback = const std::string& command, bool disable_shell_protocol,
&DEFAULT_STANDARD_STREAMS_CALLBACK); StandardStreamsCallbackInterface* callback = &DEFAULT_STANDARD_STREAMS_CALLBACK);
#endif // COMMANDLINE_H #endif // COMMANDLINE_H

View file

@ -187,7 +187,7 @@ int reverse_service(const char* command) {
return -1; return -1;
} }
VLOG(SERVICES) << "service socketpair: " << s[0] << ", " << s[1]; VLOG(SERVICES) << "service socketpair: " << s[0] << ", " << s[1];
if (handle_forward_request(command, kTransportAny, nullptr, s[1]) < 0) { if (handle_forward_request(command, kTransportAny, nullptr, 0, s[1]) < 0) {
SendFail(s[1], "not a reverse forwarding command"); SendFail(s[1], "not a reverse forwarding command");
} }
adb_close(s[1]); adb_close(s[1]);
@ -334,6 +334,7 @@ int service_to_fd(const char* name, const atransport* transport) {
struct state_info { struct state_info {
TransportType transport_type; TransportType transport_type;
std::string serial; std::string serial;
TransportId transport_id;
ConnectionState state; ConnectionState state;
}; };
@ -346,7 +347,8 @@ static void wait_for_state(int fd, void* data) {
bool is_ambiguous = false; bool is_ambiguous = false;
std::string error = "unknown error"; std::string error = "unknown error";
const char* serial = sinfo->serial.length() ? sinfo->serial.c_str() : NULL; const char* serial = sinfo->serial.length() ? sinfo->serial.c_str() : NULL;
atransport* t = acquire_one_transport(sinfo->transport_type, serial, &is_ambiguous, &error); atransport* t = acquire_one_transport(sinfo->transport_type, serial, sinfo->transport_id,
&is_ambiguous, &error);
if (t != nullptr && (sinfo->state == kCsAny || sinfo->state == t->GetConnectionState())) { if (t != nullptr && (sinfo->state == kCsAny || sinfo->state == t->GetConnectionState())) {
SendOkay(fd); SendOkay(fd);
break; break;
@ -437,7 +439,7 @@ static void connect_service(int fd, void* data) {
#endif #endif
#if ADB_HOST #if ADB_HOST
asocket* host_service_to_socket(const char* name, const char* serial) { asocket* host_service_to_socket(const char* name, const char* serial, TransportId transport_id) {
if (!strcmp(name,"track-devices")) { if (!strcmp(name,"track-devices")) {
return create_device_tracker(); return create_device_tracker();
} else if (android::base::StartsWith(name, "wait-for-")) { } else if (android::base::StartsWith(name, "wait-for-")) {
@ -450,6 +452,7 @@ asocket* host_service_to_socket(const char* name, const char* serial) {
} }
if (serial) sinfo->serial = serial; if (serial) sinfo->serial = serial;
sinfo->transport_id = transport_id;
if (android::base::StartsWith(name, "local")) { if (android::base::StartsWith(name, "local")) {
name += strlen("local"); name += strlen("local");

View file

@ -96,7 +96,7 @@ void install_local_socket(asocket* s) {
} }
void remove_socket(asocket* s) { void remove_socket(asocket* s) {
// socket_list_lock should already be held std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock);
if (s->prev && s->next) { if (s->prev && s->next) {
s->prev->next = s->next; s->prev->next = s->next;
s->next->prev = s->prev; s->next->prev = s->prev;
@ -430,10 +430,11 @@ asocket* create_local_service_socket(const char* name, const atransport* transpo
} }
#if ADB_HOST #if ADB_HOST
static asocket* create_host_service_socket(const char* name, const char* serial) { static asocket* create_host_service_socket(const char* name, const char* serial,
TransportId transport_id) {
asocket* s; asocket* s;
s = host_service_to_socket(name, serial); s = host_service_to_socket(name, serial, transport_id);
if (s != NULL) { if (s != NULL) {
D("LS(%d) bound to '%s'", s->id, name); D("LS(%d) bound to '%s'", s->id, name);
@ -658,6 +659,7 @@ static int smart_socket_enqueue(asocket* s, apacket* p) {
#if ADB_HOST #if ADB_HOST
char* service = nullptr; char* service = nullptr;
char* serial = nullptr; char* serial = nullptr;
TransportId transport_id = 0;
TransportType type = kTransportAny; TransportType type = kTransportAny;
#endif #endif
@ -715,6 +717,14 @@ static int smart_socket_enqueue(asocket* s, apacket* p) {
serial = service; serial = service;
service = serial_end + 1; service = serial_end + 1;
} }
} else if (!strncmp(service, "host-transport-id:", strlen("host-transport-id:"))) {
service += strlen("host-transport-id:");
transport_id = strtoll(service, &service, 10);
if (*service != ':') {
return -1;
}
service++;
} else if (!strncmp(service, "host-usb:", strlen("host-usb:"))) { } else if (!strncmp(service, "host-usb:", strlen("host-usb:"))) {
type = kTransportUsb; type = kTransportUsb;
service += strlen("host-usb:"); service += strlen("host-usb:");
@ -736,7 +746,7 @@ static int smart_socket_enqueue(asocket* s, apacket* p) {
** the OKAY or FAIL message and all we have to do ** the OKAY or FAIL message and all we have to do
** is clean up. ** is clean up.
*/ */
if (handle_host_request(service, type, serial, s->peer->fd, s) == 0) { if (handle_host_request(service, type, serial, transport_id, s->peer->fd, s) == 0) {
/* XXX fail message? */ /* XXX fail message? */
D("SS(%d): handled host service '%s'", s->id, service); D("SS(%d): handled host service '%s'", s->id, service);
goto fail; goto fail;
@ -751,7 +761,7 @@ static int smart_socket_enqueue(asocket* s, apacket* p) {
** if no such service exists, we'll fail out ** if no such service exists, we'll fail out
** and tear down here. ** and tear down here.
*/ */
s2 = create_host_service_socket(service, serial); s2 = create_host_service_socket(service, serial, transport_id);
if (s2 == 0) { if (s2 == 0) {
D("SS(%d): couldn't create host service '%s'", s->id, service); D("SS(%d): couldn't create host service '%s'", s->id, service);
SendFail(s->peer->fd, "unknown host service"); SendFail(s->peer->fd, "unknown host service");
@ -783,7 +793,7 @@ static int smart_socket_enqueue(asocket* s, apacket* p) {
#else /* !ADB_HOST */ #else /* !ADB_HOST */
if (s->transport == nullptr) { if (s->transport == nullptr) {
std::string error_msg = "unknown failure"; std::string error_msg = "unknown failure";
s->transport = acquire_one_transport(kTransportAny, nullptr, nullptr, &error_msg); s->transport = acquire_one_transport(kTransportAny, nullptr, 0, nullptr, &error_msg);
if (s->transport == nullptr) { if (s->transport == nullptr) {
SendFail(s->peer->fd, error_msg); SendFail(s->peer->fd, error_msg);
goto fail; goto fail;

View file

@ -21,6 +21,7 @@
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <inttypes.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -36,6 +37,7 @@
#include <android-base/quick_exit.h> #include <android-base/quick_exit.h>
#include <android-base/stringprintf.h> #include <android-base/stringprintf.h>
#include <android-base/strings.h> #include <android-base/strings.h>
#include <android-base/thread_annotations.h>
#include "adb.h" #include "adb.h"
#include "adb_auth.h" #include "adb_auth.h"
@ -46,10 +48,11 @@
static void transport_unref(atransport *t); static void transport_unref(atransport *t);
// TODO: unordered_map<TransportId, atransport*>
static auto& transport_list = *new std::list<atransport*>(); static auto& transport_list = *new std::list<atransport*>();
static auto& pending_list = *new std::list<atransport*>(); static auto& pending_list = *new std::list<atransport*>();
static std::mutex& transport_lock = *new std::mutex(); static auto& transport_lock = *new std::recursive_mutex();
const char* const kFeatureShell2 = "shell_v2"; const char* const kFeatureShell2 = "shell_v2";
const char* const kFeatureCmd = "cmd"; const char* const kFeatureCmd = "cmd";
@ -57,6 +60,11 @@ const char* const kFeatureStat2 = "stat_v2";
const char* const kFeatureLibusb = "libusb"; const char* const kFeatureLibusb = "libusb";
const char* const kFeaturePushSync = "push_sync"; const char* const kFeaturePushSync = "push_sync";
TransportId NextTransportId() {
static std::atomic<TransportId> next(1);
return next++;
}
static std::string dump_packet(const char* name, const char* func, apacket* p) { static std::string dump_packet(const char* name, const char* func, apacket* p) {
unsigned command = p->msg.command; unsigned command = p->msg.command;
int len = p->msg.data_length; int len = p->msg.data_length;
@ -298,9 +306,11 @@ static void write_transport_thread(void* _t) {
} }
void kick_transport(atransport* t) { void kick_transport(atransport* t) {
std::lock_guard<std::mutex> lock(transport_lock); std::lock_guard<std::recursive_mutex> lock(transport_lock);
// As kick_transport() can be called from threads without guarantee that t is valid, // As kick_transport() can be called from threads without guarantee that t is valid,
// check if the transport is in transport_list first. // check if the transport is in transport_list first.
//
// TODO(jmgao): WTF? Is this actually true?
if (std::find(transport_list.begin(), transport_list.end(), t) != transport_list.end()) { if (std::find(transport_list.begin(), transport_list.end(), t) != transport_list.end()) {
t->Kick(); t->Kick();
} }
@ -330,7 +340,7 @@ static void device_tracker_remove(device_tracker* tracker) {
device_tracker** pnode = &device_tracker_list; device_tracker** pnode = &device_tracker_list;
device_tracker* node = *pnode; device_tracker* node = *pnode;
std::lock_guard<std::mutex> lock(transport_lock); std::lock_guard<std::recursive_mutex> lock(transport_lock);
while (node) { while (node) {
if (node == tracker) { if (node == tracker) {
*pnode = node->next; *pnode = node->next;
@ -403,7 +413,7 @@ asocket* create_device_tracker(void) {
// Check if all of the USB transports are connected. // Check if all of the USB transports are connected.
bool iterate_transports(std::function<bool(const atransport*)> fn) { bool iterate_transports(std::function<bool(const atransport*)> fn) {
std::lock_guard<std::mutex> lock(transport_lock); std::lock_guard<std::recursive_mutex> lock(transport_lock);
for (const auto& t : transport_list) { for (const auto& t : transport_list) {
if (!fn(t)) { if (!fn(t)) {
return false; return false;
@ -507,7 +517,7 @@ static void transport_registration_func(int _fd, unsigned ev, void* data) {
adb_close(t->fd); adb_close(t->fd);
{ {
std::lock_guard<std::mutex> lock(transport_lock); std::lock_guard<std::recursive_mutex> lock(transport_lock);
transport_list.remove(t); transport_list.remove(t);
} }
@ -546,7 +556,7 @@ static void transport_registration_func(int _fd, unsigned ev, void* data) {
} }
{ {
std::lock_guard<std::mutex> lock(transport_lock); std::lock_guard<std::recursive_mutex> lock(transport_lock);
pending_list.remove(t); pending_list.remove(t);
transport_list.push_front(t); transport_list.push_front(t);
} }
@ -573,7 +583,7 @@ void init_transport_registration(void) {
void kick_all_transports() { void kick_all_transports() {
// To avoid only writing part of a packet to a transport after exit, kick all transports. // To avoid only writing part of a packet to a transport after exit, kick all transports.
std::lock_guard<std::mutex> lock(transport_lock); std::lock_guard<std::recursive_mutex> lock(transport_lock);
for (auto t : transport_list) { for (auto t : transport_list) {
t->Kick(); t->Kick();
} }
@ -603,15 +613,15 @@ static void remove_transport(atransport* transport) {
static void transport_unref(atransport* t) { static void transport_unref(atransport* t) {
CHECK(t != nullptr); CHECK(t != nullptr);
size_t old_refcount = t->ref_count--; std::lock_guard<std::recursive_mutex> lock(transport_lock);
CHECK_GT(old_refcount, 0u); CHECK_GT(t->ref_count, 0u);
t->ref_count--;
if (old_refcount == 1u) { if (t->ref_count == 0) {
D("transport: %s unref (kicking and closing)", t->serial); D("transport: %s unref (kicking and closing)", t->serial);
t->close(t); t->close(t);
remove_transport(t); remove_transport(t);
} else { } else {
D("transport: %s unref (count=%zu)", t->serial, old_refcount - 1); D("transport: %s unref (count=%zu)", t->serial, t->ref_count);
} }
} }
@ -638,11 +648,15 @@ static int qual_match(const char* to_test, const char* prefix, const char* qual,
return !*to_test; return !*to_test;
} }
atransport* acquire_one_transport(TransportType type, const char* serial, bool* is_ambiguous, atransport* acquire_one_transport(TransportType type, const char* serial, TransportId transport_id,
std::string* error_out, bool accept_any_state) { bool* is_ambiguous, std::string* error_out,
bool accept_any_state) {
atransport* result = nullptr; atransport* result = nullptr;
if (serial) { if (transport_id != 0) {
*error_out =
android::base::StringPrintf("no device with transport id '%" PRIu64 "'", transport_id);
} else if (serial) {
*error_out = android::base::StringPrintf("device '%s' not found", serial); *error_out = android::base::StringPrintf("device '%s' not found", serial);
} else if (type == kTransportLocal) { } else if (type == kTransportLocal) {
*error_out = "no emulators found"; *error_out = "no emulators found";
@ -652,7 +666,7 @@ atransport* acquire_one_transport(TransportType type, const char* serial, bool*
*error_out = "no devices found"; *error_out = "no devices found";
} }
std::unique_lock<std::mutex> lock(transport_lock); std::unique_lock<std::recursive_mutex> lock(transport_lock);
for (const auto& t : transport_list) { for (const auto& t : transport_list) {
if (t->GetConnectionState() == kCsNoPerm) { if (t->GetConnectionState() == kCsNoPerm) {
#if ADB_HOST #if ADB_HOST
@ -661,8 +675,12 @@ atransport* acquire_one_transport(TransportType type, const char* serial, bool*
continue; continue;
} }
// Check for matching serial number. if (transport_id) {
if (serial) { if (t->id == transport_id) {
result = t;
break;
}
} else if (serial) {
if (t->MatchesTarget(serial)) { if (t->MatchesTarget(serial)) {
if (result) { if (result) {
*error_out = "more than one device"; *error_out = "more than one device";
@ -889,18 +907,23 @@ bool atransport::MatchesTarget(const std::string& target) const {
#if ADB_HOST #if ADB_HOST
// We use newline as our delimiter, make sure to never output it.
static std::string sanitize(std::string str, bool alphanumeric) {
auto pred = alphanumeric ? [](const char c) { return !isalnum(c); }
: [](const char c) { return c == '\n'; };
std::replace_if(str.begin(), str.end(), pred, '_');
return str;
}
static void append_transport_info(std::string* result, const char* key, const char* value, static void append_transport_info(std::string* result, const char* key, const char* value,
bool sanitize) { bool alphanumeric) {
if (value == nullptr || *value == '\0') { if (value == nullptr || *value == '\0') {
return; return;
} }
*result += ' '; *result += ' ';
*result += key; *result += key;
*result += sanitize(value, alphanumeric);
for (const char* p = value; *p; ++p) {
result->push_back((!sanitize || isalnum(*p)) ? *p : '_');
}
} }
static void append_transport(const atransport* t, std::string* result, bool long_listing) { static void append_transport(const atransport* t, std::string* result, bool long_listing) {
@ -920,6 +943,11 @@ static void append_transport(const atransport* t, std::string* result, bool long
append_transport_info(result, "product:", t->product, false); append_transport_info(result, "product:", t->product, false);
append_transport_info(result, "model:", t->model, true); append_transport_info(result, "model:", t->model, true);
append_transport_info(result, "device:", t->device, false); append_transport_info(result, "device:", t->device, false);
// Put id at the end, so that anyone parsing the output here can always find it by scanning
// backwards from newlines, even with hypothetical devices named 'transport_id:1'.
*result += " transport_id:";
*result += std::to_string(t->id);
} }
*result += '\n'; *result += '\n';
} }
@ -927,7 +955,7 @@ static void append_transport(const atransport* t, std::string* result, bool long
std::string list_transports(bool long_listing) { std::string list_transports(bool long_listing) {
std::string result; std::string result;
std::lock_guard<std::mutex> lock(transport_lock); std::lock_guard<std::recursive_mutex> lock(transport_lock);
for (const auto& t : transport_list) { for (const auto& t : transport_list) {
append_transport(t, &result, long_listing); append_transport(t, &result, long_listing);
} }
@ -935,7 +963,7 @@ std::string list_transports(bool long_listing) {
} }
void close_usb_devices(std::function<bool(const atransport*)> predicate) { void close_usb_devices(std::function<bool(const atransport*)> predicate) {
std::lock_guard<std::mutex> lock(transport_lock); std::lock_guard<std::recursive_mutex> lock(transport_lock);
for (auto& t : transport_list) { for (auto& t : transport_list) {
if (predicate(t)) { if (predicate(t)) {
t->Kick(); t->Kick();
@ -964,7 +992,7 @@ int register_socket_transport(int s, const char* serial, int port, int local) {
return -1; return -1;
} }
std::unique_lock<std::mutex> lock(transport_lock); std::unique_lock<std::recursive_mutex> lock(transport_lock);
for (const auto& transport : pending_list) { for (const auto& transport : pending_list) {
if (transport->serial && strcmp(serial, transport->serial) == 0) { if (transport->serial && strcmp(serial, transport->serial) == 0) {
VLOG(TRANSPORT) << "socket transport " << transport->serial VLOG(TRANSPORT) << "socket transport " << transport->serial
@ -996,7 +1024,7 @@ int register_socket_transport(int s, const char* serial, int port, int local) {
atransport* find_transport(const char* serial) { atransport* find_transport(const char* serial) {
atransport* result = nullptr; atransport* result = nullptr;
std::lock_guard<std::mutex> lock(transport_lock); std::lock_guard<std::recursive_mutex> lock(transport_lock);
for (auto& t : transport_list) { for (auto& t : transport_list) {
if (t->serial && strcmp(serial, t->serial) == 0) { if (t->serial && strcmp(serial, t->serial) == 0) {
result = t; result = t;
@ -1008,7 +1036,7 @@ atransport* find_transport(const char* serial) {
} }
void kick_all_tcp_devices() { void kick_all_tcp_devices() {
std::lock_guard<std::mutex> lock(transport_lock); std::lock_guard<std::recursive_mutex> lock(transport_lock);
for (auto& t : transport_list) { for (auto& t : transport_list) {
if (t->IsTcpDevice()) { if (t->IsTcpDevice()) {
// Kicking breaks the read_transport thread of this transport out of any read, then // Kicking breaks the read_transport thread of this transport out of any read, then
@ -1037,7 +1065,7 @@ void register_usb_transport(usb_handle* usb, const char* serial, const char* dev
} }
{ {
std::lock_guard<std::mutex> lock(transport_lock); std::lock_guard<std::recursive_mutex> lock(transport_lock);
pending_list.push_front(t); pending_list.push_front(t);
} }
@ -1046,7 +1074,7 @@ void register_usb_transport(usb_handle* usb, const char* serial, const char* dev
// This should only be used for transports with connection_state == kCsNoPerm. // This should only be used for transports with connection_state == kCsNoPerm.
void unregister_usb_transport(usb_handle* usb) { void unregister_usb_transport(usb_handle* usb) {
std::lock_guard<std::mutex> lock(transport_lock); std::lock_guard<std::recursive_mutex> lock(transport_lock);
transport_list.remove_if( transport_list.remove_if(
[usb](atransport* t) { return t->usb == usb && t->GetConnectionState() == kCsNoPerm; }); [usb](atransport* t) { return t->usb == usb && t->GetConnectionState() == kCsNoPerm; });
} }

View file

@ -54,14 +54,17 @@ extern const char* const kFeatureLibusb;
// The server supports `push --sync`. // The server supports `push --sync`.
extern const char* const kFeaturePushSync; extern const char* const kFeaturePushSync;
TransportId NextTransportId();
class atransport { class atransport {
public: public:
// TODO(danalbert): We expose waaaaaaay too much stuff because this was // TODO(danalbert): We expose waaaaaaay too much stuff because this was
// historically just a struct, but making the whole thing a more idiomatic // historically just a struct, but making the whole thing a more idiomatic
// class in one go is a very large change. Given how bad our testing is, // class in one go is a very large change. Given how bad our testing is,
// it's better to do this piece by piece. // it's better to do this piece by piece.
atransport(ConnectionState state = kCsOffline) : ref_count(0), connection_state_(state) { atransport(ConnectionState state = kCsOffline)
: id(NextTransportId()), connection_state_(state) {
transport_fde = {}; transport_fde = {};
protocol_version = A_VERSION; protocol_version = A_VERSION;
max_payload = MAX_PAYLOAD; max_payload = MAX_PAYLOAD;
@ -72,12 +75,8 @@ public:
void (*close)(atransport* t) = nullptr; void (*close)(atransport* t) = nullptr;
void SetWriteFunction(int (*write_func)(apacket*, atransport*)) { write_func_ = write_func; } void SetWriteFunction(int (*write_func)(apacket*, atransport*)) { write_func_ = write_func; }
void SetKickFunction(void (*kick_func)(atransport*)) { void SetKickFunction(void (*kick_func)(atransport*)) { kick_func_ = kick_func; }
kick_func_ = kick_func; bool IsKicked() { return kicked_; }
}
bool IsKicked() {
return kicked_;
}
int Write(apacket* p); int Write(apacket* p);
void Kick(); void Kick();
@ -85,10 +84,11 @@ public:
ConnectionState GetConnectionState() const; ConnectionState GetConnectionState() const;
void SetConnectionState(ConnectionState state); void SetConnectionState(ConnectionState state);
const TransportId id;
int fd = -1; int fd = -1;
int transport_socket = -1; int transport_socket = -1;
fdevent transport_fde; fdevent transport_fde;
std::atomic<size_t> ref_count; size_t ref_count = 0;
uint32_t sync_token = 0; uint32_t sync_token = 0;
bool online = false; bool online = false;
TransportType type = kTransportAny; TransportType type = kTransportAny;
@ -191,12 +191,14 @@ private:
/* /*
* Obtain a transport from the available transports. * Obtain a transport from the available transports.
* If serial is non-null then only the device with that serial will be chosen. * If serial is non-null then only the device with that serial will be chosen.
* If transport_id is non-zero then only the device with that transport ID will be chosen.
* If multiple devices/emulators would match, *is_ambiguous (if non-null) * If multiple devices/emulators would match, *is_ambiguous (if non-null)
* is set to true and nullptr returned. * is set to true and nullptr returned.
* If no suitable transport is found, error is set and nullptr returned. * If no suitable transport is found, error is set and nullptr returned.
*/ */
atransport* acquire_one_transport(TransportType type, const char* serial, bool* is_ambiguous, atransport* acquire_one_transport(TransportType type, const char* serial, TransportId transport_id,
std::string* error_out, bool accept_any_state = false); bool* is_ambiguous, std::string* error_out,
bool accept_any_state = false);
void kick_transport(atransport* t); void kick_transport(atransport* t);
void update_transports(void); void update_transports(void);