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