Fix sensor uuid, retrofit recent event logger

Fix an issue that causes uuid field not being initialzed in
sensorservice.

MostRecentEventLogger in sensorservice is migrated to use RingBuffer
instead of a custom circular buffer. This is expected to improve
readability and maintainability of code.

Dumpsys print format is retouched to offer more information in easier
to read format.

Bug: 28305085

Change-Id: I190e43350b60a22a9fccb92a95d6eab06a471560
diff --git a/include/gui/Sensor.h b/include/gui/Sensor.h
index 353003c..3f60741 100644
--- a/include/gui/Sensor.h
+++ b/include/gui/Sensor.h
@@ -52,12 +52,18 @@
         TYPE_PROXIMITY      = ASENSOR_TYPE_PROXIMITY
     };
 
-    typedef struct {
-        uint8_t b[16];
-    } uuid_t;
+    struct uuid_t{
+        union {
+            uint8_t b[16];
+            int64_t i64[2];
+        };
+        uuid_t(const uint8_t (&uuid)[16]) { memcpy(b, uuid, sizeof(b));}
+        uuid_t() : b{0} {}
+    };
 
     Sensor(const char * name = "");
     Sensor(struct sensor_t const* hwSensor, int halVersion = 0);
+    Sensor(struct sensor_t const& hwSensor, const uuid_t& uuid, int halVersion = 0);
     ~Sensor();
 
     const String8& getName() const;
@@ -81,6 +87,7 @@
     uint32_t getFlags() const;
     bool isWakeUpSensor() const;
     bool isDynamicSensor() const;
+    bool hasAdditionalInfo() const;
     int32_t getReportingMode() const;
     const uuid_t& getUuid() const;
 
diff --git a/libs/gui/Sensor.cpp b/libs/gui/Sensor.cpp
index 0340d6b..cc865d1 100644
--- a/libs/gui/Sensor.cpp
+++ b/libs/gui/Sensor.cpp
@@ -14,69 +14,70 @@
  * limitations under the License.
  */
 
+
+#include <binder/AppOpsManager.h>
+#include <binder/IServiceManager.h>
+#include <gui/Sensor.h>
+#include <hardware/sensors.h>
+#include <log/log.h>
+#include <utils/Errors.h>
+#include <utils/String8.h>
+#include <utils/Flattenable.h>
+
 #include <inttypes.h>
 #include <stdint.h>
 #include <sys/types.h>
 #include <sys/limits.h>
 
-#include <utils/Errors.h>
-#include <utils/String8.h>
-#include <utils/Flattenable.h>
-
-#include <hardware/sensors.h>
-
-#include <binder/AppOpsManager.h>
-#include <binder/IServiceManager.h>
-
-#include <gui/Sensor.h>
-#include <log/log.h>
-
 // ----------------------------------------------------------------------------
 namespace android {
 // ----------------------------------------------------------------------------
 
-Sensor::Sensor(const char * name)
-    : mName(name), mHandle(0), mType(0),
-      mMinValue(0), mMaxValue(0), mResolution(0),
-      mPower(0), mMinDelay(0), mVersion(0), mFifoReservedEventCount(0),
-      mFifoMaxEventCount(0), mRequiredAppOp(0),
-      mMaxDelay(0), mFlags(0)
-{
+Sensor::Sensor(const char * name) :
+        mName(name), mHandle(0), mType(0),
+        mMinValue(0), mMaxValue(0), mResolution(0),
+        mPower(0), mMinDelay(0), mVersion(0), mFifoReservedEventCount(0),
+        mFifoMaxEventCount(0), mRequiredAppOp(0),
+        mMaxDelay(0), mFlags(0) {
 }
 
-Sensor::Sensor(struct sensor_t const* hwSensor, int halVersion)
-{
-    mName = hwSensor->name;
-    mVendor = hwSensor->vendor;
-    mVersion = hwSensor->version;
-    mHandle = hwSensor->handle;
-    mType = hwSensor->type;
+Sensor::Sensor(struct sensor_t const* hwSensor, int halVersion) :
+        Sensor(*hwSensor, uuid_t(), halVersion) {
+}
+
+Sensor::Sensor(struct sensor_t const& hwSensor, const uuid_t& uuid, int halVersion) {
+    mName = hwSensor.name;
+    mVendor = hwSensor.vendor;
+    mVersion = hwSensor.version;
+    mHandle = hwSensor.handle;
+    mType = hwSensor.type;
     mMinValue = 0;                      // FIXME: minValue
-    mMaxValue = hwSensor->maxRange;     // FIXME: maxValue
-    mResolution = hwSensor->resolution;
-    mPower = hwSensor->power;
-    mMinDelay = hwSensor->minDelay;
+    mMaxValue = hwSensor.maxRange;     // FIXME: maxValue
+    mResolution = hwSensor.resolution;
+    mPower = hwSensor.power;
+    mMinDelay = hwSensor.minDelay;
     mFlags = 0;
+    mUuid = uuid;
 
     // Set fifo event count zero for older devices which do not support batching. Fused
     // sensors also have their fifo counts set to zero.
     if (halVersion > SENSORS_DEVICE_API_VERSION_1_0) {
-        mFifoReservedEventCount = hwSensor->fifoReservedEventCount;
-        mFifoMaxEventCount = hwSensor->fifoMaxEventCount;
+        mFifoReservedEventCount = hwSensor.fifoReservedEventCount;
+        mFifoMaxEventCount = hwSensor.fifoMaxEventCount;
     } else {
         mFifoReservedEventCount = 0;
         mFifoMaxEventCount = 0;
     }
 
     if (halVersion >= SENSORS_DEVICE_API_VERSION_1_3) {
-        if (hwSensor->maxDelay > INT_MAX) {
+        if (hwSensor.maxDelay > INT_MAX) {
             // Max delay is declared as a 64 bit integer for 64 bit architectures. But it should
             // always fit in a 32 bit integer, log error and cap it to INT_MAX.
             ALOGE("Sensor maxDelay overflow error %s %" PRId64, mName.string(),
-                  static_cast<int64_t>(hwSensor->maxDelay));
+                  static_cast<int64_t>(hwSensor.maxDelay));
             mMaxDelay = INT_MAX;
         } else {
-            mMaxDelay = static_cast<int32_t>(hwSensor->maxDelay);
+            mMaxDelay = static_cast<int32_t>(hwSensor.maxDelay);
         }
     } else {
         // For older hals set maxDelay to 0.
@@ -245,11 +246,11 @@
         break;
     default:
         // Only pipe the stringType, requiredPermission and flags for custom sensors.
-        if (halVersion > SENSORS_DEVICE_API_VERSION_1_0 && hwSensor->stringType) {
-            mStringType = hwSensor->stringType;
+        if (halVersion > SENSORS_DEVICE_API_VERSION_1_0 && hwSensor.stringType) {
+            mStringType = hwSensor.stringType;
         }
-        if (halVersion > SENSORS_DEVICE_API_VERSION_1_0 && hwSensor->requiredPermission) {
-            mRequiredPermission = hwSensor->requiredPermission;
+        if (halVersion > SENSORS_DEVICE_API_VERSION_1_0 && hwSensor.requiredPermission) {
+            mRequiredPermission = hwSensor.requiredPermission;
             if (!strcmp(mRequiredPermission, SENSOR_PERMISSION_BODY_SENSORS)) {
                 AppOpsManager appOps;
                 mRequiredAppOp = appOps.permissionToOpCode(String16(SENSOR_PERMISSION_BODY_SENSORS));
@@ -257,7 +258,7 @@
         }
 
         if (halVersion >= SENSORS_DEVICE_API_VERSION_1_3) {
-            mFlags = static_cast<uint32_t>(hwSensor->flags);
+            mFlags = static_cast<uint32_t>(hwSensor.flags);
         } else {
             // This is an OEM defined sensor on an older HAL. Use minDelay to determine the
             // reporting mode of the sensor.
@@ -272,31 +273,28 @@
         break;
     }
 
+    if (halVersion >= SENSORS_DEVICE_API_VERSION_1_3) {
+        // Wake-up flag of HAL 1.3 and above is set here
+        mFlags |= (hwSensor.flags & SENSOR_FLAG_WAKE_UP);
+
+        // Log error if the reporting mode is not as expected, but respect HAL setting.
+        int actualReportingMode = (hwSensor.flags & REPORTING_MODE_MASK) >> REPORTING_MODE_SHIFT;
+        int expectedReportingMode = (mFlags & REPORTING_MODE_MASK) >> REPORTING_MODE_SHIFT;
+        if (actualReportingMode != expectedReportingMode) {
+            ALOGE("Reporting Mode incorrect: sensor %s handle=%#010" PRIx32 " type=%" PRId32 " "
+                   "actual=%d expected=%d",
+                   mName.string(), mHandle, mType, actualReportingMode, expectedReportingMode);
+        }
+    }
+
+    // Feature flags
     // Set DYNAMIC_SENSOR_MASK and ADDITIONAL_INFO_MASK flag here. Compatible with HAL 1_3.
     if (halVersion >= SENSORS_DEVICE_API_VERSION_1_3) {
-        mFlags |= (hwSensor->flags & (DYNAMIC_SENSOR_MASK | ADDITIONAL_INFO_MASK));
+        mFlags |= (hwSensor.flags & (DYNAMIC_SENSOR_MASK | ADDITIONAL_INFO_MASK));
     }
-
     // Set DATA_INJECTION flag here. Defined in HAL 1_4.
     if (halVersion >= SENSORS_DEVICE_API_VERSION_1_4) {
-        mFlags |= (hwSensor->flags & DATA_INJECTION_MASK);
-    }
-
-    // For the newer HALs log errors if reporting mask flags are set incorrectly.
-    if (halVersion >= SENSORS_DEVICE_API_VERSION_1_3) {
-        // Wake-up flag is set here.
-        mFlags |= (hwSensor->flags & SENSOR_FLAG_WAKE_UP);
-        if (mFlags != hwSensor->flags) {
-            int actualReportingMode =
-                 (hwSensor->flags & REPORTING_MODE_MASK) >> REPORTING_MODE_SHIFT;
-            int expectedReportingMode = (mFlags & REPORTING_MODE_MASK) >> REPORTING_MODE_SHIFT;
-            if (actualReportingMode != expectedReportingMode) {
-                ALOGE("Reporting Mode incorrect: sensor %s handle=%d type=%d "
-                       "actual=%d expected=%d",
-                       mName.string(), mHandle, mType, actualReportingMode, expectedReportingMode);
-            }
-
-        }
+        mFlags |= (hwSensor.flags & DATA_INJECTION_MASK);
     }
 
     if (mRequiredPermission.length() > 0) {
@@ -311,8 +309,7 @@
     }
 }
 
-Sensor::~Sensor()
-{
+Sensor::~Sensor() {
 }
 
 const String8& Sensor::getName() const {
@@ -392,11 +389,15 @@
 }
 
 bool Sensor::isWakeUpSensor() const {
-    return mFlags & SENSOR_FLAG_WAKE_UP;
+    return (mFlags & SENSOR_FLAG_WAKE_UP) != 0;
 }
 
 bool Sensor::isDynamicSensor() const {
-    return mFlags & SENSOR_FLAG_DYNAMIC_SENSOR;
+    return (mFlags & SENSOR_FLAG_DYNAMIC_SENSOR) != 0;
+}
+
+bool Sensor::hasAdditionalInfo() const {
+    return (mFlags & SENSOR_FLAG_ADDITIONAL_INFO) != 0;
 }
 
 int32_t Sensor::getReportingMode() const {
@@ -407,8 +408,7 @@
     return mUuid;
 }
 
-size_t Sensor::getFlattenedSize() const
-{
+size_t Sensor::getFlattenedSize() const {
     size_t fixedSize =
             sizeof(mVersion) + sizeof(mHandle) + sizeof(mType) +
             sizeof(mMinValue) + sizeof(mMaxValue) + sizeof(mResolution) +
diff --git a/services/sensorservice/Android.mk b/services/sensorservice/Android.mk
index 85e96d6..5a36961 100644
--- a/services/sensorservice/Android.mk
+++ b/services/sensorservice/Android.mk
@@ -2,21 +2,22 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-	BatteryService.cpp \
-	CorrectedGyroSensor.cpp \
+    BatteryService.cpp \
+    CorrectedGyroSensor.cpp \
     Fusion.cpp \
     GravitySensor.cpp \
     LinearAccelerationSensor.cpp \
     OrientationSensor.cpp \
+    RecentEventLogger.cpp \
     RotationVectorSensor.cpp \
     SensorDevice.cpp \
+    SensorEventConnection.cpp \
     SensorFusion.cpp \
     SensorInterface.cpp \
-    SensorService.cpp \
-    SensorEventConnection.cpp \
-    MostRecentEventLogger.cpp \
-    SensorRecord.cpp \
     SensorList.cpp \
+    SensorRecord.cpp \
+    SensorService.cpp \
+    SensorServiceUtils.cpp \
 
 
 LOCAL_CFLAGS:= -DLOG_TAG=\"SensorService\"
@@ -26,14 +27,14 @@
 LOCAL_CFLAGS += -fvisibility=hidden
 
 LOCAL_SHARED_LIBRARIES := \
-	libcutils \
-	libhardware \
-	libhardware_legacy \
-	libutils \
-	liblog \
-	libbinder \
-	libui \
-	libgui
+    libcutils \
+    libhardware \
+    libhardware_legacy \
+    libutils \
+    liblog \
+    libbinder \
+    libui \
+    libgui
 
 LOCAL_MODULE:= libsensorservice
 
@@ -44,12 +45,12 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-	main_sensorservice.cpp
+    main_sensorservice.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libsensorservice \
-	libbinder \
-	libutils
+    libsensorservice \
+    libbinder \
+    libutils
 
 LOCAL_CFLAGS := -Wall -Werror -Wextra
 
diff --git a/services/sensorservice/MostRecentEventLogger.cpp b/services/sensorservice/MostRecentEventLogger.cpp
deleted file mode 100644
index a5d8456..0000000
--- a/services/sensorservice/MostRecentEventLogger.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "MostRecentEventLogger.h"
-
-#include <inttypes.h>
-
-namespace android {
-
-SensorService::MostRecentEventLogger::MostRecentEventLogger(int sensorType) :
-        mNextInd(0), mSensorType(sensorType) {
-
-    mBufSize = (sensorType == SENSOR_TYPE_STEP_COUNTER ||
-                sensorType == SENSOR_TYPE_SIGNIFICANT_MOTION ||
-                sensorType == SENSOR_TYPE_ACCELEROMETER) ? LOG_SIZE : LOG_SIZE_LARGE;
-
-    mTrimmedSensorEventArr = new TrimmedSensorEvent *[mBufSize];
-    mSensorType = sensorType;
-    for (int i = 0; i < mBufSize; ++i) {
-        mTrimmedSensorEventArr[i] = new TrimmedSensorEvent(mSensorType);
-    }
-}
-
-void SensorService::MostRecentEventLogger::addEvent(const sensors_event_t& event) {
-    TrimmedSensorEvent *curr_event = mTrimmedSensorEventArr[mNextInd];
-    curr_event->mTimestamp = event.timestamp;
-    if (mSensorType == SENSOR_TYPE_STEP_COUNTER) {
-        curr_event->mStepCounter = event.u64.step_counter;
-    } else {
-        memcpy(curr_event->mData, event.data,
-                 sizeof(float) * SensorService::getNumEventsForSensorType(mSensorType));
-    }
-    time_t rawtime = time(NULL);
-    struct tm * timeinfo = localtime(&rawtime);
-    curr_event->mHour = timeinfo->tm_hour;
-    curr_event->mMin = timeinfo->tm_min;
-    curr_event->mSec = timeinfo->tm_sec;
-    mNextInd = (mNextInd + 1) % mBufSize;
-}
-
-void SensorService::MostRecentEventLogger::printBuffer(String8& result) const {
-    const int numData = SensorService::getNumEventsForSensorType(mSensorType);
-    int i = mNextInd, eventNum = 1;
-    result.appendFormat("last %d events = < ", mBufSize);
-    do {
-        if (TrimmedSensorEvent::isSentinel(*mTrimmedSensorEventArr[i])) {
-            // Sentinel, ignore.
-            i = (i + 1) % mBufSize;
-            continue;
-        }
-        result.appendFormat("%d) ", eventNum++);
-        if (mSensorType == SENSOR_TYPE_STEP_COUNTER) {
-            result.appendFormat("%" PRIu64 ",", mTrimmedSensorEventArr[i]->mStepCounter);
-        } else {
-            for (int j = 0; j < numData; ++j) {
-                result.appendFormat("%5.1f,", mTrimmedSensorEventArr[i]->mData[j]);
-            }
-        }
-        result.appendFormat("%" PRId64 " %02d:%02d:%02d ", mTrimmedSensorEventArr[i]->mTimestamp,
-                mTrimmedSensorEventArr[i]->mHour, mTrimmedSensorEventArr[i]->mMin,
-                mTrimmedSensorEventArr[i]->mSec);
-        i = (i + 1) % mBufSize;
-    } while (i != mNextInd);
-    result.appendFormat(">\n");
-}
-
-bool SensorService::MostRecentEventLogger::populateLastEvent(sensors_event_t *event) {
-    int lastEventInd = (mNextInd - 1 + mBufSize) % mBufSize;
-    // Check if the buffer is empty.
-    if (TrimmedSensorEvent::isSentinel(*mTrimmedSensorEventArr[lastEventInd])) {
-        return false;
-    }
-    event->version = sizeof(sensors_event_t);
-    event->type = mSensorType;
-    event->timestamp = mTrimmedSensorEventArr[lastEventInd]->mTimestamp;
-    if (mSensorType == SENSOR_TYPE_STEP_COUNTER) {
-          event->u64.step_counter = mTrimmedSensorEventArr[lastEventInd]->mStepCounter;
-    } else {
-        memcpy(event->data, mTrimmedSensorEventArr[lastEventInd]->mData,
-                 sizeof(float) * SensorService::getNumEventsForSensorType(mSensorType));
-    }
-    return true;
-}
-
-SensorService::MostRecentEventLogger::~MostRecentEventLogger() {
-    for (int i = 0; i < mBufSize; ++i) {
-        delete mTrimmedSensorEventArr[i];
-    }
-    delete [] mTrimmedSensorEventArr;
-}
-
-// -----------------------------------------------------------------------------
-SensorService::MostRecentEventLogger::TrimmedSensorEvent::TrimmedSensorEvent(int sensorType) {
-    mTimestamp = -1;
-    const int numData = SensorService::getNumEventsForSensorType(sensorType);
-    if (sensorType == SENSOR_TYPE_STEP_COUNTER) {
-        mStepCounter = 0;
-    } else {
-        mData = new float[numData];
-        for (int i = 0; i < numData; ++i) {
-            mData[i] = -1.0;
-        }
-    }
-    mHour = mMin = mSec = INT32_MIN;
-}
-
-bool SensorService::MostRecentEventLogger::TrimmedSensorEvent::
-    isSentinel(const TrimmedSensorEvent& event) {
-    return (event.mHour == INT32_MIN && event.mMin == INT32_MIN && event.mSec == INT32_MIN);
-}
-
-} // namespace android
diff --git a/services/sensorservice/MostRecentEventLogger.h b/services/sensorservice/MostRecentEventLogger.h
deleted file mode 100644
index 68c1661..0000000
--- a/services/sensorservice/MostRecentEventLogger.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_MOST_RECENT_EVENT_LOGGER_H
-#define ANDROID_MOST_RECENT_EVENT_LOGGER_H
-
-#include "SensorService.h"
-
-namespace android {
-
-class SensorService;
-
-// A circular buffer of TrimmedSensorEvents. The size of this buffer is typically 10. The last N
-// events generated from the sensor are stored in this buffer. The buffer is NOT cleared when the
-// sensor unregisters and as a result very old data in the dumpsys output can be seen, which is an
-// intended behavior.
-class SensorService::MostRecentEventLogger {
-public:
-    MostRecentEventLogger(int sensorType);
-    void addEvent(const sensors_event_t& event);
-    void printBuffer(String8& buffer) const;
-    bool populateLastEvent(sensors_event_t *event);
-    ~MostRecentEventLogger();
-
-private:
-    // sensor_event_t with only the data and the timestamp.
-    static const size_t LOG_SIZE = 10;
-    static const size_t LOG_SIZE_LARGE = 50;
-
-    struct TrimmedSensorEvent {
-        union {
-            float *mData;
-            uint64_t mStepCounter;
-        };
-        // Timestamp from the sensors_event_t.
-        int64_t mTimestamp;
-        // HH:MM:SS local time at which this sensor event is read at SensorService. Useful
-        // for debugging.
-        int32_t mHour, mMin, mSec;
-
-        TrimmedSensorEvent(int sensorType);
-        static bool isSentinel(const TrimmedSensorEvent& event);
-
-        ~TrimmedSensorEvent() {
-            delete [] mData;
-        }
-    };
-
-    int mNextInd;
-    int mSensorType;
-    int mBufSize;
-    TrimmedSensorEvent ** mTrimmedSensorEventArr;
-};
-
-} // namespace android;
-
-#endif // ANDROID_MOST_RECENT_EVENT_LOGGER_H
-
diff --git a/services/sensorservice/RecentEventLogger.cpp b/services/sensorservice/RecentEventLogger.cpp
new file mode 100644
index 0000000..dba7211
--- /dev/null
+++ b/services/sensorservice/RecentEventLogger.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "RecentEventLogger.h"
+#include "SensorServiceUtils.h"
+
+#include <utils/Timers.h>
+
+#include <inttypes.h>
+
+namespace android {
+namespace SensorServiceUtil {
+
+namespace {
+    constexpr size_t LOG_SIZE = 10;
+    constexpr size_t LOG_SIZE_LARGE = 50;  // larger samples for debugging
+}// unnamed namespace
+
+RecentEventLogger::RecentEventLogger(int sensorType) :
+        mSensorType(sensorType), mEventSize(eventSizeBySensorType(mSensorType)),
+        mRecentEvents(logSizeBySensorType(sensorType)) {
+    // blank
+}
+
+void RecentEventLogger::addEvent(const sensors_event_t& event) {
+    std::lock_guard<std::mutex> lk(mLock);
+    mRecentEvents.emplace(event);
+}
+
+bool RecentEventLogger::isEmpty() const {
+    return mRecentEvents.size() == 0;
+}
+
+std::string RecentEventLogger::dump() const {
+    std::lock_guard<std::mutex> lk(mLock);
+
+    //TODO: replace String8 with std::string completely in this function
+    String8 buffer;
+
+    buffer.appendFormat("last %zu events\n", mRecentEvents.size());
+    int j = 0;
+    for (int i = mRecentEvents.size() - 1; i >= 0; --i) {
+        const auto& ev = mRecentEvents[i];
+        struct tm * timeinfo = localtime(&(ev.mWallTime.tv_sec));
+        buffer.appendFormat("\t%2d (ts=%.9f, wall=%02d:%02d:%02d.%03d) ",
+                ++j, ev.mEvent.timestamp/1e9, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec,
+                (int) ns2ms(ev.mWallTime.tv_nsec));
+
+        // data
+        if (mSensorType == SENSOR_TYPE_STEP_COUNTER) {
+            buffer.appendFormat("%" PRIu64 ", ", ev.mEvent.u64.step_counter);
+        } else {
+            for (size_t k = 0; k < mEventSize; ++k) {
+                buffer.appendFormat("%.2f, ", ev.mEvent.data[k]);
+            }
+        }
+        buffer.append("\n");
+    }
+    return std::string(buffer.string());
+}
+
+bool RecentEventLogger::populateLastEvent(sensors_event_t *event) const {
+    std::lock_guard<std::mutex> lk(mLock);
+
+    if (mRecentEvents.size()) {
+        *event = mRecentEvents[mRecentEvents.size()-1].mEvent;
+        return true;
+    } else {
+        return false;
+    }
+}
+
+
+size_t RecentEventLogger::logSizeBySensorType(int sensorType) {
+    return (sensorType == SENSOR_TYPE_STEP_COUNTER ||
+            sensorType == SENSOR_TYPE_SIGNIFICANT_MOTION ||
+            sensorType == SENSOR_TYPE_ACCELEROMETER) ? LOG_SIZE_LARGE : LOG_SIZE;
+}
+
+RecentEventLogger::SensorEventLog::SensorEventLog(const sensors_event_t& e) : mEvent(e) {
+    clock_gettime(CLOCK_REALTIME, &mWallTime);
+}
+
+} // namespace SensorServiceUtil
+} // namespace android
diff --git a/services/sensorservice/RecentEventLogger.h b/services/sensorservice/RecentEventLogger.h
new file mode 100644
index 0000000..4f9bc4a
--- /dev/null
+++ b/services/sensorservice/RecentEventLogger.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SENSOR_SERVICE_UTIL_RECENT_EVENT_LOGGER_H
+#define ANDROID_SENSOR_SERVICE_UTIL_RECENT_EVENT_LOGGER_H
+
+#include "RingBuffer.h"
+#include "SensorServiceUtils.h"
+
+#include <hardware/sensors.h>
+#include <utils/String8.h>
+
+#include <mutex>
+
+namespace android {
+namespace SensorServiceUtil {
+
+// A circular buffer that record the last N events of a sensor type for debugging. The size of this
+// buffer depends on sensor type and is controlled by logSizeBySensorType(). The last N events
+// generated from the sensor are stored in this buffer.  The buffer is NOT cleared when the sensor
+// unregisters and as a result very old data in the dumpsys output can be seen, which is an intended
+// behavior.
+class RecentEventLogger : public Dumpable {
+public:
+    RecentEventLogger(int sensorType);
+    void addEvent(const sensors_event_t& event);
+    bool populateLastEvent(sensors_event_t *event) const;
+    bool isEmpty() const;
+    virtual ~RecentEventLogger() {}
+
+    // Dumpable interface
+    virtual std::string dump() const override;
+
+protected:
+    struct SensorEventLog {
+        SensorEventLog(const sensors_event_t& e);
+        timespec mWallTime;
+        sensors_event_t mEvent;
+    };
+
+    const int mSensorType;
+    const size_t mEventSize;
+
+    mutable std::mutex mLock;
+    RingBuffer<SensorEventLog> mRecentEvents;
+
+private:
+    static size_t logSizeBySensorType(int sensorType);
+};
+
+} // namespace SensorServiceUtil
+} // namespace android;
+
+#endif // ANDROID_SENSOR_SERVICE_UTIL_RECENT_EVENT_LOGGER_H
+
diff --git a/services/sensorservice/RingBuffer.h b/services/sensorservice/RingBuffer.h
new file mode 100644
index 0000000..ec98a01
--- /dev/null
+++ b/services/sensorservice/RingBuffer.h
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SENSOR_SERVICE_UTIL_RING_BUFFER_H
+#define ANDROID_SENSOR_SERVICE_UTIL_RING_BUFFER_H
+
+#include <utils/Log.h>
+#include <cutils/compiler.h>
+
+#include <iterator>
+#include <utility>
+#include <vector>
+
+namespace android {
+namespace SensorServiceUtil {
+
+/**
+ * A RingBuffer class that maintains an array of objects that can grow up to a certain size.
+ * Elements added to the RingBuffer are inserted in the logical front of the buffer, and
+ * invalidate all current iterators for that RingBuffer object.
+ */
+template <class T>
+class RingBuffer final {
+public:
+
+    /**
+     * Construct a RingBuffer that can grow up to the given length.
+     */
+    RingBuffer(size_t length);
+
+    /**
+     * Forward iterator to this class.  Implements an std:forward_iterator.
+     */
+    class iterator : public std::iterator<std::forward_iterator_tag, T> {
+    public:
+        iterator(T* ptr, size_t size, size_t pos, size_t ctr);
+
+        iterator& operator++();
+
+        iterator operator++(int);
+
+        bool operator==(const iterator& rhs);
+
+        bool operator!=(const iterator& rhs);
+
+        T& operator*();
+
+        T* operator->();
+
+    private:
+        T* mPtr;
+        size_t mSize;
+        size_t mPos;
+        size_t mCtr;
+    };
+
+    /**
+     * Constant forward iterator to this class.  Implements an std:forward_iterator.
+     */
+    class const_iterator : public std::iterator<std::forward_iterator_tag, T> {
+    public:
+        const_iterator(const T* ptr, size_t size, size_t pos, size_t ctr);
+
+        const_iterator& operator++();
+
+        const_iterator operator++(int);
+
+        bool operator==(const const_iterator& rhs);
+
+        bool operator!=(const const_iterator& rhs);
+
+        const T& operator*();
+
+        const T* operator->();
+
+    private:
+        const T* mPtr;
+        size_t mSize;
+        size_t mPos;
+        size_t mCtr;
+    };
+
+    /**
+     * Adds item to the front of this RingBuffer.  If the RingBuffer is at its maximum length,
+     * this will result in the last element being replaced (this is done using the element's
+     * assignment operator).
+     *
+     * All current iterators are invalidated.
+     */
+    void add(const T& item);
+
+    /**
+     * Moves item to the front of this RingBuffer.  Following a call to this, item should no
+     * longer be used.  If the RingBuffer is at its maximum length, this will result in the
+     * last element being replaced (this is done using the element's assignment operator).
+     *
+     * All current iterators are invalidated.
+     */
+    void add(T&& item);
+
+    /**
+     * Construct item in-place in the front of this RingBuffer using the given arguments.  If
+     * the RingBuffer is at its maximum length, this will result in the last element being
+     * replaced (this is done using the element's assignment operator).
+     *
+     * All current iterators are invalidated.
+     */
+    template <class... Args>
+    void emplace(Args&&... args);
+
+    /**
+     * Get an iterator to the front of this RingBuffer.
+     */
+    iterator begin();
+
+    /**
+     * Get an iterator to the end of this RingBuffer.
+     */
+    iterator end();
+
+    /**
+     * Get a const_iterator to the front of this RingBuffer.
+     */
+    const_iterator begin() const;
+
+    /**
+     * Get a const_iterator to the end of this RingBuffer.
+     */
+    const_iterator end() const;
+
+    /**
+     * Return a reference to the element at a given index.  If the index is out of range for
+     * this ringbuffer, [0, size), the behavior for this is undefined.
+     */
+    T& operator[](size_t index);
+
+    /**
+     * Return a const reference to the element at a given index.  If the index is out of range
+     * for this ringbuffer, [0, size), the behavior for this is undefined.
+     */
+    const T& operator[](size_t index) const;
+
+    /**
+     * Return the current size of this RingBuffer.
+     */
+    size_t size() const;
+
+    /**
+     * Remove all elements from this RingBuffer and set the size to 0.
+     */
+    void clear();
+
+private:
+    size_t mFrontIdx;
+    size_t mMaxBufferSize;
+    std::vector<T> mBuffer;
+}; // class RingBuffer
+
+
+template <class T>
+RingBuffer<T>::RingBuffer(size_t length) : mFrontIdx{0}, mMaxBufferSize{length} {}
+
+template <class T>
+RingBuffer<T>::iterator::iterator(T* ptr, size_t size, size_t pos, size_t ctr) :
+        mPtr{ptr}, mSize{size}, mPos{pos}, mCtr{ctr} {}
+
+template <class T>
+typename RingBuffer<T>::iterator& RingBuffer<T>::iterator::operator++() {
+    ++mCtr;
+
+    if (CC_UNLIKELY(mCtr == mSize)) {
+        mPos = mSize;
+        return *this;
+    }
+
+    mPos = ((CC_UNLIKELY(mPos == 0)) ? mSize - 1 : mPos - 1);
+    return *this;
+}
+
+template <class T>
+typename RingBuffer<T>::iterator RingBuffer<T>::iterator::operator++(int) {
+    iterator tmp{mPtr, mSize, mPos, mCtr};
+    ++(*this);
+    return tmp;
+}
+
+template <class T>
+bool RingBuffer<T>::iterator::operator==(const iterator& rhs) {
+    return (mPtr + mPos) == (rhs.mPtr + rhs.mPos);
+}
+
+template <class T>
+bool RingBuffer<T>::iterator::operator!=(const iterator& rhs) {
+    return (mPtr + mPos) != (rhs.mPtr + rhs.mPos);
+}
+
+template <class T>
+T& RingBuffer<T>::iterator::operator*() {
+    return *(mPtr + mPos);
+}
+
+template <class T>
+T* RingBuffer<T>::iterator::operator->() {
+    return mPtr + mPos;
+}
+
+template <class T>
+RingBuffer<T>::const_iterator::const_iterator(const T* ptr, size_t size, size_t pos, size_t ctr) :
+        mPtr{ptr}, mSize{size}, mPos{pos}, mCtr{ctr} {}
+
+template <class T>
+typename RingBuffer<T>::const_iterator& RingBuffer<T>::const_iterator::operator++() {
+    ++mCtr;
+
+    if (CC_UNLIKELY(mCtr == mSize)) {
+        mPos = mSize;
+        return *this;
+    }
+
+    mPos = ((CC_UNLIKELY(mPos == 0)) ? mSize - 1 : mPos - 1);
+    return *this;
+}
+
+template <class T>
+typename RingBuffer<T>::const_iterator RingBuffer<T>::const_iterator::operator++(int) {
+    const_iterator tmp{mPtr, mSize, mPos, mCtr};
+    ++(*this);
+    return tmp;
+}
+
+template <class T>
+bool RingBuffer<T>::const_iterator::operator==(const const_iterator& rhs) {
+    return (mPtr + mPos) == (rhs.mPtr + rhs.mPos);
+}
+
+template <class T>
+bool RingBuffer<T>::const_iterator::operator!=(const const_iterator& rhs) {
+    return (mPtr + mPos) != (rhs.mPtr + rhs.mPos);
+}
+
+template <class T>
+const T& RingBuffer<T>::const_iterator::operator*() {
+    return *(mPtr + mPos);
+}
+
+template <class T>
+const T* RingBuffer<T>::const_iterator::operator->() {
+    return mPtr + mPos;
+}
+
+template <class T>
+void RingBuffer<T>::add(const T& item) {
+    if (mBuffer.size() < mMaxBufferSize) {
+        mBuffer.push_back(item);
+        mFrontIdx = ((mFrontIdx + 1) % mMaxBufferSize);
+        return;
+    }
+
+    mBuffer[mFrontIdx] = item;
+    mFrontIdx = ((mFrontIdx + 1) % mMaxBufferSize);
+}
+
+template <class T>
+void RingBuffer<T>::add(T&& item) {
+    if (mBuffer.size() != mMaxBufferSize) {
+        mBuffer.push_back(std::forward<T>(item));
+        mFrontIdx = ((mFrontIdx + 1) % mMaxBufferSize);
+        return;
+    }
+
+    // Only works for types with move assignment operator
+    mBuffer[mFrontIdx] = std::forward<T>(item);
+    mFrontIdx = ((mFrontIdx + 1) % mMaxBufferSize);
+}
+
+template <class T>
+template <class... Args>
+void RingBuffer<T>::emplace(Args&&... args) {
+    if (mBuffer.size() != mMaxBufferSize) {
+        mBuffer.emplace_back(std::forward<Args>(args)...);
+        mFrontIdx = ((mFrontIdx + 1) % mMaxBufferSize);
+        return;
+    }
+
+    // Only works for types with move assignment operator
+    mBuffer[mFrontIdx] = T(std::forward<Args>(args)...);
+    mFrontIdx = ((mFrontIdx + 1) % mMaxBufferSize);
+}
+
+template <class T>
+typename RingBuffer<T>::iterator RingBuffer<T>::begin() {
+    size_t tmp = (mBuffer.size() == 0) ? 0 : mBuffer.size() - 1;
+    return iterator(mBuffer.data(), mBuffer.size(), (mFrontIdx == 0) ? tmp : mFrontIdx - 1, 0);
+}
+
+template <class T>
+typename RingBuffer<T>::iterator RingBuffer<T>::end() {
+    size_t s = mBuffer.size();
+    return iterator(mBuffer.data(), s, s, s);
+}
+
+template <class T>
+typename RingBuffer<T>::const_iterator RingBuffer<T>::begin() const {
+    size_t tmp = (mBuffer.size() == 0) ? 0 : mBuffer.size() - 1;
+    return const_iterator(mBuffer.data(), mBuffer.size(),
+            (mFrontIdx == 0) ? tmp : mFrontIdx - 1, 0);
+}
+
+template <class T>
+typename RingBuffer<T>::const_iterator RingBuffer<T>::end() const {
+    size_t s = mBuffer.size();
+    return const_iterator(mBuffer.data(), s, s, s);
+}
+
+template <class T>
+T& RingBuffer<T>::operator[](size_t index) {
+    LOG_ALWAYS_FATAL_IF(index >= mBuffer.size(), "Index %zu out of bounds, size is %zu.",
+            index, mBuffer.size());
+    size_t pos = (index >= mFrontIdx) ?
+            mBuffer.size() - 1 - (index - mFrontIdx) : mFrontIdx - 1 - index;
+    return mBuffer[pos];
+}
+
+template <class T>
+const T& RingBuffer<T>::operator[](size_t index) const {
+    LOG_ALWAYS_FATAL_IF(index >= mBuffer.size(), "Index %zu out of bounds, size is %zu.",
+            index, mBuffer.size());
+    size_t pos = (index >= mFrontIdx) ?
+            mBuffer.size() - 1 - (index - mFrontIdx) : mFrontIdx - 1 - index;
+    return mBuffer[pos];
+}
+
+template <class T>
+size_t RingBuffer<T>::size() const {
+    return mBuffer.size();
+}
+
+template <class T>
+void RingBuffer<T>::clear() {
+    mBuffer.clear();
+    mFrontIdx = 0;
+}
+
+}  // namespace SensorServiceUtil
+}; // namespace android
+
+#endif // ANDROID_SENSOR_SERVICE_UTIL_RING_BUFFER_H
+
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 179b1c5..4fbaa50 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -39,8 +39,7 @@
 
 SensorDevice::SensorDevice()
     :  mSensorDevice(0),
-       mSensorModule(0)
-{
+       mSensorModule(0) {
     status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID,
             (hw_module_t const**)&mSensorModule);
 
@@ -84,37 +83,43 @@
     }
 }
 
-void SensorDevice::dump(String8& result)
-{
-    if (!mSensorModule) return;
-    sensor_t const* list;
-    ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list);
+std::string SensorDevice::dump() const {
+    if (!mSensorModule) return "HAL not initialized\n";
 
-    result.appendFormat("halVersion 0x%08x\n", getHalDeviceVersion());
-    result.appendFormat("%d h/w sensors:\n", int(count));
+    String8 result;
+    sensor_t const* list;
+    int count = mSensorModule->get_sensors_list(mSensorModule, &list);
+
+    result.appendFormat("HAL: %s (%s), version %#010x\n",
+                        mSensorModule->common.name,
+                        mSensorModule->common.author,
+                        getHalDeviceVersion());
+    result.appendFormat("Total %d h/w sensors, %zu running:\n", count, mActivationCount.size());
 
     Mutex::Autolock _l(mLock);
-    for (size_t i=0 ; i<size_t(count) ; i++) {
+    for (int i = 0 ; i < count ; i++) {
         const Info& info = mActivationCount.valueFor(list[i].handle);
         if (info.batchParams.isEmpty()) continue;
-        result.appendFormat("handle=0x%08x, active-count=%zu, batch_period(ms)={ ", list[i].handle,
+        result.appendFormat("0x%08x) active-count = %zu; ", list[i].handle,
                             info.batchParams.size());
+
+        result.append("sampling_period(ms) = {");
         for (size_t j = 0; j < info.batchParams.size(); j++) {
             const BatchParams& params = info.batchParams.valueAt(j);
-            result.appendFormat("%4.1f%s", params.batchDelay / 1e6f,
+            result.appendFormat("%.1f%s", params.batchDelay / 1e6f,
                                 j < info.batchParams.size() - 1 ? ", " : "");
         }
-        result.appendFormat(" }, selected=%4.1f ms\n", info.bestBatchParams.batchDelay / 1e6f);
+        result.appendFormat("}, selected = %.1f ms; ", info.bestBatchParams.batchDelay / 1e6f);
 
-        result.appendFormat("handle=0x%08x, active-count=%zu, batch_timeout(ms)={ ", list[i].handle,
-                            info.batchParams.size());
+        result.append("batching_period(ms) = {");
         for (size_t j = 0; j < info.batchParams.size(); j++) {
             BatchParams params = info.batchParams.valueAt(j);
-            result.appendFormat("%4.1f%s", params.batchTimeout / 1e6f,
+            result.appendFormat("%.1f%s", params.batchTimeout / 1e6f,
                                 j < info.batchParams.size() - 1 ? ", " : "");
         }
-        result.appendFormat(" }, selected=%4.1f ms\n", info.bestBatchParams.batchTimeout / 1e6f);
+        result.appendFormat("}, selected = %.1f ms\n", info.bestBatchParams.batchTimeout / 1e6f);
     }
+    return result.string();
 }
 
 ssize_t SensorDevice::getSensorList(sensor_t const** list) {
@@ -143,8 +148,7 @@
     info.removeBatchParamsForIdent(ident);
 }
 
-status_t SensorDevice::activate(void* ident, int handle, int enabled)
-{
+status_t SensorDevice::activate(void* ident, int handle, int enabled) {
     if (!mSensorDevice) return NO_INIT;
     status_t err(NO_ERROR);
     bool actuateHardware = false;
@@ -293,8 +297,7 @@
     return err;
 }
 
-status_t SensorDevice::setDelay(void* ident, int handle, int64_t samplingPeriodNs)
-{
+status_t SensorDevice::setDelay(void* ident, int handle, int64_t samplingPeriodNs) {
     if (!mSensorDevice) return NO_INIT;
     if (samplingPeriodNs < MINIMUM_EVENTS_PERIOD) {
         samplingPeriodNs = MINIMUM_EVENTS_PERIOD;
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index c12630a..68bb853 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -17,21 +17,44 @@
 #ifndef ANDROID_SENSOR_DEVICE_H
 #define ANDROID_SENSOR_DEVICE_H
 
-#include <stdint.h>
-#include <sys/types.h>
+#include "SensorServiceUtils.h"
 
+#include <gui/Sensor.h>
 #include <utils/KeyedVector.h>
 #include <utils/Singleton.h>
 #include <utils/String8.h>
 
-#include <gui/Sensor.h>
+#include <stdint.h>
+#include <sys/types.h>
 
 // ---------------------------------------------------------------------------
 
 namespace android {
 // ---------------------------------------------------------------------------
+using SensorServiceUtil::Dumpable;
 
-class SensorDevice : public Singleton<SensorDevice> {
+class SensorDevice : public Singleton<SensorDevice>, public Dumpable {
+public:
+    ssize_t getSensorList(sensor_t const** list);
+    void handleDynamicSensorConnection(int handle, bool connected);
+    status_t initCheck() const;
+    int getHalDeviceVersion() const;
+    ssize_t poll(sensors_event_t* buffer, size_t count);
+    status_t activate(void* ident, int handle, int enabled);
+    status_t batch(void* ident, int handle, int flags, int64_t samplingPeriodNs,
+                   int64_t maxBatchReportLatencyNs);
+    // Call batch with timeout zero instead of calling setDelay() for newer devices.
+    status_t setDelay(void* ident, int handle, int64_t ns);
+    status_t flush(void* ident, int handle);
+    status_t setMode(uint32_t mode);
+    void disableAllSensors();
+    void enableAllSensors();
+    void autoDisable(void *ident, int handle);
+    status_t injectSensorData(const sensors_event_t *event);
+
+    // Dumpable
+    virtual std::string dump() const;
+private:
     friend class Singleton<SensorDevice>;
     sensors_poll_device_1_t* mSensorDevice;
     struct sensors_module_t* mSensorModule;
@@ -87,24 +110,6 @@
 
     bool isClientDisabled(void* ident);
     bool isClientDisabledLocked(void* ident);
-public:
-    ssize_t getSensorList(sensor_t const** list);
-    void handleDynamicSensorConnection(int handle, bool connected);
-    status_t initCheck() const;
-    int getHalDeviceVersion() const;
-    ssize_t poll(sensors_event_t* buffer, size_t count);
-    status_t activate(void* ident, int handle, int enabled);
-    status_t batch(void* ident, int handle, int flags, int64_t samplingPeriodNs,
-                   int64_t maxBatchReportLatencyNs);
-    // Call batch with timeout zero instead of calling setDelay() for newer devices.
-    status_t setDelay(void* ident, int handle, int64_t ns);
-    status_t flush(void* ident, int handle);
-    status_t setMode(uint32_t mode);
-    void disableAllSensors();
-    void enableAllSensors();
-    void autoDisable(void *ident, int handle);
-    status_t injectSensorData(const sensors_event_t *event);
-    void dump(String8& result);
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/sensorservice/SensorInterface.cpp b/services/sensorservice/SensorInterface.cpp
index cb24229..73a6db5 100644
--- a/services/sensorservice/SensorInterface.cpp
+++ b/services/sensorservice/SensorInterface.cpp
@@ -34,12 +34,21 @@
         mSensor(&sensor, mSensorDevice.getHalDeviceVersion()) {
 }
 
+BaseSensor::BaseSensor(const sensor_t& sensor, const uint8_t (&uuid)[16]) :
+        mSensorDevice(SensorDevice::getInstance()),
+        mSensor(sensor, Sensor::uuid_t(uuid), mSensorDevice.getHalDeviceVersion()) {
+}
+
 // ---------------------------------------------------------------------------
 
 HardwareSensor::HardwareSensor(const sensor_t& sensor):
         BaseSensor(sensor) {
 }
 
+HardwareSensor::HardwareSensor(const sensor_t& sensor, const uint8_t (&uuid)[16]):
+        BaseSensor(sensor, uuid) {
+}
+
 HardwareSensor::~HardwareSensor() {
 }
 
diff --git a/services/sensorservice/SensorInterface.h b/services/sensorservice/SensorInterface.h
index d1cee41..dafcf2d 100644
--- a/services/sensorservice/SensorInterface.h
+++ b/services/sensorservice/SensorInterface.h
@@ -48,6 +48,7 @@
 class BaseSensor : public SensorInterface {
 public:
     BaseSensor(const sensor_t& sensor);
+    BaseSensor(const sensor_t& sensor, const uint8_t (&uuid)[16]);
 
     // Not all sensors need to support batching.
     virtual status_t batch(void* ident, int handle, int, int64_t samplingPeriodNs,
@@ -74,6 +75,7 @@
 class HardwareSensor : public BaseSensor {
 public:
     HardwareSensor(const sensor_t& sensor);
+    HardwareSensor(const sensor_t& sensor, const uint8_t (&uuid)[16]);
 
     virtual ~HardwareSensor();
 
diff --git a/services/sensorservice/SensorList.cpp b/services/sensorservice/SensorList.cpp
index c23e21f..f6d3d94 100644
--- a/services/sensorservice/SensorList.cpp
+++ b/services/sensorservice/SensorList.cpp
@@ -19,6 +19,8 @@
 #include <hardware/sensors.h>
 #include <utils/String8.h>
 
+#include <cinttypes>
+
 namespace android {
 namespace SensorServiceUtil {
 
@@ -119,17 +121,17 @@
 std::string SensorList::dump() const {
     String8 result;
 
-    result.append("Sensor List:\n");
     forEachSensor([&result] (const Sensor& s) -> bool {
             result.appendFormat(
-                    "%-15s| %-10s| version=%d |%-20s| 0x%08x | \"%s\" | type=%d |",
+                    "%#010x) %-25s | %-15s | ver: %" PRId32 " | type: %20s(%" PRId32
+                        ") | perm: %s\n\t",
+                    s.getHandle(),
                     s.getName().string(),
                     s.getVendor().string(),
                     s.getVersion(),
                     s.getStringType().string(),
-                    s.getHandle(),
-                    s.getRequiredPermission().string(),
-                    s.getType());
+                    s.getType(),
+                    s.getRequiredPermission().size() ? s.getRequiredPermission().string() : "n/a");
 
             const int reportingMode = s.getReportingMode();
             if (reportingMode == AREPORTING_MODE_CONTINUOUS) {
@@ -147,18 +149,19 @@
             if (s.getMaxDelay() > 0) {
                 result.appendFormat("minRate=%.2fHz | ", 1e6f / s.getMaxDelay());
             } else {
-                result.appendFormat("maxDelay=%dus | ", s.getMaxDelay());
+                result.appendFormat("maxDelay=%" PRId32 "us | ", s.getMaxDelay());
             }
 
             if (s.getMinDelay() > 0) {
                 result.appendFormat("maxRate=%.2fHz | ", 1e6f / s.getMinDelay());
             } else {
-                result.appendFormat("minDelay=%dus | ", s.getMinDelay());
+                result.appendFormat("minDelay=%" PRId32 "us | ", s.getMinDelay());
             }
 
             if (s.getFifoMaxEventCount() > 0) {
-                result.appendFormat("FifoMax=%d events | ",
-                        s.getFifoMaxEventCount());
+                result.appendFormat("FIFO (max,reserved) = (%" PRIu32 ", %" PRIu32 ") events | ",
+                        s.getFifoMaxEventCount(),
+                        s.getFifoReservedEventCount());
             } else {
                 result.append("no batching | ");
             }
@@ -169,6 +172,20 @@
                 result.appendFormat("non-wakeUp | ");
             }
 
+            if (s.isDynamicSensor()) {
+                result.appendFormat("dynamic, ");
+            }
+            if (s.hasAdditionalInfo()) {
+                result.appendFormat("has-additional-info, ");
+            }
+            result.append("| ");
+
+            if (s.isDynamicSensor()) {
+                result.append("uuid: ");
+                for (uint8_t i : s.getUuid().b) {
+                    result.appendFormat("%02x", i);
+                }
+            }
             result.append("\n");
             return true;
         });
diff --git a/services/sensorservice/SensorList.h b/services/sensorservice/SensorList.h
index ffde619..8209d96 100644
--- a/services/sensorservice/SensorList.h
+++ b/services/sensorservice/SensorList.h
@@ -14,18 +14,18 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_SENSOR_LIST_H
-#define ANDROID_SENSOR_LIST_H
+#ifndef ANDROID_SENSOR_SERVICE_UTIL_SENSOR_LIST_H
+#define ANDROID_SENSOR_SERVICE_UTIL_SENSOR_LIST_H
 
 #include "SensorInterface.h"
+#include "SensorServiceUtils.h"
 
 #include <gui/Sensor.h>
 #include <utils/String8.h>
 #include <utils/Vector.h>
 
-#include <mutex>
 #include <map>
-#include <string>
+#include <mutex>
 #include <unordered_set>
 #include <vector>
 
@@ -34,13 +34,6 @@
 
 namespace SensorServiceUtil {
 
-class Dumpable {
-public:
-    virtual std::string dump() const;
-    virtual void setFormat(std::string ) {}
-    virtual ~Dumpable() {}
-};
-
 class SensorList : public Dumpable {
 public:
     // After SensorInterface * is added into SensorList, it can be assumed that SensorList own the
@@ -142,4 +135,4 @@
 } // namespace SensorServiceUtil
 } // namespace android
 
-#endif // ANDROID_SENSOR_LIST_H
+#endif // ANDROID_SENSOR_SERVICE_UTIL_SENSOR_LIST_H
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index b7a8740..6caa85b 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -36,11 +36,10 @@
 #include "SensorInterface.h"
 
 #include "SensorService.h"
-#include "SensorEventConnection.h"
 #include "SensorEventAckReceiver.h"
+#include "SensorEventConnection.h"
 #include "SensorRecord.h"
 #include "SensorRegistrationInfo.h"
-#include "MostRecentEventLogger.h"
 
 #include <inttypes.h>
 #include <math.h>
@@ -86,7 +85,6 @@
                     (1<<SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR) |
                     (1<<SENSOR_TYPE_GAME_ROTATION_VECTOR);
 
-            mLastEventSeen.setCapacity(count);
             for (ssize_t i=0 ; i<count ; i++) {
                 bool useThisSensor=true;
 
@@ -218,25 +216,27 @@
 
 const Sensor& SensorService::registerSensor(SensorInterface* s, bool isDebug, bool isVirtual) {
     int handle = s->getSensor().getHandle();
+    int type = s->getSensor().getType();
     if (mSensors.add(handle, s, isDebug, isVirtual)){
-        mLastEventSeen.add(handle, nullptr);
+        mRecentEvent.emplace(handle, new RecentEventLogger(type));
         return s->getSensor();
     } else {
         return mSensors.getNonSensor();
     }
 }
 
-const Sensor& SensorService::registerDynamicSensor(SensorInterface* s, bool isDebug) {
+const Sensor& SensorService::registerDynamicSensorLocked(SensorInterface* s, bool isDebug) {
     return registerSensor(s, isDebug);
 }
 
-bool SensorService::unregisterDynamicSensor(int handle) {
+bool SensorService::unregisterDynamicSensorLocked(int handle) {
     bool ret = mSensors.remove(handle);
-    MostRecentEventLogger *buf = mLastEventSeen.valueFor(handle);
-    if (buf) {
-        delete buf;
+
+    const auto i = mRecentEvent.find(handle);
+    if (i != mRecentEvent.end()) {
+        delete i->second;
+        mRecentEvent.erase(i);
     }
-    mLastEventSeen.removeItem(handle);
     return ret;
 }
 
@@ -245,6 +245,9 @@
 }
 
 SensorService::~SensorService() {
+    for (auto && entry : mRecentEvent) {
+        delete entry.second;
+    }
 }
 
 status_t SensorService::dump(int fd, const Vector<String16>& args) {
@@ -313,25 +316,25 @@
         } else {
             // Default dump the sensor list and debugging information.
             //
+            result.append("Sensor Device:\n");
+            result.append(SensorDevice::getInstance().dump().c_str());
+
+            result.append("Sensor List:\n");
             result.append(mSensors.dump().c_str());
 
+            result.append("Fusion States:\n");
             SensorFusion::getInstance().dump(result);
-            SensorDevice::getInstance().dump(result);
 
             result.append("Recent Sensor events:\n");
-            auto& lastEvents = mLastEventSeen;
-            mSensors.forEachSensor([&result, &lastEvents] (const Sensor& s) -> bool {
-                    int bufIndex = lastEvents.indexOfKey(s.getHandle());
-                    if (bufIndex >= 0) {
-                        const MostRecentEventLogger* buf = lastEvents.valueAt(bufIndex);
-                        if (buf != nullptr && s.getRequiredPermission().isEmpty()) {
-                            result.appendFormat("%s (handle:0x%08x): ",
-                                          s.getName().string(), s.getHandle());
-                            buf->printBuffer(result);
-                        }
-                    }
-                    return true;
-                });
+            for (auto&& i : mRecentEvent) {
+                sp<SensorInterface> s = mSensors.getInterface(i.first);
+                if (!i.second->isEmpty() &&
+                    s->getSensor().getRequiredPermission().isEmpty()) {
+                    // if there is events and sensor does not need special permission.
+                    result.appendFormat("%s: ", s->getSensor().getName().string());
+                    result.append(i.second->dump().c_str());
+                }
+            }
 
             result.append("Active sensors:\n");
             for (size_t i=0 ; i<mActiveSensors.size() ; i++) {
@@ -554,17 +557,19 @@
                           handle, dynamicSensor.type, dynamicSensor.name);
 
                     if (mSensors.isNewHandle(handle)) {
+                        const auto& uuid = mSensorEventBuffer[i].dynamic_sensor_meta.uuid;
                         sensor_t s = dynamicSensor;
                         // make sure the dynamic sensor flag is set
                         s.flags |= DYNAMIC_SENSOR_MASK;
                         // force the handle to be consistent
                         s.handle = handle;
-                        SensorInterface *si = new HardwareSensor(s);
+
+                        SensorInterface *si = new HardwareSensor(s, uuid);
 
                         // This will release hold on dynamic sensor meta, so it should be called
                         // after Sensor object is created.
                         device.handleDynamicSensorConnection(handle, true /*connected*/);
-                        registerDynamicSensor(si);
+                        registerDynamicSensorLocked(si);
                     } else {
                         ALOGE("Handle %d has been used, cannot use again before reboot.", handle);
                     }
@@ -573,7 +578,7 @@
                     ALOGI("Dynamic sensor handle 0x%x disconnected", handle);
 
                     device.handleDynamicSensorConnection(handle, false /*connected*/);
-                    if (!unregisterDynamicSensor(handle)) {
+                    if (!unregisterDynamicSensorLocked(handle)) {
                         ALOGE("Dynamic sensor release error.");
                     }
 
@@ -674,16 +679,14 @@
     for (size_t i = 0; i < count; i++) {
         if (buffer[i].type == SENSOR_TYPE_META_DATA ||
             buffer[i].type == SENSOR_TYPE_DYNAMIC_SENSOR_META ||
-            buffer[i].type == SENSOR_TYPE_ADDITIONAL_INFO ||
-            mLastEventSeen.indexOfKey(buffer[i].sensor) <0 ) {
+            buffer[i].type == SENSOR_TYPE_ADDITIONAL_INFO) {
             continue;
         }
 
-        MostRecentEventLogger* &circular_buf = mLastEventSeen.editValueFor(buffer[i].sensor);
-        if (circular_buf == NULL) {
-            circular_buf = new MostRecentEventLogger(buffer[i].type);
+        auto logger = mRecentEvent.find(buffer[i].sensor);
+        if (logger != mRecentEvent.end()) {
+            logger->second->addEvent(buffer[i]);
         }
-        circular_buf->addEvent(buffer[i]);
     }
 }
 
@@ -881,14 +884,14 @@
             if (sensor->getSensor().getReportingMode() == AREPORTING_MODE_ON_CHANGE) {
                 // NOTE: The wake_up flag of this event may get set to
                 // WAKE_UP_SENSOR_EVENT_NEEDS_ACK if this is a wake_up event.
-                MostRecentEventLogger *circular_buf = mLastEventSeen.valueFor(handle);
-                if (circular_buf) {
+
+                auto logger = mRecentEvent.find(handle);
+                if (logger != mRecentEvent.end()) {
                     sensors_event_t event;
-                    memset(&event, 0, sizeof(event));
                     // It is unlikely that this buffer is empty as the sensor is already active.
                     // One possible corner case may be two applications activating an on-change
                     // sensor at the same time.
-                    if(circular_buf->populateLastEvent(&event)) {
+                    if(logger->second->populateLastEvent(&event)) {
                         event.sensor = handle;
                         if (event.version == sizeof(sensors_event_t)) {
                             if (isWakeUpSensorEvent(event) && !mWakeLockAcquired) {
@@ -1179,31 +1182,5 @@
     return (packageName.contains(mWhiteListedPackage.string()));
 }
 
-int SensorService::getNumEventsForSensorType(int sensor_event_type) {
-    if (sensor_event_type >= SENSOR_TYPE_DEVICE_PRIVATE_BASE) {
-        return 16;
-    }
-    switch (sensor_event_type) {
-        case SENSOR_TYPE_ROTATION_VECTOR:
-        case SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR:
-            return 5;
-
-        case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
-        case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
-            return 6;
-
-        case SENSOR_TYPE_GAME_ROTATION_VECTOR:
-            return 4;
-
-        case SENSOR_TYPE_SIGNIFICANT_MOTION:
-        case SENSOR_TYPE_STEP_DETECTOR:
-        case SENSOR_TYPE_STEP_COUNTER:
-            return 1;
-
-         default:
-            return 3;
-    }
-}
-
 }; // namespace android
 
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 6473edb..0d04478 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -18,6 +18,7 @@
 #define ANDROID_SENSOR_SERVICE_H
 
 #include "SensorList.h"
+#include "RecentEventLogger.h"
 
 #include <binder/BinderService.h>
 #include <cutils/compiler.h>
@@ -35,6 +36,7 @@
 
 #include <stdint.h>
 #include <sys/types.h>
+#include <unordered_map>
 #include <unordered_set>
 
 #if __clang__
@@ -56,6 +58,7 @@
 namespace android {
 // ---------------------------------------------------------------------------
 class SensorInterface;
+using namespace SensorServiceUtil;
 
 class SensorService :
         public BinderService<SensorService>,
@@ -86,8 +89,6 @@
     // nested class/struct for internal use
     class SensorRecord;
     class SensorEventAckReceiver;
-    struct TrimmedSensorEvent;
-    class MostRecentEventLogger;
     struct SensorRegistrationInfo;
 
     enum Mode {
@@ -155,7 +156,6 @@
     virtual int isDataInjectionEnabled();
     virtual status_t dump(int fd, const Vector<String16>& args);
 
-    static int getNumEventsForSensorType(int sensor_event_type);
     String8 getSensorName(int handle) const;
     bool isVirtualSensor(int handle) const;
     sp<SensorInterface> getSensorInterfaceFromHandle(int handle) const;
@@ -165,8 +165,8 @@
     const Sensor& registerSensor(SensorInterface* sensor,
                                  bool isDebug = false, bool isVirtual = false);
     const Sensor& registerVirtualSensor(SensorInterface* sensor, bool isDebug = false);
-    const Sensor& registerDynamicSensor(SensorInterface* sensor, bool isDebug = false);
-    bool unregisterDynamicSensor(int handle);
+    const Sensor& registerDynamicSensorLocked(SensorInterface* sensor, bool isDebug = false);
+    bool unregisterDynamicSensorLocked(int handle);
     status_t cleanupWithoutDisable(const sp<SensorEventConnection>& connection, int handle);
     status_t cleanupWithoutDisableLocked(const sp<SensorEventConnection>& connection, int handle);
     void cleanupAutoDisabledSensorLocked(const sp<SensorEventConnection>& connection,
@@ -208,7 +208,7 @@
     status_t resetToNormalMode();
     status_t resetToNormalModeLocked();
 
-    SensorServiceUtil::SensorList mSensors;
+    SensorList mSensors;
     status_t mInitCheck;
 
     // Socket buffersize used to initialize BitTube. This size depends on whether batching is
@@ -225,7 +225,7 @@
     bool mWakeLockAcquired;
     sensors_event_t *mSensorEventBuffer, *mSensorEventScratch;
     SensorEventConnection const **mMapFlushEventsToConnections;
-    KeyedVector<int32_t, MostRecentEventLogger*> mLastEventSeen;
+    std::unordered_map<int, RecentEventLogger*> mRecentEvent;
     Mode mCurrentOperatingMode;
 
     // This packagaName is set when SensorService is in RESTRICTED or DATA_INJECTION mode. Only
diff --git a/services/sensorservice/SensorServiceUtils.cpp b/services/sensorservice/SensorServiceUtils.cpp
new file mode 100644
index 0000000..1996a00
--- /dev/null
+++ b/services/sensorservice/SensorServiceUtils.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SensorServiceUtils.h"
+
+#include <hardware/sensors.h>
+
+namespace android {
+namespace SensorServiceUtil {
+
+// Keep in sync with sSensorReportingMode in Sensor.java
+size_t eventSizeBySensorType(int type) {
+    if (type >= SENSOR_TYPE_DEVICE_PRIVATE_BASE) {
+        return 16;
+    }
+    switch (type) {
+        case SENSOR_TYPE_POSE_6DOF:
+            return 16;
+
+        case SENSOR_TYPE_ROTATION_VECTOR:
+        case SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR:
+            return 5;
+
+        case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
+        case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:
+            return 6;
+
+        case SENSOR_TYPE_GAME_ROTATION_VECTOR:
+            return 4;
+
+        case SENSOR_TYPE_SIGNIFICANT_MOTION:
+        case SENSOR_TYPE_STEP_DETECTOR:
+        case SENSOR_TYPE_STEP_COUNTER:
+        case SENSOR_TYPE_HEART_RATE:
+        case SENSOR_TYPE_TILT_DETECTOR:
+        case SENSOR_TYPE_WAKE_GESTURE:
+        case SENSOR_TYPE_GLANCE_GESTURE:
+        case SENSOR_TYPE_PICK_UP_GESTURE:
+        case SENSOR_TYPE_WRIST_TILT_GESTURE:
+        case SENSOR_TYPE_DEVICE_ORIENTATION:
+        case SENSOR_TYPE_STATIONARY_DETECT:
+        case SENSOR_TYPE_MOTION_DETECT:
+        case SENSOR_TYPE_HEART_BEAT:
+            return 1;
+
+        default:
+            return 3;
+    }
+}
+
+} // namespace SensorServiceUtil
+} // namespace android;
diff --git a/services/sensorservice/SensorServiceUtils.h b/services/sensorservice/SensorServiceUtils.h
new file mode 100644
index 0000000..1558feb
--- /dev/null
+++ b/services/sensorservice/SensorServiceUtils.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SENSOR_SERVICE_UTIL
+#define ANDROID_SENSOR_SERVICE_UTIL
+
+#include <cstddef>
+#include <string>
+
+namespace android {
+namespace SensorServiceUtil {
+
+class Dumpable {
+public:
+    virtual std::string dump() const = 0;
+    virtual void setFormat(std::string ) {}
+    virtual ~Dumpable() {}
+};
+
+size_t eventSizeBySensorType(int type);
+
+} // namespace SensorServiceUtil
+} // namespace android;
+
+#endif // ANDROID_SENSOR_SERVICE_UTIL
diff --git a/services/sensorservice/tests/sensorservicetest.cpp b/services/sensorservice/tests/sensorservicetest.cpp
index cfdf6a3..186b60c 100644
--- a/services/sensorservice/tests/sensorservicetest.cpp
+++ b/services/sensorservice/tests/sensorservicetest.cpp
@@ -62,7 +62,7 @@
 
 int main()
 {
-    SensorManager mgr(String16("Sensor Service Test"));
+    SensorManager& mgr = SensorManager::getInstanceForPackage(String16("Sensor Service Test"));
 
     Sensor const* const* list;
     ssize_t count = mgr.getSensorList(&list);