adb_helper_routines.cpp revision dceaaa52cec11631c72cfea5fb74ee607602ecde
1/*
2 * Copyright (C) 2006 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_helper_routines.h"
25#include "adb_interface_enum.h"
26
27bool EnumerateDeviceInterfaces(HDEVINFO hardware_dev_info,
28                               GUID class_id,
29                               bool exclude_removed,
30                               bool active_only,
31                               AdbEnumInterfaceArray* interfaces) {
32  AdbEnumInterfaceArray tmp;
33  bool ret = false;
34
35  // Enumerate interfaces on this device
36  for (ULONG index = 0; ; index++) {
37    SP_DEVICE_INTERFACE_DATA interface_data;
38    interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
39
40    // SetupDiEnumDeviceInterfaces() returns information about device
41    // interfaces exposed by one or more devices defined by our interface
42    // class. Each call returns information about one interface. The routine
43    // can be called repeatedly to get information about several interfaces
44    // exposed by one or more devices.
45    if (SetupDiEnumDeviceInterfaces(hardware_dev_info,
46                                    0,
47                                    &class_id,
48                                    index,
49                                    &interface_data)) {
50      // Satisfy "exclude removed" and "active only" filters.
51      if ((!exclude_removed || (0 == (interface_data.Flags & SPINT_REMOVED))) &&
52          (!active_only || (interface_data.Flags & SPINT_ACTIVE))) {
53        std::wstring dev_name;
54
55        if (GetUsbDeviceName(hardware_dev_info, &interface_data, &dev_name)) {
56          try {
57            // Add new entry to the array
58            tmp.push_back(AdbInstanceEnumEntry(dev_name.c_str(),
59                                               interface_data.InterfaceClassGuid,
60                                               interface_data.Flags));
61          } catch (... ) {
62            SetLastError(ERROR_OUTOFMEMORY);
63            break;
64          }
65        } else {
66          // Something went wrong in getting device name
67          break;
68        }
69      }
70    } else {
71      if (ERROR_NO_MORE_ITEMS == GetLastError()) {
72        // There are no more items in the list. Enum is completed.
73        ret = true;
74        break;
75      } else {
76        // Something went wrong in SDK enum
77        break;
78      }
79    }
80  }
81
82  // On success, swap temp array with the returning one
83  if (ret)
84    interfaces->swap(tmp);
85
86  return ret;
87}
88
89bool EnumerateDeviceInterfaces(GUID class_id,
90                               ULONG flags,
91                               bool exclude_removed,
92                               bool active_only,
93                               AdbEnumInterfaceArray* interfaces) {
94  // Open a handle to the plug and play dev node.
95  // SetupDiGetClassDevs() returns a device information set that
96  // contains info on all installed devices of a specified class.
97  HDEVINFO hardware_dev_info =
98    SetupDiGetClassDevs(&class_id, NULL, NULL, flags);
99
100  bool ret = false;
101
102  if (INVALID_HANDLE_VALUE != hardware_dev_info) {
103    // Do the enum
104    ret = EnumerateDeviceInterfaces(hardware_dev_info,
105                                    class_id,
106                                    exclude_removed,
107                                    active_only,
108                                    interfaces);
109
110    // Preserve last error accross hardware_dev_info destruction
111    ULONG error_to_report = ret ? NO_ERROR : GetLastError();
112
113    SetupDiDestroyDeviceInfoList(hardware_dev_info);
114
115    if (NO_ERROR != error_to_report)
116      SetLastError(error_to_report);
117  }
118
119  return ret;
120}
121
122bool GetUsbDeviceDetails(
123    HDEVINFO hardware_dev_info,
124    PSP_DEVICE_INTERFACE_DATA dev_info_data,
125    PSP_DEVICE_INTERFACE_DETAIL_DATA* dev_info_detail_data) {
126  ULONG required_len = 0;
127
128  // First query for the structure size. At this point we expect this call
129  // to fail with ERROR_INSUFFICIENT_BUFFER error code.
130  if (SetupDiGetDeviceInterfaceDetail(hardware_dev_info,
131                                      dev_info_data,
132                                      NULL,
133                                      0,
134                                      &required_len,
135                                      NULL)) {
136    return false;
137  }
138
139  if (ERROR_INSUFFICIENT_BUFFER != GetLastError())
140    return false;
141
142  // Allocate buffer for the structure
143  PSP_DEVICE_INTERFACE_DETAIL_DATA buffer =
144    reinterpret_cast<PSP_DEVICE_INTERFACE_DETAIL_DATA>(malloc(required_len));
145
146  if (NULL == buffer) {
147    SetLastError(ERROR_OUTOFMEMORY);
148    return false;
149  }
150
151  buffer->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
152
153  // Retrieve the information from Plug and Play.
154  if (SetupDiGetDeviceInterfaceDetail(hardware_dev_info,
155                                      dev_info_data,
156                                      buffer,
157                                      required_len,
158                                      &required_len,
159                                      NULL)) {
160    *dev_info_detail_data = buffer;
161    return true;
162  } else {
163    // Free the buffer if this call failed
164    free(buffer);
165
166    return false;
167  }
168}
169
170bool GetUsbDeviceName(HDEVINFO hardware_dev_info,
171                      PSP_DEVICE_INTERFACE_DATA dev_info_data,
172                      std::wstring* name) {
173  PSP_DEVICE_INTERFACE_DETAIL_DATA func_class_dev_data = NULL;
174  if (!GetUsbDeviceDetails(hardware_dev_info,
175                           dev_info_data,
176                           &func_class_dev_data)) {
177    return false;
178  }
179
180  try {
181    *name = func_class_dev_data->DevicePath;
182  } catch (...) {
183    SetLastError(ERROR_OUTOFMEMORY);
184  }
185
186  free(func_class_dev_data);
187
188  return !name->empty();
189}
190