Home | History | Annotate | Download | only in usb
      1 /*
      2  * Copyright (C) 2016 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 package com.google.android.car.kitchensink.setting.usb;
     17 
     18 import android.car.IUsbAoapSupportCheckService;
     19 import android.content.ComponentName;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.content.ServiceConnection;
     23 import android.content.pm.ActivityInfo;
     24 import android.content.pm.PackageManager;
     25 import android.content.pm.PackageManager.NameNotFoundException;
     26 import android.content.pm.ResolveInfo;
     27 import android.content.res.XmlResourceParser;
     28 import android.hardware.usb.UsbDevice;
     29 import android.hardware.usb.UsbInterface;
     30 import android.hardware.usb.UsbManager;
     31 import android.os.Handler;
     32 import android.os.HandlerThread;
     33 import android.os.IBinder;
     34 import android.os.Looper;
     35 import android.os.Message;
     36 import android.os.RemoteException;
     37 import android.util.Log;
     38 import android.util.Pair;
     39 
     40 import com.android.internal.util.XmlUtils;
     41 
     42 import org.xmlpull.v1.XmlPullParser;
     43 import org.xmlpull.v1.XmlPullParserException;
     44 
     45 import java.io.IOException;
     46 import java.util.ArrayList;
     47 import java.util.LinkedList;
     48 import java.util.List;
     49 import java.util.Queue;
     50 
     51 /**
     52  * Resolves supported handlers for USB device.
     53  */
     54 public final class UsbDeviceHandlerResolver
     55         implements UsbDeviceStateController.UsbDeviceStateListener {
     56     private static final String TAG = UsbDeviceHandlerResolver.class.getSimpleName();
     57     private static final boolean LOCAL_LOGD = true;
     58 
     59     private static final int MODE_OFF = 0;
     60     private static final int MODE_PROBE = 1;
     61     private static final int MODE_PROBE_AOAP = 2;
     62     private static final int MODE_DISPATCH = 3;
     63 
     64     /**
     65      * Callbacks for device reolver.
     66      */
     67     public interface UsbDeviceHandlerResolverCallback {
     68         /** Handlers are reolved */
     69         void onHandlersResolveCompleted(
     70                 UsbDevice device, List<UsbDeviceSettings> availableSettings);
     71         /** Device was dispatched */
     72         void onDeviceDispatched();
     73     }
     74 
     75     private final UsbManager mUsbManager;
     76     private final PackageManager mPackageManager;
     77     private final UsbDeviceHandlerResolverCallback mDeviceCallback;
     78     private final Context mContext;
     79     private final HandlerThread mHandlerThread;
     80     private final UsbDeviceResolverHandler mHandler;
     81     private final UsbDeviceStateController mStateController;
     82     private final Queue<Pair<ResolveInfo, DeviceFilter>> mActiveDeviceOptions = new LinkedList<>();
     83     private final List<UsbDeviceSettings> mActiveDeviceSettings = new ArrayList<>();
     84 
     85     private String mActiveDeviceSerial;
     86     private UsbDevice mActiveUsbDevice;
     87     private UsbDeviceSettings mBaseSettings;
     88     private int mDeviceMode = MODE_OFF;
     89     private Intent mDispatchIntent;
     90     private int mDispatchUid;
     91     private IUsbAoapSupportCheckService mIUsbAoapSupportCheckService;
     92     private boolean mBound;
     93 
     94     // This class is used to describe a USB device.
     95     // When used in HashMaps all values must be specified,
     96     // but wildcards can be used for any of the fields in
     97     // the package meta-data.
     98     private static class DeviceFilter {
     99         // USB Vendor ID (or -1 for unspecified)
    100         public final int mVendorId;
    101         // USB Product ID (or -1 for unspecified)
    102         public final int mProductId;
    103         // USB device or interface class (or -1 for unspecified)
    104         public final int mClass;
    105         // USB device subclass (or -1 for unspecified)
    106         public final int mSubclass;
    107         // USB device protocol (or -1 for unspecified)
    108         public final int mProtocol;
    109         // USB device manufacturer name string (or null for unspecified)
    110         public final String mManufacturerName;
    111         // USB device product name string (or null for unspecified)
    112         public final String mProductName;
    113         // USB device serial number string (or null for unspecified)
    114         public final String mSerialNumber;
    115 
    116         // USB device in AOAP mode manufacturer
    117         public final String mAoapManufacturer;
    118         // USB device in AOAP mode modeal
    119         public final String mAoapModel;
    120         // USB device in AOAP mode description string
    121         public final String mAoapDescription;
    122         // USB device in AOAP mode version
    123         public final String mAoapVersion;
    124         // USB device in AOAP mode URI
    125         public final String mAoapUri;
    126         // USB device in AOAP mode serial
    127         public final String mAoapSerial;
    128         // USB device in AOAP mode verification service
    129         public final String mAoapService;
    130 
    131         DeviceFilter(int vid, int pid, int clasz, int subclass, int protocol,
    132                             String manufacturer, String product, String serialnum,
    133                             String aoapManufacturer, String aoapModel, String aoapDescription,
    134                             String aoapVersion, String aoapUri, String aoapSerial,
    135                             String aoapService) {
    136             mVendorId = vid;
    137             mProductId = pid;
    138             mClass = clasz;
    139             mSubclass = subclass;
    140             mProtocol = protocol;
    141             mManufacturerName = manufacturer;
    142             mProductName = product;
    143             mSerialNumber = serialnum;
    144 
    145             mAoapManufacturer = aoapManufacturer;
    146             mAoapModel = aoapModel;
    147             mAoapDescription = aoapDescription;
    148             mAoapVersion = aoapVersion;
    149             mAoapUri = aoapUri;
    150             mAoapSerial = aoapSerial;
    151             mAoapService = aoapService;
    152         }
    153 
    154         DeviceFilter(UsbDevice device) {
    155             mVendorId = device.getVendorId();
    156             mProductId = device.getProductId();
    157             mClass = device.getDeviceClass();
    158             mSubclass = device.getDeviceSubclass();
    159             mProtocol = device.getDeviceProtocol();
    160             mManufacturerName = device.getManufacturerName();
    161             mProductName = device.getProductName();
    162             mSerialNumber = device.getSerialNumber();
    163             mAoapManufacturer = null;
    164             mAoapModel = null;
    165             mAoapDescription = null;
    166             mAoapVersion = null;
    167             mAoapUri = null;
    168             mAoapSerial = null;
    169             mAoapService = null;
    170         }
    171 
    172         public static DeviceFilter read(XmlPullParser parser, boolean aoapData)
    173                 throws XmlPullParserException, IOException {
    174             int vendorId = -1;
    175             int productId = -1;
    176             int deviceClass = -1;
    177             int deviceSubclass = -1;
    178             int deviceProtocol = -1;
    179             String manufacturerName = null;
    180             String productName = null;
    181             String serialNumber = null;
    182 
    183             String aoapManufacturer = null;
    184             String aoapModel = null;
    185             String aoapDescription = null;
    186             String aoapVersion = null;
    187             String aoapUri = null;
    188             String aoapSerial = null;
    189             String aoapService = null;
    190 
    191             int count = parser.getAttributeCount();
    192             for (int i = 0; i < count; i++) {
    193                 String name = parser.getAttributeName(i);
    194                 String value = parser.getAttributeValue(i);
    195                 // Attribute values are ints or strings
    196                 if (!aoapData && "manufacturer-name".equals(name)) {
    197                     manufacturerName = value;
    198                 } else if (!aoapData && "product-name".equals(name)) {
    199                     productName = value;
    200                 } else if (!aoapData && "serial-number".equals(name)) {
    201                     serialNumber = value;
    202                 } else if (aoapData && "manufacturer".equals(name)) {
    203                     aoapManufacturer = value;
    204                 } else if (aoapData && "model".equals(name)) {
    205                     aoapModel = value;
    206                 } else if (aoapData && "description".equals(name)) {
    207                     aoapDescription = value;
    208                 } else if (aoapData && "version".equals(name)) {
    209                     aoapVersion = value;
    210                 } else if (aoapData && "uri".equals(name)) {
    211                     aoapUri = value;
    212                 } else if (aoapData && "serial".equals(name)) {
    213                     aoapSerial = value;
    214                 } else if (aoapData && "service".equals(name)) {
    215                     aoapService = value;
    216                 } else if (!aoapData) {
    217                     int intValue = -1;
    218                     int radix = 10;
    219                     if (value != null && value.length() > 2 && value.charAt(0) == '0'
    220                             && (value.charAt(1) == 'x' || value.charAt(1) == 'X')) {
    221                         // allow hex values starting with 0x or 0X
    222                         radix = 16;
    223                         value = value.substring(2);
    224                     }
    225                     try {
    226                         intValue = Integer.parseInt(value, radix);
    227                     } catch (NumberFormatException e) {
    228                         Log.e(TAG, "invalid number for field " + name, e);
    229                         continue;
    230                     }
    231                     if ("vendor-id".equals(name)) {
    232                         vendorId = intValue;
    233                     } else if ("product-id".equals(name)) {
    234                         productId = intValue;
    235                     } else if ("class".equals(name)) {
    236                         deviceClass = intValue;
    237                     } else if ("subclass".equals(name)) {
    238                         deviceSubclass = intValue;
    239                     } else if ("protocol".equals(name)) {
    240                         deviceProtocol = intValue;
    241                     }
    242                 }
    243             }
    244             return new DeviceFilter(vendorId, productId,
    245                                     deviceClass, deviceSubclass, deviceProtocol,
    246                                     manufacturerName, productName, serialNumber, aoapManufacturer,
    247                                     aoapModel, aoapDescription, aoapVersion, aoapUri, aoapSerial,
    248                                     aoapService);
    249         }
    250 
    251         private boolean matches(int clasz, int subclass, int protocol) {
    252             return ((mClass == -1 || clasz == mClass)
    253                     && (mSubclass == -1 || subclass == mSubclass)
    254                     && (mProtocol == -1 || protocol == mProtocol));
    255         }
    256 
    257         public boolean isAoap() {
    258             return (mVendorId == AoapInterface.USB_ACCESSORY_VENDOR_ID
    259                     && mProductId == AoapInterface.USB_ACCESSORY_PRODUCT_ID);
    260         }
    261 
    262         public boolean matches(UsbDevice device) {
    263             if (mVendorId != -1 && device.getVendorId() != mVendorId) {
    264                 return false;
    265             }
    266             if (mProductId != -1 && device.getProductId() != mProductId) {
    267                 return false;
    268             }
    269             if (mManufacturerName != null && device.getManufacturerName() == null) {
    270                 return false;
    271             }
    272             if (mProductName != null && device.getProductName() == null) {
    273                 return false;
    274             }
    275             if (mSerialNumber != null && device.getSerialNumber() == null) {
    276                 return false;
    277             }
    278             if (mManufacturerName != null && device.getManufacturerName() != null
    279                     && !mManufacturerName.equals(device.getManufacturerName())) {
    280                 return false;
    281             }
    282             if (mProductName != null && device.getProductName() != null
    283                     && !mProductName.equals(device.getProductName())) {
    284                 return false;
    285             }
    286             if (mSerialNumber != null && device.getSerialNumber() != null
    287                     && !mSerialNumber.equals(device.getSerialNumber())) {
    288                 return false;
    289             }
    290 
    291             // check device class/subclass/protocol
    292             if (matches(device.getDeviceClass(), device.getDeviceSubclass(),
    293                         device.getDeviceProtocol())) {
    294                 return true;
    295             }
    296 
    297             // if device doesn't match, check the interfaces
    298             int count = device.getInterfaceCount();
    299             for (int i = 0; i < count; i++) {
    300                 UsbInterface intf = device.getInterface(i);
    301                 if (matches(intf.getInterfaceClass(), intf.getInterfaceSubclass(),
    302                             intf.getInterfaceProtocol())) {
    303                     return true;
    304                 }
    305             }
    306 
    307             return false;
    308         }
    309 
    310         @Override
    311         public boolean equals(Object obj) {
    312             // can't compare if we have wildcard strings
    313             if (mVendorId == -1 || mProductId == -1
    314                     || mClass == -1 || mSubclass == -1 || mProtocol == -1) {
    315                 return false;
    316             }
    317             if (obj instanceof DeviceFilter) {
    318                 DeviceFilter filter = (DeviceFilter) obj;
    319 
    320                 if (filter.mVendorId != mVendorId
    321                         || filter.mProductId != mProductId
    322                         || filter.mClass != mClass
    323                         || filter.mSubclass != mSubclass
    324                         || filter.mProtocol != mProtocol) {
    325                     return false;
    326                 }
    327                 if ((filter.mManufacturerName != null && mManufacturerName == null)
    328                         || (filter.mManufacturerName == null && mManufacturerName != null)
    329                         || (filter.mProductName != null && mProductName == null)
    330                         || (filter.mProductName == null && mProductName != null)
    331                         || (filter.mSerialNumber != null && mSerialNumber == null)
    332                         || (filter.mSerialNumber == null && mSerialNumber != null)) {
    333                     return false;
    334                 }
    335                 if  ((filter.mManufacturerName != null && mManufacturerName != null
    336                           && !mManufacturerName.equals(filter.mManufacturerName))
    337                           || (filter.mProductName != null && mProductName != null
    338                           && !mProductName.equals(filter.mProductName))
    339                           || (filter.mSerialNumber != null && mSerialNumber != null
    340                           && !mSerialNumber.equals(filter.mSerialNumber))) {
    341                     return false;
    342                 }
    343                 return true;
    344             }
    345             if (obj instanceof UsbDevice) {
    346                 UsbDevice device = (UsbDevice) obj;
    347                 if (device.getVendorId() != mVendorId
    348                         || device.getProductId() != mProductId
    349                         || device.getDeviceClass() != mClass
    350                         || device.getDeviceSubclass() != mSubclass
    351                         || device.getDeviceProtocol() != mProtocol) {
    352                     return false;
    353                 }
    354                 if ((mManufacturerName != null && device.getManufacturerName() == null)
    355                         || (mManufacturerName == null && device.getManufacturerName() != null)
    356                         || (mProductName != null && device.getProductName() == null)
    357                         || (mProductName == null && device.getProductName() != null)
    358                         || (mSerialNumber != null && device.getSerialNumber() == null)
    359                         || (mSerialNumber == null && device.getSerialNumber() != null)) {
    360                     return false;
    361                 }
    362                 if ((device.getManufacturerName() != null
    363                         && !mManufacturerName.equals(device.getManufacturerName()))
    364                         || (device.getProductName() != null
    365                         && !mProductName.equals(device.getProductName()))
    366                         || (device.getSerialNumber() != null
    367                         && !mSerialNumber.equals(device.getSerialNumber()))) {
    368                     return false;
    369                 }
    370                 return true;
    371             }
    372             return false;
    373         }
    374 
    375         @Override
    376         public int hashCode() {
    377             return (((mVendorId << 16) | mProductId)
    378                     ^ ((mClass << 16) | (mSubclass << 8) | mProtocol));
    379         }
    380 
    381         @Override
    382         public String toString() {
    383             return "DeviceFilter[mVendorId=" + mVendorId + ",mProductId=" + mProductId
    384                     + ",mClass=" + mClass + ",mSubclass=" + mSubclass
    385                     + ",mProtocol=" + mProtocol + ",mManufacturerName=" + mManufacturerName
    386                     + ",mProductName=" + mProductName + ",mSerialNumber=" + mSerialNumber + "]";
    387         }
    388     }
    389 
    390     private final ServiceConnection mConnection = new ServiceConnection() {
    391         @Override
    392         public void onServiceConnected(ComponentName className, IBinder service) {
    393             Log.i(TAG, "onServiceConnected: " + className);
    394             mHandler.requestOnServiceConnectionStateChanged(
    395                     IUsbAoapSupportCheckService.Stub.asInterface(service));
    396         }
    397 
    398         @Override
    399         public void onServiceDisconnected(ComponentName className) {
    400             Log.i(TAG, "onServiceDisconnected: " + className);
    401             mHandler.requestOnServiceConnectionStateChanged(null);
    402         }
    403     };
    404 
    405     public UsbDeviceHandlerResolver(UsbManager manager, Context context,
    406             UsbDeviceHandlerResolverCallback deviceListener) {
    407         mUsbManager = manager;
    408         mContext = context;
    409         mDeviceCallback = deviceListener;
    410         mHandlerThread = new HandlerThread(TAG);
    411         mHandlerThread.start();
    412         mHandler = new UsbDeviceResolverHandler(mHandlerThread.getLooper());
    413         mPackageManager = context.getPackageManager();
    414         mStateController = new UsbDeviceStateController(context, this, manager);
    415         mStateController.init();
    416     }
    417 
    418     /**
    419      * Releases current object.
    420      */
    421     public void release() {
    422         if (mHandlerThread != null) {
    423             mHandlerThread.quitSafely();
    424         }
    425         if (mStateController != null) {
    426             mStateController.release();
    427         }
    428     }
    429 
    430     /**
    431      * Resolves handlers for USB device.
    432      */
    433     public void resolve(UsbDevice device) {
    434         mHandler.requestResolveHandlers(device);
    435     }
    436 
    437     /**
    438      * Dispatches device to component.
    439      */
    440     public boolean dispatch(UsbDevice device, ComponentName component, boolean inAoap) {
    441         if (LOCAL_LOGD) {
    442             Log.d(TAG, "dispatch: " + device + " component: " + component + " inAoap:" + inAoap);
    443         }
    444 
    445         mActiveUsbDevice = device;
    446         mDeviceMode = MODE_DISPATCH;
    447         ActivityInfo activityInfo;
    448         try {
    449             activityInfo = mPackageManager.getActivityInfo(component, PackageManager.GET_META_DATA);
    450         } catch (NameNotFoundException e) {
    451             Log.e(TAG, "Activity not found: " + component);
    452             return false;
    453         }
    454 
    455         Intent intent = createDeviceAttachedIntent(device);
    456         if (inAoap) {
    457             DeviceFilter filter = packageMatches(activityInfo, intent.getAction(), device, true);
    458             intent.setComponent(component);
    459             mDispatchIntent = intent;
    460             mDispatchUid = activityInfo.applicationInfo.uid;
    461             if (filter != null) {
    462                 requestAoapSwitch(filter);
    463                 return true;
    464             }
    465         }
    466 
    467         intent.setComponent(component);
    468         mUsbManager.grantPermission(device, activityInfo.applicationInfo.uid);
    469 
    470         mContext.startActivity(intent);
    471         mHandler.requestCompleteDeviceDispatch();
    472         return true;
    473     }
    474 
    475     private static Intent createDeviceAttachedIntent(UsbDevice device) {
    476         Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_ATTACHED);
    477         intent.putExtra(UsbManager.EXTRA_DEVICE, device);
    478         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    479         return intent;
    480     }
    481 
    482     private void doHandleResolveHandlers(
    483             UsbDevice device) {
    484         mActiveDeviceSettings.clear();
    485         mActiveDeviceOptions.clear();
    486         mActiveUsbDevice = device;
    487         mDeviceMode = MODE_PROBE;
    488 
    489         if (LOCAL_LOGD) {
    490             Log.d(TAG, "doHandleResolveHandlers: " + device);
    491         }
    492         boolean maySupportAoap = UsbUtil.possiblyAndroid(device);
    493         boolean isInAoap = AoapInterface.isDeviceInAoapMode(device);
    494 
    495         Intent intent = createDeviceAttachedIntent(device);
    496         List<Pair<ResolveInfo, DeviceFilter>> matches = getDeviceMatches(device, intent, false);
    497         if (LOCAL_LOGD) {
    498             Log.d(TAG, "matches size: " + matches.size());
    499         }
    500         for (Pair<ResolveInfo, DeviceFilter> info : matches) {
    501             UsbDeviceSettings setting = UsbDeviceSettings.constructSettings(mActiveUsbDevice);
    502             setting.setHandler(
    503                     new ComponentName(
    504                             info.first.activityInfo.packageName, info.first.activityInfo.name));
    505             mActiveDeviceSettings.add(setting);
    506         }
    507         mBaseSettings = UsbDeviceSettings.constructSettings(mActiveUsbDevice);
    508         if (!AoapInterface.isDeviceInAoapMode(device) && maySupportAoap) {
    509             mActiveDeviceOptions.addAll(getDeviceMatches(device, intent, true));
    510             handleTryNextAoapMode();
    511         } else {
    512             doHandleCompleteDeviceProbing();
    513         }
    514     }
    515 
    516     private void handleTryNextAoapMode() {
    517         if (LOCAL_LOGD) {
    518             Log.d(TAG, "handleTryNextAoapMode");
    519         }
    520         Pair<ResolveInfo, DeviceFilter> option = mActiveDeviceOptions.peek();
    521         if (option == null) {
    522             mHandler.requestCompleteDeviceProbing();
    523             return;
    524         }
    525         requestAoapSwitch(option.second);
    526     }
    527 
    528     private void requestAoapSwitch(DeviceFilter filter) {
    529         UsbDeviceStateController.AoapSwitchRequest request =
    530                 new UsbDeviceStateController.AoapSwitchRequest(
    531                         mActiveUsbDevice,
    532                         filter.mAoapManufacturer,
    533                         filter.mAoapModel,
    534                         filter.mAoapDescription,
    535                         filter.mAoapVersion,
    536                         filter.mAoapUri,
    537                         filter.mAoapSerial);
    538         mStateController.startAoap(request);
    539     }
    540 
    541     private void doHandleCompleteDeviceProbing() {
    542         if (LOCAL_LOGD) {
    543             Log.d(TAG, "doHandleCompleteDeviceProbing");
    544         }
    545         mDeviceCallback.onHandlersResolveCompleted(mActiveUsbDevice, mActiveDeviceSettings);
    546         stopDeviceProcessing(mActiveUsbDevice);
    547         mActiveUsbDevice = null;
    548         mBaseSettings = null;
    549         mDeviceMode = MODE_OFF;
    550     }
    551 
    552     private void doHandleAoapStartComplete(UsbDevice device) {
    553         if (LOCAL_LOGD) {
    554             Log.d(TAG, "doHandleAoapStartComplete:" + device + " mode: " + MODE_DISPATCH);
    555         }
    556         if (mDeviceMode == MODE_DISPATCH && mDispatchIntent != null) {
    557             mDispatchIntent.putExtra(UsbManager.EXTRA_DEVICE, device);
    558             mUsbManager.grantPermission(device, mDispatchUid);
    559             mContext.startActivity(mDispatchIntent);
    560             mDispatchIntent = null;
    561             mDispatchUid = 0;
    562             mDeviceMode = MODE_OFF;
    563             mDeviceCallback.onDeviceDispatched();
    564             return;
    565         }
    566         mActiveUsbDevice = device;
    567         mDeviceMode = MODE_PROBE_AOAP;
    568         if (device == null) {
    569             mActiveDeviceOptions.poll();
    570             handleTryNextAoapMode();
    571         }
    572 
    573         Pair<ResolveInfo, DeviceFilter> option = mActiveDeviceOptions.peek();
    574         if (option == null) {
    575             Log.w(TAG, "No more options left.");
    576             mStateController.startDeviceReset(mActiveUsbDevice);
    577             return;
    578         }
    579         DeviceFilter filter = option.second;
    580         Intent serviceIntent = new Intent();
    581         serviceIntent.setComponent(ComponentName.unflattenFromString(option.second.mAoapService));
    582         boolean bound = mContext.bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE);
    583         if (bound) {
    584             mHandler.requestServiceConnectionTimeout();
    585         } else {
    586             if (LOCAL_LOGD) {
    587                 Log.d(TAG, "Failed to bind to the service");
    588             }
    589             mStateController.startDeviceReset(mActiveUsbDevice);
    590         }
    591     }
    592 
    593     private void doHandleDeviceResetComplete(UsbDevice device) {
    594         if (LOCAL_LOGD) {
    595             Log.d(TAG, "doHandleDeviceResetComplete:" + device);
    596         }
    597         mActiveDeviceOptions.poll();
    598         mActiveUsbDevice = device;
    599         mDeviceMode = MODE_PROBE;
    600         handleTryNextAoapMode();
    601     }
    602 
    603     private void doHandleServiceConnectionStateChanged(IUsbAoapSupportCheckService service) {
    604         if (LOCAL_LOGD) {
    605             Log.d(TAG, "doHandleServiceConnectionStateChanged: " + service);
    606         }
    607         mBound = service != null;
    608         mIUsbAoapSupportCheckService = service;
    609         if (mBound && mActiveUsbDevice != null && mDeviceMode == MODE_PROBE_AOAP) {
    610             boolean deviceSupported = false;
    611             try {
    612                 deviceSupported =
    613                         mIUsbAoapSupportCheckService.isDeviceSupported(mActiveUsbDevice);
    614             } catch (RemoteException e) {
    615                 Log.e(TAG, "Call to remote service failed", e);
    616             }
    617             if (deviceSupported) {
    618                 Pair<ResolveInfo, DeviceFilter> option = mActiveDeviceOptions.peek();
    619 
    620                 UsbDeviceSettings setting = UsbDeviceSettings.constructSettings(mBaseSettings);
    621                 setting.setHandler(
    622                         new ComponentName(
    623                             option.first.activityInfo.packageName, option.first.activityInfo.name));
    624                 setting.setAoap(true);
    625                 mActiveDeviceSettings.add(setting);
    626             }
    627             mContext.unbindService(mConnection);
    628             mBound = false;
    629             mIUsbAoapSupportCheckService = null;
    630             mStateController.startDeviceReset(mActiveUsbDevice);
    631         } else if (mActiveUsbDevice != null && mDeviceMode == MODE_PROBE_AOAP) {
    632             mStateController.startDeviceReset(mActiveUsbDevice);
    633         } else {
    634             handleTryNextAoapMode();
    635         }
    636     }
    637 
    638     private List<Pair<ResolveInfo, DeviceFilter>> getDeviceMatches(
    639             UsbDevice device, Intent intent, boolean forAoap) {
    640         List<Pair<ResolveInfo, DeviceFilter>> matches = new ArrayList<>();
    641         List<ResolveInfo> resolveInfos =
    642                 mPackageManager.queryIntentActivities(intent, PackageManager.GET_META_DATA);
    643         for (ResolveInfo resolveInfo : resolveInfos) {
    644             DeviceFilter filter = packageMatches(resolveInfo.activityInfo,
    645                     intent.getAction(), device, forAoap);
    646             if (filter != null) {
    647                 matches.add(Pair.create(resolveInfo, filter));
    648             }
    649         }
    650         return matches;
    651     }
    652 
    653     private DeviceFilter packageMatches(ActivityInfo ai, String metaDataName, UsbDevice device,
    654             boolean forAoap) {
    655         if (LOCAL_LOGD) {
    656             Log.d(TAG, "packageMatches ai: " + ai + "metaDataName: " + metaDataName + " forAoap: "
    657                     + forAoap);
    658         }
    659         String filterTagName = forAoap ? "usb-aoap-accessory" : "usb-device";
    660         XmlResourceParser parser = null;
    661         try {
    662             parser = ai.loadXmlMetaData(mPackageManager, metaDataName);
    663             if (parser == null) {
    664                 Log.w(TAG, "no meta-data for " + ai);
    665                 return null;
    666             }
    667 
    668             XmlUtils.nextElement(parser);
    669             while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
    670                 String tagName = parser.getName();
    671                 if (device != null && filterTagName.equals(tagName)) {
    672                     DeviceFilter filter = DeviceFilter.read(parser, forAoap);
    673                     if (forAoap || filter.matches(device)) {
    674                         return filter;
    675                     }
    676                 }
    677                 XmlUtils.nextElement(parser);
    678             }
    679         } catch (Exception e) {
    680             Log.w(TAG, "Unable to load component info " + ai.toString(), e);
    681         } finally {
    682             if (parser != null) parser.close();
    683         }
    684         return null;
    685     }
    686 
    687     @Override
    688     public void onDeviceResetComplete(UsbDevice device) {
    689         if (LOCAL_LOGD) {
    690             Log.d(TAG, "onDeviceResetComplete: " + device);
    691         }
    692         mHandler.requestOnDeviceResetComplete(device);
    693     }
    694 
    695     @Override
    696     public void onAoapStartComplete(UsbDevice device) {
    697         if (LOCAL_LOGD) {
    698             Log.d(TAG, "onAoapStartComplete: " + device);
    699         }
    700         mHandler.requestOnAoapStartComplete(device);
    701     }
    702 
    703     @Override
    704     public void onAoapStartFailed(UsbDevice device) {
    705         if (LOCAL_LOGD) {
    706             Log.d(TAG, "onAoapStartFailed: " + device);
    707         }
    708         mActiveDeviceOptions.poll();
    709         handleTryNextAoapMode();
    710     }
    711 
    712     private boolean isDeviceProcessing(UsbDevice device) {
    713         return mActiveDeviceSerial != null
    714                 && mActiveDeviceSerial.equals(device.getSerialNumber());
    715     }
    716 
    717     private boolean stopDeviceProcessing(UsbDevice device) {
    718         if (device == null || device.getSerialNumber().equals(mActiveDeviceSerial)) {
    719             mActiveDeviceSerial = null;
    720             return true;
    721         }
    722         return false;
    723     }
    724 
    725     private boolean startDeviceProcessing(UsbDevice device) {
    726         if (mActiveDeviceSerial != null) {
    727             return false;
    728         } else {
    729             mActiveDeviceSerial = device.getSerialNumber();
    730             return true;
    731         }
    732     }
    733 
    734     private class UsbDeviceResolverHandler extends Handler {
    735         private static final int MSG_RESOLVE_HANDLERS = 0;
    736         private static final int MSG_DEVICE_RESET_COMPLETE = 1;
    737         private static final int MSG_AOAP_START_COMPLETE = 2;
    738         private static final int MSG_SERVICE_CONNECTION_STATE_CHANGE = 3;
    739         private static final int MSG_SERVICE_CONNECTION_TIMEOUT = 4;
    740         private static final int MSG_COMPLETE_PROBING = 5;
    741         private static final int MSG_COMPLETE_DISPATCH = 6;
    742 
    743         private static final long RESCHEDULE_TIMEOUT_MS = 100;
    744         private static final long CONNECT_TIMEOUT_MS = 5000;
    745         private static final long FINISH_PROBING_TIMEOUT_MS = 200;
    746 
    747         private UsbDeviceResolverHandler(Looper looper) {
    748             super(looper);
    749         }
    750 
    751         public void requestResolveHandlers(UsbDevice device) {
    752             Message msg = obtainMessage(MSG_RESOLVE_HANDLERS, device);
    753             sendMessage(msg);
    754         }
    755 
    756         public void requestOnAoapStartComplete(UsbDevice device) {
    757             sendMessage(obtainMessage(MSG_AOAP_START_COMPLETE, device));
    758         }
    759 
    760         public void requestOnDeviceResetComplete(UsbDevice device) {
    761             sendMessage(obtainMessage(MSG_DEVICE_RESET_COMPLETE, device));
    762         }
    763 
    764         public void requestOnServiceConnectionStateChanged(IUsbAoapSupportCheckService service) {
    765             sendMessage(obtainMessage(MSG_SERVICE_CONNECTION_STATE_CHANGE, service));
    766         }
    767 
    768         public void requestServiceConnectionTimeout() {
    769             sendEmptyMessageDelayed(MSG_SERVICE_CONNECTION_TIMEOUT, CONNECT_TIMEOUT_MS);
    770         }
    771 
    772         public void requestCompleteDeviceProbing() {
    773             sendEmptyMessageDelayed(MSG_COMPLETE_PROBING, FINISH_PROBING_TIMEOUT_MS);
    774         }
    775 
    776         public void requestCompleteDeviceDispatch() {
    777             sendEmptyMessage(MSG_COMPLETE_DISPATCH);
    778         }
    779 
    780         @Override
    781         public void handleMessage(Message msg) {
    782             switch (msg.what) {
    783                 case MSG_RESOLVE_HANDLERS:
    784                     UsbDevice device = (UsbDevice) msg.obj;
    785                     // if this device is already being processed - drop the request.
    786                     if (!isDeviceProcessing(device)) {
    787                         if (startDeviceProcessing(device)) {
    788                             doHandleResolveHandlers(device);
    789                         } else {
    790                             // Reschedule this device for processing at later time.
    791                             sendMessageDelayed(msg, RESCHEDULE_TIMEOUT_MS);
    792                         }
    793                     } else {
    794                         Log.i(TAG, "Device is already being processed: " + device);
    795                     }
    796                     break;
    797                 case MSG_AOAP_START_COMPLETE:
    798                     doHandleAoapStartComplete((UsbDevice) msg.obj);
    799                     break;
    800                 case MSG_DEVICE_RESET_COMPLETE:
    801                     doHandleDeviceResetComplete((UsbDevice) msg.obj);
    802                     break;
    803                 case MSG_SERVICE_CONNECTION_STATE_CHANGE:
    804                     removeMessages(MSG_SERVICE_CONNECTION_TIMEOUT);
    805                     doHandleServiceConnectionStateChanged((IUsbAoapSupportCheckService) msg.obj);
    806                     break;
    807                 case MSG_SERVICE_CONNECTION_TIMEOUT:
    808                     Log.i(TAG, "Service connection timeout");
    809                     doHandleServiceConnectionStateChanged(null);
    810                     break;
    811                 case MSG_COMPLETE_PROBING:
    812                     doHandleCompleteDeviceProbing();
    813                     break;
    814                 case MSG_COMPLETE_DISPATCH:
    815                     mDeviceCallback.onDeviceDispatched();
    816                     break;
    817                 default:
    818                     Log.w(TAG, "Unsupported message: " + msg);
    819             }
    820         }
    821     }
    822 }
    823