Home | History | Annotate | Download | only in verifierusbcompanion
      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 
     17 package com.android.cts.verifierusbcompanion;
     18 
     19 import static org.junit.Assert.assertEquals;
     20 
     21 import android.app.PendingIntent;
     22 import android.content.BroadcastReceiver;
     23 import android.content.Context;
     24 import android.content.Intent;
     25 import android.content.IntentFilter;
     26 import android.hardware.usb.UsbConstants;
     27 import android.hardware.usb.UsbDevice;
     28 import android.hardware.usb.UsbDeviceConnection;
     29 import android.hardware.usb.UsbEndpoint;
     30 import android.hardware.usb.UsbInterface;
     31 import android.hardware.usb.UsbManager;
     32 import android.support.annotation.NonNull;
     33 
     34 import java.nio.ByteBuffer;
     35 import java.nio.charset.Charset;
     36 
     37 /**
     38  * Companion code for com.android.cts.verifier.usb.device.UsbAccessoryTestActivity
     39  */
     40 class AccessoryTestCompanion extends TestCompanion {
     41     private static final int TIMEOUT_MILLIS = 500;
     42     private static final int MAX_BUFFER_SIZE = 16384;
     43     private static final int TEST_DATA_SIZE_THRESHOLD = 100 * 1024 * 1024; // 100MB
     44 
     45     private static final String ACTION_USB_PERMISSION =
     46             "com.android.cts.verifierusbcompanion.USB_PERMISSION";
     47 
     48     private UsbManager mUsbManager;
     49     private BroadcastReceiver mUsbDeviceConnectionReceiver;
     50     private UsbDevice mDevice;
     51 
     52     AccessoryTestCompanion(@NonNull Context context, @NonNull TestObserver observer) {
     53         super(context, observer);
     54     }
     55 
     56     /**
     57      * @throws Throwable
     58      */
     59     @Override
     60     protected void runTest() throws Throwable {
     61         updateStatus("Waiting for device under test to connect");
     62 
     63         mUsbManager = getContext().getSystemService(UsbManager.class);
     64 
     65         mUsbDeviceConnectionReceiver = new BroadcastReceiver() {
     66             @Override
     67             public void onReceive(Context context, Intent intent) {
     68                 synchronized (AccessoryTestCompanion.this) {
     69                     UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
     70 
     71                     switch (intent.getAction()) {
     72                         case UsbManager.ACTION_USB_DEVICE_ATTACHED:
     73                             if (mUsbManager.hasPermission(device)) {
     74                                 onDeviceAccessPermitted(device);
     75                             } else {
     76                                 mUsbManager.requestPermission(device,
     77                                         PendingIntent.getBroadcast(getContext(), 0,
     78                                                 new Intent(ACTION_USB_PERMISSION), 0));
     79                             }
     80                             break;
     81                         case ACTION_USB_PERMISSION:
     82                             boolean granted = intent.getBooleanExtra(
     83                                     UsbManager.EXTRA_PERMISSION_GRANTED, false);
     84 
     85                             if (granted) {
     86                                 onDeviceAccessPermitted(device);
     87                             } else {
     88                                 fail("Permission to connect to " + device.getProductName()
     89                                         + " not granted");
     90                             }
     91                             break;
     92                     }
     93                 }
     94             }
     95         };
     96 
     97         IntentFilter filter = new IntentFilter();
     98         filter.addAction(ACTION_USB_PERMISSION);
     99         filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
    100 
    101         getContext().registerReceiver(mUsbDeviceConnectionReceiver, filter);
    102 
    103         synchronized (this) {
    104             while (mDevice == null) {
    105                 wait();
    106             }
    107         }
    108 
    109         UsbInterface iface = null;
    110         for (int i = 0; i < mDevice.getConfigurationCount(); i++) {
    111             if (mDevice.getInterface(i).getName().equals("Android Accessory Interface")) {
    112                 iface = mDevice.getInterface(i);
    113                 break;
    114             }
    115         }
    116 
    117         UsbEndpoint in = getEndpoint(iface, UsbConstants.USB_DIR_IN);
    118         UsbEndpoint out = getEndpoint(iface, UsbConstants.USB_DIR_OUT);
    119 
    120         UsbDeviceConnection connection = mUsbManager.openDevice(mDevice);
    121 
    122         try {
    123             String testName;
    124             do {
    125                 testName = nextTest(connection, in, out, true);
    126 
    127                 updateStatus("Running test \"" + testName + "\"");
    128 
    129                 switch (testName) {
    130                     case "echo 32 bytes": {
    131                         byte[] buffer = new byte[32];
    132 
    133                         int numTransferred = connection.bulkTransfer(in, buffer, 32, 0);
    134                         assertEquals(32, numTransferred);
    135 
    136                         numTransferred = connection.bulkTransfer(out, buffer, 32, 0);
    137                         assertEquals(32, numTransferred);
    138                     }
    139                     break;
    140 
    141                     case "echo two 16 byte transfers as one": {
    142                         byte[] buffer = new byte[48];
    143 
    144                         // We receive the individual transfers even if we wait for more data
    145                         int numTransferred = connection.bulkTransfer(in, buffer, 32, 0);
    146                         assertEquals(16, numTransferred);
    147                         numTransferred = connection.bulkTransfer(in, buffer, 16, 32, 0);
    148                         assertEquals(16, numTransferred);
    149 
    150                         numTransferred = connection.bulkTransfer(out, buffer, 32, 0);
    151                         assertEquals(32, numTransferred);
    152                     }
    153                     break;
    154 
    155                     case "echo 32 bytes as two 16 byte transfers": {
    156                         byte[] buffer = new byte[32];
    157 
    158                         int numTransferred = connection.bulkTransfer(in, buffer, 32, 0);
    159                         assertEquals(32, numTransferred);
    160 
    161                         numTransferred = connection.bulkTransfer(out, buffer, 16, 0);
    162                         assertEquals(16, numTransferred);
    163                         numTransferred = connection.bulkTransfer(out, buffer, 16, 16, 0);
    164                         assertEquals(16, numTransferred);
    165                     }
    166                     break;
    167 
    168                     case "measure out transfer speed": {
    169                         byte[] buffer = new byte[MAX_BUFFER_SIZE];
    170 
    171                         long bytesRead = 0;
    172                         while (bytesRead < TEST_DATA_SIZE_THRESHOLD) {
    173                             int numTransferred = connection.bulkTransfer(
    174                                     in, buffer, MAX_BUFFER_SIZE, 0);
    175                             bytesRead += numTransferred;
    176                         }
    177 
    178                         // MAX_BUFFER_SIZE is a multiple of the package size, hence we get a zero
    179                         // sized package after. Some older devices do not send these packages, but
    180                         // this is not compliant anymore.
    181                         int numTransferred = connection.bulkTransfer(in, buffer, 1, TIMEOUT_MILLIS);
    182                         assertEquals(0, numTransferred);
    183 
    184                         byte[] confirm = new byte[] {1};
    185                         numTransferred = connection.bulkTransfer(out, confirm, 1, 0);
    186                         assertEquals(1, numTransferred);
    187                     }
    188                     break;
    189 
    190                     case "measure in transfer speed": {
    191                         byte[] buffer = new byte[MAX_BUFFER_SIZE];
    192 
    193                         long bytesWritten = 0;
    194                         int numTransferred = 0;
    195                         while (bytesWritten < TEST_DATA_SIZE_THRESHOLD) {
    196                             numTransferred =
    197                                     connection.bulkTransfer(out, buffer, MAX_BUFFER_SIZE, 0);
    198                             assertEquals(MAX_BUFFER_SIZE, numTransferred);
    199                             bytesWritten += numTransferred;
    200                         }
    201 
    202                         byte[] confirm = new byte[] {1};
    203                         numTransferred = connection.bulkTransfer(out, confirm, 1, 0);
    204                         assertEquals(1, numTransferred);
    205                     }
    206                     break;
    207 
    208                     case "echo max bytes": {
    209                         byte[] buffer = new byte[MAX_BUFFER_SIZE];
    210 
    211                         int numTransferred = connection.bulkTransfer(in, buffer, MAX_BUFFER_SIZE,
    212                                 0);
    213                         assertEquals(MAX_BUFFER_SIZE, numTransferred);
    214 
    215                         // MAX_BUFFER_SIZE is a multiple of the package size, hence we get a zero
    216                         // sized package after. Some older devices do not send these packages, but
    217                         // this is not compliant anymore.
    218                         numTransferred = connection.bulkTransfer(in, buffer, 1, TIMEOUT_MILLIS);
    219                         assertEquals(0, numTransferred);
    220 
    221                         numTransferred = connection.bulkTransfer(out, buffer, MAX_BUFFER_SIZE, 0);
    222                         assertEquals(MAX_BUFFER_SIZE, numTransferred);
    223                     }
    224                     break;
    225 
    226                     case "echo max*2 bytes": {
    227                         byte[] buffer = new byte[MAX_BUFFER_SIZE * 2];
    228 
    229                         int numTransferred = connection.bulkTransfer(in, buffer, MAX_BUFFER_SIZE,
    230                                 0);
    231                         assertEquals(MAX_BUFFER_SIZE, numTransferred);
    232 
    233                         // Oversized transfers get split into two
    234                         numTransferred = connection.bulkTransfer(in, buffer, MAX_BUFFER_SIZE,
    235                                 MAX_BUFFER_SIZE, 0);
    236                         assertEquals(MAX_BUFFER_SIZE, numTransferred);
    237 
    238                         // MAX_BUFFER_SIZE is a multiple of the package size, hence we get a zero
    239                         // sized package after. Some older devices do not send these packages, but
    240                         // this is not compliant anymore.
    241                         numTransferred = connection.bulkTransfer(in, buffer, 1, TIMEOUT_MILLIS);
    242                         assertEquals(0, numTransferred);
    243 
    244                         numTransferred = connection.bulkTransfer(out, buffer, MAX_BUFFER_SIZE, 100);
    245                         assertEquals(MAX_BUFFER_SIZE, numTransferred);
    246 
    247                         numTransferred = connection.bulkTransfer(out, buffer, MAX_BUFFER_SIZE,
    248                                 MAX_BUFFER_SIZE, 0);
    249                         assertEquals(MAX_BUFFER_SIZE, numTransferred);
    250                     }
    251                     break;
    252 
    253                     default:
    254                         break;
    255                 }
    256             } while (!testName.equals("done"));
    257         } finally {
    258             connection.close();
    259         }
    260     }
    261 
    262     /**
    263      * If access to a device was permitted either make the device an accessory if it already is,
    264      * start the test.
    265      *
    266      * @param device The device access was permitted to
    267      */
    268     private void onDeviceAccessPermitted(@NonNull UsbDevice device) {
    269         if (!AoapInterface.isDeviceInAoapMode(device)) {
    270             UsbDeviceConnection connection = mUsbManager.openDevice(device);
    271             try {
    272                 makeThisDeviceAnAccessory(connection);
    273             } finally {
    274                 connection.close();
    275             }
    276         } else {
    277             getContext().unregisterReceiver(mUsbDeviceConnectionReceiver);
    278             mUsbDeviceConnectionReceiver = null;
    279 
    280             synchronized (AccessoryTestCompanion.this) {
    281                 mDevice = device;
    282 
    283                 AccessoryTestCompanion.this.notifyAll();
    284             }
    285         }
    286     }
    287 
    288     @NonNull private String nextTest(@NonNull UsbDeviceConnection connection,
    289             @NonNull UsbEndpoint in, @NonNull UsbEndpoint out, boolean isSuccess) {
    290         byte[] sizeBuffer = new byte[1];
    291 
    292         updateStatus("Waiting for next test");
    293 
    294         int numTransferred = connection.bulkTransfer(in, sizeBuffer, 1, 0);
    295         assertEquals(1, numTransferred);
    296 
    297         int nameSize = sizeBuffer[0];
    298 
    299         byte[] nameBuffer = new byte[nameSize];
    300         numTransferred = connection.bulkTransfer(in, nameBuffer, nameSize, 0);
    301         assertEquals(nameSize, numTransferred);
    302 
    303         numTransferred = connection.bulkTransfer(out, new byte[]{(byte) (isSuccess ? 1 : 0)}, 1, 0);
    304         assertEquals(1, numTransferred);
    305 
    306         numTransferred = connection.bulkTransfer(in, new byte[1], 1, 0);
    307         assertEquals(1, numTransferred);
    308 
    309         String name = Charset.forName("UTF-8").decode(ByteBuffer.wrap(nameBuffer)).toString();
    310 
    311         updateStatus("Next test is " + name);
    312 
    313         return name;
    314     }
    315 
    316     /**
    317      * Search an {@link UsbInterface} for an {@link UsbEndpoint endpoint} of a certain direction.
    318      *
    319      * @param iface     The interface to search
    320      * @param direction The direction the endpoint is for.
    321      *
    322      * @return The first endpoint found or {@link null}.
    323      */
    324     @NonNull private UsbEndpoint getEndpoint(@NonNull UsbInterface iface, int direction) {
    325         for (int i = 0; i < iface.getEndpointCount(); i++) {
    326             UsbEndpoint ep = iface.getEndpoint(i);
    327             if (ep.getDirection() == direction) {
    328                 return ep;
    329             }
    330         }
    331 
    332         throw new IllegalStateException("Could not find " + direction + " endpoint in "
    333                 + iface.getName());
    334     }
    335 
    336     /**
    337      * Converts the device under test into an Android accessory. Accessories are USB hosts that are
    338      * detected on the device side via {@link UsbManager#getAccessoryList()}.
    339      *
    340      * @param connection The connection to the USB device
    341      */
    342     private void makeThisDeviceAnAccessory(@NonNull UsbDeviceConnection connection) {
    343         AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_MANUFACTURER,
    344                 "Android");
    345         AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_MODEL,
    346                 "Android device");
    347         AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_DESCRIPTION,
    348                 "Android device running CTS verifier");
    349         AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_VERSION, "1");
    350         AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_URI,
    351                 "https://source.android.com/compatibility/cts/verifier.html");
    352         AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_SERIAL, "0");
    353         AoapInterface.sendAoapStart(connection);
    354     }
    355 }
    356