adb_helper_routines.cpp revision 39164844f16c2c63d52a71652d53b233c5f28e14
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
28bool 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
83bool 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
145bool 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
178bool 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
226bool 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
247bool 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