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 ~MockUsbService() override {}
418 scoped_refptr<UsbDevice> GetDeviceById(uint32 unique_id) override {
423 void GetDevices(std::vector<scoped_refptr<UsbDevice>>* devices) override {
424 STLClearObject(devices);
425 std::copy(devices_.begin(), devices_.end(), back_inserter(*devices));
428 std::vector<scoped_refptr<UsbDevice> > devices_;
431 class MockUsbServiceForCheckingTraits : public UsbService {
433 MockUsbServiceForCheckingTraits() : step_(0) {}
435 ~MockUsbServiceForCheckingTraits() override {}
437 scoped_refptr<UsbDevice> GetDeviceById(uint32 unique_id) override {
442 void GetDevices(std::vector<scoped_refptr<UsbDevice>>* devices) override {
443 STLClearObject(devices);
444 // This switch should be kept in sync with
445 // AndroidUsbBrowserTest::DeviceCountChanged.
452 devices->push_back(new MockUsbDevice<AndroidTraits>());
455 // Android and non-android device.
456 devices->push_back(new MockUsbDevice<AndroidTraits>());
457 devices->push_back(new MockUsbDevice<NonAndroidTraits>());
460 // Non-android device.
461 devices->push_back(new MockUsbDevice<NonAndroidTraits>());
471 class DevToolsAndroidBridgeWarmUp
472 : public DevToolsAndroidBridge::DeviceCountListener {
474 DevToolsAndroidBridgeWarmUp(base::Closure closure,
475 scoped_refptr<DevToolsAndroidBridge> adb_bridge)
476 : closure_(closure), adb_bridge_(adb_bridge) {}
478 void DeviceCountChanged(int count) override {
479 adb_bridge_->RemoveDeviceCountListener(this);
483 base::Closure closure_;
484 scoped_refptr<DevToolsAndroidBridge> adb_bridge_;
487 class AndroidUsbDiscoveryTest : public InProcessBrowserTest {
489 AndroidUsbDiscoveryTest()
490 : scheduler_invoked_(0) {
492 void SetUpOnMainThread() override {
493 scoped_refptr<content::MessageLoopRunner> runner =
494 new content::MessageLoopRunner;
496 BrowserThread::PostTaskAndReply(
499 base::Bind(&AndroidUsbDiscoveryTest::SetUpService, this),
500 runner->QuitClosure());
504 DevToolsAndroidBridge::Factory::GetForProfile(browser()->profile());
505 DCHECK(adb_bridge_.get());
506 adb_bridge_->set_task_scheduler_for_test(base::Bind(
507 &AndroidUsbDiscoveryTest::ScheduleDeviceCountRequest, this));
509 scoped_refptr<UsbDeviceProvider> provider =
510 new UsbDeviceProvider(browser()->profile());
512 AndroidDeviceManager::DeviceProviders providers;
513 providers.push_back(provider);
514 adb_bridge_->set_device_providers_for_test(providers);
515 runner_ = new content::MessageLoopRunner;
518 void ScheduleDeviceCountRequest(const base::Closure& request) {
519 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
520 scheduler_invoked_++;
521 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, request);
524 virtual void SetUpService() {
525 UsbService::SetInstanceForTest(new MockUsbService());
528 void TearDownOnMainThread() override {
529 scoped_refptr<content::MessageLoopRunner> runner =
530 new content::MessageLoopRunner;
531 UsbService* service = NULL;
532 BrowserThread::PostTaskAndReply(
535 base::Bind(&UsbService::SetInstanceForTest, service),
536 runner->QuitClosure());
540 scoped_refptr<content::MessageLoopRunner> runner_;
541 scoped_refptr<DevToolsAndroidBridge> adb_bridge_;
542 int scheduler_invoked_;
545 class AndroidUsbCountTest : public AndroidUsbDiscoveryTest {
547 void SetUpOnMainThread() override {
548 AndroidUsbDiscoveryTest::SetUpOnMainThread();
549 DevToolsAndroidBridgeWarmUp warmup(runner_->QuitClosure(), adb_bridge_);
550 adb_bridge_->AddDeviceCountListener(&warmup);
552 runner_ = new content::MessageLoopRunner;
556 class AndroidUsbTraitsTest : public AndroidUsbDiscoveryTest {
558 void SetUpService() override {
559 UsbService::SetInstanceForTest(new MockUsbServiceForCheckingTraits());
563 class MockListListener : public DevToolsAndroidBridge::DeviceListListener {
565 MockListListener(scoped_refptr<DevToolsAndroidBridge> adb_bridge,
566 const base::Closure& callback)
567 : adb_bridge_(adb_bridge),
568 callback_(callback) {
571 void DeviceListChanged(
572 const DevToolsAndroidBridge::RemoteDevices& devices) override {
573 if (devices.size() > 0) {
574 if (devices[0]->is_connected()) {
575 ASSERT_EQ(kDeviceModel, devices[0]->model());
576 ASSERT_EQ(kDeviceSerial, devices[0]->serial());
577 adb_bridge_->RemoveDeviceListListener(this);
583 scoped_refptr<DevToolsAndroidBridge> adb_bridge_;
584 base::Closure callback_;
587 class MockCountListener : public DevToolsAndroidBridge::DeviceCountListener {
589 explicit MockCountListener(scoped_refptr<DevToolsAndroidBridge> adb_bridge)
590 : adb_bridge_(adb_bridge),
595 void DeviceCountChanged(int count) override {
597 adb_bridge_->RemoveDeviceCountListener(this);
602 ShutdownOnUIThread();
605 void ShutdownOnUIThread() {
606 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
607 if (reposts_left_-- == 0) {
608 base::MessageLoop::current()->Quit();
610 BrowserThread::PostTask(
613 base::Bind(&MockCountListener::ShutdownOnFileThread,
614 base::Unretained(this)));
618 void ShutdownOnFileThread() {
619 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
620 BrowserThread::PostTask(BrowserThread::UI,
622 base::Bind(&MockCountListener::ShutdownOnUIThread,
623 base::Unretained(this)));
626 scoped_refptr<DevToolsAndroidBridge> adb_bridge_;
631 class MockCountListenerWithReAdd : public MockCountListener {
633 explicit MockCountListenerWithReAdd(
634 scoped_refptr<DevToolsAndroidBridge> adb_bridge)
635 : MockCountListener(adb_bridge),
639 void DeviceCountChanged(int count) override {
641 adb_bridge_->RemoveDeviceCountListener(this);
642 if (readd_count_ > 0) {
644 adb_bridge_->AddDeviceCountListener(this);
645 adb_bridge_->RemoveDeviceCountListener(this);
646 adb_bridge_->AddDeviceCountListener(this);
655 class MockCountListenerWithReAddWhileQueued : public MockCountListener {
657 MockCountListenerWithReAddWhileQueued(
658 scoped_refptr<DevToolsAndroidBridge> adb_bridge)
659 : MockCountListener(adb_bridge),
663 void DeviceCountChanged(int count) override {
667 base::MessageLoop::current()->PostTask(
669 base::Bind(&MockCountListenerWithReAddWhileQueued::ReAdd,
670 base::Unretained(this)));
672 adb_bridge_->RemoveDeviceCountListener(this);
678 adb_bridge_->RemoveDeviceCountListener(this);
679 adb_bridge_->AddDeviceCountListener(this);
685 class MockCountListenerForCheckingTraits : public MockCountListener {
687 MockCountListenerForCheckingTraits(
688 scoped_refptr<DevToolsAndroidBridge> adb_bridge)
689 : MockCountListener(adb_bridge),
692 void DeviceCountChanged(int count) override {
695 // Check for 0 devices when no devices present.
699 // Check for 1 device when only android device present.
703 // Check for 1 device when android and non-android devices present.
707 // Check for 0 devices when only non-android devices present.
709 adb_bridge_->RemoveDeviceCountListener(this);
713 EXPECT_TRUE(false) << "Unknown step " << step_;
723 IN_PROC_BROWSER_TEST_F(AndroidUsbDiscoveryTest, TestDeviceDiscovery) {
724 MockListListener listener(adb_bridge_, runner_->QuitClosure());
725 adb_bridge_->AddDeviceListListener(&listener);
729 IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest,
730 TestNoMultipleCallsRemoveInCallback) {
731 MockCountListener listener(adb_bridge_);
732 adb_bridge_->AddDeviceCountListener(&listener);
734 EXPECT_EQ(1, listener.invoked_);
735 EXPECT_EQ(listener.invoked_ - 1, scheduler_invoked_);
738 IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest,
739 TestNoMultipleCallsRemoveAddInCallback) {
740 MockCountListenerWithReAdd listener(adb_bridge_);
741 adb_bridge_->AddDeviceCountListener(&listener);
743 EXPECT_EQ(3, listener.invoked_);
744 EXPECT_EQ(listener.invoked_ - 1, scheduler_invoked_);
747 IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest,
748 TestNoMultipleCallsRemoveAddOnStart) {
749 MockCountListener listener(adb_bridge_);
750 adb_bridge_->AddDeviceCountListener(&listener);
751 adb_bridge_->RemoveDeviceCountListener(&listener);
752 adb_bridge_->AddDeviceCountListener(&listener);
754 EXPECT_EQ(1, listener.invoked_);
755 EXPECT_EQ(listener.invoked_ - 1, scheduler_invoked_);
758 IN_PROC_BROWSER_TEST_F(AndroidUsbCountTest,
759 TestNoMultipleCallsRemoveAddWhileQueued) {
760 MockCountListenerWithReAddWhileQueued listener(adb_bridge_);
761 adb_bridge_->AddDeviceCountListener(&listener);
763 EXPECT_EQ(2, listener.invoked_);
764 EXPECT_EQ(listener.invoked_ - 1, scheduler_invoked_);
767 IN_PROC_BROWSER_TEST_F(AndroidUsbTraitsTest, TestDeviceCounting) {
768 MockCountListenerForCheckingTraits listener(adb_bridge_);
769 adb_bridge_->AddDeviceCountListener(&listener);