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