summaryrefslogtreecommitdiffstats
path: root/chrome/browser/devtools/devtools_adb_bridge.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/devtools/devtools_adb_bridge.cc')
-rw-r--r--chrome/browser/devtools/devtools_adb_bridge.cc525
1 files changed, 391 insertions, 134 deletions
diff --git a/chrome/browser/devtools/devtools_adb_bridge.cc b/chrome/browser/devtools/devtools_adb_bridge.cc
index 549116f..6879517 100644
--- a/chrome/browser/devtools/devtools_adb_bridge.cc
+++ b/chrome/browser/devtools/devtools_adb_bridge.cc
@@ -44,10 +44,13 @@ using content::BrowserThread;
namespace {
const char kDeviceModelCommand[] = "shell:getprop ro.product.model";
+const char kInstalledChromePackagesCommand[] = "shell:pm list packages";
const char kOpenedUnixSocketsCommand[] = "shell:cat /proc/net/unix";
const char kListProcessesCommand[] = "shell:ps";
const char kDumpsysCommand[] = "shell:dumpsys window policy";
const char kDumpsysScreenSizePrefix[] = "mStable=";
+const char kLaunchBrowserCommand[] =
+ "shell:am start -a android.intent.action.VIEW -n %s/%s";
const char kUnknownModel[] = "Offline";
@@ -64,7 +67,9 @@ const char kUrlParam[] = "url";
const char kPageReloadCommand[] = "Page.reload";
const char kPageNavigateCommand[] = "Page.navigate";
-const char kChromeProductName[] = "Chrome";
+const char kChromeDefaultName[] = "Chrome";
+const char kChromeDefaultActivity[] = "com.google.android.apps.chrome.Main";
+const char kChromeDefaultSocket[] = "chrome_devtools_remote";
const int kMinVersionNewWithURL = 32;
const int kNewPageNavigateDelayMs = 500;
@@ -77,6 +82,160 @@ typedef std::vector<scoped_refptr<AndroidDevice> >
AndroidDevices;
typedef base::Callback<void(const AndroidDevices&)> AndroidDevicesCallback;
+
+struct BrowserDescriptor {
+ const char* package;
+ const char* launch_activity;
+ const char* socket;
+ const char* display_name;
+};
+
+const BrowserDescriptor kBrowserDescriptors[] = {
+ {
+ "com.android.chrome",
+ kChromeDefaultActivity,
+ kChromeDefaultSocket,
+ kChromeDefaultName
+ },
+ {
+ "com.chrome.beta",
+ kChromeDefaultActivity,
+ kChromeDefaultSocket,
+ "Chrome Beta"
+ },
+ {
+ "com.google.android.apps.chrome_dev",
+ kChromeDefaultActivity,
+ kChromeDefaultSocket,
+ "Chrome Dev"
+ },
+ {
+ "com.google.android.apps.chrome",
+ kChromeDefaultActivity,
+ kChromeDefaultSocket,
+ "Chromium"
+ },
+ {
+ "org.chromium.content_shell_apk",
+ "org.chromium.content_shell_apk.ContentShellActivity",
+ "content_shell_devtools_remote",
+ "Content Shell"
+ },
+ {
+ "org.chromium.chrome.testshell",
+ "org.chromium.chrome.testshell.ChromiumTestShellActivity",
+ "chromium_testshell_devtools_remote",
+ "Chromium Test Shell"
+ },
+ {
+ "org.chromium.android_webview.shell",
+ "org.chromium.android_webview.shell.AwShellActivity",
+ "webview_devtools_remote",
+ "WebView Test Shell"
+ }
+};
+
+const BrowserDescriptor* FindBrowserDescriptor(const std::string& package) {
+ int count = sizeof(kBrowserDescriptors) / sizeof(kBrowserDescriptors[0]);
+ for (int i = 0; i < count; i++)
+ if (kBrowserDescriptors[i].package == package)
+ return &kBrowserDescriptors[i];
+ return NULL;
+}
+
+typedef std::map<std::string, const BrowserDescriptor*> DescriptorMap;
+
+static DescriptorMap FindInstalledBrowserPackages(
+ const std::string& response) {
+ // Parse 'pm list packages' output which on Android looks like this:
+ //
+ // package:com.android.chrome
+ // package:com.chrome.beta
+ // package:com.example.app
+ //
+ DescriptorMap package_to_descriptor;
+ const std::string package_prefix = "package:";
+ std::vector<std::string> entries;
+ Tokenize(response, "'\r\n", &entries);
+ for (size_t i = 0; i < entries.size(); ++i) {
+ if (entries[i].find(package_prefix) != 0)
+ continue;
+ std::string package = entries[i].substr(package_prefix.size());
+ const BrowserDescriptor* descriptor = FindBrowserDescriptor(package);
+ if (!descriptor)
+ continue;
+ package_to_descriptor[descriptor->package] = descriptor;
+ }
+ return package_to_descriptor;
+}
+
+typedef std::map<std::string, std::string> StringMap;
+
+static void MapProcessesToPackages(const std::string& response,
+ StringMap& pid_to_package,
+ StringMap& package_to_pid) {
+ // Parse 'ps' output which on Android looks like this:
+ //
+ // USER PID PPID VSIZE RSS WCHAN PC ? NAME
+ //
+ std::vector<std::string> entries;
+ Tokenize(response, "\n", &entries);
+ for (size_t i = 1; i < entries.size(); ++i) {
+ std::vector<std::string> fields;
+ Tokenize(entries[i], " \r", &fields);
+ if (fields.size() < 9)
+ continue;
+ std::string pid = fields[1];
+ std::string package = fields[8];
+ pid_to_package[pid] = package;
+ package_to_pid[package] = pid;
+ }
+}
+
+typedef std::map<std::string,
+ scoped_refptr<DevToolsAdbBridge::RemoteBrowser> > BrowserMap;
+
+static StringMap MapSocketsToProcesses(const std::string& response,
+ const std::string& channel_pattern) {
+ // Parse 'cat /proc/net/unix' output which on Android looks like this:
+ //
+ // Num RefCount Protocol Flags Type St Inode Path
+ // 00000000: 00000002 00000000 00010000 0001 01 331813 /dev/socket/zygote
+ // 00000000: 00000002 00000000 00010000 0001 01 358606 @xxx_devtools_remote
+ // 00000000: 00000002 00000000 00010000 0001 01 347300 @yyy_devtools_remote
+ //
+ // We need to find records with paths starting from '@' (abstract socket)
+ // and containing the channel pattern ("_devtools_remote").
+ StringMap socket_to_pid;
+ std::vector<std::string> entries;
+ Tokenize(response, "\n", &entries);
+ for (size_t i = 1; i < entries.size(); ++i) {
+ std::vector<std::string> fields;
+ Tokenize(entries[i], " \r", &fields);
+ if (fields.size() < 8)
+ continue;
+ if (fields[3] != "00010000" || fields[5] != "01")
+ continue;
+ std::string path_field = fields[7];
+ if (path_field.size() < 1 || path_field[0] != '@')
+ continue;
+ size_t socket_name_pos = path_field.find(channel_pattern);
+ if (socket_name_pos == std::string::npos)
+ continue;
+
+ std::string socket = path_field.substr(1);
+
+ std::string pid;
+ size_t socket_name_end = socket_name_pos + channel_pattern.size();
+ if (socket_name_end < path_field.size() &&
+ path_field[socket_name_end] == '_') {
+ pid = path_field.substr(socket_name_end + 1);
+ }
+ socket_to_pid[socket] = pid;
+ }
+ return socket_to_pid;
+}
+
// AdbPagesCommand ------------------------------------------------------------
class AdbPagesCommand : public base::RefCountedThreadSafe<
@@ -101,15 +260,38 @@ class AdbPagesCommand : public base::RefCountedThreadSafe<
void ProcessSerials();
void ReceivedModel(int result, const std::string& response);
- void ReceivedSockets(int result, const std::string& response);
void ReceivedDumpsys(int result, const std::string& response);
- void ReceivedProcesses(int result, const std::string& response);
+ void ReceivedPackages(int result, const std::string& response);
+ void ReceivedProcesses(
+ const std::string& packages_response,
+ int result,
+ const std::string& processes_response);
+ void ReceivedSockets(
+ const std::string& packages_response,
+ const std::string& processes_response,
+ int result,
+ const std::string& sockets_response);
void ProcessSockets();
void ReceivedVersion(int result, const std::string& response);
void ReceivedPages(int result, const std::string& response);
+
+ scoped_refptr<AndroidDevice> current_device() const {
+ return devices_.back();
+ }
+
+ scoped_refptr<DevToolsAdbBridge::RemoteBrowser> current_browser() const {
+ return browsers_.back();
+ }
+
+ void NextBrowser();
+ void NextDevice();
+
void Respond();
- void ParseSocketsList(const std::string& response);
- void ParseProcessList(const std::string& response);
+
+ void CreateBrowsers(const std::string& packages_response,
+ const std::string& processes_response,
+ const std::string& sockets_response);
+
void ParseDumpsysResponse(const std::string& response);
void ParseScreenSize(const std::string& str);
@@ -176,18 +358,17 @@ void AdbPagesCommand::ProcessSerials() {
return;
}
+ scoped_refptr<AndroidDevice> device = current_device();
#if defined(DEBUG_DEVTOOLS)
// For desktop remote debugging.
- if (devices_.back()->serial().empty()) {
- scoped_refptr<AndroidDevice> device =
- devices_.back();
+ if (device->serial().empty()) {
device->set_model(kLocalChrome);
remote_devices_->push_back(
new DevToolsAdbBridge::RemoteDevice(device));
scoped_refptr<DevToolsAdbBridge::RemoteBrowser> remote_browser =
new DevToolsAdbBridge::RemoteBrowser(
adb_thread_, device, std::string());
- remote_browser->set_product(kChromeProductName);
+ remote_browser->set_display_name(kChromeDefaultName);
remote_devices_->back()->AddBrowser(remote_browser);
browsers_.push_back(remote_browser);
device->HttpQuery(
@@ -197,44 +378,25 @@ void AdbPagesCommand::ProcessSerials() {
}
#endif // defined(DEBUG_DEVTOOLS)
- scoped_refptr<AndroidDevice> device = devices_.back();
if (device->is_connected()) {
device->RunCommand(kDeviceModelCommand,
base::Bind(&AdbPagesCommand::ReceivedModel, this));
} else {
device->set_model(kUnknownModel);
remote_devices_->push_back(new DevToolsAdbBridge::RemoteDevice(device));
- devices_.pop_back();
- ProcessSerials();
+ NextDevice();
}
}
void AdbPagesCommand::ReceivedModel(int result, const std::string& response) {
DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
if (result < 0) {
- devices_.pop_back();
- ProcessSerials();
+ NextDevice();
return;
}
- scoped_refptr<AndroidDevice> device = devices_.back();
+ scoped_refptr<AndroidDevice> device = current_device();
device->set_model(response);
- remote_devices_->push_back(
- new DevToolsAdbBridge::RemoteDevice(device));
- device->RunCommand(kOpenedUnixSocketsCommand,
- base::Bind(&AdbPagesCommand::ReceivedSockets, this));
-}
-
-void AdbPagesCommand::ReceivedSockets(int result,
- const std::string& response) {
- DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
- if (result < 0) {
- devices_.pop_back();
- ProcessSerials();
- return;
- }
-
- ParseSocketsList(response);
- scoped_refptr<AndroidDevice> device = devices_.back();
+ remote_devices_->push_back(new DevToolsAdbBridge::RemoteDevice(device));
device->RunCommand(kDumpsysCommand,
base::Bind(&AdbPagesCommand::ReceivedDumpsys, this));
}
@@ -245,42 +407,74 @@ void AdbPagesCommand::ReceivedDumpsys(int result,
if (result >= 0)
ParseDumpsysResponse(response);
- scoped_refptr<AndroidDevice> device = devices_.back();
- device->RunCommand(kListProcessesCommand,
- base::Bind(&AdbPagesCommand::ReceivedProcesses, this));
+ current_device()->RunCommand(
+ kInstalledChromePackagesCommand,
+ base::Bind(&AdbPagesCommand::ReceivedPackages, this));
}
-void AdbPagesCommand::ReceivedProcesses(int result,
- const std::string& response) {
- if (result >= 0)
- ParseProcessList(response);
+void AdbPagesCommand::ReceivedPackages(int result,
+ const std::string& packages_response) {
+ DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
+ if (result < 0) {
+ NextDevice();
+ return;
+ }
+ current_device()->RunCommand(
+ kListProcessesCommand,
+ base::Bind(&AdbPagesCommand::ReceivedProcesses, this, packages_response));
+}
- if (browsers_.size() == 0) {
- devices_.pop_back();
- ProcessSerials();
- } else {
- ProcessSockets();
+void AdbPagesCommand::ReceivedProcesses(
+ const std::string& packages_response,
+ int result,
+ const std::string& processes_response) {
+ DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
+ if (result < 0) {
+ NextDevice();
+ return;
}
+ current_device()->RunCommand(
+ kOpenedUnixSocketsCommand,
+ base::Bind(&AdbPagesCommand::ReceivedSockets,
+ this,
+ packages_response,
+ processes_response));
+}
+
+void AdbPagesCommand::ReceivedSockets(
+ const std::string& packages_response,
+ const std::string& processes_response,
+ int result,
+ const std::string& sockets_response) {
+ DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
+ if (result >= 0)
+ CreateBrowsers(packages_response, processes_response, sockets_response);
+ ProcessSockets();
}
void AdbPagesCommand::ProcessSockets() {
DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
if (browsers_.size() == 0) {
- devices_.pop_back();
- ProcessSerials();
- } else {
- scoped_refptr<AndroidDevice> device = devices_.back();
- device->HttpQuery(browsers_.back()->socket(), kVersionRequest,
- base::Bind(&AdbPagesCommand::ReceivedVersion, this));
+ NextDevice();
+ return;
+ }
+
+ if (!current_device()->serial().empty() &&
+ current_browser()->socket().empty()) {
+ NextBrowser();
+ return;
}
+ current_device()->HttpQuery(
+ current_browser()->socket(),
+ kVersionRequest,
+ base::Bind(&AdbPagesCommand::ReceivedVersion, this));
}
void AdbPagesCommand::ReceivedVersion(int result,
- const std::string& response) {
+ const std::string& response) {
DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
if (result < 0) {
- browsers_.pop_back();
- ProcessSockets();
+ NextBrowser();
return;
}
@@ -292,116 +486,145 @@ void AdbPagesCommand::ReceivedVersion(int result,
if (dict->GetString("Browser", &browser)) {
std::vector<std::string> parts;
Tokenize(browser, "/", &parts);
- if (parts.size() == 2) {
- if (parts[0] != "Version") // WebView has this for legacy reasons.
- browsers_.back()->set_product(parts[0]);
- browsers_.back()->set_version(parts[1]);
- } else {
- browsers_.back()->set_version(browser);
- }
+ if (parts.size() == 2)
+ current_browser()->set_version(parts[1]);
+ else
+ current_browser()->set_version(browser);
+ }
+ std::string package;
+ if (dict->GetString("Android-Package", &package)) {
+ const BrowserDescriptor* descriptor = FindBrowserDescriptor(package);
+ if (descriptor)
+ current_browser()->set_display_name(descriptor->display_name);
}
}
- scoped_refptr<AndroidDevice> device = devices_.back();
- device->HttpQuery(browsers_.back()->socket(), kPageListRequest,
- base::Bind(&AdbPagesCommand::ReceivedPages, this));
+ current_device()->HttpQuery(
+ current_browser()->socket(),
+ kPageListRequest,
+ base::Bind(&AdbPagesCommand::ReceivedPages, this));
}
void AdbPagesCommand::ReceivedPages(int result,
- const std::string& response) {
+ const std::string& response) {
DCHECK_EQ(adb_thread_->message_loop(), base::MessageLoop::current());
- scoped_refptr<DevToolsAdbBridge::RemoteBrowser> browser = browsers_.back();
- browsers_.pop_back();
- if (result < 0) {
- ProcessSockets();
- return;
+ if (result >= 0) {
+ scoped_ptr<base::Value> value(base::JSONReader::Read(response));
+ base::ListValue* list_value;
+ if (value && value->GetAsList(&list_value))
+ current_browser()->SetPageDescriptors(*list_value);
}
+ NextBrowser();
+}
- scoped_ptr<base::Value> value(base::JSONReader::Read(response));
- base::ListValue* list_value;
- if (value && value->GetAsList(&list_value)) {
- browser->SetPageDescriptors(*list_value);
- }
+void AdbPagesCommand::NextBrowser() {
+ browsers_.pop_back();
ProcessSockets();
}
+void AdbPagesCommand::NextDevice() {
+ devices_.pop_back();
+ ProcessSerials();
+}
+
void AdbPagesCommand::Respond() {
callback_.Run(remote_devices_.release());
}
-void AdbPagesCommand::ParseSocketsList(const std::string& response) {
- // On Android, '/proc/net/unix' looks like this:
- //
- // Num RefCount Protocol Flags Type St Inode Path
- // 00000000: 00000002 00000000 00010000 0001 01 331813 /dev/socket/zygote
- // 00000000: 00000002 00000000 00010000 0001 01 358606 @xxx_devtools_remote
- // 00000000: 00000002 00000000 00010000 0001 01 347300 @yyy_devtools_remote
- //
- // We need to find records with paths starting from '@' (abstract socket)
- // and containing "devtools_remote". We have to extract the inode number
- // in order to find the owning process name.
+void AdbPagesCommand::CreateBrowsers(
+ const std::string& packages_response,
+ const std::string& processes_response,
+ const std::string& sockets_response) {
+ DescriptorMap package_to_descriptor =
+ FindInstalledBrowserPackages(packages_response);
- scoped_refptr<DevToolsAdbBridge::RemoteDevice> remote_device =
- remote_devices_->back();
+ StringMap pid_to_package;
+ StringMap package_to_pid;
+ MapProcessesToPackages(processes_response, pid_to_package, package_to_pid);
- std::vector<std::string> entries;
- Tokenize(response, "\n", &entries);
const std::string channel_pattern =
base::StringPrintf(kDevToolsChannelNameFormat, "");
- for (size_t i = 1; i < entries.size(); ++i) {
- std::vector<std::string> fields;
- Tokenize(entries[i], " \r", &fields);
- if (fields.size() < 8)
- continue;
- if (fields[3] != "00010000" || fields[5] != "01")
- continue;
- std::string path_field = fields[7];
- if (path_field.size() < 1 || path_field[0] != '@')
- continue;
- size_t socket_name_pos = path_field.find(channel_pattern);
- if (socket_name_pos == std::string::npos)
- continue;
- std::string socket = path_field.substr(1);
- scoped_refptr<DevToolsAdbBridge::RemoteBrowser> remote_browser =
+ StringMap socket_to_pid = MapSocketsToProcesses(sockets_response,
+ channel_pattern);
+
+ scoped_refptr<DevToolsAdbBridge::RemoteDevice> remote_device =
+ remote_devices_->back();
+
+ // Create RemoteBrowser instances.
+ BrowserMap package_to_running_browser;
+ BrowserMap socket_to_unnamed_browser;
+ for (StringMap::iterator it = socket_to_pid.begin();
+ it != socket_to_pid.end(); ++it) {
+ std::string socket = it->first;
+ std::string pid = it->second;
+
+ scoped_refptr<DevToolsAdbBridge::RemoteBrowser> browser =
new DevToolsAdbBridge::RemoteBrowser(
adb_thread_, remote_device->device(), socket);
- std::string product = path_field.substr(1, socket_name_pos - 1);
- product[0] = base::ToUpperASCII(product[0]);
- remote_browser->set_product(product);
-
- size_t socket_name_end = socket_name_pos + channel_pattern.size();
- if (socket_name_end < path_field.size() &&
- path_field[socket_name_end] == '_') {
- remote_browser->set_pid(path_field.substr(socket_name_end + 1));
+ StringMap::iterator pit = pid_to_package.find(pid);
+ if (pit != pid_to_package.end()) {
+ std::string package = pit->second;
+ package_to_running_browser[package] = browser;
+ const BrowserDescriptor* descriptor = FindBrowserDescriptor(package);
+ if (descriptor)
+ browser->set_display_name(descriptor->display_name);
+ else
+ browser->set_display_name(package);
+ } else {
+ // Set fallback display name.
+ std::string name = socket.substr(0, socket.find(channel_pattern));
+ name[0] = base::ToUpperASCII(name[0]);
+ browser->set_display_name(name);
+
+ socket_to_unnamed_browser[socket] = browser;
}
- remote_device->AddBrowser(remote_browser);
+ remote_device->AddBrowser(browser);
}
+
browsers_ = remote_device->browsers();
-}
-void AdbPagesCommand::ParseProcessList(const std::string& response) {
- // On Android, 'ps' output looks like this:
- // USER PID PPID VSIZE RSS WCHAN PC ? NAME
- typedef std::map<std::string, std::string> StringMap;
- StringMap pid_to_package;
- std::vector<std::string> entries;
- Tokenize(response, "\n", &entries);
- for (size_t i = 1; i < entries.size(); ++i) {
- std::vector<std::string> fields;
- Tokenize(entries[i], " \r", &fields);
- if (fields.size() < 9)
+ // Create RemotePackage instances.
+ typedef std::multimap<std::string, const BrowserDescriptor*>
+ DescriptorMultimap;
+ DescriptorMultimap socket_to_descriptor;
+ for (DescriptorMap::iterator it = package_to_descriptor.begin();
+ it != package_to_descriptor.end(); ++it) {
+ std::string package = it->first;
+ const BrowserDescriptor* descriptor = it->second;
+
+ if (package_to_running_browser.find(package) !=
+ package_to_running_browser.end())
+ continue; // This package is already mapped to a browser.
+
+ if (package_to_pid.find(package) != package_to_pid.end()) {
+ // This package is running but not mapped to a browser.
+ socket_to_descriptor.insert(
+ DescriptorMultimap::value_type(descriptor->socket, descriptor));
continue;
- pid_to_package[fields[1]] = fields[8];
+ }
+
+ remote_device->AddPackage(new DevToolsAdbBridge::RemotePackage(
+ adb_thread_,
+ remote_device->device(),
+ descriptor->display_name,
+ descriptor->package,
+ descriptor->launch_activity));
}
- DevToolsAdbBridge::RemoteBrowsers browsers =
- remote_devices_->back()->browsers();
- for (DevToolsAdbBridge::RemoteBrowsers::iterator it = browsers.begin();
- it != browsers.end(); ++it) {
- StringMap::iterator pit = pid_to_package.find((*it)->pid());
- if (pit != pid_to_package.end())
- (*it)->set_package(pit->second);
+
+ // Try naming remaining unnamed browsers.
+ for (DescriptorMultimap::iterator it = socket_to_descriptor.begin();
+ it != socket_to_descriptor.end(); ++it) {
+ std::string socket = it->first;
+ const BrowserDescriptor* descriptor = it->second;
+
+ if (socket_to_descriptor.count(socket) != 1)
+ continue; // No definitive match.
+
+ BrowserMap::iterator bit = socket_to_unnamed_browser.find(socket);
+ if (bit != socket_to_unnamed_browser.end())
+ bit->second->set_display_name(descriptor->display_name);
}
}
@@ -750,7 +973,7 @@ DevToolsAdbBridge::RemoteBrowser::RemoteBrowser(
}
bool DevToolsAdbBridge::RemoteBrowser::IsChrome() const {
- return product_.find(kChromeProductName) == 0;
+ return socket_.find(kChromeDefaultSocket) == 0;
}
DevToolsAdbBridge::RemoteBrowser::ParsedVersion
@@ -859,6 +1082,35 @@ DevToolsAdbBridge::RemoteBrowser::~RemoteBrowser() {
}
+// DevToolsAdbBridge::RemotePackage -------------------------------------------
+
+DevToolsAdbBridge::RemotePackage::RemotePackage(
+ scoped_refptr<RefCountedAdbThread> adb_thread,
+ scoped_refptr<AndroidDevice> device,
+ const std::string& display_name,
+ const std::string& package_name,
+ const std::string& launch_activity)
+ : adb_thread_(adb_thread),
+ device_(device),
+ display_name_(display_name),
+ package_name_(package_name),
+ launch_activity_(launch_activity) {
+}
+
+
+void DevToolsAdbBridge::RemotePackage::Launch() {
+ adb_thread_->message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&AndroidDevice::RunCommand,
+ device_,
+ base::StringPrintf(kLaunchBrowserCommand,
+ package_name_.c_str(),
+ launch_activity_.c_str()),
+ base::Bind(&NoOp)));
+}
+
+DevToolsAdbBridge::RemotePackage::~RemotePackage() {}
+
// DevToolsAdbBridge::RemoteDevice --------------------------------------------
DevToolsAdbBridge::RemoteDevice::RemoteDevice(
@@ -883,6 +1135,11 @@ void DevToolsAdbBridge::RemoteDevice::AddBrowser(
browsers_.push_back(browser);
}
+void DevToolsAdbBridge::RemoteDevice::AddPackage(
+ scoped_refptr<RemotePackage> package) {
+ packages_.push_back(package);
+}
+
DevToolsAdbBridge::RemoteDevice::~RemoteDevice() {
}