Home | History | Annotate | Download | only in devtools
      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:
    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 
    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 AndroidDeviceProvider {
    239   virtual ~MockDeviceProvider()
    240   {}
    241 
    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>
    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:
    265   virtual void RemoteDevicesChanged(
    266       DevToolsAdbBridge::RemoteDevices* devices) OVERRIDE{
    267     devices_ = *devices;
    268     runner_->Quit();
    269   }
    270 
    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 
    342   void init() {
    343     runner_ = new content::MessageLoopRunner;
    344   }
    345 
    346 protected:
    347   scoped_refptr<content::MessageLoopRunner> runner_;
    348   DevToolsAdbBridge::RemoteDevices devices_;
    349 };
    350 
    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