1/*
2 * Copyright (C) 2018 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
17package com.android.internal.usb;
18
19import static android.hardware.usb.UsbPort.MODE_AUDIO_ACCESSORY;
20import static android.hardware.usb.UsbPort.MODE_DEBUG_ACCESSORY;
21import static android.hardware.usb.UsbPort.MODE_DFP;
22import static android.hardware.usb.UsbPort.MODE_DUAL;
23import static android.hardware.usb.UsbPort.MODE_NONE;
24import static android.hardware.usb.UsbPort.MODE_UFP;
25
26import static com.android.internal.util.dump.DumpUtils.writeStringIfNotNull;
27
28import android.annotation.NonNull;
29import android.hardware.usb.UsbAccessory;
30import android.hardware.usb.UsbConfiguration;
31import android.hardware.usb.UsbDevice;
32import android.hardware.usb.UsbEndpoint;
33import android.hardware.usb.UsbInterface;
34import android.hardware.usb.UsbPort;
35import android.hardware.usb.UsbPortStatus;
36import android.hardware.usb.V1_0.Constants;
37import android.service.usb.UsbAccessoryProto;
38import android.service.usb.UsbConfigurationProto;
39import android.service.usb.UsbDeviceProto;
40import android.service.usb.UsbEndPointProto;
41import android.service.usb.UsbInterfaceProto;
42import android.service.usb.UsbPortProto;
43import android.service.usb.UsbPortStatusProto;
44import android.service.usb.UsbPortStatusRoleCombinationProto;
45
46import com.android.internal.util.dump.DualDumpOutputStream;
47
48/** Dump methods for public USB classes */
49public class DumpUtils {
50    public static void writeAccessory(@NonNull DualDumpOutputStream dump, @NonNull String idName,
51            long id, @NonNull UsbAccessory accessory) {
52        long token = dump.start(idName, id);
53
54        dump.write("manufacturer", UsbAccessoryProto.MANUFACTURER, accessory.getManufacturer());
55        dump.write("model", UsbAccessoryProto.MODEL, accessory.getModel());
56        writeStringIfNotNull(dump, "description", UsbAccessoryProto.DESCRIPTION,
57                accessory.getManufacturer());
58        dump.write("version", UsbAccessoryProto.VERSION, accessory.getVersion());
59        writeStringIfNotNull(dump, "uri", UsbAccessoryProto.URI, accessory.getUri());
60        dump.write("serial", UsbAccessoryProto.SERIAL, accessory.getSerial());
61
62        dump.end(token);
63    }
64
65    public static void writeDevice(@NonNull DualDumpOutputStream dump, @NonNull String idName,
66            long id, @NonNull UsbDevice device) {
67        long token = dump.start(idName, id);
68
69        dump.write("name", UsbDeviceProto.NAME, device.getDeviceName());
70        dump.write("vendor_id", UsbDeviceProto.VENDOR_ID, device.getVendorId());
71        dump.write("product_id", UsbDeviceProto.PRODUCT_ID, device.getProductId());
72        dump.write("class", UsbDeviceProto.CLASS, device.getDeviceClass());
73        dump.write("subclass", UsbDeviceProto.SUBCLASS, device.getDeviceSubclass());
74        dump.write("protocol", UsbDeviceProto.PROTOCOL, device.getDeviceProtocol());
75        dump.write("manufacturer_name", UsbDeviceProto.MANUFACTURER_NAME,
76                device.getManufacturerName());
77        dump.write("product_name", UsbDeviceProto.PRODUCT_NAME, device.getProductName());
78        dump.write("version", UsbDeviceProto.VERSION, device.getVersion());
79        dump.write("serial_number", UsbDeviceProto.SERIAL_NUMBER, device.getSerialNumber());
80
81        int numConfigurations = device.getConfigurationCount();
82        for (int i = 0; i < numConfigurations; i++) {
83            writeConfiguration(dump, "configurations", UsbDeviceProto.CONFIGURATIONS,
84                    device.getConfiguration(i));
85        }
86
87        dump.end(token);
88    }
89
90    private static void writeConfiguration(@NonNull DualDumpOutputStream dump,
91            @NonNull String idName, long id, @NonNull UsbConfiguration configuration) {
92        long token = dump.start(idName, id);
93        dump.write("id", UsbConfigurationProto.ID, configuration.getId());
94        dump.write("name", UsbConfigurationProto.NAME, configuration.getName());
95        dump.write("attributes", UsbConfigurationProto.ATTRIBUTES, configuration.getAttributes());
96        dump.write("max_power", UsbConfigurationProto.MAX_POWER, configuration.getMaxPower());
97
98        int numInterfaces = configuration.getInterfaceCount();
99        for (int i = 0; i < numInterfaces; i++) {
100            writeInterface(dump, "interfaces", UsbConfigurationProto.INTERFACES,
101                    configuration.getInterface(i));
102        }
103        dump.end(token);
104    }
105
106    private static void writeInterface(@NonNull DualDumpOutputStream dump, @NonNull String idName,
107            long id, @NonNull UsbInterface iface) {
108        long token = dump.start(idName, id);
109
110        dump.write("id", UsbInterfaceProto.ID, iface.getId());
111        dump.write("alternate_settings", UsbInterfaceProto.ALTERNATE_SETTINGS,
112                iface.getAlternateSetting());
113        dump.write("name", UsbInterfaceProto.NAME, iface.getName());
114        dump.write("class", UsbInterfaceProto.CLASS, iface.getInterfaceClass());
115        dump.write("subclass", UsbInterfaceProto.SUBCLASS, iface.getInterfaceSubclass());
116        dump.write("protocol", UsbInterfaceProto.PROTOCOL, iface.getInterfaceProtocol());
117
118        int numEndpoints = iface.getEndpointCount();
119        for (int i = 0; i < numEndpoints; i++) {
120            writeEndpoint(dump, "endpoints", UsbInterfaceProto.ENDPOINTS, iface.getEndpoint(i));
121        }
122        dump.end(token);
123    }
124
125    private static void writeEndpoint(@NonNull DualDumpOutputStream dump, @NonNull String idName,
126            long id, @NonNull UsbEndpoint endpoint) {
127        long token = dump.start(idName, id);
128
129        dump.write("endpoint_number", UsbEndPointProto.ENDPOINT_NUMBER,
130                endpoint.getEndpointNumber());
131        dump.write("direction", UsbEndPointProto.DIRECTION, endpoint.getDirection());
132        dump.write("address", UsbEndPointProto.ADDRESS, endpoint.getAddress());
133        dump.write("type", UsbEndPointProto.TYPE, endpoint.getType());
134        dump.write("attributes", UsbEndPointProto.ATTRIBUTES,
135                endpoint.getAttributes());
136        dump.write("max_packet_size", UsbEndPointProto.MAX_PACKET_SIZE,
137                endpoint.getMaxPacketSize());
138        dump.write("interval", UsbEndPointProto.INTERVAL, endpoint.getInterval());
139
140        dump.end(token);
141    }
142
143    public static void writePort(@NonNull DualDumpOutputStream dump, @NonNull String idName,
144            long id, @NonNull UsbPort port) {
145        long token = dump.start(idName, id);
146
147        dump.write("id", UsbPortProto.ID, port.getId());
148
149        int mode = port.getSupportedModes();
150        if (dump.isProto()) {
151            if (mode == MODE_NONE) {
152                dump.write("supported_modes", UsbPortProto.SUPPORTED_MODES, MODE_NONE);
153            } else {
154                if ((mode & MODE_DUAL) == MODE_DUAL) {
155                    dump.write("supported_modes", UsbPortProto.SUPPORTED_MODES, MODE_DUAL);
156                } else {
157                    if ((mode & MODE_DFP) == MODE_DFP) {
158                        dump.write("supported_modes", UsbPortProto.SUPPORTED_MODES, MODE_DFP);
159                    } else if ((mode & MODE_UFP) == MODE_UFP) {
160                        dump.write("supported_modes", UsbPortProto.SUPPORTED_MODES, MODE_UFP);
161                    }
162                }
163
164                if ((mode & MODE_AUDIO_ACCESSORY) == MODE_AUDIO_ACCESSORY) {
165                    dump.write("supported_modes", UsbPortProto.SUPPORTED_MODES,
166                            MODE_AUDIO_ACCESSORY);
167                }
168
169                if ((mode & MODE_DEBUG_ACCESSORY) == MODE_DEBUG_ACCESSORY) {
170                    dump.write("supported_modes", UsbPortProto.SUPPORTED_MODES,
171                            MODE_DEBUG_ACCESSORY);
172                }
173            }
174        } else {
175            dump.write("supported_modes", UsbPortProto.SUPPORTED_MODES, UsbPort.modeToString(mode));
176        }
177
178        dump.end(token);
179    }
180
181    private static void writePowerRole(@NonNull DualDumpOutputStream dump, @NonNull String idName,
182            long id, int powerRole) {
183        if (dump.isProto()) {
184            dump.write(idName, id, powerRole);
185        } else {
186            dump.write(idName, id, UsbPort.powerRoleToString(powerRole));
187        }
188    }
189
190    private static void writeDataRole(@NonNull DualDumpOutputStream dump, @NonNull String idName,
191            long id, int dataRole) {
192        if (dump.isProto()) {
193            dump.write(idName, id, dataRole);
194        } else {
195            dump.write(idName, id, UsbPort.dataRoleToString(dataRole));
196        }
197    }
198
199
200    public static void writePortStatus(@NonNull DualDumpOutputStream dump, @NonNull String idName,
201            long id, @NonNull UsbPortStatus status) {
202        long token = dump.start(idName, id);
203
204        dump.write("connected", UsbPortStatusProto.CONNECTED, status.isConnected());
205
206        if (dump.isProto()) {
207            dump.write("current_mode", UsbPortStatusProto.CURRENT_MODE, status.getCurrentMode());
208        } else {
209            dump.write("current_mode", UsbPortStatusProto.CURRENT_MODE,
210                    UsbPort.modeToString(status.getCurrentMode()));
211        }
212
213        writePowerRole(dump, "power_role", UsbPortStatusProto.POWER_ROLE,
214                status.getCurrentPowerRole());
215        writeDataRole(dump, "data_role", UsbPortStatusProto.DATA_ROLE, status.getCurrentDataRole());
216
217        int undumpedCombinations = status.getSupportedRoleCombinations();
218        while (undumpedCombinations != 0) {
219            int index = Integer.numberOfTrailingZeros(undumpedCombinations);
220            undumpedCombinations &= ~(1 << index);
221
222            int powerRole = (index / Constants.PortDataRole.NUM_DATA_ROLES
223                    + Constants.PortPowerRole.NONE);
224            int dataRole = index % Constants.PortDataRole.NUM_DATA_ROLES;
225
226            long roleCombinationToken = dump.start("role_combinations",
227                    UsbPortStatusProto.ROLE_COMBINATIONS);
228            writePowerRole(dump, "power_role", UsbPortStatusRoleCombinationProto.POWER_ROLE,
229                    powerRole);
230            writeDataRole(dump, "data_role", UsbPortStatusRoleCombinationProto.DATA_ROLE,
231                    dataRole);
232            dump.end(roleCombinationToken);
233        }
234
235        dump.end(token);
236    }
237}
238