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.SensorEvent; 26 import android.hardware.SensorEventListener; 27 import android.hardware.SensorManager; 28 import android.hardware.cts.helpers.SensorCtsHelper; 29 import android.hardware.cts.helpers.SensorCtsHelper.TestResultCollector; 30 import android.os.MemoryFile; 31 import android.os.SystemClock; 32 import android.util.Log; 33 34 import java.io.IOException; 35 import java.io.UncheckedIOException; 36 import java.nio.ByteBuffer; 37 import java.nio.ByteOrder; 38 import java.util.ArrayList; 39 import java.util.Arrays; 40 import java.util.List; 41 import java.util.concurrent.CountDownLatch; 42 import java.util.concurrent.TimeUnit; 43 44 /** 45 * Checks Sensor Direct Report functionality 46 * 47 * This testcase tests operation of: 48 * - SensorManager.createDirectChannel() 49 * - SensorDirectChannel.* 50 * - Sensor.getHighestDirectReportRateLevel() 51 * - Sensor.isDirectChannelTypeSupported() 52 * 53 * Tests: 54 * - test<Sensor><SharedMemoryType><RateLevel> 55 * tests basic operation of sensor in direct report mode at various rate level specification. 56 * - testRateIndependency<Sensor1><Sensor2>SingleChannel 57 * tests if two sensors in the same direct channel are able to run at different rates. 58 * - testRateIndependency<Sensor>MultiChannel 59 * tests if a sensor is able to be configured to different rate levels for multiple channels. 60 * - testRateIndependency<Sensor>MultiMode 61 * tests if a sensor is able to report at different rates in direct report mode and traditional 62 * report mode (polling). 63 * - testTimestamp<Sensor> 64 * tests if the timestamp is correct both in absolute sense and relative to traditional report. 65 * - testAtomicCounter<Sensor> 66 * test if atomic counter is increased as specified and if sensor event content is fully updated 67 * before update of atomic counter. 68 * - testRegisterMultipleChannels 69 * test scenarios when multiple channels are registered simultaneously. 70 * - testReconfigure 71 * test channel reconfiguration (configure to a rate level; configure to stop; configure to 72 * another rate level) 73 * - testRegisterMultipleChannelsUsingSameMemory 74 * test a negative case when the same memory is being used twice for registering sensor direct 75 * channel 76 * - testCloseWithoutConfigStop 77 * test a common mistake in API usage and make sure no negative effect is made to system. 78 */ 79 public class SensorDirectReportTest extends SensorTestCase { 80 private static final String TAG = "SensorDirectReportTest"; 81 // nominal rates of each rate level supported 82 private static final float RATE_NORMAL_NOMINAL = 50; 83 private static final float RATE_FAST_NOMINAL = 200; 84 private static final float RATE_VERY_FAST_NOMINAL = 800; 85 86 // actuall value is allowed to be 55% to 220% of nominal value 87 private static final float FREQ_LOWER_BOUND = 0.55f; 88 private static final float FREQ_UPPER_BOUND = 2.2f; 89 90 // actuall value is allowed to be 90% to 200% of nominal value in poll() interface 91 private static final float FREQ_LOWER_BOUND_POLL = 0.90f; 92 private static final float FREQ_UPPER_BOUND_POLL = 2.00f; 93 94 // sensor reading assumption 95 private static final float GRAVITY_MIN = 9.81f - 1.0f; 96 private static final float GRAVITY_MAX = 9.81f + 1.0f; 97 private static final float GYRO_NORM_MAX = 0.1f; 98 99 // test constants 100 private static final int REST_PERIOD_BEFORE_TEST_MILLISEC = 3000; 101 private static final int TEST_RUN_TIME_PERIOD_MILLISEC = 5000; 102 private static final int ALLOWED_SENSOR_INIT_TIME_MILLISEC = 500; 103 private static final int SENSORS_EVENT_SIZE = 104; 104 private static final int ATOMIC_COUNTER_OFFSET = 12; 105 private static final int ATOMIC_COUNTER_SIZE = 4; 106 private static final int SENSORS_EVENT_COUNT = 10240; // 800Hz * 2.2 * 5 sec + extra 107 private static final int SHARED_MEMORY_SIZE = SENSORS_EVENT_COUNT * SENSORS_EVENT_SIZE; 108 private static final float MERCY_FACTOR = 0.1f; 109 private static final boolean CHECK_ABSOLUTE_LATENCY = false; 110 111 // list of rate levels being tested 112 private static final int[] POSSIBLE_RATE_LEVELS = new int[] { 113 SensorDirectChannel.RATE_NORMAL, 114 SensorDirectChannel.RATE_FAST, 115 SensorDirectChannel.RATE_VERY_FAST 116 }; 117 118 // list of channel types being tested 119 private static final int[] POSSIBLE_CHANNEL_TYPES = new int [] { 120 SensorDirectChannel.TYPE_MEMORY_FILE, 121 SensorDirectChannel.TYPE_HARDWARE_BUFFER 122 }; 123 124 // list of sensor types being tested 125 private static final int[] POSSIBLE_SENSOR_TYPES = new int [] { 126 Sensor.TYPE_ACCELEROMETER, 127 Sensor.TYPE_GYROSCOPE, 128 Sensor.TYPE_MAGNETIC_FIELD 129 }; 130 131 // list of sampling period being tested 132 private static final int[] POSSIBLE_SAMPLE_PERIOD_US = new int [] { 133 200_000, // Normal 5 Hz 134 66_667, // UI 15 Hz 135 20_000, // Game 50 Hz 136 5_000, // 200Hz 137 0 // fastest 138 }; 139 140 private static final ByteOrder NATIVE_BYTE_ORDER = ByteOrder.nativeOrder(); 141 nativeReadHardwareBuffer(HardwareBuffer hardwareBuffer, byte[] buffer, int srcOffset, int destOffset, int count)142 private static native boolean nativeReadHardwareBuffer(HardwareBuffer hardwareBuffer, 143 byte[] buffer, int srcOffset, int destOffset, int count); 144 145 private boolean mNeedMemoryFile; 146 private MemoryFile mMemoryFile; 147 private MemoryFile mMemoryFileSecondary; 148 private boolean mNeedHardwareBuffer; 149 private HardwareBuffer mHardwareBuffer; 150 private HardwareBuffer mHardwareBufferSecondary; 151 private ByteBuffer mByteBuffer; 152 private byte[] mBuffer; 153 154 private SensorManager mSensorManager; 155 private SensorDirectChannel mChannel; 156 private SensorDirectChannel mChannelSecondary; 157 158 private EventPool mEventPool; 159 160 static { 161 System.loadLibrary("cts-sensors-ndk-jni"); 162 } 163 164 @Override setUp()165 protected void setUp() throws Exception { 166 super.setUp(); 167 168 mByteBuffer = ByteBuffer.allocate(SHARED_MEMORY_SIZE); 169 mBuffer = mByteBuffer.array(); 170 mByteBuffer.order(ByteOrder.nativeOrder()); 171 172 mEventPool = new EventPool(10 * SENSORS_EVENT_COUNT); 173 mSensorManager = (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE); 174 175 mNeedMemoryFile = isMemoryTypeNeeded(SensorDirectChannel.TYPE_MEMORY_FILE); 176 mNeedHardwareBuffer = isMemoryTypeNeeded(SensorDirectChannel.TYPE_HARDWARE_BUFFER); 177 178 allocateSharedMemory(); 179 } 180 181 @Override tearDown()182 protected void tearDown() throws Exception { 183 if (mChannel != null) { 184 mChannel.close(); 185 mChannel = null; 186 } 187 188 if (mChannelSecondary != null) { 189 mChannelSecondary.close(); 190 mChannelSecondary = null; 191 } 192 193 freeSharedMemory(); 194 super.tearDown(); 195 } 196 testSharedMemoryAllocation()197 public void testSharedMemoryAllocation() throws AssertionError { 198 assertTrue("allocating MemoryFile returned null: " 199 + (mMemoryFile == null) + ", " + (mMemoryFileSecondary == null), 200 !mNeedMemoryFile || (mMemoryFile != null && mMemoryFileSecondary != null)); 201 assertTrue("allocating HardwareBuffer returned null: " 202 + (mHardwareBuffer == null) + ", " + (mHardwareBufferSecondary == null), 203 !mNeedHardwareBuffer || 204 (mHardwareBuffer != null && mHardwareBufferSecondary != null)); 205 } 206 testAccelerometerAshmemNormal()207 public void testAccelerometerAshmemNormal() { 208 runSensorDirectReportTest( 209 Sensor.TYPE_ACCELEROMETER, 210 SensorDirectChannel.TYPE_MEMORY_FILE, 211 SensorDirectChannel.RATE_NORMAL); 212 } 213 testGyroscopeAshmemNormal()214 public void testGyroscopeAshmemNormal() { 215 runSensorDirectReportTest( 216 Sensor.TYPE_GYROSCOPE, 217 SensorDirectChannel.TYPE_MEMORY_FILE, 218 SensorDirectChannel.RATE_NORMAL); 219 } 220 testMagneticFieldAshmemNormal()221 public void testMagneticFieldAshmemNormal() { 222 runSensorDirectReportTest( 223 Sensor.TYPE_MAGNETIC_FIELD, 224 SensorDirectChannel.TYPE_MEMORY_FILE, 225 SensorDirectChannel.RATE_NORMAL); 226 } 227 testAccelerometerAshmemFast()228 public void testAccelerometerAshmemFast() { 229 runSensorDirectReportTest( 230 Sensor.TYPE_ACCELEROMETER, 231 SensorDirectChannel.TYPE_MEMORY_FILE, 232 SensorDirectChannel.RATE_FAST); 233 234 } 235 testGyroscopeAshmemFast()236 public void testGyroscopeAshmemFast() { 237 runSensorDirectReportTest( 238 Sensor.TYPE_GYROSCOPE, 239 SensorDirectChannel.TYPE_MEMORY_FILE, 240 SensorDirectChannel.RATE_FAST); 241 } 242 testMagneticFieldAshmemFast()243 public void testMagneticFieldAshmemFast() { 244 runSensorDirectReportTest( 245 Sensor.TYPE_MAGNETIC_FIELD, 246 SensorDirectChannel.TYPE_MEMORY_FILE, 247 SensorDirectChannel.RATE_FAST); 248 } 249 testAccelerometerAshmemVeryFast()250 public void testAccelerometerAshmemVeryFast() { 251 runSensorDirectReportTest( 252 Sensor.TYPE_ACCELEROMETER, 253 SensorDirectChannel.TYPE_MEMORY_FILE, 254 SensorDirectChannel.RATE_VERY_FAST); 255 256 } 257 testGyroscopeAshmemVeryFast()258 public void testGyroscopeAshmemVeryFast() { 259 runSensorDirectReportTest( 260 Sensor.TYPE_GYROSCOPE, 261 SensorDirectChannel.TYPE_MEMORY_FILE, 262 SensorDirectChannel.RATE_VERY_FAST); 263 } 264 testMagneticFieldAshmemVeryFast()265 public void testMagneticFieldAshmemVeryFast() { 266 runSensorDirectReportTest( 267 Sensor.TYPE_MAGNETIC_FIELD, 268 SensorDirectChannel.TYPE_MEMORY_FILE, 269 SensorDirectChannel.RATE_VERY_FAST); 270 } 271 testAccelerometerHardwareBufferNormal()272 public void testAccelerometerHardwareBufferNormal() { 273 runSensorDirectReportTest( 274 Sensor.TYPE_ACCELEROMETER, 275 SensorDirectChannel.TYPE_HARDWARE_BUFFER, 276 SensorDirectChannel.RATE_NORMAL); 277 } 278 testGyroscopeHardwareBufferNormal()279 public void testGyroscopeHardwareBufferNormal() { 280 runSensorDirectReportTest( 281 Sensor.TYPE_GYROSCOPE, 282 SensorDirectChannel.TYPE_HARDWARE_BUFFER, 283 SensorDirectChannel.RATE_NORMAL); 284 } 285 testMagneticFieldHardwareBufferNormal()286 public void testMagneticFieldHardwareBufferNormal() { 287 runSensorDirectReportTest( 288 Sensor.TYPE_MAGNETIC_FIELD, 289 SensorDirectChannel.TYPE_HARDWARE_BUFFER, 290 SensorDirectChannel.RATE_NORMAL); 291 } 292 testAccelerometerHardwareBufferFast()293 public void testAccelerometerHardwareBufferFast() { 294 runSensorDirectReportTest( 295 Sensor.TYPE_ACCELEROMETER, 296 SensorDirectChannel.TYPE_HARDWARE_BUFFER, 297 SensorDirectChannel.RATE_FAST); 298 } 299 testGyroscopeHardwareBufferFast()300 public void testGyroscopeHardwareBufferFast() { 301 runSensorDirectReportTest( 302 Sensor.TYPE_GYROSCOPE, 303 SensorDirectChannel.TYPE_HARDWARE_BUFFER, 304 SensorDirectChannel.RATE_FAST); 305 } 306 testMagneticFieldHardwareBufferFast()307 public void testMagneticFieldHardwareBufferFast() { 308 runSensorDirectReportTest( 309 Sensor.TYPE_MAGNETIC_FIELD, 310 SensorDirectChannel.TYPE_HARDWARE_BUFFER, 311 SensorDirectChannel.RATE_FAST); 312 } 313 testAccelerometerHardwareBufferVeryFast()314 public void testAccelerometerHardwareBufferVeryFast() { 315 runSensorDirectReportTest( 316 Sensor.TYPE_ACCELEROMETER, 317 SensorDirectChannel.TYPE_HARDWARE_BUFFER, 318 SensorDirectChannel.RATE_VERY_FAST); 319 } 320 testGyroscopeHardwareBufferVeryFast()321 public void testGyroscopeHardwareBufferVeryFast() { 322 runSensorDirectReportTest( 323 Sensor.TYPE_GYROSCOPE, 324 SensorDirectChannel.TYPE_HARDWARE_BUFFER, 325 SensorDirectChannel.RATE_VERY_FAST); 326 } 327 testMagneticFieldHardwareBufferVeryFast()328 public void testMagneticFieldHardwareBufferVeryFast() { 329 runSensorDirectReportTest( 330 Sensor.TYPE_MAGNETIC_FIELD, 331 SensorDirectChannel.TYPE_HARDWARE_BUFFER, 332 SensorDirectChannel.RATE_VERY_FAST); 333 } 334 testRateIndependencyAccelGyroSingleChannel()335 public void testRateIndependencyAccelGyroSingleChannel() { 336 runSingleChannelRateIndependencyTestGroup(Sensor.TYPE_ACCELEROMETER, 337 Sensor.TYPE_GYROSCOPE); 338 } 339 testRateIndependencyAccelMagSingleChannel()340 public void testRateIndependencyAccelMagSingleChannel() { 341 runSingleChannelRateIndependencyTestGroup(Sensor.TYPE_ACCELEROMETER, 342 Sensor.TYPE_MAGNETIC_FIELD); 343 } 344 testRateIndependencyGyroMagSingleChannel()345 public void testRateIndependencyGyroMagSingleChannel() { 346 runSingleChannelRateIndependencyTestGroup(Sensor.TYPE_GYROSCOPE, 347 Sensor.TYPE_MAGNETIC_FIELD); 348 } 349 testRateIndependencyAccelUncalAccelSingleChannel()350 public void testRateIndependencyAccelUncalAccelSingleChannel() { 351 runSingleChannelRateIndependencyTestGroup(Sensor.TYPE_ACCELEROMETER, 352 Sensor.TYPE_ACCELEROMETER_UNCALIBRATED); 353 } 354 testRateIndependencyGyroUncalGyroSingleChannel()355 public void testRateIndependencyGyroUncalGyroSingleChannel() { 356 runSingleChannelRateIndependencyTestGroup(Sensor.TYPE_GYROSCOPE, 357 Sensor.TYPE_GYROSCOPE_UNCALIBRATED); 358 } 359 testRateIndependencyMagUncalMagSingleChannel()360 public void testRateIndependencyMagUncalMagSingleChannel() { 361 runSingleChannelRateIndependencyTestGroup(Sensor.TYPE_MAGNETIC_FIELD, 362 Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED); 363 } 364 testRateIndependencyAccelMultiChannel()365 public void testRateIndependencyAccelMultiChannel() { 366 runMultiChannelRateIndependencyTestGroup(Sensor.TYPE_ACCELEROMETER); 367 } 368 testRateIndependencyGyroMultiChannel()369 public void testRateIndependencyGyroMultiChannel() { 370 runMultiChannelRateIndependencyTestGroup(Sensor.TYPE_GYROSCOPE); 371 } 372 testRateIndependencyMagMultiChannel()373 public void testRateIndependencyMagMultiChannel() { 374 runMultiChannelRateIndependencyTestGroup(Sensor.TYPE_MAGNETIC_FIELD); 375 } 376 testRateIndependencyAccelMultiMode()377 public void testRateIndependencyAccelMultiMode() { 378 runMultiModeRateIndependencyTestGroup(Sensor.TYPE_ACCELEROMETER); 379 } 380 testRateIndependencyGyroMultiMode()381 public void testRateIndependencyGyroMultiMode() { 382 runMultiModeRateIndependencyTestGroup(Sensor.TYPE_GYROSCOPE); 383 } 384 testRateIndependencyMagMultiMode()385 public void testRateIndependencyMagMultiMode() { 386 runMultiModeRateIndependencyTestGroup(Sensor.TYPE_MAGNETIC_FIELD); 387 } 388 testTimestampAccel()389 public void testTimestampAccel() { 390 runTimestampTestGroup(Sensor.TYPE_ACCELEROMETER); 391 } 392 testTimestampGyro()393 public void testTimestampGyro() { 394 runTimestampTestGroup(Sensor.TYPE_GYROSCOPE); 395 } 396 testTimestampMag()397 public void testTimestampMag() { 398 runTimestampTestGroup(Sensor.TYPE_MAGNETIC_FIELD); 399 } 400 testAtomicCounterAccel()401 public void testAtomicCounterAccel() { 402 for (int memType : POSSIBLE_CHANNEL_TYPES) { 403 runAtomicCounterTest(Sensor.TYPE_ACCELEROMETER, memType); 404 } 405 } 406 testAtomicCounterGyro()407 public void testAtomicCounterGyro() { 408 for (int memType : POSSIBLE_CHANNEL_TYPES) { 409 runAtomicCounterTest(Sensor.TYPE_GYROSCOPE, memType); 410 } 411 } 412 testAtomicCounterMag()413 public void testAtomicCounterMag() { 414 for (int memType : POSSIBLE_CHANNEL_TYPES) { 415 runAtomicCounterTest(Sensor.TYPE_MAGNETIC_FIELD, memType); 416 } 417 } 418 testRegisterMultipleChannels()419 public void testRegisterMultipleChannels() throws AssertionError { 420 resetEvent(); 421 freeSharedMemory(); 422 423 for (int memType : POSSIBLE_CHANNEL_TYPES) { 424 if (!isMemoryTypeNeeded(memType)) { 425 continue; 426 } 427 428 for (int repeat = 0; repeat < 10; ++repeat) { 429 // allocate new memory every time 430 allocateSharedMemory(); 431 432 mChannel = prepareDirectChannel(memType, false /* secondary */); 433 assertNotNull("mChannel is null", mChannel); 434 435 mChannelSecondary = prepareDirectChannel(memType, true /* secondary */); 436 assertNotNull("mChannelSecondary is null", mChannelSecondary); 437 438 if (mChannel != null) { 439 mChannel.close(); 440 mChannel = null; 441 } 442 if (mChannelSecondary != null) { 443 mChannelSecondary.close(); 444 mChannelSecondary = null; 445 } 446 447 // free shared memory 448 freeSharedMemory(); 449 } 450 } 451 } 452 testRegisterMultipleChannelsUsingSameMemory()453 public void testRegisterMultipleChannelsUsingSameMemory() throws AssertionError { 454 // MemoryFile identification is not supported by Android yet 455 int memType = SensorDirectChannel.TYPE_HARDWARE_BUFFER; 456 if (!isMemoryTypeNeeded(memType)) { 457 return; 458 } 459 460 mChannel = prepareDirectChannel(memType, false /* secondary */); 461 assertNotNull("mChannel is null", mChannel); 462 463 // use same memory to register, should fail. 464 mChannelSecondary = prepareDirectChannel(memType, false /* secondary */); 465 assertNull("mChannelSecondary is not null", mChannelSecondary); 466 467 mChannel.close(); 468 // after mChannel.close(), memory should free up and this should return non-null 469 // channel 470 mChannelSecondary = prepareDirectChannel(memType, false /* secondary */); 471 assertNotNull("mChannelSecondary is null", mChannelSecondary); 472 mChannelSecondary.close(); 473 } 474 testReconfigure()475 public void testReconfigure() { 476 TestResultCollector c = new TestResultCollector("testReconfigure", TAG); 477 478 for (int type : POSSIBLE_SENSOR_TYPES) { 479 for (int memType : POSSIBLE_CHANNEL_TYPES) { 480 c.perform(() -> { runReconfigureTest(type, memType);}, 481 String.format("sensor type %d, mem type %d", type, memType)); 482 } 483 } 484 c.judge(); 485 } 486 testCloseWithoutConfigStop()487 public void testCloseWithoutConfigStop() { 488 for (int type : POSSIBLE_SENSOR_TYPES) { 489 for (int memType : POSSIBLE_CHANNEL_TYPES) { 490 Sensor s = mSensorManager.getDefaultSensor(type); 491 if (s == null 492 || s.getHighestDirectReportRateLevel() == SensorDirectChannel.RATE_STOP 493 || !s.isDirectChannelTypeSupported(memType)) { 494 continue; 495 } 496 497 mChannel = prepareDirectChannel(memType, false /* secondary */); 498 assertTrue("createDirectChannel failed", mChannel != null); 499 500 try { 501 waitBeforeStartSensor(); 502 mChannel.configure(s, s.getHighestDirectReportRateLevel()); 503 504 // wait for a while 505 waitBeforeStartSensor(); 506 507 // The following line is commented out intentionally. 508 // mChannel.configure(s, SensorDirectChannel.RATE_STOP); 509 } finally { 510 mChannel.close(); 511 mChannel = null; 512 } 513 waitBeforeStartSensor(); 514 } 515 } 516 } 517 runSingleChannelRateIndependencyTestGroup(int type1, int type2)518 private void runSingleChannelRateIndependencyTestGroup(int type1, int type2) { 519 if (type1 == type2) { 520 throw new IllegalArgumentException("Cannot run single channel rate independency test " 521 + "on type " + type1 + " and " + type2); 522 } 523 String stype1 = SensorCtsHelper.sensorTypeShortString(type1); 524 String stype2 = SensorCtsHelper.sensorTypeShortString(type2); 525 526 TestResultCollector c = 527 new TestResultCollector( 528 "testRateIndependency" + stype1 + stype2 + "SingleChannel", TAG); 529 530 for (int rate1 : POSSIBLE_RATE_LEVELS) { 531 for (int rate2 : POSSIBLE_RATE_LEVELS) { 532 for (int memType : POSSIBLE_CHANNEL_TYPES) { 533 c.perform( 534 () -> { 535 runSingleChannelRateIndependencyTest( 536 type1, rate1, type2, rate2, 537 SensorDirectChannel.TYPE_MEMORY_FILE); 538 }, 539 String.format("(%s rate %d, %s rate %d, mem %d)", 540 stype1, rate1, stype2, rate2, memType)); 541 } 542 } 543 } 544 c.judge(); 545 } 546 runMultiChannelRateIndependencyTestGroup(int sensorType)547 public void runMultiChannelRateIndependencyTestGroup(int sensorType) { 548 TestResultCollector c = new TestResultCollector( 549 "testRateIndependency" + SensorCtsHelper.sensorTypeShortString(sensorType) 550 + "MultiChannel", TAG); 551 552 for (int rate1 : POSSIBLE_RATE_LEVELS) { 553 for (int rate2 : POSSIBLE_RATE_LEVELS) { 554 for (int type1 : POSSIBLE_CHANNEL_TYPES) { 555 for (int type2 : POSSIBLE_CHANNEL_TYPES) { 556 // only test upper triangle 557 if (rate1 > rate2 || type1 > type2) { 558 continue; 559 } 560 c.perform(() -> { 561 runMultiChannelRateIndependencyTest( 562 sensorType, rate1, rate2, type1, type2);}, 563 String.format("rate1 %d, rate2 %d, type1 %d, type2 %d", 564 rate1, rate2, type1, type2)); 565 } 566 } 567 } 568 } 569 c.judge(); 570 } 571 runMultiModeRateIndependencyTestGroup(int sensorType)572 public void runMultiModeRateIndependencyTestGroup(int sensorType) { 573 TestResultCollector c = new TestResultCollector( 574 "testRateIndependency" + SensorCtsHelper.sensorTypeShortString(sensorType) 575 + "MultiMode", TAG); 576 577 for (int rate : POSSIBLE_RATE_LEVELS) { 578 for (int type : POSSIBLE_CHANNEL_TYPES) { 579 for (int samplingPeriodUs : POSSIBLE_SAMPLE_PERIOD_US) { 580 c.perform(() -> {runMultiModeRateIndependencyTest( 581 sensorType, rate, type, samplingPeriodUs);}, 582 String.format("rateLevel %d, memType %d, period %d", 583 rate, type, samplingPeriodUs)); 584 } 585 } 586 } 587 c.judge(); 588 } 589 runTimestampTestGroup(int sensorType)590 private void runTimestampTestGroup(int sensorType) { 591 String stype = SensorCtsHelper.sensorTypeShortString(sensorType); 592 593 TestResultCollector c = 594 new TestResultCollector("testTimestamp" + stype, TAG); 595 596 for (int rateLevel : POSSIBLE_RATE_LEVELS) { 597 for (int memType : POSSIBLE_CHANNEL_TYPES) { 598 c.perform( 599 () -> { 600 runTimestampTest(sensorType, rateLevel, memType); 601 }, 602 String.format("(%s, rate %d, memtype %d)", stype, rateLevel, memType)); 603 } 604 } 605 c.judge(); 606 } 607 runSensorDirectReportTest(int sensorType, int memType, int rateLevel)608 private void runSensorDirectReportTest(int sensorType, int memType, int rateLevel) 609 throws AssertionError { 610 Sensor s = mSensorManager.getDefaultSensor(sensorType); 611 if (s == null 612 || s.getHighestDirectReportRateLevel() < rateLevel 613 || !s.isDirectChannelTypeSupported(memType)) { 614 return; 615 } 616 resetEvent(); 617 618 mChannel = prepareDirectChannel(memType, false /* secondary */); 619 assertTrue("createDirectChannel failed", mChannel != null); 620 621 try { 622 assertTrue("Shared memory is not formatted", isSharedMemoryFormatted(memType)); 623 waitBeforeStartSensor(); 624 625 int token = mChannel.configure(s, rateLevel); 626 assertTrue("configure direct mChannel failed", token > 0); 627 628 waitSensorCollection(); 629 630 //stop sensor and analyze content 631 mChannel.configure(s, SensorDirectChannel.RATE_STOP); 632 checkSharedMemoryContent(s, memType, rateLevel, token); 633 } finally { 634 mChannel.close(); 635 mChannel = null; 636 } 637 } 638 runSingleChannelRateIndependencyTest( int type1, int rateLevel1, int type2, int rateLevel2, int memType)639 private void runSingleChannelRateIndependencyTest( 640 int type1, int rateLevel1, int type2, int rateLevel2, int memType) 641 throws AssertionError { 642 Sensor s1 = mSensorManager.getDefaultSensor(type1); 643 Sensor s2 = mSensorManager.getDefaultSensor(type2); 644 if (s1 == null 645 || s1.getHighestDirectReportRateLevel() < rateLevel1 646 || !s1.isDirectChannelTypeSupported(memType)) { 647 return; 648 } 649 650 if (s2 == null 651 || s2.getHighestDirectReportRateLevel() < rateLevel2 652 || !s2.isDirectChannelTypeSupported(memType)) { 653 return; 654 } 655 resetEvent(); 656 657 mChannel = prepareDirectChannel(memType, false /* secondary */); 658 assertTrue("createDirectChannel failed", mChannel != null); 659 660 try { 661 assertTrue("Shared memory is not formatted", isSharedMemoryFormatted(memType)); 662 waitBeforeStartSensor(); 663 664 int token1 = mChannel.configure(s1, rateLevel1); 665 int token2 = mChannel.configure(s2, rateLevel2); 666 assertTrue("configure direct mChannel failed, token1 = " + token1, token1 > 0); 667 assertTrue("configure direct mChannel failed, token2 = " + token2, token2 > 0); 668 669 // run half amount of time so buffer is enough for both sensors 670 try { 671 SensorCtsHelper.sleep(TEST_RUN_TIME_PERIOD_MILLISEC / 2, TimeUnit.MILLISECONDS); 672 } catch (InterruptedException e) { 673 Thread.currentThread().interrupt(); 674 } 675 676 //stop sensor and analyze content 677 mChannel.configure(s1, SensorDirectChannel.RATE_STOP); 678 mChannel.configure(s2, SensorDirectChannel.RATE_STOP); 679 680 readSharedMemory(memType, false /*secondary*/); 681 checkEventRate(TEST_RUN_TIME_PERIOD_MILLISEC / 2, parseEntireBuffer(mBuffer, token1), 682 type1, rateLevel1); 683 checkEventRate(TEST_RUN_TIME_PERIOD_MILLISEC / 2, parseEntireBuffer(mBuffer, token2), 684 type2, rateLevel2); 685 } finally { 686 mChannel.close(); 687 mChannel = null; 688 } 689 } 690 runMultiChannelRateIndependencyTest( int type, int rateLevel1, int rateLevel2, int memType1, int memType2)691 private void runMultiChannelRateIndependencyTest( 692 int type, int rateLevel1, int rateLevel2, int memType1, int memType2) 693 throws AssertionError { 694 Sensor s = mSensorManager.getDefaultSensor(type); 695 if (s == null 696 || s.getHighestDirectReportRateLevel() < Math.max(rateLevel1, rateLevel2) 697 || !s.isDirectChannelTypeSupported(memType1) 698 || !s.isDirectChannelTypeSupported(memType2)) { 699 return; 700 } 701 resetEvent(); 702 703 mChannel = prepareDirectChannel(memType1, false /* secondary */); 704 mChannelSecondary = prepareDirectChannel(memType2, true /* secondary */); 705 706 try { 707 assertTrue("createDirectChannel failed", mChannel != null); 708 assertTrue("Shared memory is not formatted", 709 isSharedMemoryFormatted(memType1)); 710 711 assertTrue("createDirectChannel(secondary) failed", mChannelSecondary != null); 712 assertTrue("Shared memory(secondary) is not formatted", 713 isSharedMemoryFormatted(memType2, true)); 714 715 waitBeforeStartSensor(); 716 717 int token1 = mChannel.configure(s, rateLevel1); 718 int token2 = mChannelSecondary.configure(s, rateLevel2); 719 assertTrue("configure direct mChannel failed", token1 > 0); 720 assertTrue("configure direct mChannelSecondary failed", token2 > 0); 721 722 waitSensorCollection(); 723 724 //stop sensor and analyze content 725 mChannel.configure(s, SensorDirectChannel.RATE_STOP); 726 mChannelSecondary.configure(s, SensorDirectChannel.RATE_STOP); 727 728 // check rate 729 readSharedMemory(memType1, false /*secondary*/); 730 checkEventRate(TEST_RUN_TIME_PERIOD_MILLISEC, parseEntireBuffer(mBuffer, token1), 731 type, rateLevel1); 732 733 readSharedMemory(memType2, true /*secondary*/); 734 checkEventRate(TEST_RUN_TIME_PERIOD_MILLISEC, parseEntireBuffer(mBuffer, token2), 735 type, rateLevel2); 736 } finally { 737 if (mChannel != null) { 738 mChannel.close(); 739 mChannel = null; 740 } 741 if (mChannelSecondary != null) { 742 mChannelSecondary.close(); 743 mChannelSecondary = null; 744 } 745 } 746 } 747 runMultiModeRateIndependencyTest( int type , int rateLevel, int memType, int samplingPeriodUs)748 private void runMultiModeRateIndependencyTest( 749 int type , int rateLevel, int memType, int samplingPeriodUs) 750 throws AssertionError { 751 final Sensor s = mSensorManager.getDefaultSensor(type); 752 if (s == null 753 || s.getHighestDirectReportRateLevel() < rateLevel 754 || !s.isDirectChannelTypeSupported(memType)) { 755 return; 756 } 757 758 if (samplingPeriodUs == 0) { 759 samplingPeriodUs = s.getMinDelay(); 760 } 761 762 if (samplingPeriodUs < s.getMinDelay()) { 763 return; 764 } 765 resetEvent(); 766 767 mChannel = prepareDirectChannel(memType, false /* secondary */); 768 assertTrue("createDirectChannel failed", mChannel != null); 769 SensorEventCollection listener = new SensorEventCollection(s); 770 771 try { 772 waitBeforeStartSensor(); 773 int token = mChannel.configure(s, rateLevel); 774 boolean registerRet = mSensorManager.registerListener(listener, s, samplingPeriodUs); 775 assertTrue("Register listener failed", registerRet); 776 777 waitSensorCollection(); 778 779 mChannel.configure(s, SensorDirectChannel.RATE_STOP); 780 mSensorManager.unregisterListener(listener); 781 782 // check direct report rate 783 readSharedMemory(memType, false /*secondary*/); 784 List<DirectReportSensorEvent> events = parseEntireBuffer(mBuffer, token); 785 checkEventRate(TEST_RUN_TIME_PERIOD_MILLISEC, events, type, rateLevel); 786 787 // check callback interface rate 788 checkEventRateUs(TEST_RUN_TIME_PERIOD_MILLISEC, listener.getEvents(), type, 789 samplingPeriodUs); 790 } finally { 791 mChannel.close(); 792 mChannel = null; 793 mSensorManager.unregisterListener(listener); 794 } 795 } 796 runTimestampTest(int type, int rateLevel, int memType)797 private void runTimestampTest(int type, int rateLevel, int memType) { 798 Sensor s = mSensorManager.getDefaultSensor(type); 799 if (s == null 800 || s.getHighestDirectReportRateLevel() < rateLevel 801 || !s.isDirectChannelTypeSupported(memType)) { 802 return; 803 } 804 resetEvent(); 805 806 mChannel = prepareDirectChannel(memType, false /* secondary */); 807 assertTrue("createDirectChannel failed", mChannel != null); 808 809 SensorEventCollection listener = new SensorEventCollection(s); 810 811 try { 812 float nominalFreq = getNominalFreq(rateLevel); 813 int samplingPeriodUs = Math.max((int) (1e6f / nominalFreq), s.getMinDelay()); 814 815 assertTrue("Shared memory is not formatted", 816 isSharedMemoryFormatted(memType)); 817 818 int token = mChannel.configure(s, rateLevel); 819 assertTrue("configure direct mChannel failed", token > 0); 820 821 boolean registerRet = mSensorManager.registerListener(listener, s, samplingPeriodUs); 822 assertTrue("Register listener failed", registerRet); 823 824 List<DirectReportSensorEvent> events = collectSensorEventsRealtime( 825 memType, false /*secondary*/, TEST_RUN_TIME_PERIOD_MILLISEC); 826 assertTrue("Realtime event collection failed", events != null); 827 assertTrue("Realtime event collection got no data", events.size() > 0); 828 829 //stop sensor and analyze content 830 mChannel.configure(s, SensorDirectChannel.RATE_STOP); 831 mSensorManager.unregisterListener(listener); 832 833 // check rate 834 checkTimestampRelative(events, listener.getEvents()); 835 checkTimestampAbsolute(events); 836 } finally { 837 mChannel.close(); 838 mChannel = null; 839 } 840 } 841 runAtomicCounterTest(int sensorType, int memType)842 private void runAtomicCounterTest(int sensorType, int memType) throws AssertionError { 843 Sensor s = mSensorManager.getDefaultSensor(sensorType); 844 if (s == null 845 || s.getHighestDirectReportRateLevel() == SensorDirectChannel.RATE_STOP 846 || !s.isDirectChannelTypeSupported(memType)) { 847 return; 848 } 849 resetEvent(); 850 851 mChannel = prepareDirectChannel(memType, false /* secondary */); 852 assertTrue("createDirectChannel failed", mChannel != null); 853 854 try { 855 assertTrue("Shared memory is not formatted", isSharedMemoryFormatted(memType)); 856 waitBeforeStartSensor(); 857 858 //int token = mChannel.configure(s, SensorDirectChannel.RATE_FAST); 859 int token = mChannel.configure(s, s.getHighestDirectReportRateLevel()); 860 assertTrue("configure direct mChannel failed", token > 0); 861 862 checkAtomicCounterUpdate(memType, 30 * 1000); // half min 863 864 //stop sensor and analyze content 865 mChannel.configure(s, SensorDirectChannel.RATE_STOP); 866 } finally { 867 mChannel.close(); 868 mChannel = null; 869 } 870 } 871 runReconfigureTest(int type, int memType)872 private void runReconfigureTest(int type, int memType) { 873 Sensor s = mSensorManager.getDefaultSensor(type); 874 if (s == null 875 || s.getHighestDirectReportRateLevel() == SensorDirectChannel.RATE_STOP 876 || !s.isDirectChannelTypeSupported(memType)) { 877 return; 878 } 879 resetEvent(); 880 881 mChannel = prepareDirectChannel(memType, false /* secondary */); 882 assertTrue("createDirectChannel failed", mChannel != null); 883 884 try { 885 assertTrue("Shared memory is not formatted", isSharedMemoryFormatted(memType)); 886 waitBeforeStartSensor(); 887 888 int offset = 0; 889 long counter = 1; 890 List<Integer> rateLevels = new ArrayList<>(); 891 List<DirectReportSensorEvent> events; 892 893 rateLevels.add(s.getHighestDirectReportRateLevel()); 894 rateLevels.add(s.getHighestDirectReportRateLevel()); 895 if (s.getHighestDirectReportRateLevel() != SensorDirectChannel.RATE_NORMAL) { 896 rateLevels.add(SensorDirectChannel.RATE_NORMAL); 897 } 898 899 for (int rateLevel : rateLevels) { 900 int token = mChannel.configure(s, rateLevel); 901 assertTrue("configure direct mChannel failed", token > 0); 902 903 events = collectSensorEventsRealtime(memType, false /*secondary*/, 904 TEST_RUN_TIME_PERIOD_MILLISEC, 905 offset, counter); 906 // stop sensor 907 mChannel.configure(s, SensorDirectChannel.RATE_STOP); 908 checkEventRate(TEST_RUN_TIME_PERIOD_MILLISEC, events, type, rateLevel); 909 910 // collect all events after stop 911 events = collectSensorEventsRealtime(memType, false /*secondary*/, 912 REST_PERIOD_BEFORE_TEST_MILLISEC, 913 offset, counter); 914 if (events.size() > 0) { 915 offset += (events.size() * SENSORS_EVENT_SIZE ) % SHARED_MEMORY_SIZE; 916 counter = events.get(events.size() - 1).serial; 917 } 918 } 919 920 // finally stop the report 921 mChannel.configure(s, SensorDirectChannel.RATE_STOP); 922 } finally { 923 mChannel.close(); 924 mChannel = null; 925 } 926 } 927 waitBeforeStartSensor()928 private void waitBeforeStartSensor() { 929 // wait for sensor system to come to a rest after previous test to avoid flakiness. 930 try { 931 SensorCtsHelper.sleep(REST_PERIOD_BEFORE_TEST_MILLISEC, TimeUnit.MILLISECONDS); 932 } catch (InterruptedException e) { 933 Thread.currentThread().interrupt(); 934 } 935 } 936 waitSensorCollection()937 private void waitSensorCollection() { 938 // wait for sensor collection to finish 939 try { 940 SensorCtsHelper.sleep(TEST_RUN_TIME_PERIOD_MILLISEC, TimeUnit.MILLISECONDS); 941 } catch (InterruptedException e) { 942 Thread.currentThread().interrupt(); 943 } 944 } 945 collectSensorEventsRealtime( int memType, boolean secondary, int timeoutMs)946 private List<DirectReportSensorEvent> collectSensorEventsRealtime( 947 int memType, boolean secondary, int timeoutMs) { 948 return collectSensorEventsRealtime(memType, secondary, timeoutMs, 949 0 /*initialOffset*/, 1l /*initialCounter*/); 950 } 951 collectSensorEventsRealtime( int memType, boolean secondary, int timeoutMs, int initialOffset, long initialCounter)952 private List<DirectReportSensorEvent> collectSensorEventsRealtime( 953 int memType, boolean secondary, int timeoutMs, int initialOffset, long initialCounter) { 954 List<DirectReportSensorEvent> events = new ArrayList<>(); 955 long endTime = SystemClock.elapsedRealtime() + timeoutMs; 956 957 long atomicCounter = initialCounter; 958 int offset = initialOffset; 959 960 long timeA = SystemClock.elapsedRealtimeNanos(); 961 boolean synced = false; 962 int filtered = 0; 963 964 while (SystemClock.elapsedRealtime() < endTime) { 965 if (!readSharedMemory( 966 memType, secondary, offset + ATOMIC_COUNTER_OFFSET, ATOMIC_COUNTER_SIZE)) { 967 return null; 968 } 969 970 long timeB = SystemClock.elapsedRealtimeNanos(); 971 if (timeB - timeA > 1_000_000L ) { // > 1ms 972 synced = false; 973 } 974 timeA = timeB; 975 976 if (readAtomicCounter(offset) == atomicCounter) { 977 // read entire event again and parse 978 if (!readSharedMemory(memType, secondary, offset, SENSORS_EVENT_SIZE)) { 979 return null; 980 } 981 DirectReportSensorEvent e = mEventPool.get(); 982 assertNotNull("cannot get event from reserve", e); 983 parseSensorEvent(offset, e); 984 985 atomicCounter += 1; 986 if (synced) { 987 events.add(e); 988 } else { 989 ++filtered; 990 } 991 992 offset += SENSORS_EVENT_SIZE; 993 if (offset + SENSORS_EVENT_SIZE > SHARED_MEMORY_SIZE) { 994 offset = 0; 995 } 996 } else { 997 synced = true; 998 } 999 } 1000 Log.d(TAG, "filtered " + filtered + " events, remain " + events.size() + " events"); 1001 return events; 1002 } 1003 checkAtomicCounterUpdate(int memType, int timeoutMs)1004 private void checkAtomicCounterUpdate(int memType, int timeoutMs) { 1005 List<DirectReportSensorEvent> events = new ArrayList<>(); 1006 long endTime = SystemClock.elapsedRealtime() + timeoutMs; 1007 1008 boolean lastValid = false; 1009 long atomicCounter = 1; 1010 int lastOffset = 0; 1011 int offset = 0; 1012 1013 byte[] lastArray = new byte[SENSORS_EVENT_SIZE]; 1014 DirectReportSensorEvent e = getEvent(); 1015 1016 while (SystemClock.elapsedRealtime() < endTime) { 1017 if (!readSharedMemory(memType, false/*secondary*/, lastOffset, SENSORS_EVENT_SIZE) 1018 || !readSharedMemory(memType, false/*secondary*/, 1019 offset + ATOMIC_COUNTER_OFFSET, ATOMIC_COUNTER_SIZE)) { 1020 throw new IllegalStateException("cannot read shared memory, type " + memType); 1021 } 1022 1023 if (lastValid) { 1024 boolean failed = false; 1025 int i; 1026 for (i = 0; i < SENSORS_EVENT_SIZE; ++i) { 1027 if (lastArray[i] != mBuffer[lastOffset + i]) { 1028 failed = true; 1029 break; 1030 } 1031 } 1032 1033 if (failed) { 1034 byte[] currentArray = new byte[SENSORS_EVENT_SIZE]; 1035 System.arraycopy(mBuffer, lastOffset, currentArray, 0, SENSORS_EVENT_SIZE); 1036 1037 // wait for 100ms and read again to see if the change settle 1038 try { 1039 SensorCtsHelper.sleep(100, TimeUnit.MILLISECONDS); 1040 } catch (InterruptedException ex) { 1041 Thread.currentThread().interrupt(); 1042 } 1043 1044 byte[] delayedRead = new byte[SENSORS_EVENT_SIZE]; 1045 if (!readSharedMemory( 1046 memType, false/*secondary*/, lastOffset, SENSORS_EVENT_SIZE)) { 1047 throw new IllegalStateException( 1048 "cannot read shared memory, type " + memType); 1049 } 1050 System.arraycopy(mBuffer, lastOffset, delayedRead, 0, SENSORS_EVENT_SIZE); 1051 1052 fail(String.format( 1053 "At offset %d(0x%x), byte %d(0x%x) changed after atomicCounter" 1054 + "(expecting %d, 0x%x) update, old = [%s], new = [%s], " 1055 + "delayed = [%s]", 1056 lastOffset, lastOffset, i, i, atomicCounter, atomicCounter, 1057 SensorCtsHelper.bytesToHex(lastArray, -1, -1), 1058 SensorCtsHelper.bytesToHex(currentArray, -1, -1), 1059 SensorCtsHelper.bytesToHex(delayedRead, -1, -1))); 1060 } 1061 } 1062 1063 if (readAtomicCounter(offset) == atomicCounter) { 1064 // read entire event again and parse 1065 if (!readSharedMemory(memType, false/*secondary*/, offset, SENSORS_EVENT_SIZE)) { 1066 throw new IllegalStateException("cannot read shared memory, type " + memType); 1067 } 1068 parseSensorEvent(offset, e); 1069 1070 atomicCounter += 1; 1071 1072 lastOffset = offset; 1073 System.arraycopy(mBuffer, lastOffset, lastArray, 0, SENSORS_EVENT_SIZE); 1074 lastValid = true; 1075 1076 offset += SENSORS_EVENT_SIZE; 1077 if (offset + SENSORS_EVENT_SIZE > SHARED_MEMORY_SIZE) { 1078 offset = 0; 1079 } 1080 } 1081 } 1082 Log.d(TAG, "at finish checkAtomicCounterUpdate has atomic counter = " + atomicCounter); 1083 // atomicCounter will not wrap back in reasonable amount of time 1084 assertTrue("Realtime event collection got no data", atomicCounter != 1); 1085 } 1086 allocateMemoryFile()1087 private MemoryFile allocateMemoryFile() { 1088 MemoryFile memFile = null; 1089 try { 1090 memFile = new MemoryFile("Sensor Channel", SHARED_MEMORY_SIZE); 1091 } catch (IOException e) { 1092 Log.e(TAG, "IOException when allocating MemoryFile"); 1093 } 1094 return memFile; 1095 } 1096 allocateHardwareBuffer()1097 private HardwareBuffer allocateHardwareBuffer() { 1098 HardwareBuffer hardwareBuffer; 1099 1100 hardwareBuffer = HardwareBuffer.create( 1101 SHARED_MEMORY_SIZE, 1 /* height */, HardwareBuffer.BLOB, 1 /* layer */, 1102 HardwareBuffer.USAGE_CPU_READ_OFTEN | HardwareBuffer.USAGE_GPU_DATA_BUFFER 1103 | HardwareBuffer.USAGE_SENSOR_DIRECT_DATA); 1104 return hardwareBuffer; 1105 } 1106 prepareDirectChannel(int memType, boolean secondary)1107 private SensorDirectChannel prepareDirectChannel(int memType, boolean secondary) { 1108 SensorDirectChannel channel = null; 1109 1110 try { 1111 switch(memType) { 1112 case SensorDirectChannel.TYPE_MEMORY_FILE: { 1113 MemoryFile memoryFile = secondary ? mMemoryFileSecondary : mMemoryFile; 1114 assertTrue("MemoryFile" + (secondary ? "(secondary)" : "") + " is null", 1115 memoryFile != null); 1116 channel = mSensorManager.createDirectChannel(memoryFile); 1117 break; 1118 } 1119 case SensorDirectChannel.TYPE_HARDWARE_BUFFER: { 1120 HardwareBuffer hardwareBuffer 1121 = secondary ? mHardwareBufferSecondary : mHardwareBuffer; 1122 assertTrue("HardwareBuffer" + (secondary ? "(secondary)" : "") + " is null", 1123 hardwareBuffer != null); 1124 channel = mSensorManager.createDirectChannel(hardwareBuffer); 1125 break; 1126 } 1127 default: 1128 Log.e(TAG, "Specified illegal memory type " + memType); 1129 } 1130 } catch (IllegalStateException | UncheckedIOException e) { 1131 Log.e(TAG, "Cannot initialize channel for memory type " + memType 1132 + ", details:" + e); 1133 channel = null; 1134 } 1135 return channel; 1136 } 1137 readSharedMemory(int memType, boolean secondary, int offset, int length)1138 private boolean readSharedMemory(int memType, boolean secondary, int offset, int length) { 1139 switch(memType) { 1140 case SensorDirectChannel.TYPE_MEMORY_FILE: 1141 try { 1142 MemoryFile f = secondary ? mMemoryFileSecondary : mMemoryFile; 1143 if (f.readBytes(mBuffer, offset, offset, length) != length) { 1144 Log.e(TAG, "cannot read entire MemoryFile"); 1145 return false; 1146 } 1147 } catch (IOException e) { 1148 Log.e(TAG, "accessing MemoryFile causes IOException"); 1149 return false; 1150 } 1151 return true; 1152 case SensorDirectChannel.TYPE_HARDWARE_BUFFER: 1153 return nativeReadHardwareBuffer( 1154 secondary ? mHardwareBufferSecondary : mHardwareBuffer, 1155 mBuffer, offset, offset, length); 1156 default: 1157 return false; 1158 } 1159 } 1160 readSharedMemory(int memType, boolean secondary)1161 private boolean readSharedMemory(int memType, boolean secondary) { 1162 return readSharedMemory(memType, secondary, 0, SHARED_MEMORY_SIZE); 1163 } 1164 readSharedMemory(int memType)1165 private boolean readSharedMemory(int memType) { 1166 return readSharedMemory(memType, false /*secondary*/); 1167 } 1168 isMemoryTypeNeeded(int memType)1169 private boolean isMemoryTypeNeeded(int memType) { 1170 List<Sensor> sensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL); 1171 for (Sensor s : sensorList) { 1172 if (s.isDirectChannelTypeSupported(memType)) { 1173 return true; 1174 } 1175 } 1176 return false; 1177 } 1178 isSharedMemoryFormatted(int memType)1179 private boolean isSharedMemoryFormatted(int memType) { 1180 return isSharedMemoryFormatted(memType, false /* secondary */); 1181 } 1182 isSharedMemoryFormatted(int memType, boolean secondary)1183 private boolean isSharedMemoryFormatted(int memType, boolean secondary) { 1184 readSharedMemory(memType, secondary); 1185 1186 for (byte b : mBuffer) { 1187 if (b != 0) { 1188 return false; 1189 } 1190 } 1191 return true; 1192 } 1193 checkSharedMemoryContent(Sensor s, int memType, int rateLevel, int token)1194 private void checkSharedMemoryContent(Sensor s, int memType, int rateLevel, int token) { 1195 assertTrue("read mem type " + memType + " content failed", readSharedMemory(memType)); 1196 1197 int offset = 0; 1198 int nextSerial = 1; 1199 DirectReportSensorEvent e = getEvent(); 1200 while (offset <= SHARED_MEMORY_SIZE - SENSORS_EVENT_SIZE) { 1201 parseSensorEvent(offset, e); 1202 1203 if (e.serial == 0) { 1204 // reaches end of events 1205 break; 1206 } 1207 1208 assertTrue("incorrect size " + e.size + " at offset " + offset, 1209 e.size == SENSORS_EVENT_SIZE); 1210 assertTrue("incorrect token " + e.token + " at offset " + offset, 1211 e.token == token); 1212 assertTrue("incorrect serial " + e.serial + " at offset " + offset, 1213 e.serial == nextSerial); 1214 assertTrue("incorrect type " + e.type + " offset " + offset, 1215 e.type == s.getType()); 1216 1217 switch(s.getType()) { 1218 case Sensor.TYPE_ACCELEROMETER: 1219 double accNorm = Math.sqrt(e.x * e.x + e.y * e.y + e.z * e.z); 1220 assertTrue("incorrect gravity norm " + accNorm + " at offset " + offset, 1221 accNorm < GRAVITY_MAX && accNorm > GRAVITY_MIN); 1222 break; 1223 case Sensor.TYPE_GYROSCOPE: 1224 double gyroNorm = Math.sqrt(e.x * e.x + e.y * e.y + e.z * e.z); 1225 assertTrue("gyro norm too large (" + gyroNorm + ") at offset " + offset, 1226 gyroNorm < GYRO_NORM_MAX); 1227 break; 1228 } 1229 1230 ++nextSerial; 1231 offset += SENSORS_EVENT_SIZE; 1232 } 1233 1234 int nEvents = nextSerial - 1; 1235 float nominalFreq = 0; 1236 1237 switch (rateLevel) { 1238 case SensorDirectChannel.RATE_NORMAL: 1239 nominalFreq = RATE_NORMAL_NOMINAL; 1240 break; 1241 case SensorDirectChannel.RATE_FAST: 1242 nominalFreq = RATE_FAST_NOMINAL; 1243 break; 1244 case SensorDirectChannel.RATE_VERY_FAST: 1245 nominalFreq = RATE_VERY_FAST_NOMINAL; 1246 break; 1247 } 1248 1249 if (nominalFreq != 0) { 1250 int minEvents; 1251 int maxEvents; 1252 minEvents = (int) Math.floor( 1253 nominalFreq 1254 * FREQ_LOWER_BOUND 1255 * (TEST_RUN_TIME_PERIOD_MILLISEC - ALLOWED_SENSOR_INIT_TIME_MILLISEC) 1256 * (1 - MERCY_FACTOR) 1257 / 1000); 1258 maxEvents = (int) Math.ceil( 1259 nominalFreq 1260 * FREQ_UPPER_BOUND 1261 * TEST_RUN_TIME_PERIOD_MILLISEC 1262 * (1 + MERCY_FACTOR) 1263 / 1000); 1264 1265 assertTrue("nEvent is " + nEvents + " not between " + minEvents + " and " + maxEvents, 1266 nEvents >= minEvents && nEvents <=maxEvents); 1267 } 1268 } 1269 checkEventRate(int testTimeMs, List<DirectReportSensorEvent> events, int type, int rateLevel)1270 private void checkEventRate(int testTimeMs, List<DirectReportSensorEvent> events, 1271 int type, int rateLevel) { 1272 assertTrue("insufficient events of type " + type, events.size() > 1); 1273 for (DirectReportSensorEvent e : events) { 1274 assertTrue("incorrect type " + e.type + " expecting " + type, e.type == type); 1275 } 1276 1277 // check number of events 1278 int[] minMax = calculateExpectedNEvents(testTimeMs, rateLevel); 1279 assertTrue( 1280 "Number of event of type " + type + " is " + events.size() 1281 + ", which is not in range [" + minMax[0] + ", " + minMax[1] + "].", 1282 minMax[0] <= events.size() && events.size() <= minMax[1]); 1283 1284 // intervals 1285 List<Long> intervals = new ArrayList<>(events.size() - 1); 1286 long minInterval = Long.MAX_VALUE; 1287 long maxInterval = Long.MIN_VALUE; 1288 long averageInterval = 0; 1289 for (int i = 1; i < events.size(); ++i) { 1290 long d = events.get(i).ts - events.get(i-1).ts; 1291 averageInterval += d; 1292 minInterval = Math.min(d, minInterval); 1293 maxInterval = Math.max(d, maxInterval); 1294 intervals.add(d); 1295 } 1296 averageInterval /= (events.size() - 1); 1297 1298 // average rate 1299 float averageFreq = 1e9f / averageInterval; 1300 float nominalFreq = getNominalFreq(rateLevel); 1301 Log.d(TAG, String.format( 1302 "checkEventRate type %d: averageFreq %f, nominalFreq %f, lbound %f, ubound %f", 1303 type, averageFreq, nominalFreq, 1304 nominalFreq * FREQ_LOWER_BOUND, 1305 nominalFreq * FREQ_UPPER_BOUND)); 1306 assertTrue("Average frequency of type " + type + " rateLevel " + rateLevel 1307 + " is " + averageFreq, 1308 nominalFreq * FREQ_LOWER_BOUND * (1 - MERCY_FACTOR) <= averageFreq && 1309 averageFreq <= nominalFreq * FREQ_UPPER_BOUND * (1 + MERCY_FACTOR)); 1310 1311 // jitter variance 1312 List<Long> percentileValues = 1313 SensorCtsHelper.getPercentileValue(intervals, 0.025f, (1 - 0.025f)); 1314 assertTrue("Timestamp jitter of type " + type + " rateLevel " + rateLevel + " is " 1315 + (percentileValues.get(1) - percentileValues.get(0) / 1000) + " us, " 1316 + "while average interval is " + (averageInterval / 1000) + "us, over-range", 1317 (percentileValues.get(1) - percentileValues.get(0)) / averageInterval < 0.05); 1318 Log.d(TAG, String.format( 1319 "checkEventRate type %d, timestamp interval range %f - %f ms, " + 1320 "span %f ms, %.2f%% of averageInterval", 1321 type, percentileValues.get(0)/1e6f, percentileValues.get(1)/1e6f, 1322 (percentileValues.get(1) - percentileValues.get(0))/1e6f, 1323 (percentileValues.get(1) - percentileValues.get(0)) / averageInterval * 100.f)); 1324 1325 } 1326 checkEventRateUs(int testTimeMs, List<DirectReportSensorEvent> events, int type, int samplingPeriodUs)1327 private void checkEventRateUs(int testTimeMs, List<DirectReportSensorEvent> events, 1328 int type, int samplingPeriodUs) { 1329 // samplingPeriodUs must be a valid one advertised by sensor 1330 assertTrue("insufficient events of type " + type, events.size() > 1); 1331 for (DirectReportSensorEvent e : events) { 1332 assertTrue("incorrect type " + e.type + " expecting " + type, e.type == type); 1333 } 1334 1335 // check number of events 1336 int[] minMax = calculateExpectedNEventsUs(testTimeMs, samplingPeriodUs); 1337 assertTrue( 1338 "Number of event of type " + type + " is " + events.size() 1339 + ", which is not in range [" + minMax[0] + ", " + minMax[1] + "].", 1340 minMax[0] <= events.size() && events.size() <= minMax[1]); 1341 1342 // intervals 1343 List<Long> intervals = new ArrayList<>(events.size() - 1); 1344 long minInterval = Long.MAX_VALUE; 1345 long maxInterval = Long.MIN_VALUE; 1346 long averageInterval = 0; 1347 for (int i = 1; i < events.size(); ++i) { 1348 long d = events.get(i).ts - events.get(i-1).ts; 1349 averageInterval += d; 1350 minInterval = Math.min(d, minInterval); 1351 maxInterval = Math.max(d, maxInterval); 1352 intervals.add(d); 1353 } 1354 averageInterval /= (events.size() - 1); 1355 1356 // average rate 1357 float averageFreq = 1e9f / averageInterval; 1358 float nominalFreq = 1e6f / samplingPeriodUs; 1359 Log.d(TAG, String.format( 1360 "checkEventRateUs type %d: averageFreq %f, nominalFreq %f, lbound %f, ubound %f", 1361 type, averageFreq, nominalFreq, 1362 nominalFreq * FREQ_LOWER_BOUND_POLL, 1363 nominalFreq * FREQ_UPPER_BOUND_POLL)); 1364 assertTrue("Average frequency of type " + type 1365 + " is " + averageFreq, 1366 nominalFreq * FREQ_LOWER_BOUND_POLL * (1 - MERCY_FACTOR) <= averageFreq && 1367 averageFreq <= nominalFreq * FREQ_UPPER_BOUND_POLL * (1 + MERCY_FACTOR)); 1368 1369 // jitter variance 1370 List<Long> percentileValues = 1371 SensorCtsHelper.getPercentileValue(intervals, 0.025f, (1 - 0.025f)); 1372 assertTrue("Timestamp jitter of type " + type + " is " 1373 + (percentileValues.get(1) - percentileValues.get(0) / 1000) + " us, " 1374 + "while average interval is " + (averageInterval / 1000) + "us, over-range", 1375 (percentileValues.get(1) - percentileValues.get(0)) / averageInterval < 0.05); 1376 Log.d(TAG, String.format( 1377 "checkEventRateUs type %d, timestamp interval range %f - %f ms, " + 1378 "span %f ms, %.2f%% of averageInterval", 1379 type, percentileValues.get(0)/1e6f, percentileValues.get(1)/1e6f, 1380 (percentileValues.get(1) - percentileValues.get(0)) / 1e6f, 1381 (percentileValues.get(1) - percentileValues.get(0)) / averageInterval * 100.f)); 1382 } 1383 allocateSharedMemory()1384 private void allocateSharedMemory() { 1385 if (mNeedMemoryFile) { 1386 mMemoryFile = allocateMemoryFile(); 1387 mMemoryFileSecondary = allocateMemoryFile(); 1388 } 1389 1390 if (mNeedHardwareBuffer) { 1391 mHardwareBuffer = allocateHardwareBuffer(); 1392 mHardwareBufferSecondary = allocateHardwareBuffer(); 1393 } 1394 } 1395 freeSharedMemory()1396 private void freeSharedMemory() { 1397 if (mMemoryFile != null) { 1398 mMemoryFile.close(); 1399 mMemoryFile = null; 1400 } 1401 1402 if (mMemoryFileSecondary != null) { 1403 mMemoryFileSecondary.close(); 1404 mMemoryFileSecondary = null; 1405 } 1406 1407 if (mHardwareBuffer != null) { 1408 mHardwareBuffer.close(); 1409 mHardwareBuffer = null; 1410 } 1411 1412 if (mHardwareBufferSecondary != null) { 1413 mHardwareBufferSecondary.close(); 1414 mHardwareBufferSecondary = null; 1415 } 1416 } 1417 getNominalFreq(int rateLevel)1418 private float getNominalFreq(int rateLevel) { 1419 float nominalFreq = 0; 1420 switch (rateLevel) { 1421 case SensorDirectChannel.RATE_NORMAL: 1422 nominalFreq = RATE_NORMAL_NOMINAL; 1423 break; 1424 case SensorDirectChannel.RATE_FAST: 1425 nominalFreq = RATE_FAST_NOMINAL; 1426 break; 1427 case SensorDirectChannel.RATE_VERY_FAST: 1428 nominalFreq = RATE_VERY_FAST_NOMINAL; 1429 break; 1430 } 1431 return nominalFreq; 1432 } 1433 calculateExpectedNEvents(int timeMs, int rateLevel)1434 private int[] calculateExpectedNEvents(int timeMs, int rateLevel) { 1435 int[] minMax = new int[] { -1, Integer.MAX_VALUE }; 1436 float nominalFreq = getNominalFreq(rateLevel); 1437 if (nominalFreq != 0) { 1438 // min 1439 if (timeMs > ALLOWED_SENSOR_INIT_TIME_MILLISEC) { 1440 minMax[0] = (int) Math.floor( 1441 nominalFreq 1442 * FREQ_LOWER_BOUND 1443 * (timeMs - ALLOWED_SENSOR_INIT_TIME_MILLISEC) 1444 * (1 - MERCY_FACTOR) 1445 / 1000); 1446 } 1447 // max 1448 minMax[1] = (int) Math.ceil( 1449 nominalFreq 1450 * FREQ_UPPER_BOUND 1451 * timeMs 1452 * (1 + MERCY_FACTOR) 1453 / 1000); 1454 } 1455 return minMax; 1456 } 1457 checkTimestampAbsolute(List<DirectReportSensorEvent> events)1458 private void checkTimestampAbsolute(List<DirectReportSensorEvent> events) { 1459 final int MAX_DETAIL_ITEM = 10; 1460 1461 StringBuffer buf = new StringBuffer(); 1462 int oneMsEarlyCount = 0; 1463 int fiveMsLateCount = 0; 1464 int tenMsLateCount = 0; 1465 int errorCount = 0; 1466 1467 for (int i = 0; i < events.size(); ++i) { 1468 DirectReportSensorEvent e = events.get(i); 1469 long d = e.arrivalTs - e.ts; 1470 boolean oneMsEarly = d < -1000_000; 1471 boolean fiveMsLate = d > 5000_000; 1472 boolean tenMsLate = d > 10_000_000; 1473 1474 if (oneMsEarly || fiveMsLate || tenMsLate) { 1475 oneMsEarlyCount += oneMsEarly ? 1 : 0; 1476 fiveMsLateCount += fiveMsLate ? 1 : 0; 1477 tenMsLateCount += tenMsLate ? 1 : 0; 1478 1479 if (errorCount++ < MAX_DETAIL_ITEM) { 1480 buf.append("[").append(i).append("] diff = ").append(d / 1e6f).append(" ms; "); 1481 } 1482 } 1483 } 1484 1485 Log.d(TAG, String.format("Irregular timestamp, %d, %d, %d out of %d", 1486 oneMsEarlyCount, fiveMsLateCount, tenMsLateCount, events.size())); 1487 1488 if (CHECK_ABSOLUTE_LATENCY) { 1489 assertTrue(String.format( 1490 "Timestamp error, out of %d events, %d is >1ms early, %d is >5ms late, " 1491 + "%d is >10ms late, details: %s%s", 1492 events.size(), oneMsEarlyCount, fiveMsLateCount, tenMsLateCount, 1493 buf.toString(), errorCount > MAX_DETAIL_ITEM ? "..." : ""), 1494 oneMsEarlyCount == 0 1495 && fiveMsLateCount <= events.size() / 20 1496 && tenMsLateCount <= events.size() / 100); 1497 } 1498 } 1499 checkTimestampRelative(List<DirectReportSensorEvent> directEvents, List<DirectReportSensorEvent> pollEvents)1500 private void checkTimestampRelative(List<DirectReportSensorEvent> directEvents, 1501 List<DirectReportSensorEvent> pollEvents) { 1502 if (directEvents.size() < 10 || pollEvents.size() < 10) { 1503 // cannot check with so few data points 1504 return; 1505 } 1506 1507 long directAverageLatency = 0; 1508 for (DirectReportSensorEvent e : directEvents) { 1509 directAverageLatency += e.arrivalTs - e.ts; 1510 } 1511 directAverageLatency /= directEvents.size(); 1512 1513 long pollAverageLatency = 0; 1514 for (DirectReportSensorEvent e : pollEvents) { 1515 pollAverageLatency += e.arrivalTs - e.ts; 1516 } 1517 pollAverageLatency /= pollEvents.size(); 1518 1519 Log.d(TAG, String.format("Direct, poll latency = %f, %f ms", 1520 directAverageLatency / 1e6f, pollAverageLatency / 1e6f)); 1521 assertTrue( 1522 String.format("Direct, poll latency = %f, %f ms, expect direct < poll", 1523 directAverageLatency / 1e6f, 1524 pollAverageLatency / 1e6f), 1525 directAverageLatency < pollAverageLatency + 1000_000); 1526 } 1527 1528 private int[] calculateExpectedNEventsUs(int timeMs, int samplingPeriodUs) { 1529 int[] minMax = new int[2]; 1530 minMax[0] = Math.max((int) Math.floor( 1531 (timeMs - ALLOWED_SENSOR_INIT_TIME_MILLISEC) * 1000/ samplingPeriodUs), 0); 1532 minMax[1] = (int) Math.ceil(timeMs * 1000 * 2 / samplingPeriodUs); 1533 return minMax; 1534 } 1535 1536 private static class DirectReportSensorEvent { 1537 public int size; 1538 public int token; 1539 public int type; 1540 public long serial; 1541 public long ts; 1542 public float x; 1543 public float y; 1544 public float z; 1545 public long arrivalTs; 1546 }; 1547 1548 // EventPool to avoid allocating too many event objects and hitting GC during test 1549 private static class EventPool { 1550 public EventPool(int n) { 1551 mEvents = Arrays.asList(new DirectReportSensorEvent[n]); 1552 for (int i = 0; i < n; ++i) { 1553 mEvents.set(i, new DirectReportSensorEvent()); 1554 } 1555 reset(); 1556 } 1557 1558 public synchronized void reset() { 1559 Log.d(TAG, "Reset EventPool (" + mIndex + " events used)"); 1560 mIndex = 0; 1561 } 1562 1563 public synchronized DirectReportSensorEvent get() { 1564 if (mIndex < mEvents.size()) { 1565 return mEvents.get(mIndex++); 1566 } else { 1567 throw new IllegalStateException("EventPool depleted"); 1568 } 1569 } 1570 1571 private List<DirectReportSensorEvent> mEvents; 1572 private int mIndex; 1573 }; 1574 1575 private DirectReportSensorEvent getEvent() { 1576 return mEventPool.get(); 1577 } 1578 1579 private DirectReportSensorEvent getEvent(DirectReportSensorEvent e) { 1580 DirectReportSensorEvent event = mEventPool.get(); 1581 event.size = e.size; 1582 event.token = e.token; 1583 event.type = e.type; 1584 event.serial = e.serial; 1585 event.ts = e.ts; 1586 event.x = e.x; 1587 event.y = e.y; 1588 event.z = e.z; 1589 event.arrivalTs = e.arrivalTs; 1590 return event; 1591 } 1592 1593 private void resetEvent() { 1594 mEventPool.reset(); 1595 } 1596 1597 private class SensorEventCollection implements SensorEventListener { 1598 List<DirectReportSensorEvent> mEvents = new ArrayList<>(); 1599 Sensor mSensor; 1600 1601 public SensorEventCollection(Sensor s) { 1602 mSensor = s; 1603 } 1604 1605 List<DirectReportSensorEvent> getEvents() { 1606 return mEvents; 1607 } 1608 1609 @Override 1610 public void onSensorChanged(SensorEvent event) { 1611 if (mSensor == null || event.sensor == mSensor) { 1612 DirectReportSensorEvent e = mEventPool.get(); 1613 e.size = SENSORS_EVENT_SIZE; 1614 e.token = event.sensor.getType(); 1615 e.type = e.token; 1616 e.serial = -1; 1617 e.ts = event.timestamp; 1618 e.arrivalTs = SystemClock.elapsedRealtimeNanos(); 1619 1620 e.x = event.values[0]; 1621 if (event.values.length > 1) { 1622 e.y = event.values[1]; 1623 } 1624 if (event.values.length > 2) { 1625 e.z = event.values[2]; 1626 } 1627 mEvents.add(e); 1628 } 1629 } 1630 1631 @Override 1632 public void onAccuracyChanged(Sensor s, int accuracy) { 1633 // do nothing 1634 } 1635 }; 1636 1637 private List<DirectReportSensorEvent> parseEntireBuffer(byte[] buffer, int token) { 1638 int offset = 0; 1639 int nextSerial = 1; 1640 List<DirectReportSensorEvent> events = new ArrayList<>(); 1641 1642 while (offset <= SHARED_MEMORY_SIZE - SENSORS_EVENT_SIZE) { 1643 DirectReportSensorEvent e = getEvent(); 1644 parseSensorEvent(offset, e); 1645 1646 if (e.serial == 0) { 1647 // reaches end of events 1648 break; 1649 } 1650 1651 assertTrue("incorrect size " + e.size + " at offset " + offset, 1652 e.size == SENSORS_EVENT_SIZE); 1653 assertTrue("incorrect serial " + e.serial + " at offset " + offset, 1654 e.serial == nextSerial); 1655 1656 if (e.token == token) { 1657 events.add(e); 1658 } 1659 1660 ++nextSerial; 1661 offset += SENSORS_EVENT_SIZE; 1662 } 1663 1664 return events; 1665 } 1666 1667 // parse sensors_event_t from mBuffer and fill information into DirectReportSensorEvent 1668 private void parseSensorEvent(int offset, DirectReportSensorEvent ev) { 1669 mByteBuffer.position(offset); 1670 1671 ev.size = mByteBuffer.getInt(); 1672 ev.token = mByteBuffer.getInt(); 1673 ev.type = mByteBuffer.getInt(); 1674 ev.serial = ((long) mByteBuffer.getInt()) & 0xFFFFFFFFl; // signed=>unsigned 1675 ev.ts = mByteBuffer.getLong(); 1676 ev.arrivalTs = SystemClock.elapsedRealtimeNanos(); 1677 ev.x = mByteBuffer.getFloat(); 1678 ev.y = mByteBuffer.getFloat(); 1679 ev.z = mByteBuffer.getFloat(); 1680 } 1681 1682 // parse sensors_event_t and fill information into DirectReportSensorEvent 1683 private static void parseSensorEvent(byte [] buf, int offset, DirectReportSensorEvent ev) { 1684 ByteBuffer b = ByteBuffer.wrap(buf, offset, SENSORS_EVENT_SIZE); 1685 b.order(NATIVE_BYTE_ORDER); 1686 1687 ev.size = b.getInt(); 1688 ev.token = b.getInt(); 1689 ev.type = b.getInt(); 1690 ev.serial = ((long) b.getInt()) & 0xFFFFFFFFl; // signed=>unsigned 1691 ev.ts = b.getLong(); 1692 ev.arrivalTs = SystemClock.elapsedRealtimeNanos(); 1693 ev.x = b.getFloat(); 1694 ev.y = b.getFloat(); 1695 ev.z = b.getFloat(); 1696 } 1697 1698 private long readAtomicCounter(int offset) { 1699 mByteBuffer.position(offset + ATOMIC_COUNTER_OFFSET); 1700 return ((long) mByteBuffer.getInt()) & 0xFFFFFFFFl; // signed => unsigned 1701 } 1702 1703 private static long readAtomicCounter(byte [] buf, int offset) { 1704 ByteBuffer b = ByteBuffer.wrap(buf, offset + ATOMIC_COUNTER_OFFSET, ATOMIC_COUNTER_SIZE); 1705 b.order(ByteOrder.nativeOrder()); 1706 1707 return ((long) b.getInt()) & 0xFFFFFFFFl; // signed => unsigned 1708 } 1709 } 1710