| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/devtools/device/android_device_manager.h" | |
| 6 #include "chrome/browser/devtools/device/devtools_android_bridge.h" | |
| 7 #include "chrome/browser/devtools/devtools_target_impl.h" | |
| 8 #include "chrome/browser/ui/browser.h" | |
| 9 #include "chrome/test/base/in_process_browser_test.h" | |
| 10 #include "content/public/test/test_utils.h" | |
| 11 | |
| 12 const char kDeviceModelCommand[] = "shell:getprop ro.product.model"; | |
| 13 const char kOpenedUnixSocketsCommand[] = "shell:cat /proc/net/unix"; | |
| 14 const char kListProcessesCommand[] = "shell:ps"; | |
| 15 const char kListPackagesCommand[] = "shell:pm list packages"; | |
| 16 const char kDumpsysCommand[] = "shell:dumpsys window policy"; | |
| 17 | |
| 18 const char kPageListRequest[] = "GET /json HTTP/1.1\r\n\r\n"; | |
| 19 const char kVersionRequest[] = "GET /json/version HTTP/1.1\r\n\r\n"; | |
| 20 | |
| 21 const char kSampleOpenedUnixSockets[] = | |
| 22 "Num RefCount Protocol Flags Type St Inode Path\n" | |
| 23 "00000000: 00000004 00000000" | |
| 24 " 00000000 0002 01 3328 /dev/socket/wpa_wlan0\n" | |
| 25 "00000000: 00000002 00000000" | |
| 26 " 00010000 0001 01 5394 /dev/socket/vold\n" | |
| 27 "00000000: 00000002 00000000" | |
| 28 " 00010000 0001 01 11810 @webview_devtools_remote_2425\n" | |
| 29 "00000000: 00000002 00000000" | |
| 30 " 00010000 0001 01 20893 @chrome_devtools_remote\n" | |
| 31 "00000000: 00000002 00000000" | |
| 32 " 00010000 0001 01 20894 @chrome_devtools_remote_1002\n" | |
| 33 "00000000: 00000002 00000000" | |
| 34 " 00010000 0001 01 20895 @noprocess_devtools_remote\n"; | |
| 35 | |
| 36 const char kSampleListProcesses[] = | |
| 37 "USER PID PPID VSIZE RSS WCHAN PC NAME\n" | |
| 38 "root 1 0 688 508 ffffffff 00000000 S /init\r\n" | |
| 39 "u0_a75 2425 123 933736 193024 ffffffff 00000000 S com.sample.feed\r\n" | |
| 40 "nfc 741 123 706448 26316 ffffffff 00000000 S com.android.nfc\r\n" | |
| 41 "u0_a76 1001 124 111111 222222 ffffffff 00000000 S com.android.chrome\r\n" | |
| 42 "u0_a77 1002 125 111111 222222 ffffffff 00000000 S com.chrome.beta\r\n" | |
| 43 "u0_a78 1003 126 111111 222222 ffffffff 00000000 S com.noprocess.app\r\n"; | |
| 44 | |
| 45 const char kSampleListPackages[] = | |
| 46 "package:com.sample.feed\r\n" | |
| 47 "package:com.android.nfc\r\n" | |
| 48 "package:com.android.chrome\r\n" | |
| 49 "package:com.chrome.beta\r\n" | |
| 50 "package:com.google.android.apps.chrome\r\n"; | |
| 51 | |
| 52 const char kSampleDumpsysCommand[] = | |
| 53 "WINDOW MANAGER POLICY STATE (dumpsys window policy)\r\n" | |
| 54 " mSafeMode=false mSystemReady=true mSystemBooted=true\r\n" | |
| 55 " mStable=(0,50)-(720,1184)\r\n" // Only mStable parameter is parsed | |
| 56 " mForceStatusBar=false mForceStatusBarFromKeyguard=false\r\n"; | |
| 57 | |
| 58 char kSampleChromeVersion[] = "{\n" | |
| 59 " \"Browser\": \"Chrome/32.0.1679.0\",\n" | |
| 60 " \"Protocol-Version\": \"1.0\",\n" | |
| 61 " \"User-Agent\": \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 " | |
| 62 "(KHTML, like Gecko) Chrome/32.0.1679.0 Safari/537.36\",\n" | |
| 63 " \"WebKit-Version\": \"537.36 (@160162)\"\n" | |
| 64 "}"; | |
| 65 | |
| 66 char kSampleChromeBetaVersion[] = "{\n" | |
| 67 " \"Browser\": \"Chrome/31.0.1599.0\",\n" | |
| 68 " \"Protocol-Version\": \"1.0\",\n" | |
| 69 " \"User-Agent\": \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 " | |
| 70 "(KHTML, like Gecko) Chrome/32.0.1679.0 Safari/537.36\",\n" | |
| 71 " \"WebKit-Version\": \"537.36 (@160162)\"\n" | |
| 72 "}"; | |
| 73 | |
| 74 char kSampleWebViewVersion[] = "{\n" | |
| 75 " \"Browser\": \"Version/4.0\",\n" | |
| 76 " \"Protocol-Version\": \"1.0\",\n" | |
| 77 " \"User-Agent\": \"Mozilla/5.0 (Linux; Android 4.3; Build/KRS74B) " | |
| 78 "AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Safari/537.36\",\n" | |
| 79 " \"WebKit-Version\": \"537.36 (@157588)\"\n" | |
| 80 "}"; | |
| 81 | |
| 82 char kSampleChromePages[] = "[ {\n" | |
| 83 " \"description\": \"\",\n" | |
| 84 " \"devtoolsFrontendUrl\": \"/devtools/devtools.html?" | |
| 85 "ws=/devtools/page/755DE5C9-D49F-811D-0693-51B8E15C80D2\",\n" | |
| 86 " \"id\": \"755DE5C9-D49F-811D-0693-51B8E15C80D2\",\n" | |
| 87 " \"title\": \"The Chromium Projects\",\n" | |
| 88 " \"type\": \"page\",\n" | |
| 89 " \"url\": \"http://www.chromium.org/\",\n" | |
| 90 " \"webSocketDebuggerUrl\": \"" | |
| 91 "ws:///devtools/page/755DE5C9-D49F-811D-0693-51B8E15C80D2\"\n" | |
| 92 "} ]"; | |
| 93 | |
| 94 char kSampleChromeBetaPages[] = "[]"; | |
| 95 | |
| 96 char kSampleWebViewPages[] = "[ {\n" | |
| 97 " \"description\": \"{\\\"attached\\\":false,\\\"empty\\\":false," | |
| 98 "\\\"height\\\":1173,\\\"screenX\\\":0,\\\"screenY\\\":0," | |
| 99 "\\\"visible\\\":true,\\\"width\\\":800}\",\n" | |
| 100 " \"devtoolsFrontendUrl\": \"http://chrome-devtools-frontend.appspot.com/" | |
| 101 "serve_rev/@157588/devtools.html?ws=" | |
| 102 "/devtools/page/3E962D4D-B676-182D-3BE8-FAE7CE224DE7\",\n" | |
| 103 " \"faviconUrl\": \"http://chromium.org/favicon.ico\",\n" | |
| 104 " \"id\": \"3E962D4D-B676-182D-3BE8-FAE7CE224DE7\",\n" | |
| 105 " \"thumbnailUrl\": \"/thumb/3E962D4D-B676-182D-3BE8-FAE7CE224DE7\",\n" | |
| 106 " \"title\": \"Blink - The Chromium Projects\",\n" | |
| 107 " \"type\": \"page\",\n" | |
| 108 " \"url\": \"http://www.chromium.org/blink\",\n" | |
| 109 " \"webSocketDebuggerUrl\": \"ws:///devtools/" | |
| 110 "page/3E962D4D-B676-182D-3BE8-FAE7CE224DE7\"\n" | |
| 111 "}, {\n" | |
| 112 " \"description\": \"{\\\"attached\\\":true,\\\"empty\\\":true," | |
| 113 "\\\"screenX\\\":0,\\\"screenY\\\":33,\\\"visible\\\":false}\",\n" | |
| 114 " \"devtoolsFrontendUrl\": \"http://chrome-devtools-frontend.appspot.com/" | |
| 115 "serve_rev/@157588/devtools.html?ws=" | |
| 116 "/devtools/page/44681551-ADFD-2411-076B-3AB14C1C60E2\",\n" | |
| 117 " \"faviconUrl\": \"\",\n" | |
| 118 " \"id\": \"44681551-ADFD-2411-076B-3AB14C1C60E2\",\n" | |
| 119 " \"thumbnailUrl\": \"/thumb/44681551-ADFD-2411-076B-3AB14C1C60E2\",\n" | |
| 120 " \"title\": \"More Activity\",\n" | |
| 121 " \"type\": \"page\",\n" | |
| 122 " \"url\": \"about:blank\",\n" | |
| 123 " \"webSocketDebuggerUrl\": \"ws:///devtools/page/" | |
| 124 "44681551-ADFD-2411-076B-3AB14C1C60E2\"\n" | |
| 125 "}]"; | |
| 126 | |
| 127 class MockDeviceImpl : public AndroidDeviceManager::Device { | |
| 128 public: | |
| 129 MockDeviceImpl(const std::string& serial, int index, | |
| 130 bool connected, const char* device_model) | |
| 131 : Device(serial, connected), | |
| 132 device_model_(device_model) | |
| 133 {} | |
| 134 | |
| 135 virtual void RunCommand(const std::string& command, | |
| 136 const CommandCallback& callback) OVERRIDE { | |
| 137 const char* response; | |
| 138 | |
| 139 if (command == kDeviceModelCommand) { | |
| 140 response = device_model_; | |
| 141 } else if (command == kOpenedUnixSocketsCommand) { | |
| 142 response = kSampleOpenedUnixSockets; | |
| 143 } else if (command == kListProcessesCommand) { | |
| 144 response = kSampleListProcesses; | |
| 145 } else if (command == kListPackagesCommand) { | |
| 146 response = kSampleListPackages; | |
| 147 } else if (command == kDumpsysCommand) { | |
| 148 response = kSampleDumpsysCommand; | |
| 149 } else { | |
| 150 NOTREACHED(); | |
| 151 return; | |
| 152 } | |
| 153 | |
| 154 base::MessageLoop::current()->PostTask( FROM_HERE, | |
| 155 base::Bind(&MockDeviceImpl::RunCommandCallback, | |
| 156 this, callback, 0, response)); | |
| 157 } | |
| 158 | |
| 159 void RunCommandCallback(const CommandCallback& callback, int result, | |
| 160 const std::string& response) { | |
| 161 callback.Run(result, response); | |
| 162 } | |
| 163 | |
| 164 virtual void OpenSocket(const std::string& name, | |
| 165 const SocketCallback& callback) OVERRIDE { | |
| 166 NOTREACHED(); | |
| 167 } | |
| 168 | |
| 169 virtual void HttpQuery(const std::string& la_name, | |
| 170 const std::string& request, | |
| 171 const CommandCallback& callback) OVERRIDE { | |
| 172 const char* response; | |
| 173 | |
| 174 if (la_name == "chrome_devtools_remote") { | |
| 175 if (request == kVersionRequest) { | |
| 176 response = kSampleChromeVersion; | |
| 177 } else if (request == kPageListRequest) { | |
| 178 response = kSampleChromePages; | |
| 179 } else { | |
| 180 NOTREACHED(); | |
| 181 return; | |
| 182 } | |
| 183 } else if (la_name == "chrome_devtools_remote_1002") { | |
| 184 if (request == kVersionRequest) { | |
| 185 response = kSampleChromeBetaVersion; | |
| 186 } else if (request == kPageListRequest) { | |
| 187 response = kSampleChromeBetaPages; | |
| 188 } else { | |
| 189 NOTREACHED(); | |
| 190 return; | |
| 191 } | |
| 192 } else if (la_name.find("noprocess_devtools_remote") == 0) { | |
| 193 if (request == kVersionRequest) { | |
| 194 response = "{}"; | |
| 195 } else if (request == kPageListRequest) { | |
| 196 response = "[]"; | |
| 197 } else { | |
| 198 NOTREACHED(); | |
| 199 return; | |
| 200 } | |
| 201 } else if (la_name == "webview_devtools_remote_2425") { | |
| 202 if (request == kVersionRequest) { | |
| 203 response = kSampleWebViewVersion; | |
| 204 } else if (request == kPageListRequest) { | |
| 205 response = kSampleWebViewPages; | |
| 206 } else { | |
| 207 NOTREACHED(); | |
| 208 return; | |
| 209 } | |
| 210 } else { | |
| 211 NOTREACHED(); | |
| 212 return; | |
| 213 } | |
| 214 | |
| 215 base::MessageLoop::current()->PostTask( FROM_HERE, | |
| 216 base::Bind(&MockDeviceImpl::RunCommandCallback, | |
| 217 this, callback, 0, response)); | |
| 218 } | |
| 219 | |
| 220 virtual void HttpUpgrade(const std::string& la_name, | |
| 221 const std::string& request, | |
| 222 const SocketCallback& callback) { | |
| 223 NOTREACHED(); | |
| 224 } | |
| 225 | |
| 226 virtual void HttpQueryCallback(const CommandCallback& next, int code, | |
| 227 const std::string& result) { | |
| 228 NOTREACHED(); | |
| 229 } | |
| 230 | |
| 231 private: | |
| 232 virtual ~MockDeviceImpl() | |
| 233 {} | |
| 234 | |
| 235 const char* device_model_; | |
| 236 }; | |
| 237 | |
| 238 class MockDeviceProvider : public AndroidDeviceManager::DeviceProvider { | |
| 239 virtual ~MockDeviceProvider() | |
| 240 {} | |
| 241 | |
| 242 virtual void QueryDevices(const QueryDevicesCallback& callback) OVERRIDE { | |
| 243 AndroidDeviceManager::Devices devices; | |
| 244 devices.push_back(new MockDeviceImpl("FirstDevice", 0, true, "Nexus 6")); | |
| 245 devices.push_back(new MockDeviceImpl("SecondDevice", 1, false, "Nexus 8")); | |
| 246 callback.Run(devices); | |
| 247 } | |
| 248 }; | |
| 249 | |
| 250 // static | |
| 251 scoped_refptr<AndroidDeviceManager::DeviceProvider> | |
| 252 AndroidDeviceManager::GetMockDeviceProviderForTest() { | |
| 253 return new MockDeviceProvider(); | |
| 254 } | |
| 255 | |
| 256 static scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> | |
| 257 FindBrowserByDisplayName(DevToolsAndroidBridge::RemoteBrowsers browsers, | |
| 258 const std::string& name) { | |
| 259 for (DevToolsAndroidBridge::RemoteBrowsers::iterator it = browsers.begin(); | |
| 260 it != browsers.end(); ++it) | |
| 261 if ((*it)->display_name() == name) | |
| 262 return *it; | |
| 263 return NULL; | |
| 264 } | |
| 265 | |
| 266 class DevToolsAdbBridgeTest : public InProcessBrowserTest, | |
| 267 public DevToolsAndroidBridge::DeviceListListener { | |
| 268 typedef DevToolsAndroidBridge::RemoteDevices::const_iterator rdci; | |
| 269 typedef DevToolsAndroidBridge::RemoteBrowsers::const_iterator rbci; | |
| 270 public: | |
| 271 virtual void DeviceListChanged( | |
| 272 const DevToolsAndroidBridge::RemoteDevices& devices) OVERRIDE { | |
| 273 devices_ = devices; | |
| 274 runner_->Quit(); | |
| 275 } | |
| 276 | |
| 277 void CheckDevices() { | |
| 278 ASSERT_EQ(2U, devices_.size()); | |
| 279 | |
| 280 scoped_refptr<DevToolsAndroidBridge::RemoteDevice> connected = | |
| 281 devices_[0]->is_connected() ? devices_[0] : devices_[1]; | |
| 282 | |
| 283 scoped_refptr<DevToolsAndroidBridge::RemoteDevice> not_connected = | |
| 284 devices_[0]->is_connected() ? devices_[1] : devices_[0]; | |
| 285 | |
| 286 ASSERT_TRUE(connected->is_connected()); | |
| 287 ASSERT_FALSE(not_connected->is_connected()); | |
| 288 | |
| 289 ASSERT_EQ(720, connected->screen_size().width()); | |
| 290 ASSERT_EQ(1184, connected->screen_size().height()); | |
| 291 | |
| 292 ASSERT_EQ("FirstDevice", connected->serial()); | |
| 293 ASSERT_EQ("Nexus 6", connected->model()); | |
| 294 | |
| 295 ASSERT_EQ("SecondDevice", not_connected->serial()); | |
| 296 ASSERT_EQ("Offline", not_connected->model()); | |
| 297 | |
| 298 const DevToolsAndroidBridge::RemoteBrowsers& browsers = | |
| 299 connected->browsers(); | |
| 300 ASSERT_EQ(4U, browsers.size()); | |
| 301 | |
| 302 scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> chrome = | |
| 303 FindBrowserByDisplayName(browsers, "Chrome"); | |
| 304 ASSERT_TRUE(chrome); | |
| 305 | |
| 306 scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> chrome_beta = | |
| 307 FindBrowserByDisplayName(browsers, "Chrome Beta"); | |
| 308 ASSERT_TRUE(chrome_beta); | |
| 309 | |
| 310 scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> chromium = | |
| 311 FindBrowserByDisplayName(browsers, "Chromium"); | |
| 312 ASSERT_FALSE(chromium); | |
| 313 | |
| 314 scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> webview = | |
| 315 FindBrowserByDisplayName(browsers, "WebView in com.sample.feed"); | |
| 316 ASSERT_TRUE(webview); | |
| 317 | |
| 318 scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> noprocess = | |
| 319 FindBrowserByDisplayName(browsers, "Noprocess"); | |
| 320 ASSERT_TRUE(noprocess); | |
| 321 | |
| 322 ASSERT_EQ("32.0.1679.0", chrome->version()); | |
| 323 ASSERT_EQ("31.0.1599.0", chrome_beta->version()); | |
| 324 ASSERT_EQ("4.0", webview->version()); | |
| 325 | |
| 326 std::vector<DevToolsTargetImpl*> chrome_pages = | |
| 327 chrome->CreatePageTargets(); | |
| 328 std::vector<DevToolsTargetImpl*> chrome_beta_pages = | |
| 329 chrome_beta->CreatePageTargets(); | |
| 330 std::vector<DevToolsTargetImpl*> webview_pages = | |
| 331 webview->CreatePageTargets(); | |
| 332 | |
| 333 ASSERT_EQ(1U, chrome_pages.size()); | |
| 334 ASSERT_EQ(0U, chrome_beta_pages.size()); | |
| 335 ASSERT_EQ(2U, webview_pages.size()); | |
| 336 | |
| 337 // Check that we have non-empty description for webview pages. | |
| 338 ASSERT_EQ(0U, chrome_pages[0]->GetDescription().size()); | |
| 339 ASSERT_NE(0U, webview_pages[0]->GetDescription().size()); | |
| 340 ASSERT_NE(0U, webview_pages[1]->GetDescription().size()); | |
| 341 | |
| 342 ASSERT_EQ(GURL("http://www.chromium.org/"), chrome_pages[0]->GetUrl()); | |
| 343 ASSERT_EQ("The Chromium Projects", chrome_pages[0]->GetTitle()); | |
| 344 | |
| 345 STLDeleteElements(&chrome_pages); | |
| 346 STLDeleteElements(&webview_pages); | |
| 347 } | |
| 348 | |
| 349 void init() { | |
| 350 runner_ = new content::MessageLoopRunner; | |
| 351 } | |
| 352 | |
| 353 protected: | |
| 354 scoped_refptr<content::MessageLoopRunner> runner_; | |
| 355 DevToolsAndroidBridge::RemoteDevices devices_; | |
| 356 }; | |
| 357 | |
| 358 IN_PROC_BROWSER_TEST_F(DevToolsAdbBridgeTest, DiscoverAndroidBrowsers) { | |
| 359 init(); | |
| 360 | |
| 361 scoped_refptr<DevToolsAndroidBridge> android_bridge = | |
| 362 DevToolsAndroidBridge::Factory::GetForProfile(browser()->profile()); | |
| 363 | |
| 364 AndroidDeviceManager::DeviceProviders providers; | |
| 365 providers.push_back(AndroidDeviceManager::GetMockDeviceProviderForTest()); | |
| 366 | |
| 367 android_bridge->set_device_providers_for_test(providers); | |
| 368 | |
| 369 if (!android_bridge) { | |
| 370 FAIL() << "Failed to get DevToolsAndroidBridge."; | |
| 371 } | |
| 372 | |
| 373 android_bridge->AddDeviceListListener(this); | |
| 374 | |
| 375 runner_->Run(); | |
| 376 | |
| 377 CheckDevices(); | |
| 378 } | |
| OLD | NEW |