OSDN Git Service

[sensors] Default implementation and vts of direct report
authorPeng Xu <pengxu@google.com>
Tue, 10 Jan 2017 03:12:42 +0000 (19:12 -0800)
committerPeng Xu <pengxu@google.com>
Wed, 18 Jan 2017 22:28:21 +0000 (14:28 -0800)
Added support for newly added HAL function for sensor event direct
report feature, replace dummy implementation with funtional ones for
the following:

  * registerDirectChannel
  * unregisterDirectChannel
  * configDirectReport

Added a vts test case for direct report.

Added new offset definition to types.hal. This will not affect
existing client/calling code.

Bug: 30985702
Bug: 32022776

Test: vts pass

Change-Id: Ie5e3cddd7c37664e8c59d69cf70aaa1310fd3f58

sensors/1.0/default/Sensors.cpp
sensors/1.0/default/convert.cpp
sensors/1.0/default/include/sensors/convert.h
sensors/1.0/types.hal
sensors/1.0/vts/functional/Android.bp
sensors/1.0/vts/functional/sensors_hidl_hal_test.cpp
sensors/1.0/vts/types.vts

index 8903397..aadf848 100644 (file)
@@ -42,10 +42,12 @@ static Result ResultFromStatus(status_t err) {
     switch (err) {
         case OK:
             return Result::OK;
-        case BAD_VALUE:
-            return Result::BAD_VALUE;
         case PERMISSION_DENIED:
             return Result::PERMISSION_DENIED;
+        case NO_MEMORY:
+            return Result::NO_MEMORY;
+        case BAD_VALUE:
+            return Result::BAD_VALUE;
         default:
             return Result::INVALID_OPERATION;
     }
@@ -226,27 +228,68 @@ Return<Result> Sensors::injectSensorData(const Event& event) {
 
 Return<void> Sensors::registerDirectChannel(
         const SharedMemInfo& mem, registerDirectChannel_cb _hidl_cb) {
-    //TODO(b/30985702): finish implementation
-    (void) mem;
-    _hidl_cb(Result::INVALID_OPERATION, -1);
+    if (mSensorDevice->register_direct_channel == nullptr
+            || mSensorDevice->config_direct_report == nullptr) {
+        // HAL does not support
+        _hidl_cb(Result::INVALID_OPERATION, -1);
+        return Void();
+    }
+
+    sensors_direct_mem_t m;
+    if (!convertFromSharedMemInfo(mem, &m)) {
+      _hidl_cb(Result::BAD_VALUE, -1);
+      return Void();
+    }
+
+    int err = mSensorDevice->register_direct_channel(mSensorDevice, &m, -1);
+
+    if (err < 0) {
+        _hidl_cb(ResultFromStatus(err), -1);
+    } else {
+        int32_t channelHandle = static_cast<int32_t>(err);
+        _hidl_cb(Result::OK, channelHandle);
+    }
     return Void();
 }
 
 Return<Result> Sensors::unregisterDirectChannel(int32_t channelHandle) {
-    //TODO(b/30985702): finish implementation
-    (void) channelHandle;
-    return Result::INVALID_OPERATION;
+    if (mSensorDevice->register_direct_channel == nullptr
+            || mSensorDevice->config_direct_report == nullptr) {
+        // HAL does not support
+        return Result::INVALID_OPERATION;
+    }
+
+    mSensorDevice->register_direct_channel(mSensorDevice, nullptr, channelHandle);
+
+    return Result::OK;
 }
 
 Return<void> Sensors::configDirectReport(
         int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
         configDirectReport_cb _hidl_cb) {
-    //TODO(b/30985702): finish implementation
-    (void) sensorHandle;
-    (void) channelHandle;
-    (void) rate;
+    if (mSensorDevice->register_direct_channel == nullptr
+            || mSensorDevice->config_direct_report == nullptr) {
+        // HAL does not support
+        _hidl_cb(Result::INVALID_OPERATION, -1);
+        return Void();
+    }
 
-    _hidl_cb(Result::INVALID_OPERATION, -1);
+    sensors_direct_cfg_t cfg = {
+        .rate_level = convertFromRateLevel(rate)
+    };
+    if (cfg.rate_level < 0) {
+        _hidl_cb(Result::BAD_VALUE, -1);
+        return Void();
+    }
+
+    int err = mSensorDevice->config_direct_report(mSensorDevice,
+            sensorHandle, channelHandle, &cfg);
+
+    if (rate == RateLevel::STOP) {
+        _hidl_cb(ResultFromStatus(err), -1);
+    } else {
+        _hidl_cb(err > 0 ? Result::OK : ResultFromStatus(err), err);
+    }
     return Void();
 }
 
index 6735e96..acff6ca 100644 (file)
@@ -340,6 +340,50 @@ void convertToSensorEvent(const Event &src, sensors_event_t *dst) {
     }
 }
 
+bool convertFromSharedMemInfo(const SharedMemInfo& memIn, sensors_direct_mem_t *memOut) {
+    if (memOut == nullptr) {
+        return false;
+    }
+
+    switch(memIn.type) {
+        case SharedMemType::ASHMEM:
+            memOut->type = SENSOR_DIRECT_MEM_TYPE_ASHMEM;
+            break;
+        case SharedMemType::GRALLOC:
+            memOut->type = SENSOR_DIRECT_MEM_TYPE_GRALLOC;
+            break;
+        default:
+            return false;
+    }
+
+    switch(memIn.format) {
+        case SharedMemFormat::SENSORS_EVENT:
+            memOut->format = SENSOR_DIRECT_FMT_SENSORS_EVENT;
+            break;
+        default:
+            return false;
+    }
+
+    memOut->size = memIn.size;
+    memOut->handle = memIn.memoryHandle;
+    return true;
+}
+
+int convertFromRateLevel(RateLevel rate) {
+    switch(rate) {
+        case RateLevel::STOP:
+            return SENSOR_DIRECT_RATE_STOP;
+        case RateLevel::NORMAL:
+            return SENSOR_DIRECT_RATE_NORMAL;
+        case RateLevel::FAST:
+            return SENSOR_DIRECT_RATE_FAST;
+        case RateLevel::VERY_FAST:
+            return SENSOR_DIRECT_RATE_VERY_FAST;
+        default:
+            return -1;
+    }
+}
+
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace sensors
index d289a81..c3a0125 100644 (file)
@@ -33,6 +33,9 @@ void convertToSensor(const SensorInfo &src, sensor_t *dst);
 void convertFromSensorEvent(const sensors_event_t &src, Event *dst);
 void convertToSensorEvent(const Event &src, sensors_event_t *dst);
 
+bool convertFromSharedMemInfo(const SharedMemInfo& memIn, sensors_direct_mem_t *memOut);
+int convertFromRateLevel(RateLevel rate);
+
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace sensors
index c8c8dfc..552c997 100644 (file)
@@ -1224,23 +1224,32 @@ enum SharedMemType : int32_t {
 @export(name="direct_format_t", value_prefix="SENSOR_DIRECT_FMT_")
 enum SharedMemFormat : int32_t {
     SENSORS_EVENT = 1,  // shared memory is formated as an array of data
-                        // elements, each sized 104 bytes. Details of fields:
-                        //
-                        // offset   type        name
-                        //-----------------------------------
-                        // 0x0000   int32_t     size (always 104)
-                        // 0x0004   int32_t     sensor report token
-                        // 0x0008   int32_t     type (see SensorType)
-                        // 0x000C   int32_t     atomic counter
-                        // 0x0010   int64_t     timestamp (see Event)
-                        // 0x0014   float[16]/  data
-                        //          int64_t[8]
-                        // 0x0058   int32_t[4]  reserved
-                        //
+                        // elements. See SensorsEventFormatOffset for details.
                         // Upon return of channel registration call, the
                         // shared memory space must be formated to all 0 by HAL.
 };
 
+enum SensorsEventFormatOffset : uint16_t {
+    // offset   type        name
+    //-----------------------------------
+    // 0x0000   int32_t     size (always 104)
+    // 0x0004   int32_t     sensor report token
+    // 0x0008   int32_t     type (see SensorType)
+    // 0x000C   uint32_t    atomic counter
+    // 0x0010   int64_t     timestamp (see Event)
+    // 0x0018   float[16]/  data
+    //          int64_t[8]
+    // 0x0058   int32_t[4]  reserved (set to zero)
+    SIZE_FIELD      = 0x0,
+    REPORT_TOKEN    = 0x4,
+    SENSOR_TYPE     = 0x8,
+    ATOMIC_COUNTER  = 0xC,
+    TIMESTAMP       = 0x10,
+    DATA            = 0x18,
+    RESERVED        = 0x58,
+    TOTAL_LENGTH    = 0x68
+};
+
 /**
  * Shared memory information for a direct channel
  */
index 675484a..9ca6230 100644 (file)
@@ -19,10 +19,11 @@ cc_test {
     gtest: true,
     srcs: ["sensors_hidl_hal_test.cpp"],
     shared_libs: [
-        "liblog",
+        "android.hardware.sensors@1.0",
+        "libcutils",
         "libhidlbase",
+        "liblog",
         "libutils",
-        "android.hardware.sensors@1.0",
     ],
     static_libs: ["libgtest"],
     cflags: [
index 2edc5c3..c7600f3 100644 (file)
 #include <android/hardware/sensors/1.0/ISensors.h>
 #include <android/hardware/sensors/1.0/types.h>
 #include <android/log.h>
+#include <cutils/ashmem.h>
 #include <gtest/gtest.h>
 #include <hardware/sensors.h>       // for sensor type strings
 
 #include <algorithm>
 #include <cinttypes>
 #include <cmath>
+#include <memory>
 #include <mutex>
 #include <thread>
+#include <unordered_set>
 #include <vector>
 
+#include <sys/mman.h>
 #include <unistd.h>
 
 using ::android::hardware::Return;
@@ -148,6 +152,164 @@ void SensorsHidlEnvironment::pollingThread(
   ALOGD("polling thread end");
 }
 
+class SensorsTestSharedMemory {
+ public:
+  static SensorsTestSharedMemory* create(SharedMemType type, size_t size);
+  SharedMemInfo getSharedMemInfo() const;
+  char * getBuffer() const;
+  std::vector<Event> parseEvents(int64_t lastCounter = -1, size_t offset = 0) const;
+  virtual ~SensorsTestSharedMemory();
+ private:
+  SensorsTestSharedMemory(SharedMemType type, size_t size);
+
+  SharedMemType mType;
+  native_handle_t* mNativeHandle;
+  size_t mSize;
+  char* mBuffer;
+
+  DISALLOW_COPY_AND_ASSIGN(SensorsTestSharedMemory);
+};
+
+SharedMemInfo SensorsTestSharedMemory::getSharedMemInfo() const {
+  SharedMemInfo mem = {
+    .type = mType,
+    .format = SharedMemFormat::SENSORS_EVENT,
+    .size = static_cast<uint32_t>(mSize),
+    .memoryHandle = mNativeHandle
+  };
+  return mem;
+}
+
+char * SensorsTestSharedMemory::getBuffer() const {
+  return mBuffer;
+}
+
+std::vector<Event> SensorsTestSharedMemory::parseEvents(int64_t lastCounter, size_t offset) const {
+
+  constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH);
+  constexpr size_t kOffsetSize = static_cast<size_t>(SensorsEventFormatOffset::SIZE_FIELD);
+  constexpr size_t kOffsetToken = static_cast<size_t>(SensorsEventFormatOffset::REPORT_TOKEN);
+  constexpr size_t kOffsetType = static_cast<size_t>(SensorsEventFormatOffset::SENSOR_TYPE);
+  constexpr size_t kOffsetAtomicCounter =
+      static_cast<size_t>(SensorsEventFormatOffset::ATOMIC_COUNTER);
+  constexpr size_t kOffsetTimestamp = static_cast<size_t>(SensorsEventFormatOffset::TIMESTAMP);
+  constexpr size_t kOffsetData = static_cast<size_t>(SensorsEventFormatOffset::DATA);
+
+  std::vector<Event> events;
+  std::vector<float> data(16);
+
+  while (offset + kEventSize <= mSize) {
+    int64_t atomicCounter = *reinterpret_cast<uint32_t *>(mBuffer + offset + kOffsetAtomicCounter);
+    if (atomicCounter <= lastCounter) {
+      break;
+    }
+
+    int32_t size = *reinterpret_cast<int32_t *>(mBuffer + offset + kOffsetSize);
+    if (size != kEventSize) {
+      // unknown error, events parsed may be wrong, remove all
+      events.clear();
+      break;
+    }
+
+    int32_t token = *reinterpret_cast<int32_t *>(mBuffer + offset + kOffsetToken);
+    int32_t type = *reinterpret_cast<int32_t *>(mBuffer + offset + kOffsetType);
+    int64_t timestamp = *reinterpret_cast<int64_t *>(mBuffer + offset + kOffsetTimestamp);
+
+    ALOGV("offset = %zu, cnt %" PRId32 ", token %" PRId32 ", type %" PRId32 ", timestamp %" PRId64,
+        offset, atomicCounter, token, type, timestamp);
+
+    Event event = {
+      .timestamp = timestamp,
+      .sensorHandle = token,
+      .sensorType = static_cast<SensorType>(type),
+    };
+    event.u.data = android::hardware::hidl_array<float, 16>
+        (reinterpret_cast<float*>(mBuffer + offset + kOffsetData));
+
+    events.push_back(event);
+
+    lastCounter = atomicCounter;
+    offset += kEventSize;
+  }
+
+  return events;
+}
+
+SensorsTestSharedMemory::SensorsTestSharedMemory(SharedMemType type, size_t size)
+    : mType(type), mSize(0), mBuffer(nullptr) {
+  native_handle_t *handle = nullptr;
+  char *buffer = nullptr;
+  switch(type) {
+    case SharedMemType::ASHMEM: {
+      int fd;
+      handle = ::native_handle_create(1 /*nFds*/, 0/*nInts*/);
+      if (handle != nullptr) {
+        handle->data[0] = fd = ::ashmem_create_region("SensorsTestSharedMemory", size);
+        if (handle->data[0] > 0) {
+          // memory is pinned by default
+          buffer = static_cast<char *>
+              (::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
+          if (buffer != reinterpret_cast<char*>(MAP_FAILED)) {
+            break;
+          }
+          ::native_handle_close(handle);
+        }
+        ::native_handle_delete(handle);
+        handle = nullptr;
+      }
+      break;
+    }
+    default:
+      break;
+  }
+
+  if (buffer != nullptr) {
+    mNativeHandle = handle;
+    mSize = size;
+    mBuffer = buffer;
+  }
+}
+
+SensorsTestSharedMemory::~SensorsTestSharedMemory() {
+  switch(mType) {
+    case SharedMemType::ASHMEM: {
+      if (mSize != 0) {
+        ::munmap(mBuffer, mSize);
+        mBuffer = nullptr;
+
+        ::native_handle_close(mNativeHandle);
+        ::native_handle_delete(mNativeHandle);
+
+        mNativeHandle = nullptr;
+        mSize = 0;
+      }
+      break;
+    }
+    default: {
+      if (mNativeHandle != nullptr || mSize != 0 || mBuffer != nullptr) {
+        ALOGE("SensorsTestSharedMemory %p not properly destructed: "
+            "type %d, native handle %p, size %zu, buffer %p",
+            this, static_cast<int>(mType), mNativeHandle, mSize, mBuffer);
+      }
+      break;
+    }
+  }
+}
+
+SensorsTestSharedMemory* SensorsTestSharedMemory::create(SharedMemType type, size_t size) {
+  constexpr size_t kMaxSize = 128*1024*1024; // sensor test should not need more than 128M
+  if (size == 0 || size >= kMaxSize) {
+    return nullptr;
+  }
+
+  auto m = new SensorsTestSharedMemory(type, size);
+  if (m->mSize != size || m->mBuffer == nullptr) {
+    delete m;
+    m = nullptr;
+  }
+  return m;
+}
+
 // The main test class for SENSORS HIDL HAL.
 class SensorsHidlTest : public ::testing::Test {
  public:
@@ -155,51 +317,65 @@ class SensorsHidlTest : public ::testing::Test {
   }
 
   virtual void TearDown() override {
+    // stop all sensors
+    for (auto s : mSensorHandles) {
+      S()->activate(s, false);
+    }
+    mSensorHandles.clear();
+
+    // stop all direct report and channels
+    for (auto c : mDirectChannelHandles) {
+      // disable all reports
+      S()->configDirectReport(-1, c, RateLevel::STOP, [] (auto, auto){});
+      S()->unregisterDirectChannel(c);
+    }
+    mDirectChannelHandles.clear();
   }
 
  protected:
-  inline sp<ISensors>& S() {
-    return SensorsHidlEnvironment::Instance()->sensors;
+  SensorInfo defaultSensorByType(SensorType type);
+  std::vector<Event> collectEvents(useconds_t timeLimitUs, size_t nEventLimit,
+        bool clearBeforeStart = true, bool changeCollection = true);
+
+  // implementation wrapper
+  Return<void> getSensorsList(ISensors::getSensorsList_cb _hidl_cb) {
+    return S()->getSensorsList(_hidl_cb);
   }
 
-  std::vector<Event> collectEvents(useconds_t timeLimitUs, size_t nEventLimit,
-                                   bool clearBeforeStart = true,
-                                   bool changeCollection = true) {
-    std::vector<Event> events;
-    constexpr useconds_t SLEEP_GRANULARITY = 100*1000; //gradularity 100 ms
+  Return<Result> activate(
+          int32_t sensorHandle, bool enabled);
 
-    ALOGI("collect max of %zu events for %d us, clearBeforeStart %d",
-          nEventLimit, timeLimitUs, clearBeforeStart);
+  Return<Result> batch(
+          int32_t sensorHandle,
+          int64_t samplingPeriodNs,
+          int64_t maxReportLatencyNs) {
+    return S()->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs);
+  }
 
-    if (changeCollection) {
-      SensorsHidlEnvironment::Instance()->setCollection(true);
-    }
-    if (clearBeforeStart) {
-      SensorsHidlEnvironment::Instance()->catEvents(nullptr);
-    }
+  Return<Result> flush(int32_t sensorHandle) {
+    return S()->flush(sensorHandle);
+  }
 
-    while (timeLimitUs > 0) {
-      useconds_t duration = std::min(SLEEP_GRANULARITY, timeLimitUs);
-      usleep(duration);
-      timeLimitUs -= duration;
+  Return<Result> injectSensorData(const Event& event) {
+    return S()->injectSensorData(event);
+  }
 
-      SensorsHidlEnvironment::Instance()->catEvents(&events);
-      if (events.size() >= nEventLimit) {
-        break;
-      }
-      ALOGV("time to go = %d, events to go = %d",
-            (int)timeLimitUs, (int)(nEventLimit - events.size()));
-    }
+  Return<void> registerDirectChannel(
+          const SharedMemInfo& mem, ISensors::registerDirectChannel_cb _hidl_cb);
 
-    if (changeCollection) {
-      SensorsHidlEnvironment::Instance()->setCollection(false);
-    }
-    return events;
+  Return<Result> unregisterDirectChannel(int32_t channelHandle) {
+    return S()->unregisterDirectChannel(channelHandle);
   }
 
-  static bool typeMatchStringType(SensorType type, const hidl_string& stringType);
-  static bool typeMatchReportMode(SensorType type, SensorFlagBits reportMode);
-  static bool delayMatchReportMode(int32_t minDelay, int32_t maxDelay, SensorFlagBits reportMode);
+  Return<void> configDirectReport(
+          int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
+          ISensors::configDirectReport_cb _hidl_cb) {
+    return S()->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb);
+  }
+
+  inline sp<ISensors>& S() {
+    return SensorsHidlEnvironment::Instance()->sensors;
+  }
 
   inline static SensorFlagBits extractReportMode(uint64_t flag) {
     return (SensorFlagBits) (flag
@@ -219,10 +395,77 @@ class SensorsHidlTest : public ::testing::Test {
     return (int32_t) type > 0;
   }
 
+  static bool typeMatchStringType(SensorType type, const hidl_string& stringType);
+  static bool typeMatchReportMode(SensorType type, SensorFlagBits reportMode);
+  static bool delayMatchReportMode(int32_t minDelay, int32_t maxDelay, SensorFlagBits reportMode);
   static SensorFlagBits expectedReportModeForType(SensorType type);
-  SensorInfo defaultSensorByType(SensorType type);
+
+  // all sensors and direct channnels used
+  std::unordered_set<int32_t> mSensorHandles;
+  std::unordered_set<int32_t> mDirectChannelHandles;
 };
 
+
+Return<Result> SensorsHidlTest::activate(int32_t sensorHandle, bool enabled) {
+  // If activating a sensor, add the handle in a set so that when test fails it can be turned off.
+  // The handle is not removed when it is deactivating on purpose so that it is not necessary to
+  // check the return value of deactivation. Deactivating a sensor more than once does not have
+  // negative effect.
+  if (enabled) {
+    mSensorHandles.insert(sensorHandle);
+  }
+  return S()->activate(sensorHandle, enabled);
+}
+
+Return<void> SensorsHidlTest::registerDirectChannel(
+    const SharedMemInfo& mem, ISensors::registerDirectChannel_cb cb) {
+  // If registeration of a channel succeeds, add the handle of channel to a set so that it can be
+  // unregistered when test fails. Unregister a channel does not remove the handle on purpose.
+  // Unregistering a channel more than once should not have negative effect.
+  S()->registerDirectChannel(mem,
+      [&] (auto result, auto channelHandle) {
+        if (result == Result::OK) {
+          mDirectChannelHandles.insert(channelHandle);
+        }
+        cb(result, channelHandle);
+      });
+  return Void();
+}
+
+std::vector<Event> SensorsHidlTest::collectEvents(useconds_t timeLimitUs, size_t nEventLimit,
+      bool clearBeforeStart, bool changeCollection) {
+  std::vector<Event> events;
+  constexpr useconds_t SLEEP_GRANULARITY = 100*1000; //gradularity 100 ms
+
+  ALOGI("collect max of %zu events for %d us, clearBeforeStart %d",
+        nEventLimit, timeLimitUs, clearBeforeStart);
+
+  if (changeCollection) {
+    SensorsHidlEnvironment::Instance()->setCollection(true);
+  }
+  if (clearBeforeStart) {
+    SensorsHidlEnvironment::Instance()->catEvents(nullptr);
+  }
+
+  while (timeLimitUs > 0) {
+    useconds_t duration = std::min(SLEEP_GRANULARITY, timeLimitUs);
+    usleep(duration);
+    timeLimitUs -= duration;
+
+    SensorsHidlEnvironment::Instance()->catEvents(&events);
+    if (events.size() >= nEventLimit) {
+      break;
+    }
+    ALOGV("time to go = %d, events to go = %d",
+          (int)timeLimitUs, (int)(nEventLimit - events.size()));
+  }
+
+  if (changeCollection) {
+    SensorsHidlEnvironment::Instance()->setCollection(false);
+  }
+  return events;
+}
+
 bool SensorsHidlTest::typeMatchStringType(SensorType type, const hidl_string& stringType) {
 
   if (type >= SensorType::DEVICE_PRIVATE_BASE) {
@@ -303,6 +546,7 @@ bool SensorsHidlTest::delayMatchReportMode(
       break;
     case SensorFlagBits::SPECIAL_REPORTING_MODE:
       res = (minDelay == 0) && (maxDelay == 0);
+      break;
     default:
       res = false;
   }
@@ -439,10 +683,10 @@ TEST_F(SensorsHidlTest, NormalAccelerometerStreamingOperation) {
 
   int32_t handle = sensor.sensorHandle;
 
-  S()->batch(handle, samplingPeriodInNs, batchingPeriodInNs);
-  S()->activate(handle, 1);
+  ASSERT_EQ(batch(handle, samplingPeriodInNs, batchingPeriodInNs), Result::OK);
+  ASSERT_EQ(activate(handle, 1), Result::OK);
   events = collectEvents(minTimeUs, minNEvent, true /*clearBeforeStart*/);
-  S()->activate(handle, 0);
+  ASSERT_EQ(activate(handle, 0), Result::OK);
 
   ALOGI("Collected %zu samples", events.size());
 
@@ -475,7 +719,6 @@ TEST_F(SensorsHidlTest, NormalAccelerometerStreamingOperation) {
 
 // Test if sensor hal can do gyroscope streaming properly
 TEST_F(SensorsHidlTest, NormalGyroscopeStreamingOperation) {
-
   std::vector<Event> events;
 
   constexpr int64_t samplingPeriodInNs = 10ull*1000*1000; // 10ms
@@ -493,10 +736,10 @@ TEST_F(SensorsHidlTest, NormalGyroscopeStreamingOperation) {
 
   int32_t handle = sensor.sensorHandle;
 
-  S()->batch(handle, samplingPeriodInNs, batchingPeriodInNs);
-  S()->activate(handle, 1);
+  ASSERT_EQ(batch(handle, samplingPeriodInNs, batchingPeriodInNs), Result::OK);
+  ASSERT_EQ(activate(handle, 1), Result::OK);
   events = collectEvents(minTimeUs, minNEvent, true /*clearBeforeStart*/);
-  S()->activate(handle, 0);
+  ASSERT_EQ(activate(handle, 0), Result::OK);
 
   ALOGI("Collected %zu samples", events.size());
 
@@ -529,7 +772,6 @@ TEST_F(SensorsHidlTest, NormalGyroscopeStreamingOperation) {
 
 // Test if sensor hal can do accelerometer sampling rate switch properly when sensor is active
 TEST_F(SensorsHidlTest, AccelerometerSamplingPeriodHotSwitchOperation) {
-
   std::vector<Event> events1, events2;
 
   constexpr int64_t batchingPeriodInNs = 0; // no batching
@@ -553,18 +795,18 @@ TEST_F(SensorsHidlTest, AccelerometerSamplingPeriodHotSwitchOperation) {
     return;
   }
 
-  S()->batch(handle, minSamplingPeriodInNs, batchingPeriodInNs);
-  S()->activate(handle, 1);
+  ASSERT_EQ(batch(handle, minSamplingPeriodInNs, batchingPeriodInNs), Result::OK);
+  ASSERT_EQ(activate(handle, 1), Result::OK);
 
   usleep(500000); // sleep 0.5 sec to wait for change rate to happen
   events1 = collectEvents(sensor.minDelay * minNEvent, minNEvent, true /*clearBeforeStart*/);
 
-  S()->batch(handle, maxSamplingPeriodInNs, batchingPeriodInNs);
+  ASSERT_EQ(batch(handle, maxSamplingPeriodInNs, batchingPeriodInNs), Result::OK);
 
   usleep(500000); // sleep 0.5 sec to wait for change rate to happen
   events2 = collectEvents(sensor.maxDelay * minNEvent, minNEvent, true /*clearBeforeStart*/);
 
-  S()->activate(handle, 0);
+  ASSERT_EQ(activate(handle, 0), Result::OK);
 
   ALOGI("Collected %zu fast samples and %zu slow samples", events1.size(), events2.size());
 
@@ -616,7 +858,6 @@ TEST_F(SensorsHidlTest, AccelerometerSamplingPeriodHotSwitchOperation) {
 
 // Test if sensor hal can do normal accelerometer batching properly
 TEST_F(SensorsHidlTest, AccelerometerBatchingOperation) {
-
   std::vector<Event> events;
 
   constexpr int64_t oneSecondInNs = 1ull * 1000 * 1000 * 1000;
@@ -649,18 +890,17 @@ TEST_F(SensorsHidlTest, AccelerometerBatchingOperation) {
   int64_t allowedBatchDeliverTimeNs =
       std::max(oneSecondInNs, batchingPeriodInNs / 10);
 
-  S()->batch(handle, minSamplingPeriodInNs, INT64_MAX);
-  S()->activate(handle, 1);
+  ASSERT_EQ(batch(handle, minSamplingPeriodInNs, INT64_MAX), Result::OK);
+  ASSERT_EQ(activate(handle, 1), Result::OK);
 
   usleep(500000); // sleep 0.5 sec to wait for initialization
-  S()->flush(handle);
+  ASSERT_EQ(flush(handle), Result::OK);
 
   // wait for 80% of the reserved batching period
   // there should not be any significant amount of events
   // since collection is not enabled all events will go down the drain
   usleep(batchingPeriodInNs / 1000 * 8 / 10);
 
-
   SensorsHidlEnvironment::Instance()->setCollection(true);
   // 0.8 + 0.3 times the batching period
   // plus some time for the event to deliver
@@ -668,13 +908,13 @@ TEST_F(SensorsHidlTest, AccelerometerBatchingOperation) {
       batchingPeriodInNs / 1000 * 3 / 10,
         minFifoCount, true /*clearBeforeStart*/, false /*change collection*/);
 
-  S()->flush(handle);
+  ASSERT_EQ(flush(handle), Result::OK);
 
   events = collectEvents(allowedBatchDeliverTimeNs / 1000,
         minFifoCount, true /*clearBeforeStart*/, false /*change collection*/);
 
   SensorsHidlEnvironment::Instance()->setCollection(false);
-  S()->activate(handle, 0);
+  ASSERT_EQ(activate(handle, 0), Result::OK);
 
   size_t nEvent = 0;
   for (auto & e : events) {
@@ -687,6 +927,79 @@ TEST_F(SensorsHidlTest, AccelerometerBatchingOperation) {
   ASSERT_GT(nEvent, (size_t)(batchingPeriodInNs / minSamplingPeriodInNs * 9 / 10));
 }
 
+// Test sensor event direct report with ashmem for gyro sensor
+TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReport) {
+
+  constexpr SensorType type = SensorType::GYROSCOPE;
+  constexpr size_t kEventSize = 104;
+  constexpr size_t kNEvent = 500;
+  constexpr size_t kMemSize = kEventSize * kNEvent;
+
+  SensorInfo sensor = defaultSensorByType(type);
+
+  if (!(sensor.flags | SensorFlagBits::MASK_DIRECT_REPORT)
+      || !(sensor.flags | SensorFlagBits::DIRECT_CHANNEL_ASHMEM)) {
+    // does not declare support
+    return;
+  }
+
+  std::unique_ptr<SensorsTestSharedMemory>
+      mem(SensorsTestSharedMemory::create(SharedMemType::ASHMEM, kMemSize));
+  ASSERT_NE(mem, nullptr);
+
+  char* buffer = mem->getBuffer();
+  // fill memory with data
+  for (size_t i = 0; i < kMemSize; ++i) {
+    buffer[i] = '\xcc';
+  }
+
+  int32_t channelHandle;
+  registerDirectChannel(mem->getSharedMemInfo(),
+      [&channelHandle] (auto result, auto channelHandle_) {
+          ASSERT_EQ(result, Result::OK);
+          channelHandle = channelHandle_;
+      });
+
+  // check memory is zeroed
+  for (size_t i = 0; i < kMemSize; ++i) {
+    ASSERT_EQ(buffer[i], '\0');
+  }
+
+  int32_t eventToken;
+  configDirectReport(sensor.sensorHandle, channelHandle, RateLevel::NORMAL,
+      [&eventToken] (auto result, auto token) {
+          ASSERT_EQ(result, Result::OK);
+          eventToken = token;
+      });
+
+  usleep(1500000); // sleep 1 sec for data, plus 0.5 sec for initialization
+  auto events = mem->parseEvents();
+
+  // allowed to be 55% of nominal freq (50Hz)
+  ASSERT_GT(events.size(), 50 / 2);
+  ASSERT_LT(events.size(), static_cast<size_t>(110*1.5));
+
+  int64_t lastTimestamp = 0;
+  for (auto &e : events) {
+    ASSERT_EQ(e.sensorType, type);
+    ASSERT_EQ(e.sensorHandle, eventToken);
+    ASSERT_GT(e.timestamp, lastTimestamp);
+
+    Vec3 gyro = e.u.vec3;
+    double gyroNorm = std::sqrt(gyro.x * gyro.x + gyro.y * gyro.y + gyro.z * gyro.z);
+    // assert not drifting
+    ASSERT_TRUE(gyroNorm < 0.1);  // < ~5 degree/sa
+
+    lastTimestamp = e.timestamp;
+  }
+
+  // stop sensor and unregister channel
+  configDirectReport(sensor.sensorHandle, channelHandle, RateLevel::STOP,
+        [&eventToken] (auto result, auto) {
+            ASSERT_EQ(result, Result::OK);
+        });
+  ASSERT_EQ(unregisterDirectChannel(channelHandle), Result::OK);
+}
 
 int main(int argc, char **argv) {
   ::testing::AddGlobalTestEnvironment(SensorsHidlEnvironment::Instance());
@@ -695,4 +1008,4 @@ int main(int argc, char **argv) {
   ALOGI("Test result = %d", status);
   return status;
 }
-
+// vim: set ts=2 sw=2
index 2980507..1b48916 100644 (file)
@@ -374,10 +374,7 @@ attribute: {
     struct_value: {
         name: "flags"
         type: TYPE_MASK
-        enum_value: {
-            type: TYPE_ENUM
-            predefined_type: "::android::hardware::sensors::V1_0::SensorFlagBits"
-        }
+        predefined_type: "::android::hardware::sensors::V1_0::SensorFlagBits"
     }
 }
 
@@ -615,6 +612,26 @@ attribute: {
         scalar_value: {
             uint32_t: 131077
         }
+        enumerator: "AINFO_LOCAL_GEOMAGNETIC_FIELD"
+        scalar_value: {
+            uint32_t: 196608
+        }
+        enumerator: "AINFO_LOCAL_GRAVITY"
+        scalar_value: {
+            uint32_t: 196609
+        }
+        enumerator: "AINFO_DOCK_STATE"
+        scalar_value: {
+            uint32_t: 196610
+        }
+        enumerator: "AINFO_HIGH_PERFORMANCE_MODE"
+        scalar_value: {
+            uint32_t: 196611
+        }
+        enumerator: "AINFO_MAGNETIC_FIELD_CALIBRATION"
+        scalar_value: {
+            uint32_t: 196612
+        }
         enumerator: "AINFO_CUSTOM_START"
         scalar_value: {
             uint32_t: 268435456
@@ -817,6 +834,47 @@ attribute: {
 }
 
 attribute: {
+    name: "::android::hardware::sensors::V1_0::SensorsEventFormatOffset"
+    type: TYPE_ENUM
+    enum_value: {
+        scalar_type: "uint16_t"
+
+        enumerator: "SIZE_FIELD"
+        scalar_value: {
+            uint16_t: 0
+        }
+        enumerator: "REPORT_TOKEN"
+        scalar_value: {
+            uint16_t: 4
+        }
+        enumerator: "SENSOR_TYPE"
+        scalar_value: {
+            uint16_t: 8
+        }
+        enumerator: "ATOMIC_COUNTER"
+        scalar_value: {
+            uint16_t: 12
+        }
+        enumerator: "TIMESTAMP"
+        scalar_value: {
+            uint16_t: 16
+        }
+        enumerator: "DATA"
+        scalar_value: {
+            uint16_t: 24
+        }
+        enumerator: "RESERVED"
+        scalar_value: {
+            uint16_t: 88
+        }
+        enumerator: "TOTAL_LENGTH"
+        scalar_value: {
+            uint16_t: 104
+        }
+    }
+}
+
+attribute: {
     name: "::android::hardware::sensors::V1_0::SharedMemInfo"
     type: TYPE_STRUCT
     struct_value: {