Merge "Dumpsys sensorservice --proto"
diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp
index 1c9a4af..5246c78 100644
--- a/services/sensorservice/Android.bp
+++ b/services/sensorservice/Android.bp
@@ -42,6 +42,7 @@
         "libbinder",
         "libsensor",
         "libsensorprivacy",
+        "libprotoutil",
         "libcrypto",
         "libbase",
         "libhidlbase",
@@ -52,6 +53,8 @@
 
     static_libs: ["android.hardware.sensors@1.0-convert"],
 
+    generated_headers: ["framework-cppstream-protos"],
+
     // our public headers depend on libsensor and libsensorprivacy
     export_shared_lib_headers: ["libsensor", "libsensorprivacy"],
 }
diff --git a/services/sensorservice/RecentEventLogger.cpp b/services/sensorservice/RecentEventLogger.cpp
index 207b097..d7ca6e1 100644
--- a/services/sensorservice/RecentEventLogger.cpp
+++ b/services/sensorservice/RecentEventLogger.cpp
@@ -17,6 +17,8 @@
 #include "RecentEventLogger.h"
 #include "SensorServiceUtils.h"
 
+#include <android/util/ProtoOutputStream.h>
+#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
 #include <utils/Timers.h>
 
 #include <inttypes.h>
@@ -84,6 +86,40 @@
     return std::string(buffer.string());
 }
 
+/**
+ * Dump debugging information as android.service.SensorEventsProto protobuf message using
+ * ProtoOutputStream.
+ *
+ * See proto definition and some notes about ProtoOutputStream in
+ * frameworks/base/core/proto/android/service/sensor_service.proto
+ */
+void RecentEventLogger::dump(util::ProtoOutputStream* proto) const {
+    using namespace service::SensorEventsProto;
+    std::lock_guard<std::mutex> lk(mLock);
+
+    proto->write(RecentEventsLog::RECENT_EVENTS_COUNT, int(mRecentEvents.size()));
+    for (int i = mRecentEvents.size() - 1; i >= 0; --i) {
+        const auto& ev = mRecentEvents[i];
+        const uint64_t token = proto->start(RecentEventsLog::EVENTS);
+        proto->write(Event::TIMESTAMP_SEC, float(ev.mEvent.timestamp) / 1e9f);
+        proto->write(Event::WALL_TIMESTAMP_MS, ev.mWallTime.tv_sec * 1000LL
+                + ns2ms(ev.mWallTime.tv_nsec));
+
+        if (mMaskData) {
+            proto->write(Event::MASKED, true);
+        } else {
+            if (mSensorType == SENSOR_TYPE_STEP_COUNTER) {
+                proto->write(Event::INT64_DATA, int64_t(ev.mEvent.u64.step_counter));
+            } else {
+                for (size_t k = 0; k < mEventSize; ++k) {
+                    proto->write(Event::FLOAT_ARRAY, ev.mEvent.data[k]);
+                }
+            }
+        }
+        proto->end(token);
+    }
+}
+
 void RecentEventLogger::setFormat(std::string format) {
     if (format == "mask_data" ) {
         mMaskData = true;
diff --git a/services/sensorservice/RecentEventLogger.h b/services/sensorservice/RecentEventLogger.h
index 67378b7..3a2ae77 100644
--- a/services/sensorservice/RecentEventLogger.h
+++ b/services/sensorservice/RecentEventLogger.h
@@ -48,6 +48,7 @@
 
     // Dumpable interface
     virtual std::string dump() const override;
+    virtual void dump(util::ProtoOutputStream* proto) const override;
     virtual void setFormat(std::string format) override;
 
 protected:
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index c7a8f5b..33f940f 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -21,6 +21,8 @@
 #include "SensorService.h"
 
 #include <android-base/logging.h>
+#include <android/util/ProtoOutputStream.h>
+#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
 #include <sensors/convert.h>
 #include <cutils/atomic.h>
 #include <utils/Errors.h>
@@ -39,6 +41,7 @@
 using android::hardware::hidl_vec;
 using android::hardware::Return;
 using android::SensorDeviceUtils::HidlServiceRegistrationWaiter;
+using android::util::ProtoOutputStream;
 
 namespace android {
 // ---------------------------------------------------------------------------
@@ -396,6 +399,43 @@
     return result.string();
 }
 
+/**
+ * Dump debugging information as android.service.SensorDeviceProto protobuf message using
+ * ProtoOutputStream.
+ *
+ * See proto definition and some notes about ProtoOutputStream in
+ * frameworks/base/core/proto/android/service/sensor_service.proto
+ */
+void SensorDevice::dump(ProtoOutputStream* proto) const {
+    using namespace service::SensorDeviceProto;
+    if (mSensors == nullptr) {
+        proto->write(INITIALIZED , false);
+        return;
+    }
+    proto->write(INITIALIZED , true);
+    proto->write(TOTAL_SENSORS , int(mSensorList.size()));
+    proto->write(ACTIVE_SENSORS , int(mActivationCount.size()));
+
+    Mutex::Autolock _l(mLock);
+    for (const auto & s : mSensorList) {
+        int32_t handle = s.handle;
+        const Info& info = mActivationCount.valueFor(handle);
+        if (info.numActiveClients() == 0) continue;
+
+        uint64_t token = proto->start(SENSORS);
+        proto->write(SensorProto::HANDLE , handle);
+        proto->write(SensorProto::ACTIVE_COUNT , int(info.batchParams.size()));
+        for (size_t j = 0; j < info.batchParams.size(); j++) {
+            const BatchParams& params = info.batchParams[j];
+            proto->write(SensorProto::SAMPLING_PERIOD_MS , params.mTSample / 1e6f);
+            proto->write(SensorProto::BATCHING_PERIOD_MS , params.mTBatch / 1e6f);
+        }
+        proto->write(SensorProto::SAMPLING_PERIOD_SELECTED , info.bestBatchParams.mTSample / 1e6f);
+        proto->write(SensorProto::BATCHING_PERIOD_SELECTED , info.bestBatchParams.mTBatch / 1e6f);
+        proto->end(token);
+    }
+}
+
 ssize_t SensorDevice::getSensorList(sensor_t const** list) {
     *list = &mSensorList[0];
 
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index d2c6994..33aa7d6 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -123,7 +123,8 @@
     bool isSensorActive(int handle) const;
 
     // Dumpable
-    virtual std::string dump() const;
+    virtual std::string dump() const override;
+    virtual void dump(util::ProtoOutputStream* proto) const override;
 private:
     friend class Singleton<SensorDevice>;
 
diff --git a/services/sensorservice/SensorDirectConnection.cpp b/services/sensorservice/SensorDirectConnection.cpp
index cd0ea5d..106efd6 100644
--- a/services/sensorservice/SensorDirectConnection.cpp
+++ b/services/sensorservice/SensorDirectConnection.cpp
@@ -16,12 +16,16 @@
 
 #include "SensorDevice.h"
 #include "SensorDirectConnection.h"
+#include <android/util/ProtoOutputStream.h>
+#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
 #include <hardware/sensors.h>
 
 #define UNUSED(x) (void)(x)
 
 namespace android {
 
+using util::ProtoOutputStream;
+
 SensorService::SensorDirectConnection::SensorDirectConnection(const sp<SensorService>& service,
         uid_t uid, const sensors_direct_mem_t *mem, int32_t halChannelHandle,
         const String16& opPackageName)
@@ -64,6 +68,27 @@
     }
 }
 
+/**
+ * Dump debugging information as android.service.SensorDirectConnectionProto protobuf message using
+ * ProtoOutputStream.
+ *
+ * See proto definition and some notes about ProtoOutputStream in
+ * frameworks/base/core/proto/android/service/sensor_service.proto
+ */
+void SensorService::SensorDirectConnection::dump(ProtoOutputStream* proto) const {
+    using namespace service::SensorDirectConnectionProto;
+    Mutex::Autolock _l(mConnectionLock);
+    proto->write(PACKAGE_NAME, std::string(String8(mOpPackageName).string()));
+    proto->write(HAL_CHANNEL_HANDLE, getHalChannelHandle());
+    proto->write(NUM_SENSOR_ACTIVATED, int(mActivated.size()));
+    for (auto &i : mActivated) {
+        uint64_t token = proto->start(SENSORS);
+        proto->write(SensorProto::SENSOR, i.first);
+        proto->write(SensorProto::RATE, i.second);
+        proto->end(token);
+    }
+}
+
 sp<BitTube> SensorService::SensorDirectConnection::getSensorChannel() const {
     return nullptr;
 }
diff --git a/services/sensorservice/SensorDirectConnection.h b/services/sensorservice/SensorDirectConnection.h
index 5c398a8..ead08d3 100644
--- a/services/sensorservice/SensorDirectConnection.h
+++ b/services/sensorservice/SensorDirectConnection.h
@@ -40,6 +40,7 @@
             const sensors_direct_mem_t *mem, int32_t halChannelHandle,
             const String16& opPackageName);
     void dump(String8& result) const;
+    void dump(util::ProtoOutputStream* proto) const;
     uid_t getUid() const { return mUid; }
     int32_t getHalChannelHandle() const;
     bool isEquivalent(const sensors_direct_mem_t *mem) const;
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index 0e40940..9a13c00 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -17,6 +17,8 @@
 #include <sys/socket.h>
 #include <utils/threads.h>
 
+#include <android/util/ProtoOutputStream.h>
+#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
 #include <sensor/SensorEventQueue.h>
 
 #include "vec.h"
@@ -110,6 +112,51 @@
 #endif
 }
 
+/**
+ * Dump debugging information as android.service.SensorEventConnectionProto protobuf message using
+ * ProtoOutputStream.
+ *
+ * See proto definition and some notes about ProtoOutputStream in
+ * frameworks/base/core/proto/android/service/sensor_service.proto
+ */
+void SensorService::SensorEventConnection::dump(util::ProtoOutputStream* proto) const {
+    using namespace service::SensorEventConnectionProto;
+    Mutex::Autolock _l(mConnectionLock);
+
+    if (!mService->isWhiteListedPackage(getPackageName())) {
+        proto->write(OPERATING_MODE, OP_MODE_RESTRICTED);
+    } else if (mDataInjectionMode) {
+        proto->write(OPERATING_MODE, OP_MODE_DATA_INJECTION);
+    } else {
+        proto->write(OPERATING_MODE, OP_MODE_NORMAL);
+    }
+    proto->write(PACKAGE_NAME, std::string(mPackageName.string()));
+    proto->write(WAKE_LOCK_REF_COUNT, int32_t(mWakeLockRefCount));
+    proto->write(UID, int32_t(mUid));
+    proto->write(CACHE_SIZE, int32_t(mCacheSize));
+    proto->write(MAX_CACHE_SIZE, int32_t(mMaxCacheSize));
+    for (size_t i = 0; i < mSensorInfo.size(); ++i) {
+        const FlushInfo& flushInfo = mSensorInfo.valueAt(i);
+        const uint64_t token = proto->start(FLUSH_INFOS);
+        proto->write(FlushInfoProto::SENSOR_NAME,
+                std::string(mService->getSensorName(mSensorInfo.keyAt(i))));
+        proto->write(FlushInfoProto::SENSOR_HANDLE, mSensorInfo.keyAt(i));
+        proto->write(FlushInfoProto::FIRST_FLUSH_PENDING, flushInfo.mFirstFlushPending);
+        proto->write(FlushInfoProto::PENDING_FLUSH_EVENTS_TO_SEND,
+                flushInfo.mPendingFlushEventsToSend);
+        proto->end(token);
+    }
+#if DEBUG_CONNECTIONS
+    proto->write(EVENTS_RECEIVED, mEventsReceived);
+    proto->write(EVENTS_SENT, mEventsSent);
+    proto->write(EVENTS_CACHE, mEventsSentFromCache);
+    proto->write(EVENTS_DROPPED, mEventsReceived - (mEventsSentFromCache + mEventsSent +
+            mCacheSize));
+    proto->write(TOTAL_ACKS_NEEDED, mTotalAcksNeeded);
+    proto->write(TOTAL_ACKS_RECEIVED, mTotalAcksReceived);
+#endif
+}
+
 bool SensorService::SensorEventConnection::addSensor(int32_t handle) {
     Mutex::Autolock _l(mConnectionLock);
     sp<SensorInterface> si = mService->getSensorInterfaceFromHandle(handle);
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index fd881cb..caf5d7c 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -62,6 +62,7 @@
     bool removeSensor(int32_t handle);
     void setFirstFlushPending(int32_t handle, bool value);
     void dump(String8& result);
+    void dump(util::ProtoOutputStream* proto) const;
     bool needsWakeLock();
     void resetWakeLockRefCount();
     String8 getPackageName() const;
diff --git a/services/sensorservice/SensorFusion.cpp b/services/sensorservice/SensorFusion.cpp
index 414f673..e27b52b 100644
--- a/services/sensorservice/SensorFusion.cpp
+++ b/services/sensorservice/SensorFusion.cpp
@@ -18,6 +18,9 @@
 #include "SensorFusion.h"
 #include "SensorService.h"
 
+#include <android/util/ProtoOutputStream.h>
+#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
+
 namespace android {
 // ---------------------------------------------------------------------------
 
@@ -183,7 +186,7 @@
     return mAcc.getMinDelay();
 }
 
-void SensorFusion::dump(String8& result) {
+void SensorFusion::dump(String8& result) const {
     const Fusion& fusion_9axis(mFusions[FUSION_9AXIS]);
     result.appendFormat("9-axis fusion %s (%zd clients), gyro-rate=%7.2fHz, "
             "q=< %g, %g, %g, %g > (%g), "
@@ -235,5 +238,42 @@
             fusion_nogyro.getBias().z);
 }
 
+void SensorFusion::dumpFusion(FUSION_MODE mode, util::ProtoOutputStream* proto) const {
+    using namespace service::SensorFusionProto::FusionProto;
+    const Fusion& fusion(mFusions[mode]);
+    proto->write(ENABLED, mEnabled[mode]);
+    proto->write(NUM_CLIENTS, (int)mClients[mode].size());
+    proto->write(ESTIMATED_GYRO_RATE, mEstimatedGyroRate);
+    proto->write(ATTITUDE_X, fusion.getAttitude().x);
+    proto->write(ATTITUDE_Y, fusion.getAttitude().y);
+    proto->write(ATTITUDE_Z, fusion.getAttitude().z);
+    proto->write(ATTITUDE_W, fusion.getAttitude().w);
+    proto->write(ATTITUDE_LENGTH, length(fusion.getAttitude()));
+    proto->write(BIAS_X, fusion.getBias().x);
+    proto->write(BIAS_Y, fusion.getBias().y);
+    proto->write(BIAS_Z, fusion.getBias().z);
+}
+
+/**
+ * Dump debugging information as android.service.SensorFusionProto protobuf message using
+ * ProtoOutputStream.
+ *
+ * See proto definition and some notes about ProtoOutputStream in
+ * frameworks/base/core/proto/android/service/sensor_service.proto
+ */
+void SensorFusion::dump(util::ProtoOutputStream* proto) const {
+    uint64_t token = proto->start(service::SensorFusionProto::FUSION_9AXIS);
+    dumpFusion(FUSION_9AXIS, proto);
+    proto->end(token);
+
+    token = proto->start(service::SensorFusionProto::FUSION_NOMAG);
+    dumpFusion(FUSION_NOMAG, proto);
+    proto->end(token);
+
+    token = proto->start(service::SensorFusionProto::FUSION_NOGYRO);
+    dumpFusion(FUSION_NOGYRO, proto);
+    proto->end(token);
+}
+
 // ---------------------------------------------------------------------------
 }; // namespace android
diff --git a/services/sensorservice/SensorFusion.h b/services/sensorservice/SensorFusion.h
index 8c0fbf9..66a7290 100644
--- a/services/sensorservice/SensorFusion.h
+++ b/services/sensorservice/SensorFusion.h
@@ -90,7 +90,9 @@
     float getPowerUsage(int mode=FUSION_9AXIS) const;
     int32_t getMinDelay() const;
 
-    void dump(String8& result);
+    void dump(String8& result) const;
+    void dump(util::ProtoOutputStream* proto) const;
+    void dumpFusion(FUSION_MODE mode, util::ProtoOutputStream* proto) const;
 };
 
 
diff --git a/services/sensorservice/SensorList.cpp b/services/sensorservice/SensorList.cpp
index aa306d8..0ce32cc 100644
--- a/services/sensorservice/SensorList.cpp
+++ b/services/sensorservice/SensorList.cpp
@@ -16,6 +16,8 @@
 
 #include "SensorList.h"
 
+#include <android/util/ProtoOutputStream.h>
+#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
 #include <hardware/sensors.h>
 #include <utils/String8.h>
 
@@ -203,6 +205,64 @@
     return std::string(result.string());
 }
 
+/**
+ * Dump debugging information as android.service.SensorListProto protobuf message using
+ * ProtoOutputStream.
+ *
+ * See proto definition and some notes about ProtoOutputStream in
+ * frameworks/base/core/proto/android/service/sensor_service.proto
+ */
+void SensorList::dump(util::ProtoOutputStream* proto) const {
+    using namespace service::SensorListProto;
+    using namespace service::SensorListProto::SensorProto;
+
+    forEachSensor([&proto] (const Sensor& s) -> bool {
+        const uint64_t token = proto->start(SENSORS);
+        proto->write(HANDLE, s.getHandle());
+        proto->write(NAME, std::string(s.getName().string()));
+        proto->write(VENDOR, std::string(s.getVendor().string()));
+        proto->write(VERSION, s.getVersion());
+        proto->write(STRING_TYPE, std::string(s.getStringType().string()));
+        proto->write(TYPE, s.getType());
+        proto->write(REQUIRED_PERMISSION, std::string(s.getRequiredPermission().size() ?
+                s.getRequiredPermission().string() : ""));
+        proto->write(FLAGS, int(s.getFlags()));
+        switch (s.getReportingMode()) {
+            case AREPORTING_MODE_CONTINUOUS:
+                proto->write(REPORTING_MODE, RM_CONTINUOUS);
+                break;
+            case AREPORTING_MODE_ON_CHANGE:
+                proto->write(REPORTING_MODE, RM_ON_CHANGE);
+                break;
+            case AREPORTING_MODE_ONE_SHOT:
+                proto->write(REPORTING_MODE, RM_ONE_SHOT);
+                break;
+            case AREPORTING_MODE_SPECIAL_TRIGGER:
+                proto->write(REPORTING_MODE, RM_SPECIAL_TRIGGER);
+                break;
+            default:
+                proto->write(REPORTING_MODE, RM_UNKNOWN);
+        }
+        proto->write(MAX_DELAY_US, s.getMaxDelay());
+        proto->write(MIN_DELAY_US, s.getMinDelay());
+        proto->write(FIFO_MAX_EVENT_COUNT, int(s.getFifoMaxEventCount()));
+        proto->write(FIFO_RESERVED_EVENT_COUNT, int(s.getFifoReservedEventCount()));
+        proto->write(IS_WAKEUP, s.isWakeUpSensor());
+        proto->write(DATA_INJECTION_SUPPORTED, s.isDataInjectionSupported());
+        proto->write(IS_DYNAMIC, s.isDynamicSensor());
+        proto->write(HAS_ADDITIONAL_INFO, s.hasAdditionalInfo());
+        proto->write(HIGHEST_RATE_LEVEL, s.getHighestDirectReportRateLevel());
+        proto->write(ASHMEM, s.isDirectChannelTypeSupported(SENSOR_DIRECT_MEM_TYPE_ASHMEM));
+        proto->write(GRALLOC, s.isDirectChannelTypeSupported(SENSOR_DIRECT_MEM_TYPE_GRALLOC));
+        proto->write(MIN_VALUE, s.getMinValue());
+        proto->write(MAX_VALUE, s.getMaxValue());
+        proto->write(RESOLUTION, s.getResolution());
+        proto->write(POWER_USAGE, s.getPowerUsage());
+        proto->end(token);
+        return true;
+    });
+}
+
 SensorList::~SensorList() {
 }
 
diff --git a/services/sensorservice/SensorList.h b/services/sensorservice/SensorList.h
index 6b90ad9..8424b22 100644
--- a/services/sensorservice/SensorList.h
+++ b/services/sensorservice/SensorList.h
@@ -71,6 +71,7 @@
 
     // Dumpable interface
     virtual std::string dump() const override;
+    virtual void dump(util::ProtoOutputStream* proto) const override;
 
     virtual ~SensorList();
 private:
diff --git a/services/sensorservice/SensorRegistrationInfo.h b/services/sensorservice/SensorRegistrationInfo.h
index 5411515..a34a65b 100644
--- a/services/sensorservice/SensorRegistrationInfo.h
+++ b/services/sensorservice/SensorRegistrationInfo.h
@@ -17,10 +17,14 @@
 #ifndef ANDROID_SENSOR_REGISTRATION_INFO_H
 #define ANDROID_SENSOR_REGISTRATION_INFO_H
 
-#include "SensorServiceUtils.h"
-#include <utils/Thread.h>
+#include <ctime>
 #include <iomanip>
 #include <sstream>
+#include <utils/Thread.h>
+
+#include <android/util/ProtoOutputStream.h>
+#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
+#include "SensorServiceUtils.h"
 
 namespace android {
 
@@ -30,7 +34,7 @@
 public:
     SensorRegistrationInfo() : mPackageName() {
         mSensorHandle = mSamplingRateUs = mMaxReportLatencyUs = INT32_MIN;
-        mHour = mMin = mSec = INT8_MIN;
+        mRealtimeSec = 0;
         mActivated = false;
     }
 
@@ -47,25 +51,26 @@
         mPid = (thread != nullptr) ? thread->getCallingPid() : -1;
         mUid = (thread != nullptr) ? thread->getCallingUid() : -1;
 
-        time_t rawtime = time(nullptr);
-        struct tm * timeinfo = localtime(&rawtime);
-        mHour = static_cast<int8_t>(timeinfo->tm_hour);
-        mMin = static_cast<int8_t>(timeinfo->tm_min);
-        mSec = static_cast<int8_t>(timeinfo->tm_sec);
+        timespec curTime;
+        clock_gettime(CLOCK_REALTIME_COARSE, &curTime);
+        mRealtimeSec = curTime.tv_sec;
     }
 
     static bool isSentinel(const SensorRegistrationInfo& info) {
-       return (info.mHour == INT8_MIN &&
-               info.mMin == INT8_MIN &&
-               info.mSec == INT8_MIN);
+       return (info.mSensorHandle == INT32_MIN && info.mRealtimeSec == 0);
     }
 
     // Dumpable interface
     virtual std::string dump() const override {
+        struct tm* timeinfo = localtime(&mRealtimeSec);
+        const int8_t hour = static_cast<int8_t>(timeinfo->tm_hour);
+        const int8_t min = static_cast<int8_t>(timeinfo->tm_min);
+        const int8_t sec = static_cast<int8_t>(timeinfo->tm_sec);
+
         std::ostringstream ss;
-        ss << std::setfill('0') << std::setw(2) << static_cast<int>(mHour) << ":"
-           << std::setw(2) << static_cast<int>(mMin) << ":"
-           << std::setw(2) << static_cast<int>(mSec)
+        ss << std::setfill('0') << std::setw(2) << static_cast<int>(hour) << ":"
+           << std::setw(2) << static_cast<int>(min) << ":"
+           << std::setw(2) << static_cast<int>(sec)
            << (mActivated ? " +" : " -")
            << " 0x" << std::hex << std::setw(8) << mSensorHandle << std::dec
            << std::setfill(' ') << " pid=" << std::setw(5) << mPid
@@ -77,6 +82,25 @@
         return ss.str();
     }
 
+    /**
+     * Dump debugging information as android.service.SensorRegistrationInfoProto protobuf message
+     * using ProtoOutputStream.
+     *
+     * See proto definition and some notes about ProtoOutputStream in
+     * frameworks/base/core/proto/android/service/sensor_service.proto
+     */
+    virtual void dump(util::ProtoOutputStream* proto) const override {
+        using namespace service::SensorRegistrationInfoProto;
+        proto->write(TIMESTAMP_SEC, int64_t(mRealtimeSec));
+        proto->write(SENSOR_HANDLE, mSensorHandle);
+        proto->write(PACKAGE_NAME, std::string(mPackageName.string()));
+        proto->write(PID, int32_t(mPid));
+        proto->write(UID, int32_t(mUid));
+        proto->write(SAMPLING_RATE_US, mSamplingRateUs);
+        proto->write(MAX_REPORT_LATENCY_US, mMaxReportLatencyUs);
+        proto->write(ACTIVATED, mActivated);
+    }
+
 private:
     int32_t mSensorHandle;
     String8 mPackageName;
@@ -85,8 +109,7 @@
     int64_t mSamplingRateUs;
     int64_t mMaxReportLatencyUs;
     bool mActivated;
-    int8_t mHour, mMin, mSec;
-
+    time_t mRealtimeSec;
 };
 
 } // namespace android;
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index c2e1204..e803c9a 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 #include <android/content/pm/IPackageManagerNative.h>
+#include <android/util/ProtoOutputStream.h>
+#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
 #include <binder/ActivityManager.h>
 #include <binder/BinderService.h>
 #include <binder/IServiceManager.h>
@@ -404,6 +406,8 @@
                 // Transition to data injection mode supported only from NORMAL mode.
                 return INVALID_OPERATION;
             }
+        } else if (args.size() == 1 && args[0] == String16("--proto")) {
+            return dumpProtoLocked(fd, &connLock);
         } else if (!mSensors.hasAnySensor()) {
             result.append("No Sensors on the device\n");
             result.appendFormat("devInitCheck : %d\n", SensorDevice::getInstance().initCheck());
@@ -506,6 +510,124 @@
     return NO_ERROR;
 }
 
+/**
+ * Dump debugging information as android.service.SensorServiceProto protobuf message using
+ * ProtoOutputStream.
+ *
+ * See proto definition and some notes about ProtoOutputStream in
+ * frameworks/base/core/proto/android/service/sensor_service.proto
+ */
+status_t SensorService::dumpProtoLocked(int fd, ConnectionSafeAutolock* connLock) const {
+    using namespace service::SensorServiceProto;
+    util::ProtoOutputStream proto;
+    const bool privileged = IPCThreadState::self()->getCallingUid() == 0;
+
+    timespec curTime;
+    clock_gettime(CLOCK_REALTIME, &curTime);
+    proto.write(CURRENT_TIME_MS, curTime.tv_sec * 1000 + ns2ms(curTime.tv_nsec));
+
+    // Write SensorDeviceProto
+    uint64_t token = proto.start(SENSOR_DEVICE);
+    SensorDevice::getInstance().dump(&proto);
+    proto.end(token);
+
+    // Write SensorListProto
+    token = proto.start(SENSORS);
+    mSensors.dump(&proto);
+    proto.end(token);
+
+    // Write SensorFusionProto
+    token = proto.start(FUSION_STATE);
+    SensorFusion::getInstance().dump(&proto);
+    proto.end(token);
+
+    // Write SensorEventsProto
+    token = proto.start(SENSOR_EVENTS);
+    for (auto&& i : mRecentEvent) {
+        sp<SensorInterface> s = mSensors.getInterface(i.first);
+        if (!i.second->isEmpty()) {
+            i.second->setFormat(privileged || s->getSensor().getRequiredPermission().isEmpty() ?
+                    "normal" : "mask_data");
+            const uint64_t mToken = proto.start(service::SensorEventsProto::RECENT_EVENTS_LOGS);
+            proto.write(service::SensorEventsProto::RecentEventsLog::NAME,
+                    std::string(s->getSensor().getName().string()));
+            i.second->dump(&proto);
+            proto.end(mToken);
+        }
+    }
+    proto.end(token);
+
+    // Write ActiveSensorProto
+    SensorDevice& dev = SensorDevice::getInstance();
+    for (size_t i=0 ; i<mActiveSensors.size() ; i++) {
+        int handle = mActiveSensors.keyAt(i);
+        if (dev.isSensorActive(handle)) {
+            token = proto.start(ACTIVE_SENSORS);
+            proto.write(service::ActiveSensorProto::NAME,
+                    std::string(getSensorName(handle).string()));
+            proto.write(service::ActiveSensorProto::HANDLE, handle);
+            proto.write(service::ActiveSensorProto::NUM_CONNECTIONS,
+                    int(mActiveSensors.valueAt(i)->getNumConnections()));
+            proto.end(token);
+        }
+    }
+
+    proto.write(SOCKET_BUFFER_SIZE, int(mSocketBufferSize));
+    proto.write(SOCKET_BUFFER_SIZE_IN_EVENTS, int(mSocketBufferSize / sizeof(sensors_event_t)));
+    proto.write(WAKE_LOCK_ACQUIRED, mWakeLockAcquired);
+
+    switch(mCurrentOperatingMode) {
+        case NORMAL:
+            proto.write(OPERATING_MODE, OP_MODE_NORMAL);
+            break;
+        case RESTRICTED:
+            proto.write(OPERATING_MODE, OP_MODE_RESTRICTED);
+            proto.write(WHITELISTED_PACKAGE, std::string(mWhiteListedPackage.string()));
+            break;
+        case DATA_INJECTION:
+            proto.write(OPERATING_MODE, OP_MODE_DATA_INJECTION);
+            proto.write(WHITELISTED_PACKAGE, std::string(mWhiteListedPackage.string()));
+            break;
+        default:
+            proto.write(OPERATING_MODE, OP_MODE_UNKNOWN);
+    }
+    proto.write(SENSOR_PRIVACY, mSensorPrivacyPolicy->isSensorPrivacyEnabled());
+
+    // Write repeated SensorEventConnectionProto
+    const auto& activeConnections = connLock->getActiveConnections();
+    for (size_t i = 0; i < activeConnections.size(); i++) {
+        token = proto.start(ACTIVE_CONNECTIONS);
+        activeConnections[i]->dump(&proto);
+        proto.end(token);
+    }
+
+    // Write repeated SensorDirectConnectionProto
+    const auto& directConnections = connLock->getDirectConnections();
+    for (size_t i = 0 ; i < directConnections.size() ; i++) {
+        token = proto.start(DIRECT_CONNECTIONS);
+        directConnections[i]->dump(&proto);
+        proto.end(token);
+    }
+
+    // Write repeated SensorRegistrationInfoProto
+    const int startIndex = mNextSensorRegIndex;
+    int curr = startIndex;
+    do {
+        const SensorRegistrationInfo& reg_info = mLastNSensorRegistrations[curr];
+        if (SensorRegistrationInfo::isSentinel(reg_info)) {
+            // Ignore sentinel, proceed to next item.
+            curr = (curr + 1 + SENSOR_REGISTRATIONS_BUF_SIZE) % SENSOR_REGISTRATIONS_BUF_SIZE;
+            continue;
+        }
+        token = proto.start(PREVIOUS_REGISTRATIONS);
+        reg_info.dump(&proto);
+        proto.end(token);
+        curr = (curr + 1 + SENSOR_REGISTRATIONS_BUF_SIZE) % SENSOR_REGISTRATIONS_BUF_SIZE;
+    } while (startIndex != curr);
+
+    return proto.flush(fd) ? OK : UNKNOWN_ERROR;
+}
+
 void SensorService::disableAllSensors() {
     ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
     disableAllSensorsLocked(&connLock);
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index fa23da0..7d17dda 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -286,6 +286,7 @@
     virtual int setOperationParameter(
             int32_t handle, int32_t type, const Vector<float> &floats, const Vector<int32_t> &ints);
     virtual status_t dump(int fd, const Vector<String16>& args);
+    status_t dumpProtoLocked(int fd, ConnectionSafeAutolock* connLock) const;
     String8 getSensorName(int handle) const;
     bool isVirtualSensor(int handle) const;
     sp<SensorInterface> getSensorInterfaceFromHandle(int handle) const;
diff --git a/services/sensorservice/SensorServiceUtils.h b/services/sensorservice/SensorServiceUtils.h
index 1558feb..49457cf 100644
--- a/services/sensorservice/SensorServiceUtils.h
+++ b/services/sensorservice/SensorServiceUtils.h
@@ -21,11 +21,17 @@
 #include <string>
 
 namespace android {
+
+namespace util {
+class ProtoOutputStream;
+}
+
 namespace SensorServiceUtil {
 
 class Dumpable {
 public:
     virtual std::string dump() const = 0;
+    virtual void dump(util::ProtoOutputStream*) const {}
     virtual void setFormat(std::string ) {}
     virtual ~Dumpable() {}
 };