1 /*
2  * Copyright (C) 2017 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 android.hardware.cts;
18 
19 import android.content.Context;
20 import android.hardware.HardwareBuffer;
21 import android.hardware.Sensor;
22 import android.hardware.SensorAdditionalInfo;
23 import android.hardware.SensorDirectChannel;
24 import android.hardware.SensorEventCallback;
25 import android.hardware.SensorManager;
26 import android.hardware.cts.helpers.SensorCtsHelper;
27 import android.os.MemoryFile;
28 import android.util.Log;
29 
30 import java.io.IOException;
31 import java.nio.ByteBuffer;
32 import java.nio.ByteOrder;
33 import java.util.ArrayList;
34 import java.util.List;
35 import java.util.concurrent.CountDownLatch;
36 import java.util.concurrent.TimeUnit;
37 
38 /**
39  * Checks Sensor Direct Report functionality
40  *
41  * This testcase tests operation of:
42  *   - SensorManager.createDirectChannel()
43  *   - SensorDirectChannel.*
44  *   - Sensor.getHighestDirectReportRateLevel()
45  *   - Sensor.isDirectChannelTypeSupported()
46  */
47 public class SensorDirectReportTest extends SensorTestCase {
48     private static final String TAG = "SensorDirectReportTest";
49     // nominal rates of each rate level supported
50     private static final float RATE_NORMAL_NOMINAL = 50;
51     private static final float RATE_FAST_NOMINAL = 200;
52     private static final float RATE_VERY_FAST_NOMINAL = 800;
53 
54     // actuall value is allowed to be 55% to 220% of nominal value
55     private static final float FREQ_LOWER_BOUND = 0.55f;
56     private static final float FREQ_UPPER_BOUND = 2.2f;
57 
58     // sensor reading assumption
59     private static final float GRAVITY_MIN = 9.81f - 0.5f;
60     private static final float GRAVITY_MAX = 9.81f + 0.5f;
61     private static final float GYRO_NORM_MAX = 0.1f;
62 
63     // test constants
64     private static final int REST_PERIOD_BEFORE_TEST_MILLISEC = 3000;
65     private static final int TEST_RUN_TIME_PERIOD_MILLISEC = 5000;
66     private static final int ALLOWED_SENSOR_INIT_TIME_MILLISEC = 500;
67     private static final int SENSORS_EVENT_SIZE = 104;
68     private static final int SENSORS_EVENT_COUNT = 10240; // 800Hz * 2.2 * 5 sec + extra
69     private static final int SHARED_MEMORY_SIZE = SENSORS_EVENT_COUNT * SENSORS_EVENT_SIZE;
70     private static final float MERCY_FACTOR = 0.1f;
71 
nativeReadHardwareBuffer(HardwareBuffer hardwareBuffer, byte[] buffer, int srcOffset, int destOffset, int count)72     private static native boolean nativeReadHardwareBuffer(HardwareBuffer hardwareBuffer,
73             byte[] buffer, int srcOffset, int destOffset, int count);
74 
75     private boolean mNeedMemoryFile;
76     private MemoryFile mMemoryFile;
77     private boolean mNeedHardwareBuffer;
78     private HardwareBuffer mHardwareBuffer;
79     private byte[] mBuffer = new byte[SHARED_MEMORY_SIZE];
80 
81     private SensorManager mSensorManager;
82     private SensorDirectChannel mChannel;
83 
84     static {
85         System.loadLibrary("cts-sensors-ndk-jni");
86     }
87 
88     @Override
setUp()89     protected void setUp() throws Exception {
90         mSensorManager = (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE);
91 
92         mNeedMemoryFile = isMemoryTypeNeeded(SensorDirectChannel.TYPE_MEMORY_FILE);
93         mNeedHardwareBuffer = isMemoryTypeNeeded(SensorDirectChannel.TYPE_HARDWARE_BUFFER);
94 
95         if (mNeedMemoryFile) {
96             mMemoryFile = allocateMemoryFile();
97         }
98 
99         if (mNeedHardwareBuffer) {
100             mHardwareBuffer = allocateHardwareBuffer();
101         }
102     }
103 
104     @Override
tearDown()105     protected void tearDown() throws Exception {
106         if (mChannel != null) {
107             mChannel.close();
108             mChannel = null;
109         }
110 
111         if (mMemoryFile != null) {
112             mMemoryFile.close();
113             mMemoryFile = null;
114         }
115 
116         if (mHardwareBuffer != null) {
117             mHardwareBuffer.close();
118             mHardwareBuffer = null;
119         }
120     }
121 
testSharedMemoryAllocation()122     public void testSharedMemoryAllocation() throws AssertionError {
123         assertTrue("allocating MemoryFile returned null",
124                 !mNeedMemoryFile || mMemoryFile != null);
125         assertTrue("allocating HardwareBuffer returned null",
126                 !mNeedHardwareBuffer || mHardwareBuffer != null);
127     }
128 
testAccelerometerAshmemNormal()129     public void testAccelerometerAshmemNormal() {
130         runSensorDirectReportTest(
131                 Sensor.TYPE_ACCELEROMETER,
132                 SensorDirectChannel.TYPE_MEMORY_FILE,
133                 SensorDirectChannel.RATE_NORMAL);
134     }
135 
testGyroscopeAshmemNormal()136     public void testGyroscopeAshmemNormal() {
137         runSensorDirectReportTest(
138                 Sensor.TYPE_GYROSCOPE,
139                 SensorDirectChannel.TYPE_MEMORY_FILE,
140                 SensorDirectChannel.RATE_NORMAL);
141     }
142 
testMagneticFieldAshmemNormal()143     public void testMagneticFieldAshmemNormal() {
144         runSensorDirectReportTest(
145                 Sensor.TYPE_MAGNETIC_FIELD,
146                 SensorDirectChannel.TYPE_MEMORY_FILE,
147                 SensorDirectChannel.RATE_NORMAL);
148     }
149 
testAccelerometerAshmemFast()150     public void testAccelerometerAshmemFast() {
151         runSensorDirectReportTest(
152                 Sensor.TYPE_ACCELEROMETER,
153                 SensorDirectChannel.TYPE_MEMORY_FILE,
154                 SensorDirectChannel.RATE_FAST);
155 
156     }
157 
testGyroscopeAshmemFast()158     public void testGyroscopeAshmemFast() {
159         runSensorDirectReportTest(
160                 Sensor.TYPE_GYROSCOPE,
161                 SensorDirectChannel.TYPE_MEMORY_FILE,
162                 SensorDirectChannel.RATE_FAST);
163     }
164 
testMagneticFieldAshmemFast()165     public void testMagneticFieldAshmemFast() {
166         runSensorDirectReportTest(
167                 Sensor.TYPE_MAGNETIC_FIELD,
168                 SensorDirectChannel.TYPE_MEMORY_FILE,
169                 SensorDirectChannel.RATE_FAST);
170     }
171 
testAccelerometerAshmemVeryFast()172     public void testAccelerometerAshmemVeryFast() {
173         runSensorDirectReportTest(
174                 Sensor.TYPE_ACCELEROMETER,
175                 SensorDirectChannel.TYPE_MEMORY_FILE,
176                 SensorDirectChannel.RATE_VERY_FAST);
177 
178     }
179 
testGyroscopeAshmemVeryFast()180     public void testGyroscopeAshmemVeryFast() {
181         runSensorDirectReportTest(
182                 Sensor.TYPE_GYROSCOPE,
183                 SensorDirectChannel.TYPE_MEMORY_FILE,
184                 SensorDirectChannel.RATE_VERY_FAST);
185     }
186 
testMagneticFieldAshmemVeryFast()187     public void testMagneticFieldAshmemVeryFast() {
188         runSensorDirectReportTest(
189                 Sensor.TYPE_MAGNETIC_FIELD,
190                 SensorDirectChannel.TYPE_MEMORY_FILE,
191                 SensorDirectChannel.RATE_VERY_FAST);
192     }
193 
testAccelerometerHardwareBufferNormal()194     public void testAccelerometerHardwareBufferNormal() {
195         runSensorDirectReportTest(
196                 Sensor.TYPE_ACCELEROMETER,
197                 SensorDirectChannel.TYPE_HARDWARE_BUFFER,
198                 SensorDirectChannel.RATE_NORMAL);
199     }
200 
testGyroscopeHardwareBufferNormal()201     public void testGyroscopeHardwareBufferNormal() {
202         runSensorDirectReportTest(
203                 Sensor.TYPE_GYROSCOPE,
204                 SensorDirectChannel.TYPE_HARDWARE_BUFFER,
205                 SensorDirectChannel.RATE_NORMAL);
206     }
207 
testMagneticFieldHardwareBufferNormal()208     public void testMagneticFieldHardwareBufferNormal() {
209         runSensorDirectReportTest(
210                 Sensor.TYPE_MAGNETIC_FIELD,
211                 SensorDirectChannel.TYPE_HARDWARE_BUFFER,
212                 SensorDirectChannel.RATE_NORMAL);
213     }
214 
testAccelerometerHardwareBufferFast()215     public void testAccelerometerHardwareBufferFast() {
216         runSensorDirectReportTest(
217                 Sensor.TYPE_ACCELEROMETER,
218                 SensorDirectChannel.TYPE_HARDWARE_BUFFER,
219                 SensorDirectChannel.RATE_FAST);
220     }
221 
testGyroscopeHardwareBufferFast()222     public void testGyroscopeHardwareBufferFast() {
223         runSensorDirectReportTest(
224                 Sensor.TYPE_GYROSCOPE,
225                 SensorDirectChannel.TYPE_HARDWARE_BUFFER,
226                 SensorDirectChannel.RATE_FAST);
227     }
228 
testMagneticFieldHardwareBufferFast()229     public void testMagneticFieldHardwareBufferFast() {
230         runSensorDirectReportTest(
231                 Sensor.TYPE_MAGNETIC_FIELD,
232                 SensorDirectChannel.TYPE_HARDWARE_BUFFER,
233                 SensorDirectChannel.RATE_FAST);
234     }
235 
testAccelerometerHardwareBufferVeryFast()236     public void testAccelerometerHardwareBufferVeryFast() {
237         runSensorDirectReportTest(
238                 Sensor.TYPE_ACCELEROMETER,
239                 SensorDirectChannel.TYPE_HARDWARE_BUFFER,
240                 SensorDirectChannel.RATE_VERY_FAST);
241     }
242 
testGyroscopeHardwareBufferVeryFast()243     public void testGyroscopeHardwareBufferVeryFast() {
244         runSensorDirectReportTest(
245                 Sensor.TYPE_GYROSCOPE,
246                 SensorDirectChannel.TYPE_HARDWARE_BUFFER,
247                 SensorDirectChannel.RATE_VERY_FAST);
248     }
249 
testMagneticFieldHardwareBufferVeryFast()250     public void testMagneticFieldHardwareBufferVeryFast() {
251         runSensorDirectReportTest(
252                 Sensor.TYPE_MAGNETIC_FIELD,
253                 SensorDirectChannel.TYPE_HARDWARE_BUFFER,
254                 SensorDirectChannel.RATE_VERY_FAST);
255     }
256 
runSensorDirectReportTest(int sensorType, int memType, int rateLevel)257     private void runSensorDirectReportTest(int sensorType, int memType, int rateLevel)
258             throws AssertionError {
259         Sensor s = mSensorManager.getDefaultSensor(sensorType);
260         if (s == null
261                 || s.getHighestDirectReportRateLevel() < rateLevel
262                 || !s.isDirectChannelTypeSupported(memType)) {
263             return;
264         }
265 
266         try {
267             switch(memType) {
268                 case SensorDirectChannel.TYPE_MEMORY_FILE:
269                     assertTrue("MemoryFile is null", mMemoryFile != null);
270                     mChannel = mSensorManager.createDirectChannel(mMemoryFile);
271                     break;
272                 case SensorDirectChannel.TYPE_HARDWARE_BUFFER:
273                     assertTrue("HardwareBuffer is null", mHardwareBuffer != null);
274                     mChannel = mSensorManager.createDirectChannel(mHardwareBuffer);
275                     break;
276                 default:
277                     Log.e(TAG, "Specified illegal memory type " + memType);
278                     return;
279             }
280         } catch (IllegalStateException e) {
281             mChannel = null;
282         }
283         assertTrue("createDirectChannel failed", mChannel != null);
284 
285         try {
286             assertTrue("Shared memory is not formatted", isSharedMemoryFormatted(memType));
287             waitBeforeStartSensor();
288 
289             int token = mChannel.configure(s, rateLevel);
290             assertTrue("configure direct mChannel failed", token > 0);
291 
292             waitSensorCollection();
293 
294             //stop sensor and analyze content
295             mChannel.configure(s, SensorDirectChannel.RATE_STOP);
296             checkSharedMemoryContent(s, memType, rateLevel, token);
297         } finally {
298             mChannel.close();
299             mChannel = null;
300         }
301     }
302 
waitBeforeStartSensor()303     private void waitBeforeStartSensor() {
304         // wait for sensor system to come to a rest after previous test to avoid flakiness.
305         try {
306             SensorCtsHelper.sleep(REST_PERIOD_BEFORE_TEST_MILLISEC, TimeUnit.MILLISECONDS);
307         } catch (InterruptedException e) {
308             Thread.currentThread().interrupt();
309         }
310     }
311 
waitSensorCollection()312     private void waitSensorCollection() {
313         // wait for sensor system to come to a rest after previous test to avoid flakiness.
314         try {
315             SensorCtsHelper.sleep(TEST_RUN_TIME_PERIOD_MILLISEC, TimeUnit.MILLISECONDS);
316         } catch (InterruptedException e) {
317             Thread.currentThread().interrupt();
318         }
319     }
320 
allocateMemoryFile()321     private MemoryFile allocateMemoryFile() {
322         MemoryFile memFile = null;
323         try {
324             memFile = new MemoryFile("Sensor Channel", SHARED_MEMORY_SIZE);
325         } catch (IOException e) {
326             Log.e(TAG, "IOException when allocating MemoryFile");
327         }
328         return memFile;
329     }
330 
allocateHardwareBuffer()331     private HardwareBuffer allocateHardwareBuffer() {
332         HardwareBuffer hardwareBuffer;
333 
334         hardwareBuffer = HardwareBuffer.create(
335                 SHARED_MEMORY_SIZE, 1 /* height */, HardwareBuffer.BLOB, 1 /* layer */,
336                 HardwareBuffer.USAGE_CPU_READ_OFTEN | HardwareBuffer.USAGE_GPU_DATA_BUFFER
337                     | HardwareBuffer.USAGE_SENSOR_DIRECT_DATA);
338         return hardwareBuffer;
339     }
340 
isMemoryTypeNeeded(int memType)341     private boolean isMemoryTypeNeeded(int memType) {
342         List<Sensor> sensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL);
343         for (Sensor s : sensorList) {
344             if (s.isDirectChannelTypeSupported(memType)) {
345                 return true;
346             }
347         }
348         return false;
349     }
350 
isSharedMemoryFormatted(int memType)351     private boolean isSharedMemoryFormatted(int memType) {
352         if (memType == SensorDirectChannel.TYPE_MEMORY_FILE) {
353             if (!readMemoryFileContent()) {
354                 Log.e(TAG, "Read MemoryFile content fail");
355                 return false;
356             }
357         } else {
358             if (!readHardwareBufferContent()) {
359                 Log.e(TAG, "Read HardwareBuffer content fail");
360                 return false;
361             }
362         }
363 
364         for (byte b : mBuffer) {
365             if (b != 0) {
366                 return false;
367             }
368         }
369         return true;
370     }
371 
checkSharedMemoryContent(Sensor s, int memType, int rateLevel, int token)372     private void checkSharedMemoryContent(Sensor s, int memType, int rateLevel, int token) {
373         if (memType == SensorDirectChannel.TYPE_MEMORY_FILE) {
374             assertTrue("read MemoryFile content failed", readMemoryFileContent());
375         } else {
376             assertTrue("read HardwareBuffer content failed", readHardwareBufferContent());
377         }
378 
379         int offset = 0;
380         int nextSerial = 1;
381         DirectReportSensorEvent e = new DirectReportSensorEvent();
382         while (offset <= SHARED_MEMORY_SIZE - SENSORS_EVENT_SIZE) {
383             parseSensorEvent(mBuffer, offset, e);
384 
385             if (e.serial == 0) {
386                 // reaches end of events
387                 break;
388             }
389 
390             assertTrue("incorrect size " + e.size + "  at offset " + offset,
391                     e.size == SENSORS_EVENT_SIZE);
392             assertTrue("incorrect token " + e.token + " at offset " + offset,
393                     e.token == token);
394             assertTrue("incorrect serial " + e.serial + " at offset " + offset,
395                     e.serial == nextSerial);
396             assertTrue("incorrect type " + e.type + " offset " + offset,
397                     e.type == s.getType());
398 
399             switch(s.getType()) {
400                 case Sensor.TYPE_ACCELEROMETER:
401                     double accNorm = Math.sqrt(e.x * e.x + e.y * e.y + e.z * e.z);
402                     assertTrue("incorrect gravity norm " + accNorm + " at offset " + offset,
403                             accNorm < GRAVITY_MAX && accNorm > GRAVITY_MIN);
404                     break;
405                 case Sensor.TYPE_GYROSCOPE:
406                     double gyroNorm = Math.sqrt(e.x * e.x + e.y * e.y + e.z * e.z);
407                     assertTrue("gyro norm too large (" + gyroNorm + ") at offset " + offset,
408                             gyroNorm < GYRO_NORM_MAX);
409                     break;
410             }
411 
412             ++nextSerial;
413             offset += SENSORS_EVENT_SIZE;
414         }
415 
416         int nEvents = nextSerial - 1;
417         float nominalFreq = 0;
418 
419         switch (rateLevel) {
420             case SensorDirectChannel.RATE_NORMAL:
421                 nominalFreq = RATE_NORMAL_NOMINAL;
422                 break;
423             case SensorDirectChannel.RATE_FAST:
424                 nominalFreq = RATE_FAST_NOMINAL;
425                 break;
426             case SensorDirectChannel.RATE_VERY_FAST:
427                 nominalFreq = RATE_VERY_FAST_NOMINAL;
428                 break;
429         }
430 
431         if (nominalFreq != 0) {
432             int minEvents;
433             int maxEvents;
434             minEvents = (int) Math.floor(
435                     nominalFreq
436                     * FREQ_LOWER_BOUND
437                     * (TEST_RUN_TIME_PERIOD_MILLISEC - ALLOWED_SENSOR_INIT_TIME_MILLISEC)
438                     * (1 - MERCY_FACTOR)
439                     / 1000);
440             maxEvents = (int) Math.ceil(
441                     nominalFreq
442                     * FREQ_UPPER_BOUND
443                     * (TEST_RUN_TIME_PERIOD_MILLISEC - ALLOWED_SENSOR_INIT_TIME_MILLISEC)
444                     * (1 + MERCY_FACTOR)
445                     / 1000);
446 
447             assertTrue("nEvent is " + nEvents + " not between " + minEvents + " and " + maxEvents,
448                     nEvents >= minEvents && nEvents <=maxEvents);
449         }
450     }
451 
readMemoryFileContent()452     private boolean readMemoryFileContent() {
453         try {
454             if (mMemoryFile.readBytes(mBuffer, 0, 0, SHARED_MEMORY_SIZE)
455                     != SHARED_MEMORY_SIZE) {
456                 Log.e(TAG, "cannot read entire MemoryFile");
457                 return false;
458             }
459         } catch (IOException e) {
460             Log.e(TAG, "accessing MemoryFile cause IOException");
461             return false;
462         }
463         return true;
464     }
465 
readHardwareBufferContent()466     private boolean readHardwareBufferContent() {
467         return nativeReadHardwareBuffer(mHardwareBuffer, mBuffer, 0, 0, SHARED_MEMORY_SIZE);
468     }
469 
470     private class DirectReportSensorEvent {
471         int size;
472         int token;
473         int type;
474         int serial;
475         long ts;
476         float x;
477         float y;
478         float z;
479     };
480 
481     // parse sensors_event_t and fill information into DirectReportSensorEvent
parseSensorEvent(byte [] buf, int offset, DirectReportSensorEvent ev)482     private static void parseSensorEvent(byte [] buf, int offset, DirectReportSensorEvent ev) {
483         ByteBuffer b = ByteBuffer.wrap(buf, offset, SENSORS_EVENT_SIZE);
484         b.order(ByteOrder.nativeOrder());
485 
486         ev.size = b.getInt();
487         ev.token = b.getInt();
488         ev.type = b.getInt();
489         ev.serial = b.getInt();
490         ev.ts = b.getLong();
491         ev.x = b.getFloat();
492         ev.y = b.getFloat();
493         ev.z = b.getFloat();
494     }
495 }
496