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.
7 #include "base/strings/utf_string_conversions.h"
8 #include "chrome/browser/devtools/device/devtools_android_bridge.h"
9 #include "chrome/browser/devtools/device/usb/android_usb_device.h"
10 #include "chrome/browser/devtools/device/usb/usb_device_provider.h"
11 #include "chrome/browser/ui/browser.h"
12 #include "chrome/test/base/in_process_browser_test.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "content/public/test/test_utils.h"
15 #include "device/usb/usb_descriptors.h"
16 #include "device/usb/usb_device.h"
17 #include "device/usb/usb_device_handle.h"
18 #include "device/usb/usb_service.h"
19 #include "testing/gtest/include/gtest/gtest.h"
21 using content::BrowserThread;
22 using device::UsbConfigDescriptor;
23 using device::UsbDevice;
24 using device::UsbDeviceHandle;
25 using device::UsbEndpointDescriptor;
26 using device::UsbEndpointDirection;
27 using device::UsbInterfaceDescriptor;
28 using device::UsbService;
29 using device::UsbSynchronizationType;
30 using device::UsbTransferCallback;
31 using device::UsbTransferType;
32 using device::UsbUsageType;
36 struct AndroidTraits {
37 static const int kClass = 0xff;
38 static const int kSubclass = 0x42;
39 static const int kProtocol = 0x1;
42 struct NonAndroidTraits {
43 static const int kClass = 0xf0;
44 static const int kSubclass = 0x42;
45 static const int kProtocol = 0x2;
48 const uint32 kMaxPayload = 4096;
49 const uint32 kVersion = 0x01000000;
51 const char kOpenedUnixSocketsCommand[] = "shell:cat /proc/net/unix";
52 const char kDeviceModelCommand[] = "shell:getprop ro.product.model";
53 const char kDumpsysCommand[] = "shell:dumpsys window policy";
54 const char kListProcessesCommand[] = "shell:ps";
55 const char kInstalledChromePackagesCommand[] = "shell:pm list packages";
56 const char kDeviceManufacturer[] = "Test Manufacturer";
57 const char kDeviceModel[] = "Nexus 5";
58 const char kDeviceSerial[] = "Sample serial";
60 const char kSampleOpenedUnixSockets[] =
61 "Num RefCount Protocol Flags Type St Inode Path\n"
62 "00000000: 00000004 00000000"
63 " 00000000 0002 01 3328 /dev/socket/wpa_wlan0\n"
64 "00000000: 00000002 00000000"
65 " 00010000 0001 01 5394 /dev/socket/vold\n";
67 const char kSampleListProcesses[] =
68 "USER PID PPID VSIZE RSS WCHAN PC NAME\n"
69 "root 1 0 688 508 ffffffff 00000000 S /init\r\n"
70 "u0_a75 2425 123 933736 193024 ffffffff 00000000 S com.sample.feed\r\n"
71 "nfc 741 123 706448 26316 ffffffff 00000000 S com.android.nfc\r\n"
72 "u0_a76 1001 124 111111 222222 ffffffff 00000000 S com.android.chrome\r\n"
73 "u0_a78 1003 126 111111 222222 ffffffff 00000000 S com.noprocess.app\r\n";
75 const char kSampleListPackages[] =
76 "package:com.sample.feed\r\n"
77 "package:com.android.nfc\r\n"
78 "package:com.android.chrome\r\n"
79 "package:com.chrome.beta\r\n"
80 "package:com.google.android.apps.chrome\r\n";
82 const char kSampleDumpsys[] =
83 "WINDOW MANAGER POLICY STATE (dumpsys window policy)\r\n"
84 " mSafeMode=false mSystemReady=true mSystemBooted=true\r\n"
85 " mStable=(0,50)-(720,1184)\r\n" // Only mStable parameter is parsed
86 " mForceStatusBar=false mForceStatusBarFromKeyguard=false\r\n";
88 const char* GetMockShellResponse(std::string command) {
89 if (command == kDeviceModelCommand) {
91 } else if (command == kOpenedUnixSocketsCommand) {
92 return kSampleOpenedUnixSockets;
93 } else if (command == kDumpsysCommand) {
94 return kSampleDumpsys;
95 } else if (command == kListProcessesCommand) {
96 return kSampleListProcesses;
97 } else if (command == kInstalledChromePackagesCommand) {
98 return kSampleListPackages;
101 DCHECK(false) << "Should not be reached";
110 class MockUsbDeviceHandle : public UsbDeviceHandle {
112 explicit MockUsbDeviceHandle(MockUsbDevice<T>* device)
114 remaining_body_length_(0),
115 next_local_socket_(0) {}
117 virtual scoped_refptr<UsbDevice> GetDevice() const OVERRIDE {
121 virtual void Close() OVERRIDE { device_ = NULL; }
123 bool ClaimInterface(int interface_number) {
124 if (device_->claimed_interfaces_.find(interface_number) !=
125 device_->claimed_interfaces_.end())
128 device_->claimed_interfaces_.insert(interface_number);
132 bool ReleaseInterface(int interface_number) {
133 if (device_->claimed_interfaces_.find(interface_number) ==
134 device_->claimed_interfaces_.end())
137 device_->claimed_interfaces_.erase(interface_number);
141 virtual bool SetInterfaceAlternateSetting(int interface_number,
142 int alternate_setting) OVERRIDE {
146 virtual bool ResetDevice() OVERRIDE { return true; }
147 virtual bool GetStringDescriptor(uint8_t string_id, base::string16* content) {
151 // Async IO. Can be called on any thread.
152 virtual void ControlTransfer(UsbEndpointDirection direction,
153 TransferRequestType request_type,
154 TransferRecipient recipient,
158 net::IOBuffer* buffer,
160 unsigned int timeout,
161 const UsbTransferCallback& callback) OVERRIDE {}
163 virtual void BulkTransfer(UsbEndpointDirection direction,
165 net::IOBuffer* buffer,
167 unsigned int timeout,
168 const UsbTransferCallback& callback) OVERRIDE {
169 if (direction == device::USB_DIRECTION_OUTBOUND) {
170 if (remaining_body_length_ == 0) {
171 std::vector<uint32> header(6);
172 memcpy(&header[0], buffer->data(), length);
173 current_message_ = new AdbMessage(header[0], header[1], header[2], "");
174 remaining_body_length_ = header[3];
175 uint32 magic = header[5];
176 if ((current_message_->command ^ 0xffffffff) != magic) {
177 DCHECK(false) << "Header checksum error";
181 DCHECK(current_message_.get());
182 current_message_->body += std::string(buffer->data(), length);
183 remaining_body_length_ -= length;
186 if (remaining_body_length_ == 0) {
190 base::MessageLoop::current()->PostTask(
193 device::USB_TRANSFER_COMPLETED,
194 scoped_refptr<net::IOBuffer>(),
197 } else if (direction == device::USB_DIRECTION_INBOUND) {
198 queries_.push(Query(callback, make_scoped_refptr(buffer), length));
204 void append(D data) {
205 std::copy(reinterpret_cast<char*>(&data),
206 (reinterpret_cast<char*>(&data)) + sizeof(D),
207 std::back_inserter(output_buffer_));
210 // Copied from AndroidUsbDevice::Checksum
211 uint32 Checksum(const std::string& data) {
212 unsigned char* x = (unsigned char*)data.data();
213 int count = data.length();
220 void ProcessIncoming() {
221 DCHECK(current_message_.get());
222 switch (current_message_->command) {
223 case AdbMessage::kCommandCNXN:
224 WriteResponse(new AdbMessage(AdbMessage::kCommandCNXN,
227 "device::ro.product.name=SampleProduct;ro."
228 "product.model=SampleModel;ro.product."
229 "device=SampleDevice;"));
231 case AdbMessage::kCommandOPEN:
232 DCHECK(current_message_->arg1 == 0);
233 DCHECK(current_message_->arg0 != 0);
234 if (current_message_->body.find("shell:") != std::string::npos) {
235 WriteResponse(new AdbMessage(AdbMessage::kCommandOKAY,
236 ++next_local_socket_,
237 current_message_->arg0,
240 new AdbMessage(AdbMessage::kCommandWRTE,
242 current_message_->arg0,
243 GetMockShellResponse(current_message_->body.substr(
244 0, current_message_->body.size() - 1))));
245 WriteResponse(new AdbMessage(
246 AdbMessage::kCommandCLSE, 0, current_message_->arg0, ""));
254 void WriteResponse(scoped_refptr<AdbMessage> response) {
255 append(response->command);
256 append(response->arg0);
257 append(response->arg1);
258 bool add_zero = response->body.length() &&
259 (response->command != AdbMessage::kCommandWRTE);
260 append(static_cast<uint32>(response->body.length() + (add_zero ? 1 : 0)));
261 append(Checksum(response->body));
262 append(response->command ^ 0xffffffff);
263 std::copy(response->body.begin(),
264 response->body.end(),
265 std::back_inserter(output_buffer_));
267 output_buffer_.push_back(0);
272 void ProcessQueries() {
273 if (!queries_.size())
275 Query query = queries_.front();
277 if (query.size > output_buffer_.size())
281 std::copy(output_buffer_.begin(),
282 output_buffer_.begin() + query.size,
283 query.buffer->data());
284 output_buffer_.erase(output_buffer_.begin(),
285 output_buffer_.begin() + query.size);
286 base::MessageLoop::current()->PostTask(
288 base::Bind(query.callback,
289 device::USB_TRANSFER_COMPLETED,
294 virtual void InterruptTransfer(UsbEndpointDirection direction,
296 net::IOBuffer* buffer,
298 unsigned int timeout,
299 const UsbTransferCallback& callback) OVERRIDE {
302 virtual void IsochronousTransfer(
303 UsbEndpointDirection direction,
305 net::IOBuffer* buffer,
307 unsigned int packets,
308 unsigned int packet_length,
309 unsigned int timeout,
310 const UsbTransferCallback& callback) OVERRIDE {}
313 virtual ~MockUsbDeviceHandle() {}
316 UsbTransferCallback callback;
317 scoped_refptr<net::IOBuffer> buffer;
320 Query(UsbTransferCallback callback,
321 scoped_refptr<net::IOBuffer> buffer,
323 : callback(callback), buffer(buffer), size(size) {};
326 scoped_refptr<MockUsbDevice<T> > device_;
327 uint32 remaining_body_length_;
328 scoped_refptr<AdbMessage> current_message_;
329 std::vector<char> output_buffer_;
330 std::queue<Query> queries_;
331 int next_local_socket_;
335 class MockUsbDevice : public UsbDevice {
337 MockUsbDevice() : UsbDevice(0, 0, 0) {
338 UsbEndpointDescriptor bulk_in;
339 bulk_in.address = 0x81;
340 bulk_in.direction = device::USB_DIRECTION_INBOUND;
341 bulk_in.maximum_packet_size = 512;
342 bulk_in.transfer_type = device::USB_TRANSFER_BULK;
344 UsbEndpointDescriptor bulk_out;
345 bulk_out.address = 0x01;
346 bulk_out.direction = device::USB_DIRECTION_OUTBOUND;
347 bulk_out.maximum_packet_size = 512;
348 bulk_out.transfer_type = device::USB_TRANSFER_BULK;
350 UsbInterfaceDescriptor interface_desc;
351 interface_desc.interface_number = 0;
352 interface_desc.alternate_setting = 0;
353 interface_desc.interface_class = T::kClass;
354 interface_desc.interface_subclass = T::kSubclass;
355 interface_desc.interface_protocol = T::kProtocol;
356 interface_desc.endpoints.push_back(bulk_in);
357 interface_desc.endpoints.push_back(bulk_out);
359 config_desc_.interfaces.push_back(interface_desc);
362 virtual scoped_refptr<UsbDeviceHandle> Open() OVERRIDE {
363 return new MockUsbDeviceHandle<T>(this);
366 virtual const UsbConfigDescriptor& GetConfiguration() OVERRIDE {
370 virtual bool GetManufacturer(base::string16* manufacturer) OVERRIDE {
371 *manufacturer = base::UTF8ToUTF16(kDeviceManufacturer);
375 virtual bool GetProduct(base::string16* product) OVERRIDE {
376 *product = base::UTF8ToUTF16(kDeviceModel);
380 virtual bool GetSerialNumber(base::string16* serial) OVERRIDE {
381 *serial = base::UTF8ToUTF16(kDeviceSerial);
385 virtual bool Close(scoped_refptr<UsbDeviceHandle> handle) OVERRIDE {
389 #if defined(OS_CHROMEOS)
390 // On ChromeOS, if an interface of a claimed device is not claimed, the
391 // permission broker can change the owner of the device so that the unclaimed
392 // interfaces can be used. If this argument is missing, permission broker will
393 // not be used and this method fails if the device is claimed.
394 virtual void RequestUsbAccess(
396 const base::Callback<void(bool success)>& callback) OVERRIDE {
399 #endif // OS_CHROMEOS
401 std::set<int> claimed_interfaces_;
404 virtual ~MockUsbDevice() {}
407 UsbConfigDescriptor config_desc_;
410 class MockUsbService : public UsbService {
413 devices_.push_back(new MockUsbDevice<AndroidTraits>());
416 virtual ~MockUsbService() {}
418 virtual scoped_refptr<UsbDevice> GetDeviceById(uint32 unique_id) OVERRIDE {
423 virtual void GetDevices(
424 std::vector<scoped_refptr<UsbDevice> >* devices) OVERRIDE {
425 STLClearObject(devices);
426 std::copy(devices_.begin(), devices_.end(), back_inserter(*devices));
429 std::vector<scoped_refptr<UsbDevice> > devices_;
432 class MockUsbServiceForCheckingTraits : public UsbService {
434 MockUsbServiceForCheckingTraits() : step_(0) {}
436 virtual ~MockUsbServiceForCheckingTraits() {}
438 virtual scoped_refptr<UsbDevice> GetDeviceById(uint32 unique_id) OVERRIDE {
443 virtual void GetDevices(
444 std::vector<scoped_refptr<UsbDevice> >* devices) OVERRIDE {
445 STLClearObject(devices);
446 // This switch should be kept in sync with
447 // AndroidUsbBrowserTest::DeviceCountChanged.
454 devices->push_back(new MockUsbDevice<AndroidTraits>());
457 // Android and non-android device.
458 devices->push_back(new MockUsbDevice<AndroidTraits>());
459 devices->push_back(new MockUsbDevice<NonAndroidTraits>());
462 // Non-android device.
463 devices->push_back(new MockUsbDevice<NonAndroidTraits>());
473 class DevToolsAndroidBridgeWarmUp
474 : public DevToolsAndroidBridge::DeviceCountListener {
476 DevToolsAndroidBridgeWarmUp(base::Closure closure,
477 scoped_refptr<DevToolsAndroidBridge> adb_bridge)
478 : closure_(closure), adb_bridge_(adb_bridge) {}
480 virtual void DeviceCountChanged(int count) OVERRIDE {
481 adb_bridge_->RemoveDeviceCountListener(this);
485 base::Closure closure_;
486 scoped_refptr<DevToolsAndroidBridge> adb_bridge_;
489 class AndroidUsbDiscoveryTest : public InProcessBrowserTest {
491 AndroidUsbDiscoveryTest()
492 : scheduler_invoked_(0) {
494 virtual void SetUpOnMainThread() OVERRIDE {
495 scoped_refptr<content::MessageLoopRunner> runner =
496 new content::MessageLoopRunner;
498 BrowserThread::PostTaskAndReply(
501 base::Bind(&AndroidUsbDiscoveryTest::SetUpService, this),
502 runner->QuitClosure());
506 DevToolsAndroidBridge::Factory::GetForProfile(browser()->profile());
507 DCHECK(adb_bridge_.get());
508 adb_bridge_->set_task_scheduler_for_test(base::Bind(
509 &AndroidUsbDiscoveryTest::ScheduleDeviceCountRequest, this));
511 scoped_refptr<UsbDeviceProvider> provider =
512 new UsbDeviceProvider(browser()->profile());
514 AndroidDeviceManager::DeviceProviders providers;
515 providers.push_back(provider);
516 adb_bridge_->set_device_providers_for_test(providers);
517 runner_ = new content::MessageLoopRunner;
520 void ScheduleDeviceCountRequest(const base::Closure& request) {
521 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
522 scheduler_invoked_++;
523 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, request);
526 virtual void SetUpService() {
527 UsbService::SetInstanceForTest(new MockUsbService());
530 virtual void TearDownOnMainThread() OVERRIDE {
531 scoped_refptr<content::MessageLoopRunner> runner =
532 new content::MessageLoopRunner;
533 UsbService* service = NULL;
534 BrowserThread::PostTaskAndReply(
537 base::Bind(&UsbService::SetInstanceForTest, service),
538 runner->QuitClosure());
542 scoped_refptr<content::MessageLoopRunner> runner_;
543 scoped_refptr<DevToolsAndroidBridge> adb_bridge_;
544 int scheduler_invoked_;
547 class AndroidUsbCountTest : public AndroidUsbDiscoveryTest {
549 virtual void SetUpOnMainThread() OVERRIDE {
550 AndroidUsbDiscoveryTest::SetUpOnMainThread();
551 DevToolsAndroidBridgeWarmUp warmup(runner_->QuitClosure(), adb_bridge_);
552 adb_bridge_->AddDeviceCountListener(&warmup);
554 runner_ = new content::MessageLoopRunner;
558 class AndroidUsbTraitsTest : public AndroidUsbDiscoveryTest {
560 virtual void SetUpService() OVERRIDE {
561 UsbService::SetInstanceForTest(new MockUsbServiceForCheckingTraits());
565 class MockListListener : public DevToolsAndroidBridge::DeviceListListener {
567 MockListListener(scoped_refptr<DevToolsAndroidBridge> adb_bridge,
568 const base::Closure& callback)
569 : adb_bridge_(adb_bridge),
570 callback_(callback) {
573 virtual void DeviceListChanged(
574 const DevToolsAndroidBridge::RemoteDevices& devices) OVERRIDE {
575 if (devices.size() > 0) {
576 if (devices[0]->is_connected()) {
577 ASSERT_EQ(kDeviceModel, devices[0]->model());
578 ASSERT_EQ(kDeviceSerial, devices[0]->serial());
579 adb_bridge_->RemoveDeviceListListener(this);
585 scoped_refptr<DevToolsAndroidBridge> adb_bridge_;
586 base::Closure callback_;
589 class MockCountListener : public DevToolsAndroidBridge::DeviceCountListener {
591 explicit MockCountListener(scoped_refptr<DevToolsAndroidBridge> adb_bridge)
592 : adb_bridge_(adb_bridge),
597 virtual void DeviceCountChanged(int count) OVERRIDE {
599 adb_bridge_->RemoveDeviceCountListener(this);
604 ShutdownOnUIThread();
607 void ShutdownOnUIThread() {
608 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
609 if (reposts_left_-- == 0) {
610 base::MessageLoop::current()->Quit();
612 BrowserThread::PostTask(
615 base::Bind(&MockCountListener::ShutdownOnFileThread,
616 base::Unretained(this)));
620 void ShutdownOnFileThread() {
621 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
622 BrowserThread::PostTask(BrowserThread::UI,
624 base::Bind(&MockCountListener::ShutdownOnUIThread,
625 base::Unretained(this)));
628 scoped_refptr<DevToolsAndroidBridge> adb_bridge_;
633 class MockCountListenerWithReAdd : public MockCountListener {
635 explicit MockCountListenerWithReAdd(
636 scoped_refptr<DevToolsAndroidBridge> adb_bridge)
637 : MockCountListener(adb_bridge),
641 virtual void DeviceCountChanged(int count) OVERRIDE {
643 adb_bridge_->RemoveDeviceCountListener(this);
644 if (readd_count_ > 0) {
646 adb_bridge_->AddDeviceCountListener(this);
647 adb_bridge_->RemoveDeviceCountListener(this);
648 adb_bridge_->AddDeviceCountListener(this);
657 class MockCountListenerWithReAddWhileQueued : public MockCountListener {
659 MockCountListenerWithReAddWhileQueued(
660 scoped_refptr<DevToolsAndroidBridge> adb_bridge)
661 : MockCountListener(adb_bridge),
665 virtual void DeviceCountChanged(int count) OVERRIDE {
669 base::MessageLoop::current()->PostTask(
671 base::Bind(&MockCountListenerWithReAddWhileQueued::ReAdd,
672 base::Unretained(this)));
674 adb_bridge_->RemoveDeviceCountListener(this);
680 adb_bridge_->RemoveDeviceCountListener(this);
681 adb_bridge_->AddDeviceCountListener(this);
687 class MockCountListenerForCheckingTraits : public MockCountListener {
689 MockCountListenerForCheckingTraits(
690 scoped_refptr<DevToolsAndroidBridge> adb_bridge)
691 : MockCountListener(adb_bridge),
694 virtual void DeviceCountChanged(int count) OVERRIDE {
697 // Check for 0 devices when no devices present.
701 // Check for 1 device when only android device present.
705 // Check for 1 device when android and non-android devices present.
709 // Check for 0 devices when only non-android devices present.
711 adb_bridge_->RemoveDeviceCountListener(this);
715 EXPECT_TRUE(false) << "Unknown step " << step_;
725 IN_PROC_BROWSER_TEST_F(AndroidUsbDiscoveryTest, TestDeviceDiscovery) {
726 MockListListener listener(adb_bridge_, runner_->QuitClosure());
727 adb_bridge_->AddDeviceListListener(&listener);
731 IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest,
732 TestNoMultipleCallsRemoveInCallback) {
733 MockCountListener listener(adb_bridge_);
734 adb_bridge_->AddDeviceCountListener(&listener);
736 EXPECT_EQ(1, listener.invoked_);
737 EXPECT_EQ(listener.invoked_ - 1, scheduler_invoked_);
740 IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest,
741 TestNoMultipleCallsRemoveAddInCallback) {
742 MockCountListenerWithReAdd listener(adb_bridge_);
743 adb_bridge_->AddDeviceCountListener(&listener);
745 EXPECT_EQ(3, listener.invoked_);
746 EXPECT_EQ(listener.invoked_ - 1, scheduler_invoked_);
749 IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest,
750 TestNoMultipleCallsRemoveAddOnStart) {
751 MockCountListener listener(adb_bridge_);
752 adb_bridge_->AddDeviceCountListener(&listener);
753 adb_bridge_->RemoveDeviceCountListener(&listener);
754 adb_bridge_->AddDeviceCountListener(&listener);
756 EXPECT_EQ(1, listener.invoked_);
757 EXPECT_EQ(listener.invoked_ - 1, scheduler_invoked_);
760 IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest,
761 TestNoMultipleCallsRemoveAddWhileQueued) {
762 MockCountListenerWithReAddWhileQueued listener(adb_bridge_);
763 adb_bridge_->AddDeviceCountListener(&listener);
765 EXPECT_EQ(2, listener.invoked_);
766 EXPECT_EQ(listener.invoked_ - 1, scheduler_invoked_);
769 IN_PROC_BROWSER_TEST_F(AndroidUsbTraitsTest, TestDeviceCounting) {
770 MockCountListenerForCheckingTraits listener(adb_bridge_);
771 adb_bridge_->AddDeviceCountListener(&listener);