blob: cd21327ce10737bea551cce7d3a263e67d8429db [file] [log] [blame]
Girish27365ed2023-10-11 20:20:55 +00001/*
2**
3** Copyright 2023, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18//#define LOG_NDEBUG 0
19#define LOG_TAG "ResourceManagerServiceUtils"
20#include <utils/Log.h>
21
Girish6a6044d2023-11-22 21:23:14 +000022#include <binder/IServiceManager.h>
23
24#include "IMediaResourceMonitor.h"
Girish27365ed2023-10-11 20:20:55 +000025#include "ResourceManagerService.h"
26#include "ResourceManagerServiceUtils.h"
27
28namespace android {
29
Girishab17b0f2023-11-20 06:00:44 +000030// Bunch of utility functions that looks for a specific Resource.
31// Check whether a given resource (of type and subtype) is found in given resource parcel.
Girish27365ed2023-10-11 20:20:55 +000032bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
Girishab17b0f2023-11-20 06:00:44 +000033 const MediaResourceParcel& resource) {
Girish27365ed2023-10-11 20:20:55 +000034 if (type != resource.type) {
35 return false;
36 }
37 switch (type) {
Girishab17b0f2023-11-20 06:00:44 +000038 // Codec subtypes (e.g. video vs. audio and hw vs. sw) are each considered separate resources,
39 // so compare the subtypes as well.
40 case MediaResource::Type::kSecureCodec:
41 case MediaResource::Type::kNonSecureCodec:
42 if (resource.subType == subType) {
Girish27365ed2023-10-11 20:20:55 +000043 return true;
Girishab17b0f2023-11-20 06:00:44 +000044 }
45 break;
46 // Non-codec resources are not segregated by the subtype (e.g. video vs. audio).
47 default:
48 return true;
Girish27365ed2023-10-11 20:20:55 +000049 }
50 return false;
51}
52
Girishab17b0f2023-11-20 06:00:44 +000053// Check whether a given resource (of type and subtype) is found in given resource list.
Girish27365ed2023-10-11 20:20:55 +000054bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
Girishab17b0f2023-11-20 06:00:44 +000055 const ResourceList& resources) {
Girish27365ed2023-10-11 20:20:55 +000056 for (auto it = resources.begin(); it != resources.end(); it++) {
57 if (hasResourceType(type, subType, it->second)) {
58 return true;
59 }
60 }
61 return false;
62}
63
Girishab17b0f2023-11-20 06:00:44 +000064// Check whether a given resource (of type and subtype) is found in given resource info list.
Girish27365ed2023-10-11 20:20:55 +000065bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
Girishab17b0f2023-11-20 06:00:44 +000066 const ResourceInfos& infos) {
Girish27365ed2023-10-11 20:20:55 +000067 for (const auto& [id, info] : infos) {
68 if (hasResourceType(type, subType, info.resources)) {
69 return true;
70 }
71 }
72 return false;
73}
74
75ResourceInfos& getResourceInfosForEdit(int pid, PidResourceInfosMap& map) {
76 PidResourceInfosMap::iterator found = map.find(pid);
77 if (found == map.end()) {
78 // new pid
79 ResourceInfos infosForPid;
80 auto [it, inserted] = map.emplace(pid, infosForPid);
81 found = it;
82 }
83
84 return found->second;
85}
86
Girishab17b0f2023-11-20 06:00:44 +000087// Return modifiable ResourceInfo for a given client (look up by client id)
88// from the map of ResourceInfos.
89// If the item is not in the map, create one and add it to the map.
Girish27365ed2023-10-11 20:20:55 +000090ResourceInfo& getResourceInfoForEdit(const ClientInfoParcel& clientInfo,
Girishab17b0f2023-11-20 06:00:44 +000091 const std::shared_ptr<IResourceManagerClient>& client,
92 ResourceInfos& infos) {
Girish27365ed2023-10-11 20:20:55 +000093 ResourceInfos::iterator found = infos.find(clientInfo.id);
94
95 if (found == infos.end()) {
Girishab17b0f2023-11-20 06:00:44 +000096 ResourceInfo info{.pid = clientInfo.pid,
97 .uid = static_cast<uid_t>(clientInfo.uid),
Girish27365ed2023-10-11 20:20:55 +000098 .clientId = clientInfo.id,
99 .name = clientInfo.name.empty()? "<unknown client>" : clientInfo.name,
100 .client = client,
101 .deathNotifier = nullptr,
102 .pendingRemoval = false};
103 auto [it, inserted] = infos.emplace(clientInfo.id, info);
104 found = it;
105 }
106
107 return found->second;
108}
109
Girishab17b0f2023-11-20 06:00:44 +0000110// Merge resources from r2 into r1.
111void mergeResources(MediaResourceParcel& r1, const MediaResourceParcel& r2) {
112 // The resource entry on record is maintained to be in [0,INT64_MAX].
113 // Clamp if merging in the new resource value causes it to go out of bound.
114 // Note that the new resource value could be negative, eg.DrmSession, the
115 // value goes lower when the session is used more often. During reclaim
116 // the session with the highest value (lowest usage) would be closed.
117 if (r2.value < INT64_MAX - r1.value) {
118 r1.value += r2.value;
119 if (r1.value < 0) {
120 r1.value = 0;
121 }
122 } else {
123 r1.value = INT64_MAX;
124 }
125}
126
127///////////////////////////////////////////////////////////////////////
128////////////// Death Notifier implementation ////////////////////////
129///////////////////////////////////////////////////////////////////////
130
131DeathNotifier::DeathNotifier(const std::shared_ptr<IResourceManagerClient>& client,
132 const std::weak_ptr<ResourceManagerService>& service,
133 const ClientInfoParcel& clientInfo)
134 : mClient(client), mService(service), mClientInfo(clientInfo),
135 mCookie(nullptr),
136 mDeathRecipient(::ndk::ScopedAIBinder_DeathRecipient(
137 AIBinder_DeathRecipient_new(BinderDiedCallback))) {
138 // Setting callback notification when DeathRecipient gets deleted.
139 AIBinder_DeathRecipient_setOnUnlinked(mDeathRecipient.get(), BinderUnlinkedCallback);
140}
141
142//static
143void DeathNotifier::BinderUnlinkedCallback(void* cookie) {
144 BinderDiedContext* context = reinterpret_cast<BinderDiedContext*>(cookie);
145 // Since we don't need the context anymore, we are deleting it now.
146 delete context;
147}
148
149//static
150void DeathNotifier::BinderDiedCallback(void* cookie) {
151 BinderDiedContext* context = reinterpret_cast<BinderDiedContext*>(cookie);
152
153 // Validate the context and check if the DeathNotifier object is still in scope.
154 if (context != nullptr) {
155 std::shared_ptr<DeathNotifier> thiz = context->mDeathNotifier.lock();
156 if (thiz != nullptr) {
157 thiz->binderDied();
158 } else {
159 ALOGI("DeathNotifier is out of scope already");
160 }
161 }
162}
163
164void DeathNotifier::binderDied() {
165 // Don't check for pid validity since we know it's already dead.
166 std::shared_ptr<ResourceManagerService> service = mService.lock();
167 if (service == nullptr) {
168 ALOGW("ResourceManagerService is dead as well.");
169 return;
170 }
171
172 service->overridePid(mClientInfo.pid, -1);
173 // thiz is freed in the call below, so it must be last call referring thiz
174 service->removeResource(mClientInfo, false /*checkValid*/);
175}
176
177void OverrideProcessInfoDeathNotifier::binderDied() {
178 // Don't check for pid validity since we know it's already dead.
179 std::shared_ptr<ResourceManagerService> service = mService.lock();
180 if (service == nullptr) {
181 ALOGW("ResourceManagerService is dead as well.");
182 return;
183 }
184
185 service->removeProcessInfoOverride(mClientInfo.pid);
186}
187
188std::shared_ptr<DeathNotifier> DeathNotifier::Create(
189 const std::shared_ptr<IResourceManagerClient>& client,
190 const std::weak_ptr<ResourceManagerService>& service,
191 const ClientInfoParcel& clientInfo,
192 bool overrideProcessInfo) {
193 std::shared_ptr<DeathNotifier> deathNotifier = nullptr;
194 if (overrideProcessInfo) {
195 deathNotifier = std::make_shared<OverrideProcessInfoDeathNotifier>(
196 client, service, clientInfo);
197 } else {
198 deathNotifier = std::make_shared<DeathNotifier>(client, service, clientInfo);
199 }
200
201 if (deathNotifier) {
202 deathNotifier->link();
203 }
204
205 return deathNotifier;
206}
207
Girish6a6044d2023-11-22 21:23:14 +0000208void notifyResourceGranted(int pid, const std::vector<MediaResourceParcel>& resources) {
209 static const char* const kServiceName = "media_resource_monitor";
210 sp<IBinder> binder = defaultServiceManager()->checkService(String16(kServiceName));
211 if (binder != NULL) {
212 sp<IMediaResourceMonitor> service = interface_cast<IMediaResourceMonitor>(binder);
213 for (size_t i = 0; i < resources.size(); ++i) {
214 switch (resources[i].subType) {
215 case MediaResource::SubType::kHwAudioCodec:
216 case MediaResource::SubType::kSwAudioCodec:
217 service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_AUDIO_CODEC);
218 break;
219 case MediaResource::SubType::kHwVideoCodec:
220 case MediaResource::SubType::kSwVideoCodec:
221 service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_VIDEO_CODEC);
222 break;
223 case MediaResource::SubType::kHwImageCodec:
224 case MediaResource::SubType::kSwImageCodec:
225 service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_IMAGE_CODEC);
226 break;
227 case MediaResource::SubType::kUnspecifiedSubType:
228 break;
229 }
230 }
231 }
232}
233
Girish27365ed2023-10-11 20:20:55 +0000234} // namespace android