UsbHostManager.java revision c837a451946b64d70ed7c642fbde03c182c28b6f
146d0adf8256a42416584765625852b6e48497c90Mike Lockwood/*
246d0adf8256a42416584765625852b6e48497c90Mike Lockwood * Copyright (C) 2011 The Android Open Source Project
346d0adf8256a42416584765625852b6e48497c90Mike Lockwood *
446d0adf8256a42416584765625852b6e48497c90Mike Lockwood * Licensed under the Apache License, Version 2.0 (the "License");
546d0adf8256a42416584765625852b6e48497c90Mike Lockwood * you may not use this file except in compliance with the License.
646d0adf8256a42416584765625852b6e48497c90Mike Lockwood * You may obtain a copy of the License at
746d0adf8256a42416584765625852b6e48497c90Mike Lockwood *
846d0adf8256a42416584765625852b6e48497c90Mike Lockwood *      http://www.apache.org/licenses/LICENSE-2.0
946d0adf8256a42416584765625852b6e48497c90Mike Lockwood *
1046d0adf8256a42416584765625852b6e48497c90Mike Lockwood * Unless required by applicable law or agreed to in writing, software
1146d0adf8256a42416584765625852b6e48497c90Mike Lockwood * distributed under the License is distributed on an "AS IS" BASIS,
1246d0adf8256a42416584765625852b6e48497c90Mike Lockwood * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1346d0adf8256a42416584765625852b6e48497c90Mike Lockwood * See the License for the specific language governing permissions an
1446d0adf8256a42416584765625852b6e48497c90Mike Lockwood * limitations under the License.
1546d0adf8256a42416584765625852b6e48497c90Mike Lockwood */
1646d0adf8256a42416584765625852b6e48497c90Mike Lockwood
1746d0adf8256a42416584765625852b6e48497c90Mike Lockwoodpackage com.android.server.usb;
1846d0adf8256a42416584765625852b6e48497c90Mike Lockwood
1946d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.content.Context;
20c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLeanimport android.content.Intent;
217531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwoodimport android.hardware.usb.UsbConfiguration;
2246d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.hardware.usb.UsbConstants;
2346d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.hardware.usb.UsbDevice;
2446d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.hardware.usb.UsbEndpoint;
2546d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.hardware.usb.UsbInterface;
2646d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.os.Bundle;
2746d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.os.ParcelFileDescriptor;
28fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkeyimport android.os.Parcelable;
29c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLeanimport android.os.UserHandle;
3046d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport android.util.Slog;
3146d0adf8256a42416584765625852b6e48497c90Mike Lockwood
328b2c3a14603d163d7564e6f60286995079687690Jeff Sharkeyimport com.android.internal.annotations.GuardedBy;
338b2c3a14603d163d7564e6f60286995079687690Jeff Sharkey
34c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLeanimport java.io.File;
3546d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport java.io.FileDescriptor;
36c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLeanimport java.io.FileNotFoundException;
3746d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport java.io.PrintWriter;
387531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwoodimport java.util.ArrayList;
3946d0adf8256a42416584765625852b6e48497c90Mike Lockwoodimport java.util.HashMap;
40c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLeanimport java.util.Scanner;
4146d0adf8256a42416584765625852b6e48497c90Mike Lockwood
4246d0adf8256a42416584765625852b6e48497c90Mike Lockwood/**
4346d0adf8256a42416584765625852b6e48497c90Mike Lockwood * UsbHostManager manages USB state in host mode.
4446d0adf8256a42416584765625852b6e48497c90Mike Lockwood */
4546d0adf8256a42416584765625852b6e48497c90Mike Lockwoodpublic class UsbHostManager {
4646d0adf8256a42416584765625852b6e48497c90Mike Lockwood    private static final String TAG = UsbHostManager.class.getSimpleName();
47c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean    private static final boolean DEBUG_AUDIO = false;
4846d0adf8256a42416584765625852b6e48497c90Mike Lockwood
4946d0adf8256a42416584765625852b6e48497c90Mike Lockwood    // contains all connected USB devices
50fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey    private final HashMap<String, UsbDevice> mDevices = new HashMap<String, UsbDevice>();
5146d0adf8256a42416584765625852b6e48497c90Mike Lockwood
5246d0adf8256a42416584765625852b6e48497c90Mike Lockwood    // USB busses to exclude from USB host support
5346d0adf8256a42416584765625852b6e48497c90Mike Lockwood    private final String[] mHostBlacklist;
5446d0adf8256a42416584765625852b6e48497c90Mike Lockwood
5546d0adf8256a42416584765625852b6e48497c90Mike Lockwood    private final Context mContext;
5646d0adf8256a42416584765625852b6e48497c90Mike Lockwood    private final Object mLock = new Object();
5746d0adf8256a42416584765625852b6e48497c90Mike Lockwood
587531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood    private UsbDevice mNewDevice;
597531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood    private UsbConfiguration mNewConfiguration;
607531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood    private UsbInterface mNewInterface;
617531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood    private ArrayList<UsbConfiguration> mNewConfigurations;
627531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood    private ArrayList<UsbInterface> mNewInterfaces;
637531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood    private ArrayList<UsbEndpoint> mNewEndpoints;
647531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood
658b2c3a14603d163d7564e6f60286995079687690Jeff Sharkey    @GuardedBy("mLock")
66fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey    private UsbSettingsManager mCurrentSettings;
67fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey
68fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey    public UsbHostManager(Context context) {
6946d0adf8256a42416584765625852b6e48497c90Mike Lockwood        mContext = context;
7046d0adf8256a42416584765625852b6e48497c90Mike Lockwood        mHostBlacklist = context.getResources().getStringArray(
7146d0adf8256a42416584765625852b6e48497c90Mike Lockwood                com.android.internal.R.array.config_usbHostBlacklist);
7246d0adf8256a42416584765625852b6e48497c90Mike Lockwood    }
7346d0adf8256a42416584765625852b6e48497c90Mike Lockwood
74fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey    public void setCurrentSettings(UsbSettingsManager settings) {
75fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey        synchronized (mLock) {
76fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey            mCurrentSettings = settings;
77fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey        }
78fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey    }
79fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey
80fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey    private UsbSettingsManager getCurrentSettings() {
81fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey        synchronized (mLock) {
82fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey            return mCurrentSettings;
83fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey        }
84fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey    }
85fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey
8646d0adf8256a42416584765625852b6e48497c90Mike Lockwood    private boolean isBlackListed(String deviceName) {
8746d0adf8256a42416584765625852b6e48497c90Mike Lockwood        int count = mHostBlacklist.length;
8846d0adf8256a42416584765625852b6e48497c90Mike Lockwood        for (int i = 0; i < count; i++) {
8946d0adf8256a42416584765625852b6e48497c90Mike Lockwood            if (deviceName.startsWith(mHostBlacklist[i])) {
9046d0adf8256a42416584765625852b6e48497c90Mike Lockwood                return true;
9146d0adf8256a42416584765625852b6e48497c90Mike Lockwood            }
9246d0adf8256a42416584765625852b6e48497c90Mike Lockwood        }
9346d0adf8256a42416584765625852b6e48497c90Mike Lockwood        return false;
9446d0adf8256a42416584765625852b6e48497c90Mike Lockwood    }
9546d0adf8256a42416584765625852b6e48497c90Mike Lockwood
9646d0adf8256a42416584765625852b6e48497c90Mike Lockwood    /* returns true if the USB device should not be accessible by applications */
9746d0adf8256a42416584765625852b6e48497c90Mike Lockwood    private boolean isBlackListed(int clazz, int subClass, int protocol) {
9846d0adf8256a42416584765625852b6e48497c90Mike Lockwood        // blacklist hubs
9946d0adf8256a42416584765625852b6e48497c90Mike Lockwood        if (clazz == UsbConstants.USB_CLASS_HUB) return true;
10046d0adf8256a42416584765625852b6e48497c90Mike Lockwood
10146d0adf8256a42416584765625852b6e48497c90Mike Lockwood        // blacklist HID boot devices (mouse and keyboard)
10246d0adf8256a42416584765625852b6e48497c90Mike Lockwood        if (clazz == UsbConstants.USB_CLASS_HID &&
10346d0adf8256a42416584765625852b6e48497c90Mike Lockwood                subClass == UsbConstants.USB_INTERFACE_SUBCLASS_BOOT) {
10446d0adf8256a42416584765625852b6e48497c90Mike Lockwood            return true;
10546d0adf8256a42416584765625852b6e48497c90Mike Lockwood        }
10646d0adf8256a42416584765625852b6e48497c90Mike Lockwood
10746d0adf8256a42416584765625852b6e48497c90Mike Lockwood        return false;
10846d0adf8256a42416584765625852b6e48497c90Mike Lockwood    }
10946d0adf8256a42416584765625852b6e48497c90Mike Lockwood
110c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean    // Broadcasts the arrival/departure of a USB audio interface
111c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean    // card - the ALSA card number of the physical interface
112c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean    // device - the ALSA device number of the physical interface
113c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean    // enabled - if true, we're connecting a device (it's arrived), else disconnecting
114c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean    private void sendDeviceNotification(int card, int device, boolean enabled,
115c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean        boolean hasPlayback, boolean hasCapture, boolean hasMIDI) {
116c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean      // send a sticky broadcast containing current USB state
117c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean      Intent intent = new Intent(Intent.ACTION_USB_AUDIO_DEVICE_PLUG);
118c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean      intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
119c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean      intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
120c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean      intent.putExtra("state", enabled ? 1 : 0);
121c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean      intent.putExtra("card", card);
122c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean      intent.putExtra("device", device);
123c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean      intent.putExtra("hasPlayback", hasPlayback);
124c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean      intent.putExtra("hasCapture", hasCapture);
125c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean      intent.putExtra("hasMIDI", hasMIDI);
126c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean      mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
127c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean    }
128c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean
129c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean    static boolean isBuiltInUsbDevice(String deviceName) {
130c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean      // This may be too broad an assumption
131c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean      return deviceName.equals("/dev/bus/usb/001/001");
132c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean    }
133c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean
1347531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood    /* Called from JNI in monitorUsbHostBus() to report new USB devices
1357531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood       Returns true if successful, in which case the JNI code will continue adding configurations,
1367531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood       interfaces and endpoints, and finally call endUsbDeviceAdded after all descriptors
1377531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood       have been processed
1387531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood     */
1397531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood    private boolean beginUsbDeviceAdded(String deviceName, int vendorID, int productID,
14046d0adf8256a42416584765625852b6e48497c90Mike Lockwood            int deviceClass, int deviceSubclass, int deviceProtocol,
1417531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood            String manufacturerName, String productName, String serialNumber) {
14246d0adf8256a42416584765625852b6e48497c90Mike Lockwood
143c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean      if (DEBUG_AUDIO) {
144c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          Slog.d(TAG, "usb:UsbHostManager.beginUsbDeviceAdded(" + deviceName + ")");
145c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          // Audio Class Codes:
146c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          // Audio: 0x01
147c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          // Audio Subclass Codes:
148c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          // undefined: 0x00
149c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          // audio control: 0x01
150c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          // audio streaming: 0x02
151c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          // midi streaming: 0x03
152c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean
153c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          // some useful debugging info
154c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          Slog.d(TAG, "usb:UsbHostManager.usbDeviceAdded()");
155c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          Slog.d(TAG, "usb: nm:" + deviceName +
156c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean              " vnd:" + vendorID +
157c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean              " prd:" + productID +
158c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean              " cls:" + deviceClass +
159c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean              " sub:" + deviceSubclass +
160c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean              " proto:" + deviceProtocol);
161c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean      }
162c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean
163c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean      if (!isBuiltInUsbDevice(deviceName)) {
164c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          //TODO(pmclean) we will need this when we need to support USB interfaces
165c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          // beyond card1, device0 but turn them off for now
166c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          //com.android.alsascan.AlsaCardsParser cardsParser =
167c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          //    new com.android.alsascan.AlsaCardsParser();
168c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          //cardsParser.scan();
169c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          //cardsParser.Log();
170c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean
171c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          // But we need to parse the device to determine its capabilities.
172c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          com.android.alsascan.AlsaDevicesParser devicesParser =
173c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean              new com.android.alsascan.AlsaDevicesParser();
174c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          devicesParser.scan();
175c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          //devicesParser.Log();
176c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean
177c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          boolean hasPlaybackDevices = devicesParser.hasPlaybackDevices();
178c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          boolean hasCaptureDevices = devicesParser.hasCaptureDevices();
179c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          boolean hasMIDI = devicesParser.hasMIDIDevices();
180c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean
181c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          if (DEBUG_AUDIO) {
182c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean              Slog.d(TAG, "usb: hasPlayback:" + hasPlaybackDevices
183c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean                      + " hasCapture:" + hasCaptureDevices);
184c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          }
185c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean
186c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          //TODO(pmclean)
187c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          // For now just assume that any USB device that is attached is:
188c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          // 1. An audio interface and
189c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          // 2. is card:1 device:0
190c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          int cardNum = 1;
191c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          int deviceNum = 0;
192c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          sendDeviceNotification(cardNum, deviceNum, true,
193c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean                                 hasPlaybackDevices, hasCaptureDevices, hasMIDI);
194c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean        }
195c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean
19646d0adf8256a42416584765625852b6e48497c90Mike Lockwood        if (isBlackListed(deviceName) ||
19746d0adf8256a42416584765625852b6e48497c90Mike Lockwood                isBlackListed(deviceClass, deviceSubclass, deviceProtocol)) {
1987531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood            return false;
19946d0adf8256a42416584765625852b6e48497c90Mike Lockwood        }
20046d0adf8256a42416584765625852b6e48497c90Mike Lockwood
20146d0adf8256a42416584765625852b6e48497c90Mike Lockwood        synchronized (mLock) {
20246d0adf8256a42416584765625852b6e48497c90Mike Lockwood            if (mDevices.get(deviceName) != null) {
203fdc0c2984d05e32954608f46514c4cbe3a5a9424Mike Lockwood                Slog.w(TAG, "device already on mDevices list: " + deviceName);
2047531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood                return false;
20546d0adf8256a42416584765625852b6e48497c90Mike Lockwood            }
20646d0adf8256a42416584765625852b6e48497c90Mike Lockwood
2077531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood            if (mNewDevice != null) {
2087531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood                Slog.e(TAG, "mNewDevice is not null in endUsbDeviceAdded");
2097531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood                return false;
21046d0adf8256a42416584765625852b6e48497c90Mike Lockwood            }
21146d0adf8256a42416584765625852b6e48497c90Mike Lockwood
2127531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood            mNewDevice = new UsbDevice(deviceName, vendorID, productID,
213575ca85c147f1521480ea98aca13aa3b1ec38884Robin Cutshaw                    deviceClass, deviceSubclass, deviceProtocol,
2147531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood                    manufacturerName, productName, serialNumber);
2157531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood
2167531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood            mNewConfigurations = new ArrayList<UsbConfiguration>();
2177531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood            mNewInterfaces = new ArrayList<UsbInterface>();
2187531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood            mNewEndpoints = new ArrayList<UsbEndpoint>();
2197531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood        }
2207531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood        return true;
2217531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood    }
2227531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood
2237531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood    /* Called from JNI in monitorUsbHostBus() to report new USB configuration for the device
2247531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood       currently being added.  Returns true if successful, false in case of error.
2257531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood     */
2267531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood    private void addUsbConfiguration(int id, String name, int attributes, int maxPower) {
2277531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood        if (mNewConfiguration != null) {
2287531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood            mNewConfiguration.setInterfaces(
2297531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood                    mNewInterfaces.toArray(new UsbInterface[mNewInterfaces.size()]));
2307531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood            mNewInterfaces.clear();
2317531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood        }
2327531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood
2337531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood        mNewConfiguration = new UsbConfiguration(id, name, attributes, maxPower);
2347531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood        mNewConfigurations.add(mNewConfiguration);
2357531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood    }
2367531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood
2377531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood    /* Called from JNI in monitorUsbHostBus() to report new USB interface for the device
2387531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood       currently being added.  Returns true if successful, false in case of error.
2397531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood     */
2407531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood    private void addUsbInterface(int id, String name, int altSetting,
2417531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood            int Class, int subClass, int protocol) {
2427531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood        if (mNewInterface != null) {
2437531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood            mNewInterface.setEndpoints(
2447531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood                    mNewEndpoints.toArray(new UsbEndpoint[mNewEndpoints.size()]));
2457531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood            mNewEndpoints.clear();
2467531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood        }
2477531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood
2487531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood        mNewInterface = new UsbInterface(id, altSetting, name, Class, subClass, protocol);
2497531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood        mNewInterfaces.add(mNewInterface);
2507531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood    }
2517531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood
2527531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood    /* Called from JNI in monitorUsbHostBus() to report new USB endpoint for the device
2537531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood       currently being added.  Returns true if successful, false in case of error.
2547531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood     */
2557531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood    private void addUsbEndpoint(int address, int attributes, int maxPacketSize, int interval) {
2567531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood        mNewEndpoints.add(new UsbEndpoint(address, attributes, maxPacketSize, interval));
2577531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood    }
2587531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood
2597531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood    /* Called from JNI in monitorUsbHostBus() to finish adding a new device */
2607531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood    private void endUsbDeviceAdded() {
261c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean        if (DEBUG_AUDIO) {
262c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean            Slog.d(TAG, "usb:UsbHostManager.endUsbDeviceAdded()");
263c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean        }
2647531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood        if (mNewInterface != null) {
2657531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood            mNewInterface.setEndpoints(
2667531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood                    mNewEndpoints.toArray(new UsbEndpoint[mNewEndpoints.size()]));
2677531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood        }
2687531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood        if (mNewConfiguration != null) {
2697531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood            mNewConfiguration.setInterfaces(
2707531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood                    mNewInterfaces.toArray(new UsbInterface[mNewInterfaces.size()]));
2717531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood        }
2727531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood
2737531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood        synchronized (mLock) {
2747531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood            if (mNewDevice != null) {
2757531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood                mNewDevice.setConfigurations(
2767531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood                        mNewConfigurations.toArray(new UsbConfiguration[mNewConfigurations.size()]));
2777531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood                mDevices.put(mNewDevice.getDeviceName(), mNewDevice);
2787531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood                Slog.d(TAG, "Added device " + mNewDevice);
2797531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood                getCurrentSettings().deviceAttached(mNewDevice);
2807531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood            } else {
2817531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood                Slog.e(TAG, "mNewDevice is null in endUsbDeviceAdded");
2827531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood            }
2837531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood            mNewDevice = null;
2847531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood            mNewConfigurations = null;
2857531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood            mNewInterfaces = null;
2867531aa22355cf03f51def61ba67f1636bf85f408Mike Lockwood            mNewEndpoints = null;
28746d0adf8256a42416584765625852b6e48497c90Mike Lockwood        }
28846d0adf8256a42416584765625852b6e48497c90Mike Lockwood    }
28946d0adf8256a42416584765625852b6e48497c90Mike Lockwood
29046d0adf8256a42416584765625852b6e48497c90Mike Lockwood    /* Called from JNI in monitorUsbHostBus to report USB device removal */
29146d0adf8256a42416584765625852b6e48497c90Mike Lockwood    private void usbDeviceRemoved(String deviceName) {
292c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean        if (DEBUG_AUDIO) {
293c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean          Slog.d(TAG, "usb:UsbHostManager.usbDeviceRemoved() nm:" + deviceName);
294c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean        }
295c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean
296c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean        // Same assumptions as the fake-out above
297c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean        sendDeviceNotification(1, 0, false, /*NA*/false, /*NA*/false, /*NA*/false);
298c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean
29946d0adf8256a42416584765625852b6e48497c90Mike Lockwood        synchronized (mLock) {
30046d0adf8256a42416584765625852b6e48497c90Mike Lockwood            UsbDevice device = mDevices.remove(deviceName);
30146d0adf8256a42416584765625852b6e48497c90Mike Lockwood            if (device != null) {
302fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey                getCurrentSettings().deviceDetached(device);
30346d0adf8256a42416584765625852b6e48497c90Mike Lockwood            }
30446d0adf8256a42416584765625852b6e48497c90Mike Lockwood        }
30546d0adf8256a42416584765625852b6e48497c90Mike Lockwood    }
30646d0adf8256a42416584765625852b6e48497c90Mike Lockwood
30746d0adf8256a42416584765625852b6e48497c90Mike Lockwood    public void systemReady() {
30846d0adf8256a42416584765625852b6e48497c90Mike Lockwood        synchronized (mLock) {
30946d0adf8256a42416584765625852b6e48497c90Mike Lockwood            // Create a thread to call into native code to wait for USB host events.
31046d0adf8256a42416584765625852b6e48497c90Mike Lockwood            // This thread will call us back on usbDeviceAdded and usbDeviceRemoved.
31146d0adf8256a42416584765625852b6e48497c90Mike Lockwood            Runnable runnable = new Runnable() {
31246d0adf8256a42416584765625852b6e48497c90Mike Lockwood                public void run() {
31346d0adf8256a42416584765625852b6e48497c90Mike Lockwood                    monitorUsbHostBus();
31446d0adf8256a42416584765625852b6e48497c90Mike Lockwood                }
31546d0adf8256a42416584765625852b6e48497c90Mike Lockwood            };
31646d0adf8256a42416584765625852b6e48497c90Mike Lockwood            new Thread(null, runnable, "UsbService host thread").start();
31746d0adf8256a42416584765625852b6e48497c90Mike Lockwood        }
31846d0adf8256a42416584765625852b6e48497c90Mike Lockwood    }
31946d0adf8256a42416584765625852b6e48497c90Mike Lockwood
32046d0adf8256a42416584765625852b6e48497c90Mike Lockwood    /* Returns a list of all currently attached USB devices */
32146d0adf8256a42416584765625852b6e48497c90Mike Lockwood    public void getDeviceList(Bundle devices) {
32246d0adf8256a42416584765625852b6e48497c90Mike Lockwood        synchronized (mLock) {
32346d0adf8256a42416584765625852b6e48497c90Mike Lockwood            for (String name : mDevices.keySet()) {
32446d0adf8256a42416584765625852b6e48497c90Mike Lockwood                devices.putParcelable(name, mDevices.get(name));
32546d0adf8256a42416584765625852b6e48497c90Mike Lockwood            }
32646d0adf8256a42416584765625852b6e48497c90Mike Lockwood        }
32746d0adf8256a42416584765625852b6e48497c90Mike Lockwood    }
32846d0adf8256a42416584765625852b6e48497c90Mike Lockwood
32946d0adf8256a42416584765625852b6e48497c90Mike Lockwood    /* Opens the specified USB device */
33046d0adf8256a42416584765625852b6e48497c90Mike Lockwood    public ParcelFileDescriptor openDevice(String deviceName) {
33146d0adf8256a42416584765625852b6e48497c90Mike Lockwood        synchronized (mLock) {
33246d0adf8256a42416584765625852b6e48497c90Mike Lockwood            if (isBlackListed(deviceName)) {
33346d0adf8256a42416584765625852b6e48497c90Mike Lockwood                throw new SecurityException("USB device is on a restricted bus");
33446d0adf8256a42416584765625852b6e48497c90Mike Lockwood            }
33546d0adf8256a42416584765625852b6e48497c90Mike Lockwood            UsbDevice device = mDevices.get(deviceName);
33646d0adf8256a42416584765625852b6e48497c90Mike Lockwood            if (device == null) {
33746d0adf8256a42416584765625852b6e48497c90Mike Lockwood                // if it is not in mDevices, it either does not exist or is blacklisted
33846d0adf8256a42416584765625852b6e48497c90Mike Lockwood                throw new IllegalArgumentException(
33946d0adf8256a42416584765625852b6e48497c90Mike Lockwood                        "device " + deviceName + " does not exist or is restricted");
34046d0adf8256a42416584765625852b6e48497c90Mike Lockwood            }
341fc3f24b4b60c10e0d3f41f70df37e11ea311cc2cJeff Sharkey            getCurrentSettings().checkPermission(device);
34246d0adf8256a42416584765625852b6e48497c90Mike Lockwood            return nativeOpenDevice(deviceName);
34346d0adf8256a42416584765625852b6e48497c90Mike Lockwood        }
34446d0adf8256a42416584765625852b6e48497c90Mike Lockwood    }
34546d0adf8256a42416584765625852b6e48497c90Mike Lockwood
34646d0adf8256a42416584765625852b6e48497c90Mike Lockwood    public void dump(FileDescriptor fd, PrintWriter pw) {
34746d0adf8256a42416584765625852b6e48497c90Mike Lockwood        synchronized (mLock) {
34846d0adf8256a42416584765625852b6e48497c90Mike Lockwood            pw.println("  USB Host State:");
34946d0adf8256a42416584765625852b6e48497c90Mike Lockwood            for (String name : mDevices.keySet()) {
35046d0adf8256a42416584765625852b6e48497c90Mike Lockwood                pw.println("    " + name + ": " + mDevices.get(name));
35146d0adf8256a42416584765625852b6e48497c90Mike Lockwood            }
35246d0adf8256a42416584765625852b6e48497c90Mike Lockwood        }
35346d0adf8256a42416584765625852b6e48497c90Mike Lockwood    }
35446d0adf8256a42416584765625852b6e48497c90Mike Lockwood
35546d0adf8256a42416584765625852b6e48497c90Mike Lockwood    private native void monitorUsbHostBus();
35646d0adf8256a42416584765625852b6e48497c90Mike Lockwood    private native ParcelFileDescriptor nativeOpenDevice(String deviceName);
35746d0adf8256a42416584765625852b6e48497c90Mike Lockwood}
358