• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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/android_device.h"
6 #include "chrome/browser/devtools/devtools_adb_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 AndroidDevice {
128  public:
MockDeviceImpl(const std::string & serial,int index,bool connected,const char * device_model)129   MockDeviceImpl(const std::string& serial, int index,
130                  bool connected, const char* device_model)
131       : AndroidDevice(serial, connected),
132         device_model_(device_model)
133   {}
134 
RunCommand(const std::string & command,const CommandCallback & callback)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 
RunCommandCallback(const CommandCallback & callback,int result,const std::string & response)159   void RunCommandCallback(const CommandCallback& callback, int result,
160                           const std::string& response) {
161     callback.Run(result, response);
162   }
163 
OpenSocket(const std::string & name,const SocketCallback & callback)164   virtual void OpenSocket(const std::string& name,
165                           const SocketCallback& callback) OVERRIDE {
166     NOTREACHED();
167   }
168 
HttpQuery(const std::string & la_name,const std::string & request,const CommandCallback & callback)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 
HttpUpgrade(const std::string & la_name,const std::string & request,const SocketCallback & callback)220   virtual void HttpUpgrade(const std::string& la_name,
221                        const std::string& request,
222                        const SocketCallback& callback) {
223     NOTREACHED();
224   }
225 
HttpQueryCallback(const CommandCallback & next,int code,const std::string & result)226   virtual void HttpQueryCallback(const CommandCallback& next, int code,
227                                  const std::string& result) {
228     NOTREACHED();
229   }
230 
231  private:
~MockDeviceImpl()232   virtual ~MockDeviceImpl()
233   {}
234 
235   const char* device_model_;
236 };
237 
238 class MockDeviceProvider : public AndroidDeviceProvider {
~MockDeviceProvider()239   virtual ~MockDeviceProvider()
240   {}
241 
QueryDevices(const QueryDevicesCallback & callback)242   virtual void QueryDevices(const QueryDevicesCallback& callback) OVERRIDE {
243     AndroidDeviceProvider::AndroidDevices 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 scoped_refptr<DevToolsAdbBridge::RemoteBrowser>
FindBrowserByDisplayName(DevToolsAdbBridge::RemoteBrowsers browsers,const std::string & name)251 FindBrowserByDisplayName(DevToolsAdbBridge::RemoteBrowsers browsers,
252                          const std::string& name) {
253   for (DevToolsAdbBridge::RemoteBrowsers::iterator it = browsers.begin();
254       it != browsers.end(); ++it)
255     if ((*it)->display_name() == name)
256       return *it;
257   return NULL;
258 }
259 
260 class DevToolsAdbBridgeTest : public InProcessBrowserTest,
261                                public DevToolsAdbBridge::Listener {
262   typedef DevToolsAdbBridge::RemoteDevices::const_iterator rdci;
263   typedef DevToolsAdbBridge::RemoteBrowsers::const_iterator rbci;
264 public:
RemoteDevicesChanged(DevToolsAdbBridge::RemoteDevices * devices)265   virtual void RemoteDevicesChanged(
266       DevToolsAdbBridge::RemoteDevices* devices) OVERRIDE{
267     devices_ = *devices;
268     runner_->Quit();
269   }
270 
CheckDevices()271   void CheckDevices() {
272     ASSERT_EQ(2U, devices_.size());
273 
274     scoped_refptr<DevToolsAdbBridge::RemoteDevice> connected =
275         devices_[0]->IsConnected() ? devices_[0] : devices_[1];
276 
277     scoped_refptr<DevToolsAdbBridge::RemoteDevice> not_connected =
278         devices_[0]->IsConnected() ? devices_[1] : devices_[0];
279 
280     ASSERT_TRUE(connected->IsConnected());
281     ASSERT_FALSE(not_connected->IsConnected());
282 
283     ASSERT_EQ(720, connected->screen_size().width());
284     ASSERT_EQ(1184, connected->screen_size().height());
285 
286     ASSERT_EQ("FirstDevice", connected->GetSerial());
287     ASSERT_EQ("Nexus 6", connected->GetModel());
288 
289     ASSERT_EQ("SecondDevice", not_connected->GetSerial());
290     ASSERT_EQ("Offline", not_connected->GetModel());
291 
292     const DevToolsAdbBridge::RemoteBrowsers& browsers = connected->browsers();
293     ASSERT_EQ(4U, browsers.size());
294 
295     scoped_refptr<DevToolsAdbBridge::RemoteBrowser> chrome =
296         FindBrowserByDisplayName(browsers, "Chrome");
297     ASSERT_TRUE(chrome);
298 
299     scoped_refptr<DevToolsAdbBridge::RemoteBrowser> chrome_beta =
300         FindBrowserByDisplayName(browsers, "Chrome Beta");
301     ASSERT_TRUE(chrome_beta);
302 
303     scoped_refptr<DevToolsAdbBridge::RemoteBrowser> chromium =
304         FindBrowserByDisplayName(browsers, "Chromium");
305     ASSERT_FALSE(chromium);
306 
307     scoped_refptr<DevToolsAdbBridge::RemoteBrowser> webview =
308         FindBrowserByDisplayName(browsers, "WebView in com.sample.feed");
309     ASSERT_TRUE(webview);
310 
311     scoped_refptr<DevToolsAdbBridge::RemoteBrowser> noprocess =
312         FindBrowserByDisplayName(browsers, "Noprocess");
313     ASSERT_TRUE(noprocess);
314 
315     ASSERT_EQ("32.0.1679.0", chrome->version());
316     ASSERT_EQ("31.0.1599.0", chrome_beta->version());
317     ASSERT_EQ("4.0", webview->version());
318 
319     std::vector<DevToolsTargetImpl*> chrome_pages =
320         chrome->CreatePageTargets();
321     std::vector<DevToolsTargetImpl*> chrome_beta_pages =
322         chrome_beta->CreatePageTargets();
323     std::vector<DevToolsTargetImpl*> webview_pages =
324         webview->CreatePageTargets();
325 
326     ASSERT_EQ(1U, chrome_pages.size());
327     ASSERT_EQ(0U, chrome_beta_pages.size());
328     ASSERT_EQ(2U, webview_pages.size());
329 
330     // Check that we have non-empty description for webview pages.
331     ASSERT_EQ(0U, chrome_pages[0]->GetDescription().size());
332     ASSERT_NE(0U, webview_pages[0]->GetDescription().size());
333     ASSERT_NE(0U, webview_pages[1]->GetDescription().size());
334 
335     ASSERT_EQ(GURL("http://www.chromium.org/"), chrome_pages[0]->GetUrl());
336     ASSERT_EQ("The Chromium Projects", chrome_pages[0]->GetTitle());
337 
338     STLDeleteElements(&chrome_pages);
339     STLDeleteElements(&webview_pages);
340   }
341 
init()342   void init() {
343     runner_ = new content::MessageLoopRunner;
344   }
345 
346 protected:
347   scoped_refptr<content::MessageLoopRunner> runner_;
348   DevToolsAdbBridge::RemoteDevices devices_;
349 };
350 
IN_PROC_BROWSER_TEST_F(DevToolsAdbBridgeTest,DiscoverAndroidBrowsers)351 IN_PROC_BROWSER_TEST_F(DevToolsAdbBridgeTest, DiscoverAndroidBrowsers) {
352   init();
353 
354   scoped_refptr<DevToolsAdbBridge> adb_bridge =
355       DevToolsAdbBridge::Factory::GetForProfile(browser()->profile());
356 
357   DevToolsAdbBridge::DeviceProviders providers;
358   providers.push_back(new MockDeviceProvider());
359 
360   adb_bridge->set_device_providers(providers);
361 
362   if (!adb_bridge) {
363     FAIL() << "Failed to get DevToolsAdbBridge.";
364   }
365 
366   adb_bridge->AddListener(this);
367 
368   runner_->Run();
369 
370   CheckDevices();
371 }
372