Implements thread utilization updates in CHRE

Bug: 110939839
Test: Compile and run, verify CHRE's updates are reflected
      in the aggregate utilization metric
Change-Id: Ic9baa996c602974c8f017c98c3700450bab302b5
diff --git a/platform/slpi/see/include/chre/target_platform/power_control_manager_base.h b/platform/slpi/see/include/chre/target_platform/power_control_manager_base.h
index 9081262..22cdba4 100644
--- a/platform/slpi/see/include/chre/target_platform/power_control_manager_base.h
+++ b/platform/slpi/see/include/chre/target_platform/power_control_manager_base.h
@@ -17,10 +17,17 @@
 #ifndef CHRE_PLATFORM_SLPI_SEE_POWER_CONTROL_MANAGER_BASE_H_
 #define CHRE_PLATFORM_SLPI_SEE_POWER_CONTROL_MANAGER_BASE_H_
 
+extern "C" {
+#include "sns_client_thread_util.h"
+} // extern "C"
+
 namespace chre {
 
 class PowerControlManagerBase {
  public:
+   PowerControlManagerBase();
+  ~PowerControlManagerBase();
+
   /**
    * Makes a power mode request. An actual vote to the SLPI power manager may
    * not be cast depending on current power mode and mBigImageRefCount.
@@ -43,6 +50,13 @@
  protected:
   //! Set to true if the host is awake, false if suspended.
   bool mHostIsAwake = true;
+
+  //! Set to true if the thread is currently idle (no pending events),
+  //! false otherwise.
+  bool mIsThreadIdle = true;
+
+  //! A pointer to the client to compute thread utilization
+  sns_thread_util_client *mThreadUtilClient = nullptr;
 };
 
 } // namespace chre
diff --git a/platform/slpi/see/power_control_manager.cc b/platform/slpi/see/power_control_manager.cc
index 3359723..ad49094 100644
--- a/platform/slpi/see/power_control_manager.cc
+++ b/platform/slpi/see/power_control_manager.cc
@@ -23,6 +23,14 @@
 
 namespace chre {
 
+PowerControlManagerBase::PowerControlManagerBase() {
+  sns_client_create_thread_utilization_client(&mThreadUtilClient);
+}
+
+PowerControlManagerBase::~PowerControlManagerBase() {
+  sns_client_remove_thread_utilization_client(mThreadUtilClient);
+}
+
 bool PowerControlManagerBase::voteBigImage(bool bigImage) {
   return IslandVoteClientSingleton::get()->voteBigImage(bigImage);
 }
@@ -50,6 +58,23 @@
 }
 
 void PowerControlManager::postEventLoopProcess(size_t numPendingEvents) {
+  // Although this execution point does not actually represent the start
+  // of the CHRE thread's activity, we only care about cases where the
+  // CHRE's event queue is highly backlogged for voting higher clock rates.
+  if (mIsThreadIdle && numPendingEvents != 0) {
+    sns_client_thread_utilization_start(mThreadUtilClient);
+    mIsThreadIdle = false;
+  } else if (!mIsThreadIdle) {
+    // Update the time profile as frequently as possible so that clock updates
+    // are not deferred until all events are processed.
+    sns_client_thread_utilization_stop(mThreadUtilClient);
+    if (numPendingEvents != 0) {
+      sns_client_thread_utilization_start(mThreadUtilClient);
+    } else {
+      mIsThreadIdle = true;
+    }
+  }
+
   if (numPendingEvents == 0 && !slpiInUImage()) {
     voteBigImage(false /* bigImage */);
   }