Add tracing for ADPF hint sessions in client

Bug: 293324684
Test: manual

Change-Id: I417f18da69f27cc77da33fc40663b55e80822ee7
diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp
index c4c8128..abe4a3d 100644
--- a/native/android/performance_hint.cpp
+++ b/native/android/performance_hint.cpp
@@ -18,10 +18,12 @@
 
 #include <aidl/android/hardware/power/SessionHint.h>
 #include <aidl/android/hardware/power/SessionMode.h>
+#include <android-base/stringprintf.h>
 #include <android/WorkDuration.h>
 #include <android/os/IHintManager.h>
 #include <android/os/IHintSession.h>
 #include <android/performance_hint.h>
+#include <android/trace.h>
 #include <binder/Binder.h>
 #include <binder/IBinder.h>
 #include <binder/IServiceManager.h>
@@ -30,6 +32,7 @@
 #include <utils/SystemClock.h>
 
 #include <chrono>
+#include <set>
 #include <utility>
 #include <vector>
 
@@ -40,6 +43,7 @@
 
 using AidlSessionHint = aidl::android::hardware::power::SessionHint;
 using AidlSessionMode = aidl::android::hardware::power::SessionMode;
+using android::base::StringPrintf;
 
 struct APerformanceHintSession;
 
@@ -98,10 +102,21 @@
     std::vector<int64_t> mLastHintSentTimestamp;
     // Cached samples
     std::vector<WorkDuration> mActualWorkDurations;
+    std::string mSessionName;
+    static int32_t sIDCounter;
+    // The most recent set of thread IDs
+    std::vector<int32_t> mLastThreadIDs;
+    // Tracing helpers
+    void traceThreads(std::vector<int32_t>& tids);
+    void tracePowerEfficient(bool powerEfficient);
+    void traceActualDuration(int64_t actualDuration);
+    void traceBatchSize(size_t batchSize);
+    void traceTargetDuration(int64_t targetDuration);
 };
 
 static IHintManager* gIHintManagerForTesting = nullptr;
 static APerformanceHintManager* gHintManagerForTesting = nullptr;
+int32_t APerformanceHintSession::sIDCounter = 0;
 
 // ===================================== APerformanceHintManager implementation
 APerformanceHintManager::APerformanceHintManager(sp<IHintManager> manager,
@@ -150,8 +165,12 @@
     if (!ret.isOk() || !session) {
         return nullptr;
     }
-    return new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos,
-                                       initialTargetWorkDurationNanos);
+    auto out = new APerformanceHintSession(mHintManager, std::move(session), mPreferredRateNanos,
+                                           initialTargetWorkDurationNanos);
+    out->traceThreads(tids);
+    out->traceTargetDuration(initialTargetWorkDurationNanos);
+    out->tracePowerEfficient(false);
+    return out;
 }
 
 int64_t APerformanceHintManager::getPreferredRateNanos() const {
@@ -174,6 +193,7 @@
                                                         ndk::enum_range<AidlSessionHint>().end()};
 
     mLastHintSentTimestamp = std::vector<int64_t>(sessionHintRange.size(), 0);
+    mSessionName = android::base::StringPrintf("ADPF Session %" PRId32, ++sIDCounter);
 }
 
 APerformanceHintSession::~APerformanceHintSession() {
@@ -200,6 +220,8 @@
      * as they are most likely obsolete.
      */
     mActualWorkDurations.clear();
+    traceBatchSize(0);
+    traceTargetDuration(targetDurationNanos);
     mFirstTargetMetTimestamp = 0;
     mLastTargetMetTimestamp = 0;
     return 0;
@@ -254,6 +276,9 @@
         }
         return EPIPE;
     }
+
+    traceThreads(tids);
+
     return 0;
 }
 
@@ -289,6 +314,7 @@
               ret.exceptionMessage().c_str());
         return EPIPE;
     }
+    tracePowerEfficient(enabled);
     return OK;
 }
 
@@ -318,6 +344,7 @@
     int64_t actualTotalDurationNanos = workDuration->actualTotalDurationNanos;
     int64_t now = uptimeNanos();
     workDuration->timestampNanos = now;
+    traceActualDuration(workDuration->actualTotalDurationNanos);
     mActualWorkDurations.push_back(std::move(*workDuration));
 
     if (actualTotalDurationNanos >= mTargetDurationNanos) {
@@ -335,6 +362,7 @@
          */
         if (now - mFirstTargetMetTimestamp > mPreferredRateNanos &&
             now - mLastTargetMetTimestamp <= mPreferredRateNanos) {
+            traceBatchSize(mActualWorkDurations.size());
             return 0;
         }
         mLastTargetMetTimestamp = now;
@@ -346,12 +374,54 @@
               ret.exceptionMessage().c_str());
         mFirstTargetMetTimestamp = 0;
         mLastTargetMetTimestamp = 0;
+        traceBatchSize(mActualWorkDurations.size());
         return ret.exceptionCode() == binder::Status::EX_ILLEGAL_ARGUMENT ? EINVAL : EPIPE;
     }
     mActualWorkDurations.clear();
+    traceBatchSize(0);
 
     return 0;
 }
+// ===================================== Tracing helpers
+
+void APerformanceHintSession::traceThreads(std::vector<int32_t>& tids) {
+    std::set<int32_t> tidSet{tids.begin(), tids.end()};
+
+    // Disable old TID tracing
+    for (int32_t tid : mLastThreadIDs) {
+        if (!tidSet.count(tid)) {
+            std::string traceName =
+                    android::base::StringPrintf("%s TID: %" PRId32, mSessionName.c_str(), tid);
+            ATrace_setCounter(traceName.c_str(), 0);
+        }
+    }
+
+    // Add new TID tracing
+    for (int32_t tid : tids) {
+        std::string traceName =
+                android::base::StringPrintf("%s TID: %" PRId32, mSessionName.c_str(), tid);
+        ATrace_setCounter(traceName.c_str(), 1);
+    }
+
+    mLastThreadIDs = std::move(tids);
+}
+
+void APerformanceHintSession::tracePowerEfficient(bool powerEfficient) {
+    ATrace_setCounter((mSessionName + " power efficiency mode").c_str(), powerEfficient);
+}
+
+void APerformanceHintSession::traceActualDuration(int64_t actualDuration) {
+    ATrace_setCounter((mSessionName + " actual duration").c_str(), actualDuration);
+}
+
+void APerformanceHintSession::traceBatchSize(size_t batchSize) {
+    std::string traceName = StringPrintf("%s batch size", mSessionName.c_str());
+    ATrace_setCounter((mSessionName + " batch size").c_str(), batchSize);
+}
+
+void APerformanceHintSession::traceTargetDuration(int64_t targetDuration) {
+    ATrace_setCounter((mSessionName + " target duration").c_str(), targetDuration);
+}
 
 // ===================================== C API
 APerformanceHintManager* APerformanceHint_getManager() {
diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java
index 7c833cb..6f75439 100644
--- a/services/core/java/com/android/server/power/hint/HintManagerService.java
+++ b/services/core/java/com/android/server/power/hint/HintManagerService.java
@@ -481,6 +481,11 @@
         protected long mTargetDurationNanos;
         protected boolean mUpdateAllowed;
         protected int[] mNewThreadIds;
+        protected boolean mPowerEfficient;
+
+        private enum SessionModes {
+            POWER_EFFICIENCY,
+        };
 
         protected AppHintSession(
                 int uid, int pid, int[] threadIds, IBinder token,
@@ -492,6 +497,7 @@
             mHalSessionPtr = halSessionPtr;
             mTargetDurationNanos = durationNanos;
             mUpdateAllowed = true;
+            mPowerEfficient = false;
             final boolean allowed = mUidObserver.isUidForeground(mUid);
             updateHintAllowed(allowed);
             try {
@@ -634,6 +640,9 @@
                 }
                 Preconditions.checkArgument(mode >= 0, "the mode Id value should be"
                         + " greater than zero.");
+                if (mode == SessionModes.POWER_EFFICIENCY.ordinal()) {
+                    mPowerEfficient = enabled;
+                }
                 mNativeWrapper.halSetMode(mHalSessionPtr, mode, enabled);
             }
         }
@@ -653,6 +662,12 @@
             }
         }
 
+        public boolean isPowerEfficient() {
+            synchronized (this) {
+                return mPowerEfficient;
+            }
+        }
+
         void validateWorkDuration(WorkDuration workDuration) {
             if (DEBUG) {
                 Slogf.d(TAG, "WorkDuration(" + workDuration.getTimestampNanos() + ", "
@@ -718,6 +733,7 @@
                 pw.println(prefix + "SessionTIDs: " + Arrays.toString(mThreadIds));
                 pw.println(prefix + "SessionTargetDurationNanos: " + mTargetDurationNanos);
                 pw.println(prefix + "SessionAllowed: " + mUpdateAllowed);
+                pw.println(prefix + "PowerEfficient: " + (mPowerEfficient ? "true" : "false"));
             }
         }