summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/devtools/adb_client_socket_browsertest.cc22
-rw-r--r--chrome/browser/devtools/devtools_adb_bridge.cc525
-rw-r--r--chrome/browser/devtools/devtools_adb_bridge.h45
-rw-r--r--chrome/browser/devtools/devtools_adb_bridge_browsertest.cc111
-rw-r--r--chrome/browser/resources/inspect/inspect.css19
-rw-r--r--chrome/browser/resources/inspect/inspect.js66
-rw-r--r--chrome/browser/ui/webui/inspect_ui.cc65
-rw-r--r--chrome/browser/ui/webui/inspect_ui.h6
8 files changed, 659 insertions, 200 deletions
diff --git a/chrome/browser/devtools/adb_client_socket_browsertest.cc b/chrome/browser/devtools/adb_client_socket_browsertest.cc
index 0674409..c479349 100644
--- a/chrome/browser/devtools/adb_client_socket_browsertest.cc
+++ b/chrome/browser/devtools/adb_client_socket_browsertest.cc
@@ -21,6 +21,7 @@ const char kOpenedUnixSocketsCommand[] = "shell:cat /proc/net/unix";
const char kDeviceModelCommand[] = "shell:getprop ro.product.model";
const char kDumpsysCommand[] = "shell:dumpsys window policy";
const char kListProcessesCommand[] = "shell:ps";
+const char kInstalledChromePackagesCommand[] = "shell:pm list packages";
const char kDeviceModel[] = "Nexus 8";
const char kSampleOpenedUnixSocketsWithoutBrowsers[] =
@@ -38,6 +39,8 @@ const char kSampleListProcesses[] =
"USER PID PPID VSIZE RSS WCHAN PC NAME\n"
"root 1 0 688 508 ffffffff 00000000 S /init\n";
+const char kSampleListPackages[] = "package:com.example.app";
+
static const int kBufferSize = 16*1024;
static const int kAdbPort = 5037;
@@ -154,7 +157,7 @@ void SingleConnectionServer::AcceptConnection() {
}
void SingleConnectionServer::OnAccepted(int result) {
- CHECK_EQ(result, 0);
+ ASSERT_EQ(result, 0); // Fails if the socket is already in use.
ReadData();
}
@@ -280,6 +283,8 @@ class MockAdbServer: public SingleConnectionServer {
SendResponse(kSampleDumpsys);
} else if (command == kListProcessesCommand) {
SendResponse(kSampleListProcesses);
+ } else if (command == kInstalledChromePackagesCommand) {
+ SendResponse(kSampleListPackages);
} else {
NOTREACHED() << "Unknown command - " << command;
}
@@ -324,19 +329,23 @@ public:
OVERRIDE {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
adb_bridge_->RemoveListener(this);
+ devices_ = *devices;
+ EndTest();
+ }
+ void CheckDevices() {
#if defined(DEBUG_DEVTOOLS)
// Mock device is added
- ASSERT_EQ(3U, devices->size());
+ ASSERT_EQ(3U, devices_.size());
#else
- ASSERT_EQ(2U, devices->size());
+ ASSERT_EQ(2U, devices_.size());
#endif
scoped_refptr<DevToolsAdbBridge::RemoteDevice> online_device_;
scoped_refptr<DevToolsAdbBridge::RemoteDevice> offline_device_;
for (DevToolsAdbBridge::RemoteDevices::const_iterator it =
- devices->begin(); it != devices->end(); ++it) {
+ devices_.begin(); it != devices_.end(); ++it) {
if ((*it)->GetSerial() == "01498B321301A00A")
online_device_ = *it;
else if ((*it)->GetSerial() == "01498B2B0D01300E")
@@ -350,8 +359,6 @@ public:
ASSERT_EQ(online_device_->GetModel(), kDeviceModel);
ASSERT_EQ(online_device_->browsers().size(), 0U);
ASSERT_EQ(online_device_->screen_size(), gfx::Size(720, 1184));
-
- EndTest();
}
private:
@@ -405,6 +412,7 @@ public:
private:
scoped_ptr<MockAdbServer> adb_server_;
scoped_refptr<DevToolsAdbBridge> adb_bridge_;
+ DevToolsAdbBridge::RemoteDevices devices_;
};
IN_PROC_BROWSER_TEST_F(AdbClientSocketTest, TestAdbClientSocket) {
@@ -414,4 +422,6 @@ IN_PROC_BROWSER_TEST_F(AdbClientSocketTest, TestAdbClientSocket) {
StartTest();
runner->Run();
+
+ CheckDevices();
}
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() {
}
diff --git a/chrome/browser/devtools/devtools_adb_bridge.h b/chrome/browser/devtools/devtools_adb_bridge.h
index 9343d53e..c2c75fe 100644
--- a/chrome/browser/devtools/devtools_adb_bridge.h
+++ b/chrome/browser/devtools/devtools_adb_bridge.h
@@ -94,14 +94,11 @@ class DevToolsAdbBridge
scoped_refptr<AndroidDevice> device() { return device_; }
std::string socket() { return socket_; }
- std::string product() { return product_; }
- void set_product(const std::string& product) { product_ = product; }
+ std::string display_name() { return display_name_; }
+ void set_display_name(const std::string& name) { display_name_ = name; }
+
std::string version() { return version_; }
void set_version(const std::string& version) { version_ = version; }
- std::string pid() { return pid_; }
- void set_pid(const std::string& pid) { pid_ = pid; }
- std::string package() { return package_; }
- void set_package(const std::string& package) { package_ = package; }
bool IsChrome() const;
@@ -131,16 +128,43 @@ class DevToolsAdbBridge
scoped_refptr<RefCountedAdbThread> adb_thread_;
scoped_refptr<AndroidDevice> device_;
const std::string socket_;
- std::string product_;
+ std::string display_name_;
std::string version_;
- std::string pid_;
- std::string package_;
scoped_ptr<base::ListValue> page_descriptors_;
DISALLOW_COPY_AND_ASSIGN(RemoteBrowser);
};
+ class RemotePackage : public base::RefCounted<RemotePackage> {
+ public:
+ 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);
+
+ scoped_refptr<AndroidDevice> device() { return device_; }
+ std::string display_name() { return display_name_; }
+ std::string package_name() { return package_name_; }
+
+ void Launch();
+
+ private:
+ friend class base::RefCounted<RemotePackage>;
+ virtual ~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_;
+
+ DISALLOW_COPY_AND_ASSIGN(RemotePackage);
+ };
+
typedef std::vector<scoped_refptr<RemoteBrowser> > RemoteBrowsers;
+ typedef std::vector<scoped_refptr<RemotePackage> > RemotePackages;
class RemoteDevice : public base::RefCounted<RemoteDevice> {
public:
@@ -150,9 +174,11 @@ class DevToolsAdbBridge
std::string GetModel();
bool IsConnected();
void AddBrowser(scoped_refptr<RemoteBrowser> browser);
+ void AddPackage(scoped_refptr<RemotePackage> package);
scoped_refptr<AndroidDevice> device() { return device_; }
RemoteBrowsers& browsers() { return browsers_; }
+ RemotePackages& packages() { return packages_; }
gfx::Size screen_size() { return screen_size_; }
void set_screen_size(const gfx::Size& size) { screen_size_ = size; }
@@ -162,6 +188,7 @@ class DevToolsAdbBridge
scoped_refptr<AndroidDevice> device_;
RemoteBrowsers browsers_;
+ RemotePackages packages_;
gfx::Size screen_size_;
DISALLOW_COPY_AND_ASSIGN(RemoteDevice);
diff --git a/chrome/browser/devtools/devtools_adb_bridge_browsertest.cc b/chrome/browser/devtools/devtools_adb_bridge_browsertest.cc
index e12ef50..a4f2e83 100644
--- a/chrome/browser/devtools/devtools_adb_bridge_browsertest.cc
+++ b/chrome/browser/devtools/devtools_adb_bridge_browsertest.cc
@@ -12,6 +12,7 @@
const char kDeviceModelCommand[] = "shell:getprop ro.product.model";
const char kOpenedUnixSocketsCommand[] = "shell:cat /proc/net/unix";
const char kListProcessesCommand[] = "shell:ps";
+const char kListPackagesCommand[] = "shell:pm list packages";
const char kDumpsysCommand[] = "shell:dumpsys window policy";
const char kPageListRequest[] = "GET /json HTTP/1.1\r\n\r\n";
@@ -26,13 +27,27 @@ const char kSampleOpenedUnixSockets[] =
"00000000: 00000002 00000000"
" 00010000 0001 01 11810 @webview_devtools_remote_2425\n"
"00000000: 00000002 00000000"
- " 00010000 0001 01 20893 @chrome_devtools_remote\n";
+ " 00010000 0001 01 20893 @chrome_devtools_remote\n"
+ "00000000: 00000002 00000000"
+ " 00010000 0001 01 20894 @chrome_devtools_remote_1002\n"
+ "00000000: 00000002 00000000"
+ " 00010000 0001 01 20895 @noprocess_devtools_remote\n";
const char kSampleListProcesses[] =
- "USER PID PPID VSIZE RSS WCHAN PC NAME\n"
- "root 1 0 688 508 ffffffff 00000000 S /init\n"
- "u0_a75 2425 123 933736 193024 ffffffff 00000000 S com.sample.feed\n"
- "nfc 741 123 706448 26316 ffffffff 00000000 S com.android.nfc";
+ "USER PID PPID VSIZE RSS WCHAN PC NAME\n"
+ "root 1 0 688 508 ffffffff 00000000 S /init\r\n"
+ "u0_a75 2425 123 933736 193024 ffffffff 00000000 S com.sample.feed\r\n"
+ "nfc 741 123 706448 26316 ffffffff 00000000 S com.android.nfc\r\n"
+ "u0_a76 1001 124 111111 222222 ffffffff 00000000 S com.android.chrome\r\n"
+ "u0_a77 1002 125 111111 222222 ffffffff 00000000 S com.chrome.beta\r\n"
+ "u0_a78 1003 126 111111 222222 ffffffff 00000000 S com.noprocess.app\r\n";
+
+const char kSampleListPackages[] =
+ "package:com.sample.feed\r\n"
+ "package:com.android.nfc\r\n"
+ "package:com.android.chrome\r\n"
+ "package:com.chrome.beta\r\n"
+ "package:com.google.android.apps.chrome\r\n";
const char kSampleDumpsysCommand[] =
"WINDOW MANAGER POLICY STATE (dumpsys window policy)\r\n"
@@ -48,6 +63,14 @@ char kSampleChromeVersion[] = "{\n"
" \"WebKit-Version\": \"537.36 (@160162)\"\n"
"}";
+char kSampleChromeBetaVersion[] = "{\n"
+ " \"Browser\": \"Chrome/31.0.1599.0\",\n"
+ " \"Protocol-Version\": \"1.0\",\n"
+ " \"User-Agent\": \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 "
+ "(KHTML, like Gecko) Chrome/32.0.1679.0 Safari/537.36\",\n"
+ " \"WebKit-Version\": \"537.36 (@160162)\"\n"
+ "}";
+
char kSampleWebViewVersion[] = "{\n"
" \"Browser\": \"Version/4.0\",\n"
" \"Protocol-Version\": \"1.0\",\n"
@@ -68,6 +91,8 @@ char kSampleChromePages[] = "[ {\n"
"ws:///devtools/page/755DE5C9-D49F-811D-0693-51B8E15C80D2\"\n"
"} ]";
+char kSampleChromeBetaPages[] = "[]";
+
char kSampleWebViewPages[] = "[ {\n"
" \"description\": \"{\\\"attached\\\":false,\\\"empty\\\":false,"
"\\\"height\\\":1173,\\\"screenX\\\":0,\\\"screenY\\\":0,"
@@ -117,6 +142,8 @@ class MockDeviceImpl : public AndroidDevice {
response = kSampleOpenedUnixSockets;
} else if (command == kListProcessesCommand) {
response = kSampleListProcesses;
+ } else if (command == kListPackagesCommand) {
+ response = kSampleListPackages;
} else if (command == kDumpsysCommand) {
response = kSampleDumpsysCommand;
} else {
@@ -153,6 +180,24 @@ class MockDeviceImpl : public AndroidDevice {
NOTREACHED();
return;
}
+ } else if (la_name == "chrome_devtools_remote_1002") {
+ if (request == kVersionRequest) {
+ response = kSampleChromeBetaVersion;
+ } else if (request == kPageListRequest) {
+ response = kSampleChromeBetaPages;
+ } else {
+ NOTREACHED();
+ return;
+ }
+ } else if (la_name.find("noprocess_devtools_remote") == 0) {
+ if (request == kVersionRequest) {
+ response = "{}";
+ } else if (request == kPageListRequest) {
+ response = "[]";
+ } else {
+ NOTREACHED();
+ return;
+ }
} else if (la_name == "webview_devtools_remote_2425") {
if (request == kVersionRequest) {
response = kSampleWebViewVersion;
@@ -202,6 +247,15 @@ class MockDeviceProvider : public AndroidDeviceProvider {
}
};
+static scoped_refptr<DevToolsAdbBridge::RemoteBrowser>
+FindBrowserByDisplayName(DevToolsAdbBridge::RemoteBrowsers browsers,
+ const std::string& name) {
+ for (DevToolsAdbBridge::RemoteBrowsers::iterator it = browsers.begin();
+ it != browsers.end(); ++it)
+ if ((*it)->display_name() == name)
+ return *it;
+ return NULL;
+}
class DevToolsAdbBridgeTest : public InProcessBrowserTest,
public DevToolsAdbBridge::Listener {
@@ -210,13 +264,18 @@ class DevToolsAdbBridgeTest : public InProcessBrowserTest,
public:
virtual void RemoteDevicesChanged(
DevToolsAdbBridge::RemoteDevices* devices) OVERRIDE{
- ASSERT_EQ(2U, devices->size());
+ devices_ = *devices;
+ runner_->Quit();
+ }
+
+ void CheckDevices() {
+ ASSERT_EQ(2U, devices_.size());
scoped_refptr<DevToolsAdbBridge::RemoteDevice> connected =
- (*devices)[0]->IsConnected() ? (*devices)[0] : (*devices)[1];
+ devices_[0]->IsConnected() ? devices_[0] : devices_[1];
scoped_refptr<DevToolsAdbBridge::RemoteDevice> not_connected =
- (*devices)[0]->IsConnected() ? (*devices)[1] : (*devices)[0];
+ devices_[0]->IsConnected() ? devices_[1] : devices_[0];
ASSERT_TRUE(connected->IsConnected());
ASSERT_FALSE(not_connected->IsConnected());
@@ -231,29 +290,40 @@ public:
ASSERT_EQ("Offline", not_connected->GetModel());
const DevToolsAdbBridge::RemoteBrowsers& browsers = connected->browsers();
- ASSERT_EQ(2U, browsers.size());
+ ASSERT_EQ(4U, browsers.size());
scoped_refptr<DevToolsAdbBridge::RemoteBrowser> chrome =
- browsers[0]->product() == "Chrome" ? browsers[0] : browsers[1];
+ FindBrowserByDisplayName(browsers, "Chrome");
+ ASSERT_TRUE(chrome);
+
+ scoped_refptr<DevToolsAdbBridge::RemoteBrowser> chrome_beta =
+ FindBrowserByDisplayName(browsers, "Chrome Beta");
+ ASSERT_TRUE(chrome_beta);
+
+ scoped_refptr<DevToolsAdbBridge::RemoteBrowser> chromium =
+ FindBrowserByDisplayName(browsers, "Chromium");
+ ASSERT_FALSE(chromium);
scoped_refptr<DevToolsAdbBridge::RemoteBrowser> webview =
- browsers[0]->product() == "Chrome" ? browsers[1] : browsers[0];
+ FindBrowserByDisplayName(browsers, "com.sample.feed");
- ASSERT_EQ("Chrome", chrome->product());
- ASSERT_EQ("32.0.1679.0", chrome->version());
+ scoped_refptr<DevToolsAdbBridge::RemoteBrowser> noprocess =
+ FindBrowserByDisplayName(browsers, "Noprocess");
+ ASSERT_TRUE(noprocess);
- ASSERT_EQ("Webview", webview->product());
+ ASSERT_EQ("32.0.1679.0", chrome->version());
+ ASSERT_EQ("31.0.1599.0", chrome_beta->version());
ASSERT_EQ("4.0", webview->version());
- // Check that we parse process list properly.
- ASSERT_EQ("com.sample.feed", webview->package());
-
std::vector<DevToolsTargetImpl*> chrome_pages =
chrome->CreatePageTargets();
+ std::vector<DevToolsTargetImpl*> chrome_beta_pages =
+ chrome_beta->CreatePageTargets();
std::vector<DevToolsTargetImpl*> webview_pages =
webview->CreatePageTargets();
ASSERT_EQ(1U, chrome_pages.size());
+ ASSERT_EQ(0U, chrome_beta_pages.size());
ASSERT_EQ(2U, webview_pages.size());
// Check that we have non-empty description for webview pages.
@@ -266,8 +336,6 @@ public:
STLDeleteElements(&chrome_pages);
STLDeleteElements(&webview_pages);
-
- runner_->Quit();
}
void init() {
@@ -276,9 +344,10 @@ public:
protected:
scoped_refptr<content::MessageLoopRunner> runner_;
+ DevToolsAdbBridge::RemoteDevices devices_;
};
-IN_PROC_BROWSER_TEST_F(DevToolsAdbBridgeTest, Main) {
+IN_PROC_BROWSER_TEST_F(DevToolsAdbBridgeTest, DiscoverAndroidBrowsers) {
init();
scoped_refptr<DevToolsAdbBridge> adb_bridge =
@@ -296,4 +365,6 @@ IN_PROC_BROWSER_TEST_F(DevToolsAdbBridgeTest, Main) {
adb_bridge->AddListener(this);
runner_->Run();
+
+ CheckDevices();
}
diff --git a/chrome/browser/resources/inspect/inspect.css b/chrome/browser/resources/inspect/inspect.css
index c334844..4bada4c 100644
--- a/chrome/browser/resources/inspect/inspect.css
+++ b/chrome/browser/resources/inspect/inspect.css
@@ -233,6 +233,25 @@ a.disabled {
line-height: 13px;
}
+.packages-header {
+ font-size: 110%;
+ font-weight: bold;
+ margin-bottom: 4px;
+ margin-top: 10px;
+}
+
+.package {
+ margin: 6px 12px;
+}
+
+.package span {
+ font-weight: bold;
+}
+
+.package button {
+ margin-right: 12px;
+}
+
#device-settings {
border-bottom: 1px solid #eee;
padding: 5px 0;
diff --git a/chrome/browser/resources/inspect/inspect.js b/chrome/browser/resources/inspect/inspect.js
index 9a1e34f..7bbb358 100644
--- a/chrome/browser/resources/inspect/inspect.js
+++ b/chrome/browser/resources/inspect/inspect.js
@@ -27,6 +27,10 @@ function open(browserId, url) {
chrome.send('open', [browserId, url]);
}
+function launch(packageId) {
+ chrome.send('launch', [packageId]);
+}
+
function removeChildren(element_id) {
var element = $(element_id);
element.textContent = '';
@@ -170,6 +174,10 @@ function populateRemoteTargets(devices) {
browserList.className = 'browsers';
deviceSection.appendChild(browserList);
+ var packageList = document.createElement('div');
+ packageList.className = 'packages';
+ deviceSection.appendChild(packageList);
+
var authenticating = document.createElement('div');
authenticating.className = 'device-auth';
deviceSection.appendChild(authenticating);
@@ -217,15 +225,7 @@ function populateRemoteTargets(devices) {
for (var b = 0; b < device.browsers.length; b++) {
var browser = device.browsers[b];
- var isChrome = browser.adbBrowserProduct &&
- browser.adbBrowserProduct.match(/^Chrome/);
-
- var majorChromeVersion = 0;
- if (isChrome && browser.adbBrowserVersion) {
- var match = browser.adbBrowserVersion.match(/^(\d+)/);
- if (match)
- majorChromeVersion = parseInt(match[1]);
- }
+ var majorChromeVersion = browser.adbBrowserChromeVersion;
var pageList;
var browserSection = $(browser.adbGlobalId);
@@ -243,10 +243,7 @@ function populateRemoteTargets(devices) {
var browserName = document.createElement('div');
browserName.className = 'browser-name';
browserHeader.appendChild(browserName);
- if (browser.adbBrowserPackage && !isChrome)
- browserName.textContent = browser.adbBrowserPackage;
- else
- browserName.textContent = browser.adbBrowserProduct;
+ browserName.textContent = browser.adbBrowserName;
if (browser.adbBrowserVersion)
browserName.textContent += ' (' + browser.adbBrowserVersion + ')';
browserSection.appendChild(browserHeader);
@@ -291,24 +288,47 @@ function populateRemoteTargets(devices) {
// Attached targets have no unique id until Chrome 26. For such targets
// it is impossible to activate existing DevTools window.
page.hasNoUniqueId = page.attached &&
- majorChromeVersion < MIN_VERSION_TARGET_ID;
+ (majorChromeVersion && majorChromeVersion < MIN_VERSION_TARGET_ID);
var row = addTargetToList(page, pageList, ['name', 'url']);
if (page['description'])
addWebViewDetails(row, page);
else
addFavicon(row, page);
- if (isChrome) {
- if (majorChromeVersion >= MIN_VERSION_TAB_ACTIVATE) {
- addActionLink(row, 'focus tab', activate.bind(null, page), false);
- }
+ if (majorChromeVersion >= MIN_VERSION_TAB_ACTIVATE)
+ addActionLink(row, 'focus tab', activate.bind(null, page), false);
+ if (majorChromeVersion)
addActionLink(row, 'reload', reload.bind(null, page), page.attached);
- if (majorChromeVersion >= MIN_VERSION_TAB_CLOSE) {
- addActionLink(
- row, 'close', close.bind(null, page), page.attached);
- }
- }
+ if (majorChromeVersion >= MIN_VERSION_TAB_CLOSE)
+ addActionLink(row, 'close', close.bind(null, page), page.attached);
}
}
+
+ var packageList = deviceSection.querySelector('.packages');
+ packageList.textContent = '';
+
+ if (device.packages.length) {
+ var packagesHeader = document.createElement('div');
+ packagesHeader.className = 'packages-header';
+ packagesHeader.textContent =
+ device.browsers.length ? 'Also installed:' : 'Installed browsers:';
+ packageList.appendChild(packagesHeader);
+ }
+
+ for (var p = 0; p < device.packages.length; p++) {
+ var packageSection = document.createElement('div');
+ packageSection.className = 'package';
+ packageList.appendChild(packageSection);
+
+ var launchButton = document.createElement('button');
+ launchButton.textContent = 'Launch';
+ launchButton.addEventListener(
+ 'click', launch.bind(null, device.packages[p].adbGlobalId), true);
+ packageSection.appendChild(launchButton);
+
+ var packageDisplayName = document.createElement('span');
+ packageDisplayName.textContent = device.packages[p].adbBrowserName;
+ packageSection.appendChild(packageDisplayName);
+ }
}
}
diff --git a/chrome/browser/ui/webui/inspect_ui.cc b/chrome/browser/ui/webui/inspect_ui.cc
index 1952d39..f03d398 100644
--- a/chrome/browser/ui/webui/inspect_ui.cc
+++ b/chrome/browser/ui/webui/inspect_ui.cc
@@ -76,6 +76,7 @@ const char kActivateCommand[] = "activate";
const char kCloseCommand[] = "close";
const char kReloadCommand[] = "reload";
const char kOpenCommand[] = "open";
+const char kLaunchCommand[] = "launch";
const char kDiscoverUsbDevicesEnabledCommand[] =
"set-discover-usb-devices-enabled";
@@ -96,12 +97,13 @@ const char kDescription[] = "description";
const char kAdbConnectedField[] = "adbConnected";
const char kAdbModelField[] = "adbModel";
const char kAdbSerialField[] = "adbSerial";
-const char kAdbBrowserProductField[] = "adbBrowserProduct";
-const char kAdbBrowserPackageField[] = "adbBrowserPackage";
+const char kAdbBrowserNameField[] = "adbBrowserName";
const char kAdbBrowserVersionField[] = "adbBrowserVersion";
+const char kAdbBrowserChromeVersionField[] = "adbBrowserChromeVersion";
const char kAdbGlobalIdField[] = "adbGlobalId";
const char kAdbBrowsersField[] = "browsers";
const char kAdbPagesField[] = "pages";
+const char kAdbPackagesField[] = "packages";
const char kAdbPortStatus[] = "adbPortStatus";
const char kAdbScreenWidthField[] = "adbScreenWidth";
const char kAdbScreenHeightField[] = "adbScreenHeight";
@@ -138,6 +140,7 @@ class InspectMessageHandler : public WebUIMessageHandler {
void HandleCloseCommand(const ListValue* args);
void HandleReloadCommand(const ListValue* args);
void HandleOpenCommand(const ListValue* args);
+ void HandleLaunchCommand(const ListValue* args);
void HandleBooleanPrefChanged(const char* pref_name,
const ListValue* args);
void HandlePortForwardingConfigCommand(const ListValue* args);
@@ -179,6 +182,9 @@ void InspectMessageHandler::RegisterMessages() {
web_ui()->RegisterMessageCallback(kOpenCommand,
base::Bind(&InspectMessageHandler::HandleOpenCommand,
base::Unretained(this)));
+ web_ui()->RegisterMessageCallback(kLaunchCommand,
+ base::Bind(&InspectMessageHandler::HandleLaunchCommand,
+ base::Unretained(this)));
}
void InspectMessageHandler::HandleInitUICommand(const ListValue*) {
@@ -234,6 +240,19 @@ void InspectMessageHandler::HandleOpenCommand(const ListValue* args) {
remote_browser->Open(gurl.spec());
}
+void InspectMessageHandler::HandleLaunchCommand(const ListValue* args) {
+ if (args->GetSize() != 1)
+ return;
+ std::string package_id;
+ if (!args->GetString(0, &package_id))
+ return;
+ scoped_refptr<DevToolsAdbBridge::RemotePackage> remote_package =
+ inspect_ui_->FindRemotePackage(package_id);
+ if (!remote_package)
+ return;
+ remote_package->Launch();
+}
+
DevToolsTargetImpl* InspectMessageHandler::FindTarget(const ListValue* args) {
const DictionaryValue* data;
std::string type;
@@ -405,6 +424,12 @@ InspectUI::FindRemoteBrowser(const std::string& id) {
return it == remote_browsers_.end() ? NULL : it->second;
}
+scoped_refptr<DevToolsAdbBridge::RemotePackage>
+InspectUI::FindRemotePackage(const std::string& id) {
+ RemotePackages::iterator it = remote_packages_.find(id);
+ return it == remote_packages_.end() ? NULL : it->second;
+}
+
void InspectUI::InspectDevices(Browser* browser) {
content::RecordAction(content::UserMetricsAction("InspectDevices"));
chrome::NavigateParams params(chrome::GetSingletonTabNavigateParams(
@@ -558,6 +583,7 @@ void InspectUI::RemoteDevicesChanged(
port_forwarding_controller->UpdateDeviceList(*devices);
remote_browsers_.clear();
+ remote_packages_.clear();
STLDeleteValues(&remote_targets_);
ListValue device_list;
for (DevToolsAdbBridge::RemoteDevices::iterator dit = devices->begin();
@@ -579,14 +605,19 @@ void InspectUI::RemoteDevicesChanged(
browsers.begin(); bit != browsers.end(); ++bit) {
DevToolsAdbBridge::RemoteBrowser* browser = bit->get();
DictionaryValue* browser_data = new DictionaryValue();
- browser_data->SetString(kAdbBrowserProductField, browser->product());
- browser_data->SetString(kAdbBrowserPackageField, browser->package());
+ browser_data->SetString(kAdbBrowserNameField, browser->display_name());
browser_data->SetString(kAdbBrowserVersionField, browser->version());
+ DevToolsAdbBridge::RemoteBrowser::ParsedVersion parsed =
+ browser->GetParsedVersion();
+ browser_data->SetInteger(
+ kAdbBrowserChromeVersionField,
+ browser->IsChrome() && !parsed.empty() ? parsed[0] : 0);
std::string browser_id = base::StringPrintf(
- "browser:%s:%s:%s",
- device->GetSerial().c_str(),
- browser->product().c_str(), // Force sorting by product name.
- browser->socket().c_str());
+ "browser:%s:%s:%s:%s",
+ device->GetSerial().c_str(), // Ensure uniqueness across devices.
+ browser->display_name().c_str(), // Sort by display name.
+ browser->version().c_str(), // Then by version.
+ browser->socket().c_str()); // Ensure uniqueness on the device.
browser_data->SetString(kAdbGlobalIdField, browser_id);
remote_browsers_[browser_id] = browser;
ListValue* page_list = new ListValue();
@@ -613,6 +644,24 @@ void InspectUI::RemoteDevicesChanged(
browser_list->Append(browser_data);
}
+ ListValue* package_list = new ListValue();
+ device_data->Set(kAdbPackagesField, package_list);
+
+ DevToolsAdbBridge::RemotePackages& packages = device->packages();
+ for (DevToolsAdbBridge::RemotePackages::iterator pit = packages.begin();
+ pit != packages.end(); ++pit) {
+ DevToolsAdbBridge::RemotePackage* package = pit->get();
+ DictionaryValue* package_data = new DictionaryValue();
+ package_data->SetString(kAdbBrowserNameField, package->display_name());
+ std::string package_id = base::StringPrintf(
+ "package:%s:%s",
+ device->GetSerial().c_str(), // Ensure uniqueness across devices.
+ package->package_name().c_str()); // Ensure uniqueness on the device.
+ package_data->SetString(kAdbGlobalIdField, package_id);
+ remote_packages_[package_id] = package;
+ package_list->Append(package_data);
+ }
+
if (port_forwarding_controller) {
PortForwardingController::DevicesStatus::iterator sit =
port_forwarding_status.find(device->GetSerial());
diff --git a/chrome/browser/ui/webui/inspect_ui.h b/chrome/browser/ui/webui/inspect_ui.h
index d1d186e..1ee8dd5c 100644
--- a/chrome/browser/ui/webui/inspect_ui.h
+++ b/chrome/browser/ui/webui/inspect_ui.h
@@ -35,6 +35,8 @@ class InspectUI : public content::WebUIController,
const std::string& id);
scoped_refptr<DevToolsAdbBridge::RemoteBrowser> FindRemoteBrowser(
const std::string& id);
+ scoped_refptr<DevToolsAdbBridge::RemotePackage> FindRemotePackage(
+ const std::string& id);
static void InspectDevices(Browser* browser);
@@ -83,6 +85,10 @@ class InspectUI : public content::WebUIController,
scoped_refptr<DevToolsAdbBridge::RemoteBrowser> > RemoteBrowsers;
RemoteBrowsers remote_browsers_;
+ typedef std::map<std::string,
+ scoped_refptr<DevToolsAdbBridge::RemotePackage> > RemotePackages;
+ RemotePackages remote_packages_;
+
DISALLOW_COPY_AND_ASSIGN(InspectUI);
};