1 /*
2 * Copyright 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "powerhal-libperfmgr"
18 #define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)
19
20 #include "ChannelManager.h"
21
22 #include <inttypes.h>
23
24 #include "tests/mocks/MockChannelGroup.h"
25 #include "tests/mocks/MockPowerHintSession.h"
26 #include "tests/mocks/MockPowerSessionManager.h"
27
28 namespace aidl::google::hardware::power::impl::pixel {
29
30 template <class ChannelGroupT>
closeChannel(int32_t tgid,int32_t uid)31 bool ChannelManager<ChannelGroupT>::closeChannel(int32_t tgid, int32_t uid) {
32 std::scoped_lock lock{mChannelManagerMutex};
33 ChannelMapKey key{.tgid = tgid, .uid = uid};
34 auto channelIter = mChannelMap.find(key);
35 if (channelIter == mChannelMap.end()) {
36 return false;
37 }
38 ChannelMapValue value{.value = channelIter->second};
39 auto groupIter = mChannelGroups.find(value.groupId);
40 if (groupIter == mChannelGroups.end()) {
41 return false;
42 }
43
44 if (!groupIter->second.removeChannel(value.offset)) {
45 return false;
46 }
47
48 // Ensure the group is cleaned up if we remove the last channel
49 if (groupIter->second.getChannelCount() == 0) {
50 mChannelGroups.erase(groupIter);
51 }
52 mChannelMap.erase(channelIter);
53 return true;
54 }
55
56 template <class ChannelGroupT>
getOrCreateChannel(int32_t tgid,int32_t uid)57 std::shared_ptr<SessionChannel> ChannelManager<ChannelGroupT>::getOrCreateChannel(int32_t tgid,
58 int32_t uid) {
59 ChannelMapKey key{.tgid = tgid, .uid = uid};
60 auto channelIter = mChannelMap.find(key);
61 if (channelIter != mChannelMap.end()) {
62 ChannelMapValue value{.value = channelIter->second};
63 return mChannelGroups.at(value.groupId).getChannel(value.offset);
64 }
65 // If channel does not exist, we need to create it
66 int32_t groupId = -1;
67 for (auto &&group : mChannelGroups) {
68 if (group.second.getChannelCount() < kMaxChannels) {
69 groupId = group.first;
70 break;
71 }
72 }
73 // No group was found, we need to make a new one
74 if (groupId == -1) {
75 groupId = mChannelGroups.empty() ? 0 : mChannelGroups.rbegin()->first + 1;
76 mChannelGroups.emplace(std::piecewise_construct, std::forward_as_tuple(groupId),
77 std::forward_as_tuple(groupId));
78 }
79
80 std::shared_ptr<SessionChannel> channel = mChannelGroups.at(groupId).createChannel(tgid, uid);
81 mChannelMap[key] = channel->getId();
82
83 return channel;
84 }
85
86 template <class ChannelGroupT>
getChannelConfig(int32_t tgid,int32_t uid,ChannelConfig * config)87 bool ChannelManager<ChannelGroupT>::getChannelConfig(int32_t tgid, int32_t uid,
88 ChannelConfig *config) {
89 std::scoped_lock lock{mChannelManagerMutex};
90 std::shared_ptr<SessionChannel> channel = getOrCreateChannel(tgid, uid);
91 if (!channel || !channel->isValid()) {
92 return false;
93 }
94 mChannelGroups.at(ChannelMapValue{.value = channel->getId()}.groupId)
95 .getFlagDesc(&config->eventFlagDescriptor);
96 channel->getDesc(&config->channelDescriptor);
97 config->readFlagBitmask = channel->getReadBitmask();
98 config->writeFlagBitmask = channel->getWriteBitmask();
99 return true;
100 }
101
102 template <class ChannelGroupT>
getGroupCount()103 int ChannelManager<ChannelGroupT>::getGroupCount() {
104 std::scoped_lock lock{mChannelManagerMutex};
105 return mChannelGroups.size();
106 }
107
108 template <class ChannelGroupT>
getChannelCount()109 int ChannelManager<ChannelGroupT>::getChannelCount() {
110 std::scoped_lock lock{mChannelManagerMutex};
111 int out = 0;
112 for (auto &&group : mChannelGroups) {
113 out += group.second.getChannelCount();
114 }
115 return out;
116 }
117
118 template <class ChannelGroupT>
getInstance()119 ChannelManager<ChannelGroupT> *ChannelManager<ChannelGroupT>::getInstance() {
120 static ChannelManager instance{};
121 return &instance;
122 }
123
124 template class ChannelManager<>;
125 template class ChannelManager<testing::NiceMock<mock::pixel::MockChannelGroup>>;
126 template class ChannelManager<ChannelGroup<testing::NiceMock<mock::pixel::MockPowerSessionManager>,
127 testing::NiceMock<mock::pixel::MockPowerHintSession>>>;
128
129 } // namespace aidl::google::hardware::power::impl::pixel
130