adb: allow selection of a specific transport.

Extend device selection to allow selecting a specific transport via
monotonically increasing identifier (visible in devices -l).

This is useful when using multiple devices (like hikey960...) that
have identical bogus serial numbers like 0123456789ABCDEF.

Bug: http://b/37043226
Test: adb -t {1, 2, 9999999} {get-serialno, shell, features}
Change-Id: I55e5dc5a406a4eeee0012e39b52e8cd232e608a6
This commit is contained in:
Josh Gao 2017-08-16 16:57:01 -07:00
parent 11be3e54bd
commit b122b17555
13 changed files with 290 additions and 210 deletions

View file

@ -956,8 +956,8 @@ int launch_server(const std::string& socket_spec) {
// Try to handle a network forwarding request.
// This returns 1 on success, 0 on failure, and -1 to indicate this is not
// 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")) {
// Create the list of forward redirections.
std::string listeners = format_listeners();
@ -1010,7 +1010,8 @@ int handle_forward_request(const char* service, TransportType type, const char*
}
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) {
SendFail(reply_fd, error_msg);
return 1;
@ -1068,8 +1069,8 @@ static int SendOkay(int fd, const std::string& s) {
return 0;
}
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) {
if (strcmp(service, "kill") == 0) {
fprintf(stderr, "adb server killed by remote request\n");
fflush(stdout);
@ -1089,7 +1090,14 @@ int handle_host_request(const char* service, TransportType type,
if (!strncmp(service, "transport", strlen("transport"))) {
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;
} else if (!strncmp(service, "transport-local", strlen("transport-local"))) {
type = kTransportLocal;
@ -1101,7 +1109,7 @@ int handle_host_request(const char* service, TransportType type,
}
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) {
s->transport = t;
SendOkay(reply_fd);
@ -1144,7 +1152,7 @@ int handle_host_request(const char* service, TransportType type,
if (!strcmp(service, "features")) {
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) {
SendOkay(reply_fd, FeatureSetToString(t->features()));
} 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.
if (!strcmp(service, "get-serialno")) {
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) {
return SendOkay(reply_fd, t->serial ? t->serial : "unknown");
} else {
@ -1206,7 +1214,7 @@ int handle_host_request(const char* service, TransportType type,
}
if (!strcmp(service, "get-devpath")) {
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) {
return SendOkay(reply_fd, t->devpath ? t->devpath : "unknown");
} else {
@ -1215,7 +1223,7 @@ int handle_host_request(const char* service, TransportType type,
}
if (!strcmp(service, "get-state")) {
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) {
return SendOkay(reply_fd, t->connection_state_name());
} else {
@ -1233,7 +1241,7 @@ int handle_host_request(const char* service, TransportType type,
if (!strcmp(service, "reconnect")) {
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) {
kick_transport(t);
response =
@ -1242,7 +1250,7 @@ int handle_host_request(const char* service, TransportType type,
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)
return ret - 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.
#define ADB_SERVER_VERSION 39
using TransportId = uint64_t;
class atransport;
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);
#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
#if !ADB_HOST
@ -159,7 +160,8 @@ asocket* create_jdwp_tracker_service_socket();
int create_jdwp_connection_fd(int jdwp_pid);
#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
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)
#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_offline(atransport *t);

View file

@ -20,6 +20,7 @@
#include "adb_client.h"
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
@ -46,12 +47,20 @@
static TransportType __adb_transport = kTransportAny;
static const char* __adb_serial = NULL;
static TransportId __adb_transport_id = 0;
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_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) {
@ -63,7 +72,10 @@ void adb_set_socket_spec(const char* socket_spec) {
static int switch_socket_transport(int fd, std::string* error) {
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 += __adb_serial;
} else {
@ -292,15 +304,18 @@ bool adb_query(const std::string& service, std::string* result, std::string* err
return true;
}
std::string format_host_command(const char* command, TransportType type, const char* serial) {
if (serial) {
return android::base::StringPrintf("host-serial:%s:%s", serial, command);
std::string format_host_command(const char* command) {
if (__adb_transport_id) {
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";
if (type == kTransportUsb) {
if (__adb_transport == kTransportUsb) {
prefix = "host-usb";
} else if (type == kTransportLocal) {
} else if (__adb_transport == kTransportLocal) {
prefix = "host-local";
}
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) {
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);
return true;
}

View file

@ -40,7 +40,9 @@ bool adb_query(const std::string& service, std::string* _Nonnull result,
std::string* _Nonnull error);
// 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.
// 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);
// Create a host command corresponding to selected transport type/serial.
std::string format_host_command(const char* _Nonnull command, TransportType type,
const char* _Nullable serial);
std::string format_host_command(const char* _Nonnull command);
// Get the feature set of the current preferred transport.
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);
};
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]");
// Gets bugreportz version.
std::string 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_output = android::base::Trim(bugz_stdout);
@ -214,7 +214,7 @@ int Bugreport::DoIt(TransportType transport_type, const char* serial, int argc,
fprintf(stderr,
"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");
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
@ -265,7 +265,7 @@ int Bugreport::DoIt(TransportType transport_type, const char* serial, int argc,
bugz_command = "bugreportz";
}
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) {
@ -274,10 +274,9 @@ void Bugreport::UpdateProgress(const std::string& message, int progress_percenta
LinePrinter::INFO);
}
int Bugreport::SendShellCommand(TransportType transport_type, const char* serial,
const std::string& command, bool disable_shell_protocol,
int Bugreport::SendShellCommand(const std::string& command, bool disable_shell_protocol,
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,

View file

@ -29,14 +29,13 @@ class Bugreport {
public:
Bugreport() : line_printer_() {
}
int DoIt(TransportType transport_type, const char* serial, int argc, const char** argv);
int DoIt(int argc, const char** argv);
protected:
// Functions below are abstractions of external functions so they can be
// mocked on tests.
virtual int SendShellCommand(
TransportType transport_type, const char* serial, const std::string& command,
bool disable_shell_protocol,
const std::string& command, bool disable_shell_protocol,
StandardStreamsCallbackInterface* callback = &DEFAULT_STANDARD_STREAMS_CALLBACK);
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
DefaultStandardStreamsCallback DEFAULT_STANDARD_STREAMS_CALLBACK(nullptr, nullptr);
int send_shell_command(TransportType transport_type, const char* serial, const std::string& command,
bool disable_shell_protocol, StandardStreamsCallbackInterface* callback) {
int send_shell_command(const std::string& command, bool disable_shell_protocol,
StandardStreamsCallbackInterface* callback) {
ADD_FAILURE() << "send_shell_command() should have been mocked";
return -42;
}
@ -62,7 +62,7 @@ enum StreamType {
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*);
class OnStandardStreamsCallbackAction : public ActionInterface<OnStandardStreamsCallbackFunction> {
@ -118,9 +118,8 @@ Action<CallbackDoneFunction> ReturnCallbackDone(int status = -1337) {
class BugreportMock : public Bugreport {
public:
MOCK_METHOD5(SendShellCommand,
int(TransportType transport_type, const char* serial, const std::string& command,
bool disable_shell_protocol, StandardStreamsCallbackInterface* callback));
MOCK_METHOD3(SendShellCommand, int(const std::string& command, bool disable_shell_protocol,
StandardStreamsCallbackInterface* callback));
MOCK_METHOD4(DoSyncPull, bool(const std::vector<const char*>& srcs, const char* dst,
bool copy_attrs, const char* name));
MOCK_METHOD2(UpdateProgress, void(const std::string&, int));
@ -136,10 +135,9 @@ class BugreportTest : public ::testing::Test {
}
void ExpectBugreportzVersion(const std::string& version) {
EXPECT_CALL(br_,
SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -v", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStderr(version.c_str())),
WithArg<4>(ReturnCallbackDone(0))));
EXPECT_CALL(br_, SendShellCommand("bugreportz -v", false, _))
.WillOnce(DoAll(WithArg<2>(WriteOnStderr(version.c_str())),
WithArg<2>(ReturnCallbackDone(0))));
}
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
TEST_F(BugreportTest, InvalidNumberArgs) {
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
// to the flat-file format ('bugreport' binary on device)
TEST_F(BugreportTest, NoArgumentsPreNDevice) {
// clang-format off
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -v", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStderr("")),
EXPECT_CALL(br_, SendShellCommand("bugreportz -v", false, _))
.WillOnce(DoAll(WithArg<2>(WriteOnStderr("")),
// Write some bogus output on stdout to make sure it's ignored
WithArg<4>(WriteOnStdout("Dude, where is my bugreportz?")),
WithArg<4>(ReturnCallbackDone(0))));
WithArg<2>(WriteOnStdout("Dude, where is my bugreportz?")),
WithArg<2>(ReturnCallbackDone(0))));
// clang-format on
std::string bugreport = "Reported the bug was.";
CaptureStdout();
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreport", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStdout(bugreport)), Return(0)));
EXPECT_CALL(br_, SendShellCommand("bugreport", false, _))
.WillOnce(DoAll(WithArg<2>(WriteOnStdout(bugreport)), Return(0)));
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));
}
@ -183,15 +181,15 @@ TEST_F(BugreportTest, NoArgumentsNDevice) {
std::string dest_file =
android::base::StringPrintf("%s%cda_bugreport.zip", cwd_.c_str(), OS_PATH_SEPARATOR);
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device/da_bugreport.zip")),
WithArg<4>(ReturnCallbackDone())));
EXPECT_CALL(br_, SendShellCommand("bugreportz", false, _))
.WillOnce(DoAll(WithArg<2>(WriteOnStdout("OK:/device/da_bugreport.zip")),
WithArg<2>(ReturnCallbackDone())));
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
true, StrEq("pulling da_bugreport.zip")))
.WillOnce(Return(true));
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
@ -201,47 +199,47 @@ TEST_F(BugreportTest, NoArgumentsPostNDevice) {
std::string dest_file =
android::base::StringPrintf("%s%cda_bugreport.zip", cwd_.c_str(), OS_PATH_SEPARATOR);
ExpectProgress(50, "da_bugreport.zip");
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStdout("BEGIN:/device/da_bugreport.zip\n")),
WithArg<4>(WriteOnStdout("PROGRESS:50/100\n")),
WithArg<4>(WriteOnStdout("OK:/device/da_bugreport.zip\n")),
WithArg<4>(ReturnCallbackDone())));
EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
.WillOnce(DoAll(WithArg<2>(WriteOnStdout("BEGIN:/device/da_bugreport.zip\n")),
WithArg<2>(WriteOnStdout("PROGRESS:50/100\n")),
WithArg<2>(WriteOnStdout("OK:/device/da_bugreport.zip\n")),
WithArg<2>(ReturnCallbackDone())));
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
true, StrEq("pulling da_bugreport.zip")))
.WillOnce(Return(true));
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.
TEST_F(BugreportTest, OkNDevice) {
ExpectBugreportzVersion("1.0");
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device/bugreport.zip")),
WithArg<4>(ReturnCallbackDone())));
EXPECT_CALL(br_, SendShellCommand("bugreportz", false, _))
.WillOnce(DoAll(WithArg<2>(WriteOnStdout("OK:/device/bugreport.zip")),
WithArg<2>(ReturnCallbackDone())));
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
true, StrEq("pulling file.zip")))
.WillOnce(Return(true));
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
// multiple buffer writers and without progress updates.
TEST_F(BugreportTest, OkNDeviceSplitBuffer) {
ExpectBugreportzVersion("1.0");
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device")),
WithArg<4>(WriteOnStdout("/bugreport.zip")),
WithArg<4>(ReturnCallbackDone())));
EXPECT_CALL(br_, SendShellCommand("bugreportz", false, _))
.WillOnce(DoAll(WithArg<2>(WriteOnStdout("OK:/device")),
WithArg<2>(WriteOnStdout("/bugreport.zip")),
WithArg<2>(ReturnCallbackDone())));
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
true, StrEq("pulling file.zip")))
.WillOnce(Return(true));
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.
@ -252,32 +250,32 @@ TEST_F(BugreportTest, OkProgress) {
ExpectProgress(50);
ExpectProgress(99);
// 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...
.WillOnce(DoAll(
// 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
WithArg<4>(WriteOnStdout("PROGRESS:1/100\n")),
WithArg<2>(WriteOnStdout("PROGRESS:1/100\n")),
// 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
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
WithArg<4>(WriteOnStdout("PROG")),
WithArg<4>(WriteOnStdout("RESS:99")),
WithArg<4>(WriteOnStdout("/100\n")),
WithArg<2>(WriteOnStdout("PROG")),
WithArg<2>(WriteOnStdout("RESS:99")),
WithArg<2>(WriteOnStdout("/100\n")),
// Split last message as well, just in case
WithArg<4>(WriteOnStdout("OK:/device/bugreport")),
WithArg<4>(WriteOnStdout(".zip")),
WithArg<4>(ReturnCallbackDone())));
WithArg<2>(WriteOnStdout("OK:/device/bugreport")),
WithArg<2>(WriteOnStdout(".zip")),
WithArg<2>(ReturnCallbackDone())));
// clang-format on
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
true, StrEq("pulling file.zip")))
.WillOnce(Return(true));
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.
@ -287,28 +285,28 @@ TEST_F(BugreportTest, OkProgressAlwaysForward) {
ExpectProgress(50);
ExpectProgress(75);
// 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...
.WillOnce(DoAll(
WithArg<4>(WriteOnStdout("BEGIN:/device/bugreport.zip\n")),
WithArg<4>(WriteOnStdout("PROGRESS:1/100\n")), // 1%
WithArg<4>(WriteOnStdout("PROGRESS:50/100\n")), // 50%
WithArg<2>(WriteOnStdout("BEGIN:/device/bugreport.zip\n")),
WithArg<2>(WriteOnStdout("PROGRESS:1/100\n")), // 1%
WithArg<2>(WriteOnStdout("PROGRESS:50/100\n")), // 50%
// 25% should be ignored becaused it receded.
WithArg<4>(WriteOnStdout("PROGRESS:25/100\n")), // 25%
WithArg<4>(WriteOnStdout("PROGRESS:75/100\n")), // 75%
WithArg<2>(WriteOnStdout("PROGRESS:25/100\n")), // 25%
WithArg<2>(WriteOnStdout("PROGRESS:75/100\n")), // 75%
// 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
WithArg<4>(WriteOnStdout("PROGRESS:700/1000\n")), // 70%
WithArg<4>(WriteOnStdout("OK:/device/bugreport.zip")),
WithArg<4>(ReturnCallbackDone())));
WithArg<2>(WriteOnStdout("PROGRESS:700/1000\n")), // 70%
WithArg<2>(WriteOnStdout("OK:/device/bugreport.zip")),
WithArg<2>(ReturnCallbackDone())));
// clang-format on
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
true, StrEq("pulling file.zip")))
.WillOnce(Return(true));
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%
@ -317,21 +315,21 @@ TEST_F(BugreportTest, OkProgressZeroPercentIsNotIgnored) {
ExpectProgress(0);
ExpectProgress(1);
// 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...
.WillOnce(DoAll(
WithArg<4>(WriteOnStdout("BEGIN:/device/bugreport.zip\n")),
WithArg<4>(WriteOnStdout("PROGRESS:1/100000\n")),
WithArg<4>(WriteOnStdout("PROGRESS:1/100\n")), // 1%
WithArg<4>(WriteOnStdout("OK:/device/bugreport.zip")),
WithArg<4>(ReturnCallbackDone())));
WithArg<2>(WriteOnStdout("BEGIN:/device/bugreport.zip\n")),
WithArg<2>(WriteOnStdout("PROGRESS:1/100000\n")),
WithArg<2>(WriteOnStdout("PROGRESS:1/100\n")), // 1%
WithArg<2>(WriteOnStdout("OK:/device/bugreport.zip")),
WithArg<2>(ReturnCallbackDone())));
// clang-format on
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
true, StrEq("pulling file.zip")))
.WillOnce(Return(true));
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.
@ -341,30 +339,30 @@ TEST_F(BugreportTest, OkDirectory) {
std::string dest_file =
android::base::StringPrintf("%s%cda_bugreport.zip", td.path, OS_PATH_SEPARATOR);
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStdout("BEGIN:/device/da_bugreport.zip\n")),
WithArg<4>(WriteOnStdout("OK:/device/da_bugreport.zip")),
WithArg<4>(ReturnCallbackDone())));
EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
.WillOnce(DoAll(WithArg<2>(WriteOnStdout("BEGIN:/device/da_bugreport.zip\n")),
WithArg<2>(WriteOnStdout("OK:/device/da_bugreport.zip")),
WithArg<2>(ReturnCallbackDone())));
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
true, StrEq("pulling da_bugreport.zip")))
.WillOnce(Return(true));
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
TEST_F(BugreportTest, OkNoExtension) {
ExpectBugreportzVersion("1.1");
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device/bugreport.zip\n")),
WithArg<4>(ReturnCallbackDone())));
EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
.WillOnce(DoAll(WithArg<2>(WriteOnStdout("OK:/device/bugreport.zip\n")),
WithArg<2>(ReturnCallbackDone())));
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
true, StrEq("pulling file.zip")))
.WillOnce(Return(true));
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.
@ -374,28 +372,28 @@ TEST_F(BugreportTest, OkNDeviceDirectory) {
std::string dest_file =
android::base::StringPrintf("%s%cda_bugreport.zip", td.path, OS_PATH_SEPARATOR);
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStdout("BEGIN:/device/da_bugreport.zip\n")),
WithArg<4>(WriteOnStdout("OK:/device/da_bugreport.zip")),
WithArg<4>(ReturnCallbackDone())));
EXPECT_CALL(br_, SendShellCommand("bugreportz", false, _))
.WillOnce(DoAll(WithArg<2>(WriteOnStdout("BEGIN:/device/da_bugreport.zip\n")),
WithArg<2>(WriteOnStdout("OK:/device/da_bugreport.zip")),
WithArg<2>(ReturnCallbackDone())));
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file),
true, StrEq("pulling da_bugreport.zip")))
.WillOnce(Return(true));
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
TEST_F(BugreportTest, BugreportzReturnedFail) {
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:D'OH!\n")), WithArg<4>(ReturnCallbackDone())));
DoAll(WithArg<2>(WriteOnStdout("FAIL:D'OH!\n")), WithArg<2>(ReturnCallbackDone())));
CaptureStderr();
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!"));
}
@ -404,13 +402,13 @@ TEST_F(BugreportTest, BugreportzReturnedFail) {
// multiple buffer writes
TEST_F(BugreportTest, BugreportzReturnedFailSplitBuffer) {
ExpectBugreportzVersion("1.1");
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStdout("FAIL")), WithArg<4>(WriteOnStdout(":D'OH!\n")),
WithArg<4>(ReturnCallbackDone())));
EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
.WillOnce(DoAll(WithArg<2>(WriteOnStdout("FAIL")), WithArg<2>(WriteOnStdout(":D'OH!\n")),
WithArg<2>(ReturnCallbackDone())));
CaptureStderr();
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!"));
}
@ -418,23 +416,22 @@ TEST_F(BugreportTest, BugreportzReturnedFailSplitBuffer) {
// response.
TEST_F(BugreportTest, BugreportzReturnedUnsupported) {
ExpectBugreportzVersion("1.1");
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStdout("bugreportz? What am I, a zombie?")),
WithArg<4>(ReturnCallbackDone())));
EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
.WillOnce(DoAll(WithArg<2>(WriteOnStdout("bugreportz? What am I, a zombie?")),
WithArg<2>(ReturnCallbackDone())));
CaptureStderr();
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?"));
}
// Tests 'adb bugreport file.zip' when the bugreportz -v command failed
TEST_F(BugreportTest, BugreportzVersionFailed) {
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -v", false, _))
.WillOnce(Return(666));
EXPECT_CALL(br_, SendShellCommand("bugreportz -v", false, _)).WillOnce(Return(666));
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.
@ -442,29 +439,28 @@ TEST_F(BugreportTest, BugreportzVersionEmpty) {
ExpectBugreportzVersion("");
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
TEST_F(BugreportTest, BugreportzFailed) {
ExpectBugreportzVersion("1.1");
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _))
.WillOnce(Return(666));
EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _)).WillOnce(Return(666));
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
TEST_F(BugreportTest, PullFails) {
ExpectBugreportzVersion("1.1");
EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _))
.WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device/bugreport.zip")),
WithArg<4>(ReturnCallbackDone())));
EXPECT_CALL(br_, SendShellCommand("bugreportz -p", false, _))
.WillOnce(DoAll(WithArg<2>(WriteOnStdout("OK:/device/bugreport.zip")),
WithArg<2>(ReturnCallbackDone())));
EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"),
true, HasSubstr("file.zip")))
.WillOnce(Return(false));
const char* args[] = {"bugreport", "file.zip"};
ASSERT_EQ(1, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args));
ASSERT_EQ(1, br_.DoIt(2, args));
}

View file

@ -62,11 +62,11 @@
#include "shell_service.h"
#include "sysdeps/chrono.h"
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 int install_app(int argc, const char** argv);
static int install_multiple_app(int argc, const char** argv);
static int uninstall_app(int argc, const char** argv);
static int install_app_legacy(int argc, const char** argv);
static int uninstall_app_legacy(int argc, const char** argv);
extern int gListenAll;
@ -90,6 +90,7 @@ static void help() {
" -d use USB device (error if multiple devices connected)\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"
" -t ID use device with given transport id\n"
" -H name of adb server host [default=localhost]\n"
" -P port of adb server [default=5037]\n"
" -L SOCKET listen on given socket for adb server [default=tcp:localhost:5037]\n"
@ -990,13 +991,16 @@ static int ppp(int argc, const char** argv) {
#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, "-");
if (components.size() < 3 || components.size() > 4) {
fprintf(stderr, "adb: couldn't parse 'wait-for' command: %s\n", service);
return false;
}
TransportType t;
adb_get_transport(&t, nullptr, nullptr);
// 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 (components.size() == 3) {
@ -1023,7 +1027,7 @@ static bool wait_for_device(const char* service, TransportType t, const char* se
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);
}
@ -1069,8 +1073,8 @@ static bool adb_root(const char* command) {
return true;
}
int send_shell_command(TransportType transport_type, const char* serial, const std::string& command,
bool disable_shell_protocol, StandardStreamsCallbackInterface* callback) {
int send_shell_command(const std::string& command, bool disable_shell_protocol,
StandardStreamsCallbackInterface* callback) {
int fd;
bool use_shell_protocol = false;
@ -1101,7 +1105,7 @@ int send_shell_command(TransportType transport_type, const char* serial, const s
}
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;
}
}
@ -1115,7 +1119,7 @@ int send_shell_command(TransportType transport_type, const char* serial, const s
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");
std::string quoted = escape_arg(log_tags == nullptr ? "" : log_tags);
@ -1132,7 +1136,7 @@ static int logcat(TransportType transport, const char* serial, int argc, const c
}
// 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) {
@ -1344,6 +1348,7 @@ int adb_commandline(int argc, const char** argv) {
// We need to check for -d and -e before we look at $ANDROID_SERIAL.
const char* serial = nullptr;
TransportId transport_id = 0;
while (argc > 0) {
if (!strcmp(argv[0],"server")) {
@ -1363,7 +1368,7 @@ int adb_commandline(int argc, const char** argv) {
fprintf(stderr, "adb: invalid reply fd \"%s\"\n", reply_fd_str);
return 1;
}
} else if (argv[0][0]=='-' && argv[0][1]=='s') {
} else if (!strncmp(argv[0], "-s", 2)) {
if (isdigit(argv[0][2])) {
serial = argv[0] + 2;
} else {
@ -1372,6 +1377,19 @@ int adb_commandline(int argc, const char** argv) {
argc--;
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")) {
transport_type = kTransportUsb;
} else if (!strcmp(argv[0],"-e")) {
@ -1455,7 +1473,7 @@ int adb_commandline(int argc, const char** argv) {
serial = getenv("ANDROID_SERIAL");
}
adb_set_transport(transport_type, serial);
adb_set_transport(transport_type, serial, transport_id);
if (is_server) {
if (no_daemon || is_daemon) {
@ -1482,7 +1500,7 @@ int adb_commandline(int argc, const char** argv) {
if (!strncmp(argv[0], "wait-for-", strlen("wait-for-"))) {
const char* service = argv[0];
if (!wait_for_device(service, transport_type, serial)) {
if (!wait_for_device(service)) {
return 1;
}
@ -1593,7 +1611,7 @@ int adb_commandline(int argc, const char** argv) {
return adb_root(argv[0]) ? 0 : 1;
} else if (!strcmp(argv[0], "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")) {
bool reverse = !strcmp(argv[0], "reverse");
++argv;
@ -1689,20 +1707,20 @@ int adb_commandline(int argc, const char** argv) {
else if (!strcmp(argv[0], "install")) {
if (argc < 2) return syntax_error("install requires an argument");
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")) {
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")) {
if (argc < 2) return syntax_error("uninstall requires an argument");
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")) {
std::string src;
@ -1756,11 +1774,11 @@ int adb_commandline(int argc, const char** argv) {
!strcmp(argv[0],"get-serialno") ||
!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 */
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")) {
return ppp(argc, argv);
@ -1823,7 +1841,7 @@ int adb_commandline(int argc, const char** argv) {
return adb_query_command("host:host-features");
} else if (!strcmp(argv[0], "reconnect")) {
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) {
if (!strcmp(argv[1], "device")) {
std::string err;
@ -1842,7 +1860,7 @@ int adb_commandline(int argc, const char** argv) {
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
std::string cmd = "cmd package";
while (argc-- > 0) {
@ -1858,10 +1876,10 @@ static int uninstall_app(TransportType transport, const char* serial, int argc,
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
const char* file = argv[argc - 1];
if (!android::base::EndsWithIgnoreCase(file, ".apk")) {
@ -1914,9 +1932,7 @@ static int install_app(TransportType transport, const char* serial, int argc, co
return 1;
}
static int install_multiple_app(TransportType transport, const char* serial, int argc,
const char** argv)
{
static int install_multiple_app(int argc, const char** argv) {
// Find all APK arguments starting at end.
// All other arguments passed through verbatim.
int first_apk = -1;
@ -2041,17 +2057,17 @@ finalize_session:
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";
while (argc-- > 0) {
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
out with the option to uninstall the remaining data somehow (adb/ui) */
int i;
@ -2067,15 +2083,15 @@ static int uninstall_app_legacy(TransportType transport, const char* serial, int
}
/* '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);
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 SD_DEST = "/sdcard/tmp/%s";
const char* where = DATA_DEST;
@ -2104,9 +2120,9 @@ static int install_app_legacy(TransportType transport, const char* serial, int a
where, android::base::Basename(argv[last_apk]).c_str());
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 */
result = pm_command(transport, serial, argc, argv);
result = pm_command(argc, argv);
cleanup_apk:
delete_file(transport, serial, apk_dest);
delete_file(apk_dest);
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
// resulting output.
// 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,
bool disable_shell_protocol, StandardStreamsCallbackInterface* callback =
&DEFAULT_STANDARD_STREAMS_CALLBACK);
int send_shell_command(
const std::string& command, bool disable_shell_protocol,
StandardStreamsCallbackInterface* callback = &DEFAULT_STANDARD_STREAMS_CALLBACK);
#endif // COMMANDLINE_H

View file

@ -187,7 +187,7 @@ int reverse_service(const char* command) {
return -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");
}
adb_close(s[1]);
@ -334,6 +334,7 @@ int service_to_fd(const char* name, const atransport* transport) {
struct state_info {
TransportType transport_type;
std::string serial;
TransportId transport_id;
ConnectionState state;
};
@ -346,7 +347,8 @@ static void wait_for_state(int fd, void* data) {
bool is_ambiguous = false;
std::string error = "unknown error";
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())) {
SendOkay(fd);
break;
@ -437,7 +439,7 @@ static void connect_service(int fd, void* data) {
#endif
#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")) {
return create_device_tracker();
} 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;
sinfo->transport_id = transport_id;
if (android::base::StartsWith(name, "local")) {
name += strlen("local");

View file

@ -430,10 +430,11 @@ asocket* create_local_service_socket(const char* name, const atransport* transpo
}
#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;
s = host_service_to_socket(name, serial);
s = host_service_to_socket(name, serial, transport_id);
if (s != NULL) {
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
char* service = nullptr;
char* serial = nullptr;
TransportId transport_id = 0;
TransportType type = kTransportAny;
#endif
@ -715,6 +717,14 @@ static int smart_socket_enqueue(asocket* s, apacket* p) {
serial = service;
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:"))) {
type = kTransportUsb;
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
** 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? */
D("SS(%d): handled host service '%s'", s->id, service);
goto fail;
@ -751,7 +761,7 @@ static int smart_socket_enqueue(asocket* s, apacket* p) {
** if no such service exists, we'll fail out
** and tear down here.
*/
s2 = create_host_service_socket(service, serial);
s2 = create_host_service_socket(service, serial, transport_id);
if (s2 == 0) {
D("SS(%d): couldn't create host service '%s'", s->id, service);
SendFail(s->peer->fd, "unknown host service");
@ -783,7 +793,7 @@ static int smart_socket_enqueue(asocket* s, apacket* p) {
#else /* !ADB_HOST */
if (s->transport == nullptr) {
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) {
SendFail(s->peer->fd, error_msg);
goto fail;

View file

@ -21,6 +21,7 @@
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -36,6 +37,7 @@
#include <android-base/quick_exit.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/thread_annotations.h>
#include "adb.h"
#include "adb_auth.h"
@ -46,6 +48,7 @@
static void transport_unref(atransport *t);
// TODO: unordered_map<TransportId, atransport*>
static auto& transport_list = *new std::list<atransport*>();
static auto& pending_list = *new std::list<atransport*>();
@ -57,6 +60,11 @@ const char* const kFeatureStat2 = "stat_v2";
const char* const kFeatureLibusb = "libusb";
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) {
unsigned command = p->msg.command;
int len = p->msg.data_length;
@ -301,6 +309,8 @@ void kick_transport(atransport* t) {
std::lock_guard<std::recursive_mutex> lock(transport_lock);
// As kick_transport() can be called from threads without guarantee that t is valid,
// 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()) {
t->Kick();
}
@ -638,11 +648,15 @@ static int qual_match(const char* to_test, const char* prefix, const char* qual,
return !*to_test;
}
atransport* acquire_one_transport(TransportType type, const char* serial, bool* is_ambiguous,
std::string* error_out, bool accept_any_state) {
atransport* acquire_one_transport(TransportType type, const char* serial, TransportId transport_id,
bool* is_ambiguous, std::string* error_out,
bool accept_any_state) {
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);
} else if (type == kTransportLocal) {
*error_out = "no emulators found";
@ -661,8 +675,12 @@ atransport* acquire_one_transport(TransportType type, const char* serial, bool*
continue;
}
// Check for matching serial number.
if (serial) {
if (transport_id) {
if (t->id == transport_id) {
result = t;
break;
}
} else if (serial) {
if (t->MatchesTarget(serial)) {
if (result) {
*error_out = "more than one device";
@ -889,18 +907,23 @@ bool atransport::MatchesTarget(const std::string& target) const {
#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,
bool sanitize) {
bool alphanumeric) {
if (value == nullptr || *value == '\0') {
return;
}
*result += ' ';
*result += key;
for (const char* p = value; *p; ++p) {
result->push_back((!sanitize || isalnum(*p)) ? *p : '_');
}
*result += sanitize(value, alphanumeric);
}
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, "model:", t->model, true);
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';
}

View file

@ -54,14 +54,17 @@ extern const char* const kFeatureLibusb;
// The server supports `push --sync`.
extern const char* const kFeaturePushSync;
TransportId NextTransportId();
class atransport {
public:
public:
// TODO(danalbert): We expose waaaaaaay too much stuff because this was
// 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,
// 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()), ref_count(0), connection_state_(state) {
transport_fde = {};
protocol_version = A_VERSION;
max_payload = MAX_PAYLOAD;
@ -72,12 +75,8 @@ public:
void (*close)(atransport* t) = nullptr;
void SetWriteFunction(int (*write_func)(apacket*, atransport*)) { write_func_ = write_func; }
void SetKickFunction(void (*kick_func)(atransport*)) {
kick_func_ = kick_func;
}
bool IsKicked() {
return kicked_;
}
void SetKickFunction(void (*kick_func)(atransport*)) { kick_func_ = kick_func; }
bool IsKicked() { return kicked_; }
int Write(apacket* p);
void Kick();
@ -85,6 +84,7 @@ public:
ConnectionState GetConnectionState() const;
void SetConnectionState(ConnectionState state);
const TransportId id;
int fd = -1;
int transport_socket = -1;
fdevent transport_fde;
@ -191,12 +191,14 @@ private:
/*
* Obtain a transport from the available transports.
* 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)
* is set to true 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,
std::string* error_out, bool accept_any_state = false);
atransport* acquire_one_transport(TransportType type, const char* serial, TransportId transport_id,
bool* is_ambiguous, std::string* error_out,
bool accept_any_state = false);
void kick_transport(atransport* t);
void update_transports(void);