diff options
| author | 2024-11-27 20:44:42 +0000 | |
|---|---|---|
| committer | 2024-11-27 20:44:42 +0000 | |
| commit | f52ff01ff46295f00551b5a80b3bf4bd89ccca2a (patch) | |
| tree | fb0fdf623b9b160d2d8f523b28b1cb3d71902362 | |
| parent | 5870552967bf403229cf77448500c550f6563a32 (diff) | |
| parent | df439a3a726d981af029eda75629c16036a3b89a (diff) | |
Merge "Add new surface binding and auto ADPF methods for ADPF Timeline API" into main
| -rw-r--r-- | core/java/android/os/IHintManager.aidl | 6 | ||||
| -rw-r--r-- | core/java/android/os/IHintSession.aidl | 5 | ||||
| -rw-r--r-- | core/java/android/os/SessionCreationConfig.aidl | 8 | ||||
| -rw-r--r-- | native/android/libandroid.map.txt | 3 | ||||
| -rw-r--r-- | native/android/performance_hint.cpp | 160 | ||||
| -rw-r--r-- | native/android/tests/performance_hint/PerformanceHintNativeTest.cpp | 3 | ||||
| -rw-r--r-- | services/core/Android.bp | 1 | ||||
| -rw-r--r-- | services/core/java/com/android/server/power/hint/HintManagerService.java | 97 |
8 files changed, 270 insertions, 13 deletions
diff --git a/core/java/android/os/IHintManager.aidl b/core/java/android/os/IHintManager.aidl index f1936b5e0ff9..4a14a8d0faf8 100644 --- a/core/java/android/os/IHintManager.aidl +++ b/core/java/android/os/IHintManager.aidl @@ -64,4 +64,10 @@ interface IHintManager { * Get Maximum number of graphics pipeline threads allowed per-app. */ int getMaxGraphicsPipelineThreadsCount(); + + /** + * Used by the JNI to pass an interface to the SessionManager; + * for internal use only. + */ + oneway void passSessionManagerBinder(in IBinder sessionManager); } diff --git a/core/java/android/os/IHintSession.aidl b/core/java/android/os/IHintSession.aidl index 6fd4f3c7c01a..e3f899de6d01 100644 --- a/core/java/android/os/IHintSession.aidl +++ b/core/java/android/os/IHintSession.aidl @@ -27,4 +27,9 @@ oneway interface IHintSession { void sendHint(int hint); void setMode(int mode, boolean enabled); void reportActualWorkDuration2(in WorkDuration[] workDurations); + + /** + * Used by apps to associate a session to a given set of layers + */ + oneway void associateToLayers(in IBinder[] layerTokens); } diff --git a/core/java/android/os/SessionCreationConfig.aidl b/core/java/android/os/SessionCreationConfig.aidl index cdc0ef461e0c..17147e43cf83 100644 --- a/core/java/android/os/SessionCreationConfig.aidl +++ b/core/java/android/os/SessionCreationConfig.aidl @@ -36,4 +36,12 @@ parcelable SessionCreationConfig { * List of the modes to be enabled upon session creation. */ SessionMode[] modesToEnable; + + /** + * List of layers to attach this session to. + * + * Note: DO NOT STORE THESE IN HintSessionManager, as + * it will break the layer lifecycle. + */ + IBinder[] layerTokens; } diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt index 7f555a868615..077d7d350064 100644 --- a/native/android/libandroid.map.txt +++ b/native/android/libandroid.map.txt @@ -376,6 +376,7 @@ LIBANDROID { APerformanceHint_notifyWorkloadIncrease; # introduced=36 APerformanceHint_notifyWorkloadReset; # introduced=36 APerformanceHint_borrowSessionFromJava; # introduced=36 + APerformanceHint_setNativeSurfaces; # introduced=36 AWorkDuration_create; # introduced=VanillaIceCream AWorkDuration_release; # introduced=VanillaIceCream AWorkDuration_setWorkPeriodStartTimestampNanos; # introduced=VanillaIceCream @@ -388,6 +389,8 @@ LIBANDROID { ASessionCreationConfig_setTargetWorkDurationNanos; # introduced=36 ASessionCreationConfig_setPreferPowerEfficiency; # introduced=36 ASessionCreationConfig_setGraphicsPipeline; # introduced=36 + ASessionCreationConfig_setNativeSurfaces; # introduced=36 + ASessionCreationConfig_setUseAutoTiming; # introduced=36 local: *; }; diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp index 883e139cca0a..608c01caee96 100644 --- a/native/android/performance_hint.cpp +++ b/native/android/performance_hint.cpp @@ -29,13 +29,19 @@ #include <aidl/android/os/SessionCreationConfig.h> #include <android-base/stringprintf.h> #include <android-base/thread_annotations.h> +#include <android/binder_libbinder.h> #include <android/binder_manager.h> #include <android/binder_status.h> +#include <android/native_window.h> #include <android/performance_hint.h> +#include <android/surface_control.h> #include <android/trace.h> #include <android_os.h> #include <cutils/trace.h> #include <fmq/AidlMessageQueue.h> +#include <gui/Surface.h> +#include <gui/SurfaceComposerClient.h> +#include <gui/SurfaceControl.h> #include <inttypes.h> #include <jni_wrappers.h> #include <performance_hint_private.h> @@ -66,7 +72,12 @@ struct APerformanceHintSession; constexpr int64_t SEND_HINT_TIMEOUT = std::chrono::nanoseconds(100ms).count(); struct AWorkDuration : public hal::WorkDuration {}; -struct ASessionCreationConfig : public SessionCreationConfig {}; +struct ASessionCreationConfig : public SessionCreationConfig { + std::vector<wp<IBinder>> layers{}; + bool hasMode(hal::SessionMode&& mode) { + return std::find(modesToEnable.begin(), modesToEnable.end(), mode) != modesToEnable.end(); + } +}; bool kForceGraphicsPipeline = false; @@ -158,6 +169,11 @@ public: FMQWrapper& getFMQWrapper(); bool canSendLoadHints(std::vector<hal::SessionHint>& hints, int64_t now) REQUIRES(sHintMutex); void initJava(JNIEnv* _Nonnull env); + ndk::ScopedAIBinder_Weak x; + template <class T> + static void layersFromNativeSurfaces(ANativeWindow** windows, int numWindows, + ASurfaceControl** controls, int numSurfaceControls, + std::vector<T>& out); private: // Necessary to create an empty binder object @@ -203,6 +219,8 @@ public: int setPreferPowerEfficiency(bool enabled); int reportActualWorkDuration(AWorkDuration* workDuration); bool isJava(); + status_t setNativeSurfaces(ANativeWindow** windows, int numWindows, ASurfaceControl** controls, + int numSurfaceControls); private: friend struct APerformanceHintManager; @@ -231,7 +249,7 @@ private: static int64_t sIDCounter GUARDED_BY(sHintMutex); // The most recent set of thread IDs std::vector<int32_t> mLastThreadIDs GUARDED_BY(sHintMutex); - std::optional<hal::SessionConfig> mSessionConfig GUARDED_BY(sHintMutex); + std::optional<hal::SessionConfig> mSessionConfig; // Tracing helpers void traceThreads(const std::vector<int32_t>& tids) REQUIRES(sHintMutex); void tracePowerEfficient(bool powerEfficient); @@ -329,14 +347,12 @@ APerformanceHintSession* APerformanceHintManager::createSession( ndk::ScopedAStatus ret; hal::SessionConfig sessionConfig{.id = -1}; - SessionCreationConfig creationConfig{ + ASessionCreationConfig creationConfig{{ .tids = std::vector<int32_t>(threadIds, threadIds + size), .targetWorkDurationNanos = initialTargetWorkDurationNanos, - }; + }}; - return APerformanceHintManager::createSessionUsingConfig(static_cast<ASessionCreationConfig*>( - &creationConfig), - tag, isJava); + return APerformanceHintManager::createSessionUsingConfig(&creationConfig, tag, isJava); } APerformanceHintSession* APerformanceHintManager::createSessionUsingConfig( @@ -345,11 +361,29 @@ APerformanceHintSession* APerformanceHintManager::createSessionUsingConfig( hal::SessionConfig sessionConfig{.id = -1}; ndk::ScopedAStatus ret; + // Hold the tokens weakly until we actually need them, + // then promote them, then drop all strong refs after + if (!sessionCreationConfig->layers.empty()) { + for (auto&& layerIter = sessionCreationConfig->layers.begin(); + layerIter != sessionCreationConfig->layers.end();) { + sp<IBinder> promoted = layerIter->promote(); + if (promoted == nullptr) { + layerIter = sessionCreationConfig->layers.erase(layerIter); + } else { + sessionCreationConfig->layerTokens.push_back( + ndk::SpAIBinder(AIBinder_fromPlatformBinder(promoted.get()))); + ++layerIter; + } + } + } + ret = mHintManager->createHintSessionWithConfig(mToken, tag, *static_cast<SessionCreationConfig*>( sessionCreationConfig), &sessionConfig, &session); + sessionCreationConfig->layerTokens.clear(); + if (!ret.isOk() || !session) { ALOGE("%s: PerformanceHint cannot create session. %s", __FUNCTION__, ret.getMessage()); return nullptr; @@ -679,6 +713,57 @@ int APerformanceHintSession::reportActualWorkDurationInternal(AWorkDuration* wor return 0; } +status_t APerformanceHintSession::setNativeSurfaces(ANativeWindow** windows, int numWindows, + ASurfaceControl** controls, + int numSurfaceControls) { + if (!mSessionConfig.has_value()) { + return ENOTSUP; + } + + std::vector<sp<IBinder>> layerHandles; + APerformanceHintManager::layersFromNativeSurfaces<sp<IBinder>>(windows, numWindows, controls, + numSurfaceControls, + layerHandles); + + std::vector<ndk::SpAIBinder> ndkLayerHandles; + for (auto&& handle : layerHandles) { + ndkLayerHandles.emplace_back(ndk::SpAIBinder(AIBinder_fromPlatformBinder(handle))); + } + + mHintSession->associateToLayers(ndkLayerHandles); + return 0; +} + +template <class T> +void APerformanceHintManager::layersFromNativeSurfaces(ANativeWindow** windows, int numWindows, + ASurfaceControl** controls, + int numSurfaceControls, + std::vector<T>& out) { + std::scoped_lock lock(sHintMutex); + if (windows != nullptr) { + std::vector<ANativeWindow*> windowVec(windows, windows + numWindows); + for (auto&& window : windowVec) { + Surface* surface = static_cast<Surface*>(window); + if (Surface::isValid(surface)) { + const sp<IBinder>& handle = surface->getSurfaceControlHandle(); + if (handle != nullptr) { + out.push_back(handle); + } + } + } + } + + if (controls != nullptr) { + std::vector<ASurfaceControl*> controlVec(controls, controls + numSurfaceControls); + for (auto&& aSurfaceControl : controlVec) { + SurfaceControl* control = reinterpret_cast<SurfaceControl*>(aSurfaceControl); + if (control->isValid()) { + out.push_back(control->getHandle()); + } + } + } +} + // ===================================== FMQ wrapper implementation bool FMQWrapper::isActive() { @@ -963,8 +1048,7 @@ APerformanceHintSession* APerformanceHint_createSessionFromJava( hal::SessionTag::APP, true); } -APerformanceHintSession* APerformanceHint_borrowSessionFromJava(JNIEnv* env, - jobject sessionObj) { +APerformanceHintSession* APerformanceHint_borrowSessionFromJava(JNIEnv* env, jobject sessionObj) { VALIDATE_PTR(env) VALIDATE_PTR(sessionObj) return APerformanceHintManager::getInstance()->getSessionFromJava(env, sessionObj); @@ -1065,6 +1149,14 @@ int APerformanceHint_notifyWorkloadReset(APerformanceHintSession* session, bool return session->notifyWorkloadReset(cpu, gpu, debugName); } +int APerformanceHint_setNativeSurfaces(APerformanceHintSession* session, + ANativeWindow** nativeWindows, int nativeWindowsSize, + ASurfaceControl** surfaceControls, int surfaceControlsSize) { + VALIDATE_PTR(session) + return session->setNativeSurfaces(nativeWindows, nativeWindowsSize, surfaceControls, + surfaceControlsSize); +} + AWorkDuration* AWorkDuration_create() { return new AWorkDuration(); } @@ -1180,6 +1272,11 @@ int ASessionCreationConfig_setGraphicsPipeline(ASessionCreationConfig* config, b config->modesToEnable.push_back(hal::SessionMode::GRAPHICS_PIPELINE); } else { std::erase(config->modesToEnable, hal::SessionMode::GRAPHICS_PIPELINE); + + // Remove automatic timing modes if we turn off GRAPHICS_PIPELINE, + // as it is a strict pre-requisite for these to run + std::erase(config->modesToEnable, hal::SessionMode::AUTO_CPU); + std::erase(config->modesToEnable, hal::SessionMode::AUTO_GPU); } return 0; } @@ -1197,3 +1294,48 @@ void APerformanceHint_getRateLimiterPropertiesForTesting(int32_t* maxLoadHintsPe void APerformanceHint_setUseNewLoadHintBehaviorForTesting(bool newBehavior) { kForceNewHintBehavior = newBehavior; } + +int ASessionCreationConfig_setNativeSurfaces(ASessionCreationConfig* config, + ANativeWindow** nativeWindows, int nativeWindowsSize, + ASurfaceControl** surfaceControls, + int surfaceControlsSize) { + VALIDATE_PTR(config) + + APerformanceHintManager::layersFromNativeSurfaces<wp<IBinder>>(nativeWindows, nativeWindowsSize, + surfaceControls, + surfaceControlsSize, + config->layers); + + if (config->layers.empty()) { + return EINVAL; + } + + return 0; +} + +int ASessionCreationConfig_setUseAutoTiming(ASessionCreationConfig* _Nonnull config, bool cpu, + bool gpu) { + VALIDATE_PTR(config) + if ((cpu || gpu) && !config->hasMode(hal::SessionMode::GRAPHICS_PIPELINE)) { + ALOGE("Automatic timing is not supported unless graphics pipeline mode is enabled first"); + return ENOTSUP; + } + + if (config->hasMode(hal::SessionMode::AUTO_CPU)) { + if (!cpu) { + std::erase(config->modesToEnable, hal::SessionMode::AUTO_CPU); + } + } else if (cpu) { + config->modesToEnable.push_back(static_cast<hal::SessionMode>(hal::SessionMode::AUTO_CPU)); + } + + if (config->hasMode(hal::SessionMode::AUTO_GPU)) { + if (!gpu) { + std::erase(config->modesToEnable, hal::SessionMode::AUTO_GPU); + } + } else if (gpu) { + config->modesToEnable.push_back(static_cast<hal::SessionMode>(hal::SessionMode::AUTO_GPU)); + } + + return 0; +} diff --git a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp index b00658052bde..b8f574f44338 100644 --- a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp +++ b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp @@ -83,6 +83,7 @@ public: (override)); MOCK_METHOD(ScopedAStatus, getGpuHeadroomMinIntervalMillis, (int64_t* _aidl_return), (override)); + MOCK_METHOD(ScopedAStatus, passSessionManagerBinder, (const SpAIBinder& sessionManager)); MOCK_METHOD(SpAIBinder, asBinder, (), (override)); MOCK_METHOD(bool, isRemote, (), (override)); }; @@ -99,6 +100,8 @@ public: MOCK_METHOD(ScopedAStatus, close, (), (override)); MOCK_METHOD(ScopedAStatus, reportActualWorkDuration2, (const ::std::vector<hal::WorkDuration>& workDurations), (override)); + MOCK_METHOD(ScopedAStatus, associateToLayers, + (const std::vector<::ndk::SpAIBinder>& in_layerTokens), (override)); MOCK_METHOD(SpAIBinder, asBinder, (), (override)); MOCK_METHOD(bool, isRemote, (), (override)); }; diff --git a/services/core/Android.bp b/services/core/Android.bp index c6b80cb5b125..08206150cebb 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -243,6 +243,7 @@ java_library_static { "powerstats_flags_lib", "locksettings_flags_lib", "profiling_flags_lib", + "android.adpf.sessionmanager_aidl-java", ], javac_shard_size: 50, javacflags: [ 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 aba15c83f907..0f6688f73c22 100644 --- a/services/core/java/com/android/server/power/hint/HintManagerService.java +++ b/services/core/java/com/android/server/power/hint/HintManagerService.java @@ -23,6 +23,7 @@ import static com.android.server.power.hint.Flags.adpfSessionTag; import static com.android.server.power.hint.Flags.powerhintThreadCleanup; import static com.android.server.power.hint.Flags.resetOnForkEnabled; +import android.adpf.ISessionManager; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; @@ -193,6 +194,7 @@ public final class HintManagerService extends SystemService { private final Object mCpuHeadroomLock = new Object(); + private ISessionManager mSessionManager; // this cache tracks the expiration time of the items and performs cleanup on lookup private static class HeadroomCache<K, V> { @@ -818,6 +820,23 @@ public final class HintManagerService extends SystemService { for (int i = tokenMap.size() - 1; i >= 0; i--) { // Will remove the session from tokenMap ArraySet<AppHintSession> sessionSet = tokenMap.valueAt(i); + IntArray closedSessionsForSf = new IntArray(); + // Batch the closure call to SF for all the sessions that die + for (int j = sessionSet.size() - 1; j >= 0; j--) { + AppHintSession session = sessionSet.valueAt(j); + if (session.isTrackedBySf()) { + // Mark it as untracked so we don't untrack again on close + session.setTrackedBySf(false); + closedSessionsForSf.add(session.getSessionId()); + } + } + if (mSessionManager != null) { + try { + mSessionManager.trackedSessionsDied(closedSessionsForSf.toArray()); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to communicate with SessionManager"); + } + } for (int j = sessionSet.size() - 1; j >= 0; j--) { sessionSet.valueAt(j).close(); } @@ -1350,9 +1369,9 @@ public final class HintManagerService extends SystemService { } } - final long sessionId = config.id != -1 ? config.id : halSessionPtr; + final long sessionIdForTracing = config.id != -1 ? config.id : halSessionPtr; logPerformanceHintSessionAtom( - callingUid, sessionId, durationNanos, tids, tag); + callingUid, sessionIdForTracing, durationNanos, tids, tag); synchronized (mSessionSnapshotMapLock) { // Update session snapshot upon session creation @@ -1362,8 +1381,12 @@ public final class HintManagerService extends SystemService { } AppHintSession hs = null; synchronized (mLock) { + Integer configId = null; + if (config.id != -1) { + configId = new Integer((int) config.id); + } hs = new AppHintSession(callingUid, callingTgid, tag, tids, - token, halSessionPtr, durationNanos); + token, halSessionPtr, durationNanos, configId); ArrayMap<IBinder, ArraySet<AppHintSession>> tokenMap = mActiveSessions.get(callingUid); if (tokenMap == null) { @@ -1390,6 +1413,11 @@ public final class HintManagerService extends SystemService { } } + if (creationConfig.layerTokens != null + && creationConfig.layerTokens.length > 0) { + hs.associateToLayers(creationConfig.layerTokens); + } + synchronized (mThreadsUsageObject) { mThreadsUsageMap.computeIfAbsent(callingUid, k -> new ArraySet<>()); ArraySet<ThreadUsageTracker> threadsSet = mThreadsUsageMap.get(callingUid); @@ -1566,6 +1594,15 @@ public final class HintManagerService extends SystemService { } @Override + public void passSessionManagerBinder(IBinder sessionManager) { + // Ensure caller is internal + if (Process.myUid() != Binder.getCallingUid()) { + return; + } + mSessionManager = ISessionManager.Stub.asInterface(sessionManager); + } + + @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) { return; @@ -1688,6 +1725,8 @@ public final class HintManagerService extends SystemService { protected boolean mHasBeenPowerEfficient; protected boolean mHasBeenGraphicsPipeline; protected boolean mShouldForcePause; + protected Integer mSessionId; + protected boolean mTrackedBySF; enum SessionModes { POWER_EFFICIENCY, @@ -1696,7 +1735,7 @@ public final class HintManagerService extends SystemService { protected AppHintSession( int uid, int pid, int sessionTag, int[] threadIds, IBinder token, - long halSessionPtr, long durationNanos) { + long halSessionPtr, long durationNanos, Integer sessionId) { mUid = uid; mPid = pid; mTag = sessionTag; @@ -1710,6 +1749,8 @@ public final class HintManagerService extends SystemService { mHasBeenPowerEfficient = false; mHasBeenGraphicsPipeline = false; mShouldForcePause = false; + mSessionId = sessionId; + mTrackedBySF = false; final boolean allowed = mUidObserver.isUidForeground(mUid); updateHintAllowedByProcState(allowed); try { @@ -1799,6 +1840,19 @@ public final class HintManagerService extends SystemService { } catch (NoSuchElementException ignored) { Slogf.d(TAG, "Death link does not exist for session with UID " + mUid); } + if (mTrackedBySF) { + if (mSessionManager != null) { + try { + mSessionManager.trackedSessionsDied(new int[]{mSessionId}); + } catch (RemoteException e) { + throw new IllegalStateException( + "Could not communicate with SessionManager", e); + } + mTrackedBySF = false; + } else { + Slog.e(TAG, "SessionManager is null but there are tracked sessions"); + } + } } synchronized (mLock) { ArrayMap<IBinder, ArraySet<AppHintSession>> tokenMap = mActiveSessions.get(mUid); @@ -1875,6 +1929,24 @@ public final class HintManagerService extends SystemService { } } + @Override + public void associateToLayers(IBinder[] layerTokens) { + synchronized (this) { + if (mSessionManager != null && mSessionId != null && layerTokens != null) { + // Sf only untracks a session when it dies + if (layerTokens.length > 0) { + mTrackedBySF = true; + } + try { + mSessionManager.associateSessionToLayers(mSessionId, mUid, layerTokens); + } catch (RemoteException e) { + throw new IllegalStateException( + "Could not communicate with SessionManager", e); + } + } + } + } + public void setThreads(@NonNull int[] tids) { setThreadsInternal(tids, true); } @@ -2124,10 +2196,27 @@ public final class HintManagerService extends SystemService { return mUid; } + public boolean isTrackedBySf() { + synchronized (this) { + return mTrackedBySF; + } + } + + public void setTrackedBySf(boolean tracked) { + synchronized (this) { + mTrackedBySF = tracked; + } + } + + public int getTag() { return mTag; } + public Integer getSessionId() { + return mSessionId; + } + public long getTargetDurationNs() { synchronized (this) { return mTargetDurationNanos; |