diff options
author | 2024-11-18 22:30:21 -0800 | |
---|---|---|
committer | 2024-12-10 08:22:07 +0000 | |
commit | c1b8d76310794ec2f6089a36b1181b864128a30a (patch) | |
tree | 955d0dda3f0442dc4827e5cbcdcb1c23c630e3b7 | |
parent | 8a19587f2832b1c852d2a8740e5a2b85a6a2fd68 (diff) |
Create SessionManager in ADPF PowerAdvisor
Adds the "SessionManager" class, which tracks data associating
layers with specific sessions to create updates for the Power HAL
when frame composition occurs.
It also keeps track of which layers are currently "relevant" and
associated with at least one active session to streamline data
collection.
Flag: com.android.graphics.surfaceflinger.flags.adpf_native_session_manager
Bug: 360908317
Bug: 367803904
Test: atest libsurfaceflinger_unittest
Change-Id: Ic3a4df9b13a2acd9077c6ba2bc9bbe02088e214d
12 files changed, 463 insertions, 8 deletions
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 3f3d2c6cc6..7b90363763 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -42,12 +42,12 @@ cc_defaults { name: "libsurfaceflinger_defaults", defaults: [ "android.hardware.graphics.composer3-ndk_shared", - "android.hardware.power-ndk_shared", "librenderengine_deps", "libtimestats_deps", "libsurfaceflinger_common_deps", "surfaceflinger_defaults", "libsurfaceflinger_proto_deps", + "poweradvisor_deps", ], cflags: [ "-DLOG_TAG=\"SurfaceFlinger\"", @@ -79,7 +79,6 @@ cc_defaults { "libhidlbase", "liblog", "libnativewindow", - "libpowermanager", "libprocessgroup", "libprotobuf-cpp-lite", "libstatslog_surfaceflinger", diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp index 82eafd4fa8..2d0f874ad0 100644 --- a/services/surfaceflinger/CompositionEngine/Android.bp +++ b/services/surfaceflinger/CompositionEngine/Android.bp @@ -13,11 +13,11 @@ cc_defaults { defaults: [ "aconfig_lib_cc_static_link.defaults", "android.hardware.graphics.composer3-ndk_shared", - "android.hardware.power-ndk_shared", "librenderengine_deps", "libtimestats_deps", "surfaceflinger_defaults", "libsurfaceflinger_proto_deps", + "poweradvisor_deps", ], cflags: [ "-DLOG_TAG=\"CompositionEngine\"", diff --git a/services/surfaceflinger/PowerAdvisor/Common.h b/services/surfaceflinger/PowerAdvisor/Common.h new file mode 100644 index 0000000000..b4a87dd9a4 --- /dev/null +++ b/services/surfaceflinger/PowerAdvisor/Common.h @@ -0,0 +1,28 @@ +/* + * Copyright 2024 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. + */ + +#pragma once + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" +#include <aidl/android/adpf/ISessionManager.h> +#include <aidl/android/hardware/power/CompositionData.h> +#pragma clang diagnostic pop + +namespace android::adpf { +using namespace ::aidl::android::adpf; +namespace hal = ::aidl::android::hardware::power; +} // namespace android::adpf diff --git a/services/surfaceflinger/PowerAdvisor/PowerAdvisor.cpp b/services/surfaceflinger/PowerAdvisor/PowerAdvisor.cpp index c7d0b2c9ef..ff452723d5 100644 --- a/services/surfaceflinger/PowerAdvisor/PowerAdvisor.cpp +++ b/services/surfaceflinger/PowerAdvisor/PowerAdvisor.cpp @@ -28,22 +28,19 @@ #include <optional> #include <android-base/properties.h> +#include <android/binder_libbinder.h> #include <common/trace.h> #include <utils/Log.h> #include <utils/Mutex.h> #include <binder/IServiceManager.h> -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" #include <powermanager/PowerHalController.h> #include <powermanager/PowerHintSessionWrapper.h> -#pragma clang diagnostic pop #include <common/FlagManager.h> #include "PowerAdvisor.h" - -namespace hal = aidl::android::hardware::power; +#include "SessionManager.h" namespace android::adpf::impl { @@ -545,6 +542,18 @@ void PowerAdvisor::setTotalFrameTargetWorkDuration(Duration targetDuration) { mTotalFrameTargetDuration = targetDuration; } +std::shared_ptr<SessionManager> PowerAdvisor::getSessionManager() { + return mSessionManager; +} + +sp<IBinder> PowerAdvisor::getOrCreateSessionManagerForBinder(uid_t uid) { + // Flag guards the creation of SessionManager + if (mSessionManager == nullptr && FlagManager::getInstance().adpf_native_session_manager()) { + mSessionManager = ndk::SharedRefBase::make<SessionManager>(uid); + } + return AIBinder_toPlatformBinder(mSessionManager->asBinder().get()); +} + std::vector<DisplayId> PowerAdvisor::getOrderedDisplayIds( std::optional<TimePoint> DisplayTimingData::*sortBy) { std::vector<DisplayId> sortedDisplays; diff --git a/services/surfaceflinger/PowerAdvisor/PowerAdvisor.h b/services/surfaceflinger/PowerAdvisor/PowerAdvisor.h index 458b46d500..43fc21093f 100644 --- a/services/surfaceflinger/PowerAdvisor/PowerAdvisor.h +++ b/services/surfaceflinger/PowerAdvisor/PowerAdvisor.h @@ -36,6 +36,8 @@ #include <ui/DisplayIdentification.h> #include "../Scheduler/OneShotTimer.h" +#include "SessionManager.h" + using namespace std::chrono_literals; namespace android { @@ -47,6 +49,8 @@ class PowerHintSessionWrapper; namespace adpf { +namespace hal = aidl::android::hardware::power; + class PowerAdvisor { public: virtual ~PowerAdvisor() = default; @@ -102,12 +106,18 @@ public: virtual void setDisplays(std::vector<DisplayId>& displayIds) = 0; // Sets the target duration for the entire pipeline including the gpu virtual void setTotalFrameTargetWorkDuration(Duration targetDuration) = 0; + // Get the session manager, if it exists + virtual std::shared_ptr<SessionManager> getSessionManager() = 0; // --- The following methods may run on threads besides SF main --- // Send a hint about an upcoming increase in the CPU workload virtual void notifyCpuLoadUp() = 0; // Send a hint about the imminent start of a new CPU workload virtual void notifyDisplayUpdateImminentAndCpuReset() = 0; + + // --- The following methods specifically run on binder threads --- + // Retrieve a SessionManager for HintManagerService to call + virtual sp<IBinder> getOrCreateSessionManagerForBinder(uid_t uid) = 0; }; namespace impl { @@ -146,11 +156,15 @@ public: void setCompositeEnd(TimePoint compositeEndTime) override; void setDisplays(std::vector<DisplayId>& displayIds) override; void setTotalFrameTargetWorkDuration(Duration targetDuration) override; + std::shared_ptr<SessionManager> getSessionManager() override; // --- The following methods may run on threads besides SF main --- void notifyCpuLoadUp() override; void notifyDisplayUpdateImminentAndCpuReset() override; + // --- The following methods specifically run on binder threads --- + sp<IBinder> getOrCreateSessionManagerForBinder(uid_t uid) override; + private: friend class PowerAdvisorTest; @@ -323,6 +337,8 @@ private: template <aidl::android::hardware::power::ChannelMessage::ChannelMessageContents::Tag T, class In> bool writeHintSessionMessage(In* elements, size_t count) REQUIRES(mHintSessionMutex); + + std::shared_ptr<SessionManager> mSessionManager; }; } // namespace impl diff --git a/services/surfaceflinger/PowerAdvisor/SessionLayerMap.cpp b/services/surfaceflinger/PowerAdvisor/SessionLayerMap.cpp new file mode 100644 index 0000000000..9f95163e2b --- /dev/null +++ b/services/surfaceflinger/PowerAdvisor/SessionLayerMap.cpp @@ -0,0 +1,93 @@ +/* + * Copyright 2024 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 "SessionLayerMap.h" +#include <android/binder_libbinder.h> + +namespace android::adpf { + +void SessionLayerMap::notifySessionsDied(std::vector<int32_t>& sessionIds) { + for (int id : sessionIds) { + auto&& iter = mSessions.find(id); + if (iter != mSessions.end()) { + mSessions.erase(iter); + } + } +} + +void SessionLayerMap::notifyLayersDied(std::vector<int32_t>& layers) { + for (auto&& layer : layers) { + auto&& iter = mLayers.find(layer); + if (iter != mLayers.end()) { + mLayers.erase(iter); + } + } +} + +bool SessionLayerMap::bindSessionIDToLayers(int sessionId, const std::vector<int32_t>& layerIds) { + // If there is no association, just drop from map + if (layerIds.empty()) { + mSessions.erase(sessionId); + return false; + } + + // Ensure session exists + if (!mSessions.contains(sessionId)) { + mSessions.emplace(sessionId, MappedType(sessionId, mLayers)); + } + + MappedType& session = mSessions.at(sessionId); + std::set<int32_t> newLinks; + + // For each incoming link + for (auto&& layerId : layerIds) { + auto&& iter = mLayers.find(layerId); + + // If it's not in the map, add it + if (iter == mLayers.end()) { + mLayers.emplace(layerId, MappedType(layerId, mSessions)); + } + + // Make a ref to it in the session's new association map + newLinks.insert(layerId); + } + + session.swapLinks(std::move(newLinks)); + return true; +} + +void SessionLayerMap::getAssociatedSessions(int32_t layerId, std::vector<int32_t>& sessionIdsOut) { + sessionIdsOut.clear(); + auto&& iter = mLayers.find(layerId); + + if (iter == mLayers.end()) { + return; + } + + // Dump the internal association set into this vector + sessionIdsOut.insert(sessionIdsOut.begin(), iter->second.mLinks.begin(), + iter->second.mLinks.end()); +} + +void SessionLayerMap::getCurrentlyRelevantLayers( + std::unordered_set<int32_t>& currentlyRelevantLayers) { + currentlyRelevantLayers.clear(); + for (auto&& layer : mLayers) { + currentlyRelevantLayers.insert(layer.first); + } +} + +} // namespace android::adpf
\ No newline at end of file diff --git a/services/surfaceflinger/PowerAdvisor/SessionLayerMap.h b/services/surfaceflinger/PowerAdvisor/SessionLayerMap.h new file mode 100644 index 0000000000..51808a65fc --- /dev/null +++ b/services/surfaceflinger/PowerAdvisor/SessionLayerMap.h @@ -0,0 +1,111 @@ +/* + * Copyright 2024 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. + */ + +#pragma once + +#include <log/log.h> +#include <set> +#include <unordered_map> +#include <unordered_set> + +namespace android::adpf { + +class SessionLayerMap { +public: + // Inform the SessionLayerMap about dead sessions + void notifySessionsDied(std::vector<int32_t>& sessionIds); + // Inform the SessionLayerMap about dead layers + void notifyLayersDied(std::vector<int32_t>& layers); + // Associate a session with a specific set of layer ids + bool bindSessionIDToLayers(int sessionId, const std::vector<int32_t>& layerIds); + // Get the set of sessions that are mapped to a specific layer id + void getAssociatedSessions(int32_t layerId, std::vector<int32_t>& sessionIdsOut); + // Get the set of layers that are currently being tracked + void getCurrentlyRelevantLayers(std::unordered_set<int32_t>& currentlyRelevantLayers); + +private: + struct MappedType { + MappedType(int32_t id, std::unordered_map<int32_t, MappedType>& otherList) + : mId(id), mOtherList(otherList) {}; + MappedType() = delete; + ~MappedType() { swapLinks({}); } + + // Replace the set of associated IDs for this mapped type with a different set of IDs, + // updating only associations which have changed between the two sets + void swapLinks(std::set<int32_t>&& incoming) { + auto&& oldIter = mLinks.begin(); + auto&& newIter = incoming.begin(); + + // Dump all outdated values and insert new ones + while (oldIter != mLinks.end() || newIter != incoming.end()) { + // If there is a value in the new set but not the old set + // We should have already ensured what we're linking to exists + if (oldIter == mLinks.end() || (newIter != incoming.end() && *newIter < *oldIter)) { + addRemoteAssociation(*newIter); + ++newIter; + continue; + } + + // If there is a value in the old set but not the new set + if (newIter == incoming.end() || (oldIter != mLinks.end() && *oldIter < *newIter)) { + dropRemoteAssociation(*oldIter); + ++oldIter; + continue; + } + + // If they're the same, skip + if (*oldIter == *newIter) { + ++oldIter; + ++newIter; + continue; + } + } + + mLinks.swap(incoming); + } + + void addRemoteAssociation(int32_t other) { + auto&& iter = mOtherList.find(other); + if (iter != mOtherList.end()) { + iter->second.mLinks.insert(mId); + } else { + ALOGE("Existing entry in SessionLayerMap, link failed"); + } + } + + void dropRemoteAssociation(int32_t other) { + auto&& iter = mOtherList.find(other); + if (iter != mOtherList.end()) { + iter->second.mLinks.erase(mId); + if (iter->second.mLinks.empty()) { + // This only erases them from the map, not from general tracking + mOtherList.erase(iter); + } + } else { + ALOGE("Missing entry in SessionLayerMap, unlinking failed"); + } + } + + int32_t mId; + std::set<int> mLinks; + std::unordered_map<int32_t, MappedType>& mOtherList; + }; + + std::unordered_map<int32_t, MappedType> mSessions; + std::unordered_map<int32_t, MappedType> mLayers; +}; + +} // namespace android::adpf diff --git a/services/surfaceflinger/PowerAdvisor/SessionManager.cpp b/services/surfaceflinger/PowerAdvisor/SessionManager.cpp new file mode 100644 index 0000000000..a855f07914 --- /dev/null +++ b/services/surfaceflinger/PowerAdvisor/SessionManager.cpp @@ -0,0 +1,93 @@ +/* + * Copyright 2024 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 "PowerAdvisor/SessionManager.h" +#include <android/binder_libbinder.h> +#include <android/binder_status.h> +#include <binder/IPCThreadState.h> +#include "FrontEnd/LayerHandle.h" +#include "Layer.h" +#include "SurfaceFlinger.h" + +namespace android::adpf { + +SessionManager::SessionManager(uid_t uid) : mUid(uid) {} + +ndk::ScopedAStatus SessionManager::associateSessionToLayers( + int32_t sessionId, int32_t ownerUid, const std::vector<::ndk::SpAIBinder>& layerTokens) { + std::scoped_lock lock{mSessionManagerMutex}; + + std::vector<int32_t> layerIds; + + for (auto&& token : layerTokens) { + auto platformToken = AIBinder_toPlatformBinder(token.get()); + + // Get the layer id for it + int32_t layerId = + static_cast<int32_t>(surfaceflinger::LayerHandle::getLayerId(platformToken)); + auto&& iter = mTrackedLayerData.find(layerId); + + // Ensure it is being tracked + if (iter == mTrackedLayerData.end()) { + mTrackedLayerData.emplace(layerId, LayerData{.layerId = layerId}); + } + layerIds.push_back(layerId); + } + + // Register the session then track it + if (mMap.bindSessionIDToLayers(sessionId, layerIds) && + !mTrackedSessionData.contains(sessionId)) { + mTrackedSessionData.emplace(sessionId, + SessionData{.sessionId = sessionId, .uid = ownerUid}); + } + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus SessionManager::trackedSessionsDied(const std::vector<int32_t>& sessionIds) { + std::scoped_lock lock{mSessionManagerMutex}; + for (int sessionId : sessionIds) { + mDeadSessions.push_back(sessionId); + mTrackedSessionData.erase(sessionId); + } + + return ndk::ScopedAStatus::ok(); +} + +void SessionManager::updateTrackingState( + const std::vector<std::pair<uint32_t, std::string>>& handles) { + std::scoped_lock lock{mSessionManagerMutex}; + std::vector<int32_t> deadLayers; + for (auto&& handle : handles) { + int32_t handleId = static_cast<int32_t>(handle.first); + auto it = mTrackedLayerData.find(handleId); + if (it != mTrackedLayerData.end()) { + // Track any dead layers to remove from the mapping + mTrackedLayerData.erase(it); + deadLayers.push_back(it->first); + } + } + mMap.notifyLayersDied(deadLayers); + mMap.notifySessionsDied(mDeadSessions); + + mDeadSessions.clear(); + mMap.getCurrentlyRelevantLayers(mCurrentlyRelevantLayers); +} + +bool SessionManager::isLayerRelevant(int32_t layerId) { + return mCurrentlyRelevantLayers.contains(layerId); +} + +} // namespace android::adpf
\ No newline at end of file diff --git a/services/surfaceflinger/PowerAdvisor/SessionManager.h b/services/surfaceflinger/PowerAdvisor/SessionManager.h new file mode 100644 index 0000000000..93a80b55ab --- /dev/null +++ b/services/surfaceflinger/PowerAdvisor/SessionManager.h @@ -0,0 +1,102 @@ +/* + * Copyright 2024 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. + */ + +#pragma once + +#include <aidl/android/adpf/BnSessionManager.h> +#include <sys/types.h> + +#include <utils/Thread.h> +#include "Common.h" +#include "SessionLayerMap.h" + +#include <string> + +namespace android { + +class Layer; + +namespace adpf { +namespace impl { + +class PowerAdvisor; + +} + +// Talks to HMS to manage sessions for PowerHAL +class SessionManager : public BnSessionManager { +public: + SessionManager(uid_t uid); + + // ISessionManager binder methods + ndk::ScopedAStatus trackedSessionsDied(const std::vector<int32_t>& in_sessionId) override; + ndk::ScopedAStatus associateSessionToLayers( + int32_t sessionId, int32_t ownerUid, + const std::vector<::ndk::SpAIBinder>& layers) override; + + // Update the lifecycles of any tracked sessions or layers. This is intended to accepts the + // "destroyedHandles" object from updateLayerSnapshots in SF, and should reflect that type + void updateTrackingState(const std::vector<std::pair<uint32_t, std::string>>& handles); + +private: + // Session metadata tracked by the mTrackedSessionData map + struct SessionData { + int32_t sessionId; + int uid; + }; + + // Layer metadata tracked by the mTrackedSessionData map + struct LayerData { + int32_t layerId; + }; + + // Checks if the layer is currently associated with a specific session in the SessionLayerMap + // This helps us know which layers might be included in an update for the HAL + bool isLayerRelevant(int32_t layerId); + + // The UID of whoever created our ISessionManager connection + const uid_t mUid; + + // State owned by the main thread + + // Set of layers that are currently being tracked in the SessionLayerMap. This is used to + // filter out which layers we actually care about during the latching process + std::unordered_set<int32_t> mCurrentlyRelevantLayers; + + // Tracks active associations between sessions and layers. Items in this map can be thought of + // as "active" connections, and any session or layer not in this map will not receive updates or + // be collected in SurfaceFlinger + SessionLayerMap mMap; + + // The list of currently-living layers which have ever been tracked, this is used to persist any + // data we want to track across potential mapping disconnects, and to determine when to send + // death updates + std::unordered_map<int32_t, LayerData> mTrackedLayerData; + + // The list of currently-living sessions which have ever been tracked, this is used to persist + // any data we want to track across mapping disconnects + std::unordered_map<int32_t, SessionData> mTrackedSessionData; + + // State owned by mSessionManagerMutex + + std::mutex mSessionManagerMutex; + + // The list of sessions that have died since we last called updateTrackingState + std::vector<int32_t> mDeadSessions GUARDED_BY(mSessionManagerMutex); +}; + +} // namespace adpf +} // namespace android
\ No newline at end of file diff --git a/services/surfaceflinger/Tracing/tools/Android.bp b/services/surfaceflinger/Tracing/tools/Android.bp index 63c1b37166..d2ffcc0f73 100644 --- a/services/surfaceflinger/Tracing/tools/Android.bp +++ b/services/surfaceflinger/Tracing/tools/Android.bp @@ -27,6 +27,7 @@ cc_binary { defaults: [ "libsurfaceflinger_mocks_defaults", "librenderengine_deps", + "poweradvisor_deps", "surfaceflinger_defaults", "libsurfaceflinger_common_deps", ], diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 6af51435c3..42259af7b0 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -103,6 +103,7 @@ cc_defaults { "librenderengine_deps", "libsurfaceflinger_common_test_deps", "libsurfaceflinger_proto_deps", + "poweradvisor_deps", ], static_libs: [ "android.hardware.common-V2-ndk", diff --git a/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerAdvisor.h index 5c4512a2df..fd55597d7a 100644 --- a/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerAdvisor.h +++ b/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerAdvisor.h @@ -63,6 +63,8 @@ public: MOCK_METHOD(void, setCompositeEnd, (TimePoint compositeEndTime), (override)); MOCK_METHOD(void, setDisplays, (std::vector<DisplayId> & displayIds), (override)); MOCK_METHOD(void, setTotalFrameTargetWorkDuration, (Duration targetDuration), (override)); + MOCK_METHOD(std::shared_ptr<SessionManager>, getSessionManager, (), (override)); + MOCK_METHOD(sp<IBinder>, getOrCreateSessionManagerForBinder, (uid_t uid), (override)); }; } // namespace android::adpf::mock |