1 /**
2 *
3 * Copyright 2020, 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 "ResourceObserverService"
20 #include <utils/Log.h>
21
22 #include <android/binder_manager.h>
23 #include <android/binder_process.h>
24 #include <binder/IServiceManager.h>
25 #include <utils/String16.h>
26 #include <aidl/android/media/MediaResourceParcel.h>
27
28 #include "ResourceObserverService.h"
29
30 namespace android {
31
32 using ::aidl::android::media::MediaResourceParcel;
33 using ::aidl::android::media::MediaObservableEvent;
34
35 // MediaObservableEvent will be used as uint64_t flags.
36 static_assert(sizeof(MediaObservableEvent) == sizeof(uint64_t));
37
38 static std::vector<MediaObservableEvent> sEvents = {
39 MediaObservableEvent::kBusy,
40 MediaObservableEvent::kIdle,
41 };
42
getObservableType(const MediaResourceParcel & res)43 static MediaObservableType getObservableType(const MediaResourceParcel& res) {
44 if (res.subType == MediaResourceSubType::kHwVideoCodec ||
45 res.subType == MediaResourceSubType::kSwVideoCodec) {
46 if (res.type == MediaResourceType::kNonSecureCodec) {
47 return MediaObservableType::kVideoNonSecureCodec;
48 }
49 if (res.type == MediaResourceType::kSecureCodec) {
50 return MediaObservableType::kVideoSecureCodec;
51 }
52 }
53 return MediaObservableType::kInvalid;
54 }
55
56 //static
57 std::mutex ResourceObserverService::sDeathRecipientLock;
58 //static
59 std::map<uintptr_t, std::shared_ptr<ResourceObserverService::DeathRecipient> >
60 ResourceObserverService::sDeathRecipientMap;
61
62 struct ResourceObserverService::DeathRecipient {
DeathRecipientandroid::ResourceObserverService::DeathRecipient63 DeathRecipient(ResourceObserverService* _service,
64 const std::shared_ptr<IResourceObserver>& _observer)
65 : service(_service), observer(_observer) {}
~DeathRecipientandroid::ResourceObserverService::DeathRecipient66 ~DeathRecipient() {}
67
binderDiedandroid::ResourceObserverService::DeathRecipient68 void binderDied() {
69 if (service != nullptr) {
70 service->unregisterObserver(observer);
71 }
72 }
73
74 ResourceObserverService* service;
75 std::shared_ptr<IResourceObserver> observer;
76 };
77
78 // static
BinderDiedCallback(void * cookie)79 void ResourceObserverService::BinderDiedCallback(void* cookie) {
80 uintptr_t id = reinterpret_cast<uintptr_t>(cookie);
81
82 ALOGW("Observer %lld is dead", (long long)id);
83
84 std::shared_ptr<DeathRecipient> recipient;
85
86 {
87 std::scoped_lock lock{sDeathRecipientLock};
88
89 auto it = sDeathRecipientMap.find(id);
90 if (it != sDeathRecipientMap.end()) {
91 recipient = it->second;
92 }
93 }
94
95 if (recipient != nullptr) {
96 recipient->binderDied();
97 }
98 }
99
100 //static
instantiate()101 std::shared_ptr<ResourceObserverService> ResourceObserverService::instantiate() {
102 std::shared_ptr<ResourceObserverService> observerService =
103 ::ndk::SharedRefBase::make<ResourceObserverService>();
104 binder_status_t status = AServiceManager_addServiceWithFlags(
105 observerService->asBinder().get(),ResourceObserverService::getServiceName(),
106 AServiceManager_AddServiceFlag::ADD_SERVICE_ALLOW_ISOLATED);
107
108 if (status != STATUS_OK) {
109 return nullptr;
110 }
111 return observerService;
112 }
113
ResourceObserverService()114 ResourceObserverService::ResourceObserverService()
115 : mDeathRecipient(AIBinder_DeathRecipient_new(BinderDiedCallback)) {}
116
dump(int fd,const char **,uint32_t)117 binder_status_t ResourceObserverService::dump(
118 int fd, const char** /*args*/, uint32_t /*numArgs*/) {
119 String8 result;
120
121 if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
122 result.format("Permission Denial: "
123 "can't dump ResourceManagerService from pid=%d, uid=%d\n",
124 AIBinder_getCallingPid(),
125 AIBinder_getCallingUid());
126 write(fd, result.c_str(), result.size());
127 return PERMISSION_DENIED;
128 }
129
130 result.appendFormat("ResourceObserverService: %p\n", this);
131 result.appendFormat(" Registered Observers: %zu\n", mObserverInfoMap.size());
132
133 {
134 std::scoped_lock lock{mObserverLock};
135
136 for (auto &observer : mObserverInfoMap) {
137 result.appendFormat(" Observer %p:\n", observer.second.binder.get());
138 for (auto &observable : observer.second.filters) {
139 String8 enabledEventsStr;
140 for (auto &event : sEvents) {
141 if (((uint64_t)observable.eventFilter & (uint64_t)event) != 0) {
142 if (!enabledEventsStr.empty()) {
143 enabledEventsStr.append("|");
144 }
145 enabledEventsStr.append(toString(event).c_str());
146 }
147 }
148 result.appendFormat(" %s: %s\n",
149 toString(observable.type).c_str(), enabledEventsStr.c_str());
150 }
151 }
152 }
153
154 write(fd, result.c_str(), result.size());
155 return OK;
156 }
157
registerObserver(const std::shared_ptr<IResourceObserver> & in_observer,const std::vector<MediaObservableFilter> & in_filters)158 Status ResourceObserverService::registerObserver(
159 const std::shared_ptr<IResourceObserver>& in_observer,
160 const std::vector<MediaObservableFilter>& in_filters) {
161 if ((getpid() != AIBinder_getCallingPid()) &&
162 checkCallingPermission(
163 String16("android.permission.REGISTER_MEDIA_RESOURCE_OBSERVER")) == false) {
164 ALOGE("Permission Denial: "
165 "can't registerObserver from pid=%d, uid=%d\n",
166 AIBinder_getCallingPid(),
167 AIBinder_getCallingUid());
168 return Status::fromServiceSpecificError(PERMISSION_DENIED);
169 }
170
171 if (in_observer == nullptr) {
172 return Status::fromServiceSpecificError(BAD_VALUE);
173 }
174
175 ::ndk::SpAIBinder binder = in_observer->asBinder();
176
177 {
178 std::scoped_lock lock{mObserverLock};
179
180 if (mObserverInfoMap.find((uintptr_t)binder.get()) != mObserverInfoMap.end()) {
181 return Status::fromServiceSpecificError(ALREADY_EXISTS);
182 }
183
184 if (in_filters.empty()) {
185 return Status::fromServiceSpecificError(BAD_VALUE);
186 }
187
188 // Add observer info.
189 mObserverInfoMap.emplace((uintptr_t)binder.get(),
190 ObserverInfo{binder, in_observer, in_filters});
191
192 // Add observer to observable->subscribers map.
193 for (auto &filter : in_filters) {
194 for (auto &event : sEvents) {
195 if (!((uint64_t)filter.eventFilter & (uint64_t)event)) {
196 continue;
197 }
198 MediaObservableFilter key{filter.type, event};
199 mObservableToSubscribersMap[key].emplace((uintptr_t)binder.get(), in_observer);
200 }
201 }
202 }
203
204 // Add death binder and link.
205 uintptr_t cookie = (uintptr_t)binder.get();
206 {
207 std::scoped_lock lock{sDeathRecipientLock};
208 sDeathRecipientMap.emplace(
209 cookie, std::make_shared<DeathRecipient>(this, in_observer));
210 }
211
212 AIBinder_linkToDeath(binder.get(), mDeathRecipient.get(),
213 reinterpret_cast<void*>(cookie));
214
215 return Status::ok();
216 }
217
unregisterObserver(const std::shared_ptr<IResourceObserver> & in_observer)218 Status ResourceObserverService::unregisterObserver(
219 const std::shared_ptr<IResourceObserver>& in_observer) {
220 if ((getpid() != AIBinder_getCallingPid()) &&
221 checkCallingPermission(
222 String16("android.permission.REGISTER_MEDIA_RESOURCE_OBSERVER")) == false) {
223 ALOGE("Permission Denial: "
224 "can't unregisterObserver from pid=%d, uid=%d\n",
225 AIBinder_getCallingPid(),
226 AIBinder_getCallingUid());
227 return Status::fromServiceSpecificError(PERMISSION_DENIED);
228 }
229
230 if (in_observer == nullptr) {
231 return Status::fromServiceSpecificError(BAD_VALUE);
232 }
233
234 ::ndk::SpAIBinder binder = in_observer->asBinder();
235
236 {
237 std::scoped_lock lock{mObserverLock};
238
239 auto it = mObserverInfoMap.find((uintptr_t)binder.get());
240 if (it == mObserverInfoMap.end()) {
241 return Status::fromServiceSpecificError(NAME_NOT_FOUND);
242 }
243
244 // Remove observer from observable->subscribers map.
245 for (auto &filter : it->second.filters) {
246 for (auto &event : sEvents) {
247 if (!((uint64_t)filter.eventFilter & (uint64_t)event)) {
248 continue;
249 }
250 MediaObservableFilter key{filter.type, event};
251 mObservableToSubscribersMap[key].erase((uintptr_t)binder.get());
252
253 //Remove the entry if there's no more subscribers.
254 if (mObservableToSubscribersMap[key].empty()) {
255 mObservableToSubscribersMap.erase(key);
256 }
257 }
258 }
259
260 // Remove observer info.
261 mObserverInfoMap.erase(it);
262 }
263
264 // Unlink and remove death binder.
265 uintptr_t cookie = (uintptr_t)binder.get();
266 AIBinder_unlinkToDeath(binder.get(), mDeathRecipient.get(),
267 reinterpret_cast<void*>(cookie));
268
269 {
270 std::scoped_lock lock{sDeathRecipientLock};
271 sDeathRecipientMap.erase(cookie);
272 }
273
274 return Status::ok();
275 }
276
notifyObservers(MediaObservableEvent event,int uid,int pid,const ResourceList & resources)277 void ResourceObserverService::notifyObservers(
278 MediaObservableEvent event, int uid, int pid, const ResourceList &resources) {
279 struct CalleeInfo {
280 std::shared_ptr<IResourceObserver> observer;
281 std::vector<MediaObservableParcel> monitors;
282 };
283 // Build a consolidated list of observers to call with their respective observables.
284 std::map<uintptr_t, CalleeInfo> calleeList;
285
286 {
287 std::scoped_lock lock{mObserverLock};
288
289 for (const MediaResourceParcel& res : resources.getResources()) {
290 // Skip if this resource doesn't map to any observable type.
291 MediaObservableType observableType = getObservableType(res);
292 if (observableType == MediaObservableType::kInvalid) {
293 continue;
294 }
295 MediaObservableFilter key{observableType, event};
296 // Skip if no one subscribed to this observable.
297 auto observableIt = mObservableToSubscribersMap.find(key);
298 if (observableIt == mObservableToSubscribersMap.end()) {
299 continue;
300 }
301 // Loop through all subsribers.
302 for (auto &subscriber : observableIt->second) {
303 auto calleeIt = calleeList.find(subscriber.first);
304 if (calleeIt == calleeList.end()) {
305 calleeList.emplace(subscriber.first, CalleeInfo{
306 subscriber.second, {{observableType, res.value}}});
307 } else {
308 calleeIt->second.monitors.push_back({observableType, res.value});
309 }
310 }
311 }
312 }
313
314 // Finally call the observers about the status change.
315 for (auto &calleeInfo : calleeList) {
316 calleeInfo.second.observer->onStatusChanged(
317 event, uid, pid, calleeInfo.second.monitors);
318 }
319 }
320
onResourceAdded(int uid,int pid,const ResourceList & resources)321 void ResourceObserverService::onResourceAdded(
322 int uid, int pid, const ResourceList &resources) {
323 notifyObservers(MediaObservableEvent::kBusy, uid, pid, resources);
324 }
325
onResourceRemoved(int uid,int pid,const ResourceList & resources)326 void ResourceObserverService::onResourceRemoved(
327 int uid, int pid, const ResourceList &resources) {
328 notifyObservers(MediaObservableEvent::kIdle, uid, pid, resources);
329 }
330
331 } // namespace android
332