diff options
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 |