diff options
-rw-r--r-- | chrome/browser/devtools/adb_client_socket_browsertest.cc | 22 | ||||
-rw-r--r-- | chrome/browser/devtools/devtools_adb_bridge.cc | 525 | ||||
-rw-r--r-- | chrome/browser/devtools/devtools_adb_bridge.h | 45 | ||||
-rw-r--r-- | chrome/browser/devtools/devtools_adb_bridge_browsertest.cc | 111 | ||||
-rw-r--r-- | chrome/browser/resources/inspect/inspect.css | 19 | ||||
-rw-r--r-- | chrome/browser/resources/inspect/inspect.js | 66 | ||||
-rw-r--r-- | chrome/browser/ui/webui/inspect_ui.cc | 65 | ||||
-rw-r--r-- | chrome/browser/ui/webui/inspect_ui.h | 6 |
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); }; |