1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /** \file
18   This file consists of implementation of helper routines used
19   in the API.
20 */
21 
22 #include "stdafx.h"
23 #include "adb_api.h"
24 #include "adb_api_legacy.h"
25 #include "adb_helper_routines.h"
26 #include "adb_interface_enum.h"
27 
GetSDKComplientParam(AdbOpenAccessType access_type,AdbOpenSharingMode sharing_mode,ULONG * desired_access,ULONG * desired_sharing)28 bool GetSDKComplientParam(AdbOpenAccessType access_type,
29                           AdbOpenSharingMode sharing_mode,
30                           ULONG* desired_access,
31                           ULONG* desired_sharing) {
32   if (NULL != desired_access) {
33     switch (access_type) {
34       case AdbOpenAccessTypeReadWrite:
35         *desired_access = GENERIC_READ | GENERIC_WRITE;
36         break;
37 
38       case AdbOpenAccessTypeRead:
39         *desired_access = GENERIC_READ;
40         break;
41 
42       case AdbOpenAccessTypeWrite:
43         *desired_access = GENERIC_WRITE;
44         break;
45 
46       case AdbOpenAccessTypeQueryInfo:
47         *desired_access = FILE_READ_ATTRIBUTES | FILE_READ_EA;
48         break;
49 
50       default:
51         SetLastError(ERROR_INVALID_ACCESS);
52         return false;
53     }
54   }
55 
56   if (NULL != desired_sharing) {
57     switch (sharing_mode) {
58       case AdbOpenSharingModeReadWrite:
59         *desired_sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
60         break;
61 
62       case AdbOpenSharingModeRead:
63         *desired_sharing = FILE_SHARE_READ;
64         break;
65 
66       case AdbOpenSharingModeWrite:
67         *desired_sharing = FILE_SHARE_WRITE;
68         break;
69 
70       case AdbOpenSharingModeExclusive:
71         *desired_sharing = 0;
72         break;
73 
74       default:
75         SetLastError(ERROR_INVALID_PARAMETER);
76         return false;
77     }
78   }
79 
80   return true;
81 }
82 
EnumerateDeviceInterfaces(HDEVINFO hardware_dev_info,GUID class_id,bool exclude_removed,bool active_only,AdbEnumInterfaceArray * interfaces)83 bool EnumerateDeviceInterfaces(HDEVINFO hardware_dev_info,
84                                GUID class_id,
85                                bool exclude_removed,
86                                bool active_only,
87                                AdbEnumInterfaceArray* interfaces) {
88   AdbEnumInterfaceArray tmp;
89   bool ret = false;
90 
91   // Enumerate interfaces on this device
92   for (ULONG index = 0; ; index++) {
93     SP_DEVICE_INTERFACE_DATA interface_data;
94     interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
95 
96     // SetupDiEnumDeviceInterfaces() returns information about device
97     // interfaces exposed by one or more devices defined by our interface
98     // class. Each call returns information about one interface. The routine
99     // can be called repeatedly to get information about several interfaces
100     // exposed by one or more devices.
101     if (SetupDiEnumDeviceInterfaces(hardware_dev_info,
102                                     0,
103                                     &class_id,
104                                     index,
105                                     &interface_data)) {
106       // Satisfy "exclude removed" and "active only" filters.
107       if ((!exclude_removed || (0 == (interface_data.Flags & SPINT_REMOVED))) &&
108           (!active_only || (interface_data.Flags & SPINT_ACTIVE))) {
109         std::wstring dev_name;
110 
111         if (GetUsbDeviceName(hardware_dev_info, &interface_data, &dev_name)) {
112           try {
113             // Add new entry to the array
114             tmp.push_back(AdbInstanceEnumEntry(dev_name.c_str(),
115                                                interface_data.InterfaceClassGuid,
116                                                interface_data.Flags));
117           } catch (... ) {
118             SetLastError(ERROR_OUTOFMEMORY);
119             break;
120           }
121         } else {
122           // Something went wrong in getting device name
123           break;
124         }
125       }
126     } else {
127       if (ERROR_NO_MORE_ITEMS == GetLastError()) {
128         // There are no more items in the list. Enum is completed.
129         ret = true;
130         break;
131       } else {
132         // Something went wrong in SDK enum
133         break;
134       }
135     }
136   }
137 
138   // On success, swap temp array with the returning one
139   if (ret)
140     interfaces->swap(tmp);
141 
142   return ret;
143 }
144 
EnumerateDeviceInterfaces(GUID class_id,ULONG flags,bool exclude_removed,bool active_only,AdbEnumInterfaceArray * interfaces)145 bool EnumerateDeviceInterfaces(GUID class_id,
146                                ULONG flags,
147                                bool exclude_removed,
148                                bool active_only,
149                                AdbEnumInterfaceArray* interfaces) {
150   // Open a handle to the plug and play dev node.
151   // SetupDiGetClassDevs() returns a device information set that
152   // contains info on all installed devices of a specified class.
153   HDEVINFO hardware_dev_info =
154     SetupDiGetClassDevs(&class_id, NULL, NULL, flags);
155 
156   bool ret = false;
157 
158   if (INVALID_HANDLE_VALUE != hardware_dev_info) {
159     // Do the enum
160     ret = EnumerateDeviceInterfaces(hardware_dev_info,
161                                     class_id,
162                                     exclude_removed,
163                                     active_only,
164                                     interfaces);
165 
166     // Preserve last error accross hardware_dev_info destruction
167     ULONG error_to_report = ret ? NO_ERROR : GetLastError();
168 
169     SetupDiDestroyDeviceInfoList(hardware_dev_info);
170 
171     if (NO_ERROR != error_to_report)
172       SetLastError(error_to_report);
173   }
174 
175   return ret;
176 }
177 
GetUsbDeviceDetails(HDEVINFO hardware_dev_info,PSP_DEVICE_INTERFACE_DATA dev_info_data,PSP_DEVICE_INTERFACE_DETAIL_DATA * dev_info_detail_data)178 bool GetUsbDeviceDetails(
179     HDEVINFO hardware_dev_info,
180     PSP_DEVICE_INTERFACE_DATA dev_info_data,
181     PSP_DEVICE_INTERFACE_DETAIL_DATA* dev_info_detail_data) {
182   ULONG required_len = 0;
183 
184   // First query for the structure size. At this point we expect this call
185   // to fail with ERROR_INSUFFICIENT_BUFFER error code.
186   if (SetupDiGetDeviceInterfaceDetail(hardware_dev_info,
187                                       dev_info_data,
188                                       NULL,
189                                       0,
190                                       &required_len,
191                                       NULL)) {
192     return false;
193   }
194 
195   if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
196     return false;
197 
198   // Allocate buffer for the structure
199   PSP_DEVICE_INTERFACE_DETAIL_DATA buffer =
200     reinterpret_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(malloc(required_len));
201 
202   if (NULL == buffer) {
203     SetLastError(ERROR_OUTOFMEMORY);
204     return false;
205   }
206 
207   buffer->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
208 
209   // Retrieve the information from Plug and Play.
210   if (SetupDiGetDeviceInterfaceDetail(hardware_dev_info,
211                                       dev_info_data,
212                                       buffer,
213                                       required_len,
214                                       &required_len,
215                                       NULL)) {
216     *dev_info_detail_data = buffer;
217     return true;
218   } else {
219     // Free the buffer if this call failed
220     free(buffer);
221 
222     return false;
223   }
224 }
225 
GetUsbDeviceName(HDEVINFO hardware_dev_info,PSP_DEVICE_INTERFACE_DATA dev_info_data,std::wstring * name)226 bool GetUsbDeviceName(HDEVINFO hardware_dev_info,
227                       PSP_DEVICE_INTERFACE_DATA dev_info_data,
228                       std::wstring* name) {
229   PSP_DEVICE_INTERFACE_DETAIL_DATA func_class_dev_data = NULL;
230   if (!GetUsbDeviceDetails(hardware_dev_info,
231                            dev_info_data,
232                            &func_class_dev_data)) {
233     return false;
234   }
235 
236   try {
237     *name = func_class_dev_data->DevicePath;
238   } catch (...) {
239     SetLastError(ERROR_OUTOFMEMORY);
240   }
241 
242   free(func_class_dev_data);
243 
244   return !name->empty();
245 }
246 
IsLegacyInterface(const wchar_t * interface_name)247 bool IsLegacyInterface(const wchar_t* interface_name) {
248   // Open USB device for this intefface
249   HANDLE usb_device_handle = CreateFile(interface_name,
250                                         GENERIC_READ | GENERIC_WRITE,
251                                         FILE_SHARE_READ | FILE_SHARE_WRITE,
252                                         NULL,
253                                         OPEN_EXISTING,
254                                         0,
255                                         NULL);
256   if (INVALID_HANDLE_VALUE == usb_device_handle)
257     return NULL;
258 
259   // Try to issue ADB_IOCTL_GET_USB_DEVICE_DESCRIPTOR IOCTL that is supported
260   // by the legacy driver, but is not implemented in the WinUsb driver.
261   DWORD ret_bytes = 0;
262   USB_DEVICE_DESCRIPTOR descriptor;
263   BOOL ret = DeviceIoControl(usb_device_handle,
264                              ADB_IOCTL_GET_USB_DEVICE_DESCRIPTOR,
265                              NULL, 0,
266                              &descriptor,
267                              sizeof(descriptor),
268                              &ret_bytes,
269                              NULL);
270   ::CloseHandle(usb_device_handle);
271 
272   // If IOCTL succeeded we've got legacy driver underneath.
273   return ret ? true : false;
274 }
275