Home | History | Annotate | Download | only in accessory
      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.verifier.usb.accessory;
     18 
     19 import static com.android.cts.verifier.usb.Util.runAndAssertException;
     20 
     21 import static org.junit.Assert.assertArrayEquals;
     22 import static org.junit.Assert.assertEquals;
     23 import static org.junit.Assert.assertNotNull;
     24 import static org.junit.Assert.assertTrue;
     25 
     26 import android.hardware.usb.UsbAccessory;
     27 import android.hardware.usb.UsbManager;
     28 import android.os.AsyncTask;
     29 import android.os.Bundle;
     30 import android.os.ParcelFileDescriptor;
     31 import android.os.SystemClock;
     32 import androidx.annotation.NonNull;
     33 import androidx.annotation.Nullable;
     34 import android.util.Log;
     35 import android.view.View;
     36 import android.widget.ProgressBar;
     37 import android.widget.TextView;
     38 
     39 import com.android.compatibility.common.util.ResultType;
     40 import com.android.compatibility.common.util.ResultUnit;
     41 import com.android.cts.verifier.PassFailButtons;
     42 import com.android.cts.verifier.R;
     43 
     44 import java.io.IOException;
     45 import java.io.InputStream;
     46 import java.io.OutputStream;
     47 import java.nio.ByteBuffer;
     48 import java.nio.CharBuffer;
     49 import java.nio.charset.Charset;
     50 import java.util.Arrays;
     51 import java.util.Random;
     52 
     53 /**
     54  * Guide the user to run test for the USB accessory interface.
     55  */
     56 public class UsbAccessoryTestActivity extends PassFailButtons.Activity implements
     57         AccessoryAttachmentHandler.AccessoryAttachmentObserver {
     58     private static final String LOG_TAG = UsbAccessoryTestActivity.class.getSimpleName();
     59     private static final int MAX_BUFFER_SIZE = 16384;
     60 
     61     private static final int TEST_DATA_SIZE_THRESHOLD = 100 * 1024 * 1024; // 100MB
     62 
     63     private TextView mStatus;
     64     private ProgressBar mProgress;
     65 
     66     @Override
     67     protected void onCreate(@Nullable Bundle savedInstanceState) {
     68         super.onCreate(savedInstanceState);
     69 
     70         setContentView(R.layout.usb_main);
     71         setInfoResources(
     72                 R.string.usb_accessory_test, R.string.usb_accessory_test_info, -1);
     73 
     74         mStatus = (TextView) findViewById(R.id.status);
     75         mProgress = (ProgressBar) findViewById(R.id.progress_bar);
     76         mStatus.setText(R.string.usb_accessory_test_step1);
     77         getPassButton().setEnabled(false);
     78 
     79         AccessoryAttachmentHandler.addObserver(this);
     80     }
     81 
     82     @Override
     83     public void onAttached(UsbAccessory accessory) {
     84         mStatus.setText(R.string.usb_accessory_test_step2);
     85         mProgress.setVisibility(View.VISIBLE);
     86 
     87         AccessoryAttachmentHandler.removeObserver(this);
     88 
     89         UsbManager usbManager = getSystemService(UsbManager.class);
     90 
     91         (new AsyncTask<Void, Void, Throwable>() {
     92             @Override
     93             protected Throwable doInBackground(Void... params) {
     94                 try {
     95                     assertEquals("Android CTS", accessory.getManufacturer());
     96                     assertEquals("Android CTS test companion device", accessory.getModel());
     97                     assertEquals("Android device running CTS verifier", accessory.getDescription());
     98                     assertEquals("2", accessory.getVersion());
     99                     assertEquals("https://source.android.com/compatibility/cts/verifier.html",
    100                             accessory.getUri());
    101                     assertEquals("0", accessory.getSerial());
    102 
    103                     assertTrue(Arrays.asList(usbManager.getAccessoryList()).contains(accessory));
    104 
    105                     runAndAssertException(() -> usbManager.openAccessory(null),
    106                             NullPointerException.class);
    107 
    108                     ParcelFileDescriptor accessoryFd = usbManager.openAccessory(accessory);
    109                     assertNotNull(accessoryFd);
    110 
    111                     try (InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(
    112                             accessoryFd)) {
    113                         try (OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(
    114                                 accessoryFd)) {
    115                             byte[] origBuffer32 = new byte[32];
    116                             (new Random()).nextBytes(origBuffer32);
    117 
    118                             byte[] origBufferMax = new byte[MAX_BUFFER_SIZE];
    119                             (new Random()).nextBytes(origBufferMax);
    120 
    121                             byte[] bufferMax = new byte[MAX_BUFFER_SIZE];
    122                             byte[] buffer32 = new byte[32];
    123                             byte[] buffer16 = new byte[16];
    124 
    125                             // Echo a transfer
    126                             nextTest(is, os, "echo 32 bytes");
    127 
    128                             os.write(origBuffer32);
    129 
    130                             int numRead = is.read(buffer32);
    131                             assertEquals(32, numRead);
    132                             assertArrayEquals(origBuffer32, buffer32);
    133 
    134                             // Receive less data than available
    135                             nextTest(is, os, "echo 32 bytes");
    136 
    137                             os.write(origBuffer32);
    138 
    139                             numRead = is.read(buffer16);
    140                             assertEquals(16, numRead);
    141                             assertArrayEquals(Arrays.copyOf(origBuffer32, 16), buffer16);
    142 
    143                             // If a transfer was only partially read, the rest of the transfer is
    144                             // lost. We cannot read the second part, hence proceed to the next test.
    145 
    146                             // Send two transfers in a row
    147                             nextTest(is, os, "echo two 16 byte transfers as one");
    148 
    149                             os.write(Arrays.copyOf(origBuffer32, 16));
    150                             os.write(Arrays.copyOfRange(origBuffer32, 16, 32));
    151 
    152                             numRead = is.read(buffer32);
    153                             assertEquals(32, numRead);
    154                             assertArrayEquals(origBuffer32, buffer32);
    155 
    156                             // Receive two transfers in a row into a buffer that is bigger than the
    157                             // transfer
    158                             nextTest(is, os, "echo 32 bytes as two 16 byte transfers");
    159 
    160                             os.write(origBuffer32);
    161 
    162                             // Even though the buffer would hold 32 bytes the input stream will read
    163                             // the transfers individually
    164                             numRead = is.read(buffer32);
    165                             assertEquals(16, numRead);
    166                             assertArrayEquals(Arrays.copyOf(origBuffer32, 16),
    167                                     Arrays.copyOf(buffer32, 16));
    168 
    169                             numRead = is.read(buffer32);
    170                             assertEquals(16, numRead);
    171                             assertArrayEquals(Arrays.copyOfRange(origBuffer32, 16, 32),
    172                                     Arrays.copyOf(buffer32, 16));
    173 
    174                             // Echo a buffer with the maximum size
    175                             nextTest(is, os, "echo max bytes");
    176 
    177                             os.write(origBufferMax);
    178 
    179                             numRead = is.read(bufferMax);
    180                             assertEquals(MAX_BUFFER_SIZE, numRead);
    181                             assertArrayEquals(origBufferMax, bufferMax);
    182 
    183                             // Echo a buffer with twice the maximum size
    184                             nextTest(is, os, "echo max*2 bytes");
    185 
    186                             byte[] oversizeBuffer = new byte[MAX_BUFFER_SIZE * 2];
    187                             System.arraycopy(origBufferMax, 0, oversizeBuffer, 0, MAX_BUFFER_SIZE);
    188                             System.arraycopy(origBufferMax, 0, oversizeBuffer, MAX_BUFFER_SIZE,
    189                                     MAX_BUFFER_SIZE);
    190                             os.write(oversizeBuffer);
    191 
    192                             // The other side can not write more than the maximum size at once,
    193                             // hence we get two transfers in return
    194                             numRead = is.read(bufferMax);
    195                             assertEquals(MAX_BUFFER_SIZE, numRead);
    196                             assertArrayEquals(origBufferMax, bufferMax);
    197 
    198                             numRead = is.read(bufferMax);
    199                             assertEquals(MAX_BUFFER_SIZE, numRead);
    200                             assertArrayEquals(origBufferMax, bufferMax);
    201 
    202                             nextTest(is, os, "measure out transfer speed");
    203 
    204                             byte[] result = new byte[1];
    205                             long bytesSent = 0;
    206                             long timeStart = SystemClock.elapsedRealtime();
    207                             while (bytesSent < TEST_DATA_SIZE_THRESHOLD) {
    208                                 os.write(origBufferMax);
    209                                 bytesSent += MAX_BUFFER_SIZE;
    210                             }
    211                             numRead = is.read(result);
    212                             double speedKBPS = (bytesSent * 8 * 1000. / 1024.)
    213                                     / (SystemClock.elapsedRealtime() - timeStart);
    214                             assertEquals(1, numRead);
    215                             assertEquals(1, result[0]);
    216                             // We don't mandate min speed for now, let's collect data on what it is.
    217                             getReportLog().setSummary(
    218                                     "Output USB accesory transfer speed",
    219                                     speedKBPS,
    220                                     ResultType.HIGHER_BETTER,
    221                                     ResultUnit.KBPS);
    222                             Log.i(LOG_TAG, "Write data transfer speed is " + speedKBPS + "KBPS");
    223 
    224                             nextTest(is, os, "measure in transfer speed");
    225 
    226                             long bytesRead = 0;
    227                             timeStart = SystemClock.elapsedRealtime();
    228                             while (bytesRead < TEST_DATA_SIZE_THRESHOLD) {
    229                                 numRead = is.read(bufferMax);
    230                                 bytesRead += numRead;
    231                             }
    232                             numRead = is.read(result);
    233                             speedKBPS = (bytesRead * 8 * 1000. / 1024.)
    234                                     / (SystemClock.elapsedRealtime() - timeStart);
    235                             assertEquals(1, numRead);
    236                             assertEquals(1, result[0]);
    237                             // We don't mandate min speed for now, let's collect data on what it is.
    238                             getReportLog().setSummary(
    239                                     "Input USB accesory transfer speed",
    240                                     speedKBPS,
    241                                     ResultType.HIGHER_BETTER,
    242                                     ResultUnit.KBPS);
    243                             Log.i(LOG_TAG, "Read data transfer speed is " + speedKBPS + "KBPS");
    244 
    245                             nextTest(is, os, "done");
    246                         }
    247                     }
    248 
    249                     accessoryFd.close();
    250 
    251                     return null;
    252                 } catch (Throwable t) {
    253                     return  t;
    254                 }
    255             }
    256 
    257             @Override
    258             protected void onPostExecute(Throwable t) {
    259                 if (t == null) {
    260                     setTestResultAndFinish(true);
    261                 } else {
    262                     fail(null, t);
    263                 }
    264             }
    265         }).execute();
    266     }
    267 
    268     /**
    269      * Signal to the companion device that we want to switch to the next test.
    270      *
    271      * @param is       The input stream from the companion device
    272      * @param os       The output stream from the companion device
    273      * @param testName The name of the new test
    274      */
    275     private boolean nextTest(@NonNull InputStream is, @NonNull OutputStream os,
    276             @NonNull String testName) throws IOException {
    277         Log.i(LOG_TAG, "Init new test " + testName);
    278 
    279         ByteBuffer nameBuffer = Charset.forName("UTF-8").encode(CharBuffer.wrap(testName));
    280         byte[] sizeBuffer = {(byte) nameBuffer.limit()};
    281 
    282         os.write(sizeBuffer);
    283         os.write(Arrays.copyOf(nameBuffer.array(), nameBuffer.limit()));
    284 
    285         int ret = is.read();
    286         if (ret <= 0) {
    287             Log.i(LOG_TAG, "Last test failed " + ret);
    288             return false;
    289         }
    290 
    291         os.write(0);
    292 
    293         Log.i(LOG_TAG, "Running " + testName);
    294 
    295         return true;
    296     }
    297 
    298     @Override
    299     protected void onDestroy() {
    300         AccessoryAttachmentHandler.removeObserver(this);
    301 
    302         super.onDestroy();
    303     }
    304 
    305     /**
    306      * Indicate that the test failed.
    307      */
    308     private void fail(@Nullable String s, @Nullable Throwable e) {
    309         Log.e(LOG_TAG, s, e);
    310         setTestResultAndFinish(false);
    311     }
    312 }
    313