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