1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker * Copyright (C) 2020 The Android Open Source Project
3*ec779b8eSAndroid Build Coastguard Worker *
4*ec779b8eSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*ec779b8eSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*ec779b8eSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*ec779b8eSAndroid Build Coastguard Worker *
8*ec779b8eSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*ec779b8eSAndroid Build Coastguard Worker *
10*ec779b8eSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*ec779b8eSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*ec779b8eSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*ec779b8eSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*ec779b8eSAndroid Build Coastguard Worker * limitations under the License.
15*ec779b8eSAndroid Build Coastguard Worker */
16*ec779b8eSAndroid Build Coastguard Worker
17*ec779b8eSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
18*ec779b8eSAndroid Build Coastguard Worker #define LOG_TAG "TranscodingResourcePolicy"
19*ec779b8eSAndroid Build Coastguard Worker
20*ec779b8eSAndroid Build Coastguard Worker #include <aidl/android/media/BnResourceObserver.h>
21*ec779b8eSAndroid Build Coastguard Worker #include <aidl/android/media/IResourceObserverService.h>
22*ec779b8eSAndroid Build Coastguard Worker #include <android/binder_manager.h>
23*ec779b8eSAndroid Build Coastguard Worker #include <android/binder_process.h>
24*ec779b8eSAndroid Build Coastguard Worker #include <map>
25*ec779b8eSAndroid Build Coastguard Worker #include <media/TranscodingResourcePolicy.h>
26*ec779b8eSAndroid Build Coastguard Worker #include <utils/Log.h>
27*ec779b8eSAndroid Build Coastguard Worker
28*ec779b8eSAndroid Build Coastguard Worker namespace android {
29*ec779b8eSAndroid Build Coastguard Worker
30*ec779b8eSAndroid Build Coastguard Worker using Status = ::ndk::ScopedAStatus;
31*ec779b8eSAndroid Build Coastguard Worker using ::aidl::android::media::BnResourceObserver;
32*ec779b8eSAndroid Build Coastguard Worker using ::aidl::android::media::IResourceObserverService;
33*ec779b8eSAndroid Build Coastguard Worker using ::aidl::android::media::MediaObservableEvent;
34*ec779b8eSAndroid Build Coastguard Worker using ::aidl::android::media::MediaObservableFilter;
35*ec779b8eSAndroid Build Coastguard Worker using ::aidl::android::media::MediaObservableParcel;
36*ec779b8eSAndroid Build Coastguard Worker using ::aidl::android::media::MediaObservableType;
37*ec779b8eSAndroid Build Coastguard Worker
toString(const MediaObservableParcel & observable)38*ec779b8eSAndroid Build Coastguard Worker static std::string toString(const MediaObservableParcel& observable) {
39*ec779b8eSAndroid Build Coastguard Worker return "{" + ::aidl::android::media::toString(observable.type) + ", " +
40*ec779b8eSAndroid Build Coastguard Worker std::to_string(observable.value) + "}";
41*ec779b8eSAndroid Build Coastguard Worker }
42*ec779b8eSAndroid Build Coastguard Worker
43*ec779b8eSAndroid Build Coastguard Worker struct TranscodingResourcePolicy::ResourceObserver : public BnResourceObserver {
ResourceObserverandroid::TranscodingResourcePolicy::ResourceObserver44*ec779b8eSAndroid Build Coastguard Worker explicit ResourceObserver(TranscodingResourcePolicy* owner) : mOwner(owner) {}
45*ec779b8eSAndroid Build Coastguard Worker
46*ec779b8eSAndroid Build Coastguard Worker // IResourceObserver
onStatusChangedandroid::TranscodingResourcePolicy::ResourceObserver47*ec779b8eSAndroid Build Coastguard Worker ::ndk::ScopedAStatus onStatusChanged(
48*ec779b8eSAndroid Build Coastguard Worker MediaObservableEvent event, int32_t uid, int32_t pid,
49*ec779b8eSAndroid Build Coastguard Worker const std::vector<MediaObservableParcel>& observables) override {
50*ec779b8eSAndroid Build Coastguard Worker ALOGD("%s: %s, uid %d, pid %d, %s", __FUNCTION__,
51*ec779b8eSAndroid Build Coastguard Worker ::aidl::android::media::toString(event).c_str(), uid, pid,
52*ec779b8eSAndroid Build Coastguard Worker toString(observables[0]).c_str());
53*ec779b8eSAndroid Build Coastguard Worker
54*ec779b8eSAndroid Build Coastguard Worker // Only report kIdle event.
55*ec779b8eSAndroid Build Coastguard Worker if (((uint64_t)event & (uint64_t)MediaObservableEvent::kIdle) != 0) {
56*ec779b8eSAndroid Build Coastguard Worker for (auto& observable : observables) {
57*ec779b8eSAndroid Build Coastguard Worker if (observable.type == MediaObservableType::kVideoSecureCodec ||
58*ec779b8eSAndroid Build Coastguard Worker observable.type == MediaObservableType::kVideoNonSecureCodec) {
59*ec779b8eSAndroid Build Coastguard Worker mOwner->onResourceAvailable(pid);
60*ec779b8eSAndroid Build Coastguard Worker break;
61*ec779b8eSAndroid Build Coastguard Worker }
62*ec779b8eSAndroid Build Coastguard Worker }
63*ec779b8eSAndroid Build Coastguard Worker }
64*ec779b8eSAndroid Build Coastguard Worker return ::ndk::ScopedAStatus::ok();
65*ec779b8eSAndroid Build Coastguard Worker }
66*ec779b8eSAndroid Build Coastguard Worker
67*ec779b8eSAndroid Build Coastguard Worker TranscodingResourcePolicy* mOwner;
68*ec779b8eSAndroid Build Coastguard Worker };
69*ec779b8eSAndroid Build Coastguard Worker
70*ec779b8eSAndroid Build Coastguard Worker // cookie used for death recipients. The TranscodingResourcePolicy
71*ec779b8eSAndroid Build Coastguard Worker // that this cookie is associated with must outlive this cookie. It is
72*ec779b8eSAndroid Build Coastguard Worker // either deleted by binderDied, or in unregisterSelf which is also called
73*ec779b8eSAndroid Build Coastguard Worker // in the destructor of TranscodingResourcePolicy
74*ec779b8eSAndroid Build Coastguard Worker class TranscodingResourcePolicyCookie {
75*ec779b8eSAndroid Build Coastguard Worker public:
TranscodingResourcePolicyCookie(TranscodingResourcePolicy * policy)76*ec779b8eSAndroid Build Coastguard Worker TranscodingResourcePolicyCookie(TranscodingResourcePolicy* policy) : mPolicy(policy) {}
77*ec779b8eSAndroid Build Coastguard Worker TranscodingResourcePolicyCookie() = delete;
78*ec779b8eSAndroid Build Coastguard Worker TranscodingResourcePolicy* mPolicy;
79*ec779b8eSAndroid Build Coastguard Worker };
80*ec779b8eSAndroid Build Coastguard Worker
81*ec779b8eSAndroid Build Coastguard Worker static std::map<uintptr_t, std::unique_ptr<TranscodingResourcePolicyCookie>> sCookies;
82*ec779b8eSAndroid Build Coastguard Worker static uintptr_t sCookieKeyCounter;
83*ec779b8eSAndroid Build Coastguard Worker static std::mutex sCookiesMutex;
84*ec779b8eSAndroid Build Coastguard Worker
85*ec779b8eSAndroid Build Coastguard Worker // static
BinderDiedCallback(void * cookie)86*ec779b8eSAndroid Build Coastguard Worker void TranscodingResourcePolicy::BinderDiedCallback(void* cookie) {
87*ec779b8eSAndroid Build Coastguard Worker std::lock_guard<std::mutex> guard(sCookiesMutex);
88*ec779b8eSAndroid Build Coastguard Worker if (auto it = sCookies.find(reinterpret_cast<uintptr_t>(cookie)); it != sCookies.end()) {
89*ec779b8eSAndroid Build Coastguard Worker ALOGI("BinderDiedCallback unregistering TranscodingResourcePolicy");
90*ec779b8eSAndroid Build Coastguard Worker auto policy = reinterpret_cast<TranscodingResourcePolicy*>(it->second->mPolicy);
91*ec779b8eSAndroid Build Coastguard Worker if (policy) {
92*ec779b8eSAndroid Build Coastguard Worker policy->unregisterSelf();
93*ec779b8eSAndroid Build Coastguard Worker }
94*ec779b8eSAndroid Build Coastguard Worker sCookies.erase(it);
95*ec779b8eSAndroid Build Coastguard Worker }
96*ec779b8eSAndroid Build Coastguard Worker // TODO(chz): retry to connecting to IResourceObserverService after failure.
97*ec779b8eSAndroid Build Coastguard Worker // Also need to have back-up logic if IResourceObserverService is offline for
98*ec779b8eSAndroid Build Coastguard Worker // Prolonged period of time. A possible alternative could be, during period where
99*ec779b8eSAndroid Build Coastguard Worker // IResourceObserverService is not available, trigger onResourceAvailable() everytime
100*ec779b8eSAndroid Build Coastguard Worker // when top uid changes (in hope that'll free up some codec instances that we could
101*ec779b8eSAndroid Build Coastguard Worker // reclaim).
102*ec779b8eSAndroid Build Coastguard Worker }
103*ec779b8eSAndroid Build Coastguard Worker
TranscodingResourcePolicy()104*ec779b8eSAndroid Build Coastguard Worker TranscodingResourcePolicy::TranscodingResourcePolicy()
105*ec779b8eSAndroid Build Coastguard Worker : mRegistered(false),
106*ec779b8eSAndroid Build Coastguard Worker mResourceLostPid(-1),
107*ec779b8eSAndroid Build Coastguard Worker mDeathRecipient(AIBinder_DeathRecipient_new(BinderDiedCallback)) {
108*ec779b8eSAndroid Build Coastguard Worker registerSelf();
109*ec779b8eSAndroid Build Coastguard Worker }
110*ec779b8eSAndroid Build Coastguard Worker
~TranscodingResourcePolicy()111*ec779b8eSAndroid Build Coastguard Worker TranscodingResourcePolicy::~TranscodingResourcePolicy() {
112*ec779b8eSAndroid Build Coastguard Worker {
113*ec779b8eSAndroid Build Coastguard Worker std::lock_guard<std::mutex> guard(sCookiesMutex);
114*ec779b8eSAndroid Build Coastguard Worker
115*ec779b8eSAndroid Build Coastguard Worker // delete all of the cookies associated with this TranscodingResourcePolicy
116*ec779b8eSAndroid Build Coastguard Worker // instance since they are holding pointers to this object that will no
117*ec779b8eSAndroid Build Coastguard Worker // longer be valid.
118*ec779b8eSAndroid Build Coastguard Worker std::erase_if(sCookies, [this](const auto& cookieEntry) {
119*ec779b8eSAndroid Build Coastguard Worker auto const& [key, cookie] = cookieEntry;
120*ec779b8eSAndroid Build Coastguard Worker std::lock_guard guard(mCookieKeysLock);
121*ec779b8eSAndroid Build Coastguard Worker if (const auto& it = mCookieKeys.find(key); it != mCookieKeys.end()) {
122*ec779b8eSAndroid Build Coastguard Worker // No longer need to track this cookie
123*ec779b8eSAndroid Build Coastguard Worker mCookieKeys.erase(key);
124*ec779b8eSAndroid Build Coastguard Worker return true;
125*ec779b8eSAndroid Build Coastguard Worker }
126*ec779b8eSAndroid Build Coastguard Worker return false;
127*ec779b8eSAndroid Build Coastguard Worker });
128*ec779b8eSAndroid Build Coastguard Worker }
129*ec779b8eSAndroid Build Coastguard Worker unregisterSelf();
130*ec779b8eSAndroid Build Coastguard Worker }
131*ec779b8eSAndroid Build Coastguard Worker
registerSelf()132*ec779b8eSAndroid Build Coastguard Worker void TranscodingResourcePolicy::registerSelf() {
133*ec779b8eSAndroid Build Coastguard Worker ALOGI("TranscodingResourcePolicy: registerSelf");
134*ec779b8eSAndroid Build Coastguard Worker
135*ec779b8eSAndroid Build Coastguard Worker ::ndk::SpAIBinder binder(AServiceManager_getService("media.resource_observer"));
136*ec779b8eSAndroid Build Coastguard Worker
137*ec779b8eSAndroid Build Coastguard Worker std::scoped_lock lock{mRegisteredLock};
138*ec779b8eSAndroid Build Coastguard Worker
139*ec779b8eSAndroid Build Coastguard Worker if (mRegistered) {
140*ec779b8eSAndroid Build Coastguard Worker return;
141*ec779b8eSAndroid Build Coastguard Worker }
142*ec779b8eSAndroid Build Coastguard Worker
143*ec779b8eSAndroid Build Coastguard Worker // TODO(chz): retry to connecting to IResourceObserverService after failure.
144*ec779b8eSAndroid Build Coastguard Worker mService = IResourceObserverService::fromBinder(binder);
145*ec779b8eSAndroid Build Coastguard Worker if (mService == nullptr) {
146*ec779b8eSAndroid Build Coastguard Worker ALOGE("Failed to get IResourceObserverService");
147*ec779b8eSAndroid Build Coastguard Worker return;
148*ec779b8eSAndroid Build Coastguard Worker }
149*ec779b8eSAndroid Build Coastguard Worker
150*ec779b8eSAndroid Build Coastguard Worker // Only register filters for codec resource available.
151*ec779b8eSAndroid Build Coastguard Worker mObserver = ::ndk::SharedRefBase::make<ResourceObserver>(this);
152*ec779b8eSAndroid Build Coastguard Worker std::vector<MediaObservableFilter> filters = {
153*ec779b8eSAndroid Build Coastguard Worker {MediaObservableType::kVideoSecureCodec, MediaObservableEvent::kIdle},
154*ec779b8eSAndroid Build Coastguard Worker {MediaObservableType::kVideoNonSecureCodec, MediaObservableEvent::kIdle}};
155*ec779b8eSAndroid Build Coastguard Worker
156*ec779b8eSAndroid Build Coastguard Worker Status status = mService->registerObserver(mObserver, filters);
157*ec779b8eSAndroid Build Coastguard Worker if (!status.isOk()) {
158*ec779b8eSAndroid Build Coastguard Worker ALOGE("failed to register: error %d", status.getServiceSpecificError());
159*ec779b8eSAndroid Build Coastguard Worker mService = nullptr;
160*ec779b8eSAndroid Build Coastguard Worker mObserver = nullptr;
161*ec779b8eSAndroid Build Coastguard Worker return;
162*ec779b8eSAndroid Build Coastguard Worker }
163*ec779b8eSAndroid Build Coastguard Worker
164*ec779b8eSAndroid Build Coastguard Worker std::unique_ptr<TranscodingResourcePolicyCookie> cookie =
165*ec779b8eSAndroid Build Coastguard Worker std::make_unique<TranscodingResourcePolicyCookie>(this);
166*ec779b8eSAndroid Build Coastguard Worker void* cookiePtr = static_cast<void*>(cookie.get());
167*ec779b8eSAndroid Build Coastguard Worker uintptr_t cookieKey = sCookieKeyCounter++;
168*ec779b8eSAndroid Build Coastguard Worker sCookies.emplace(cookieKey, std::move(cookie));
169*ec779b8eSAndroid Build Coastguard Worker {
170*ec779b8eSAndroid Build Coastguard Worker std::lock_guard guard(mCookieKeysLock);
171*ec779b8eSAndroid Build Coastguard Worker mCookieKeys.insert(cookieKey);
172*ec779b8eSAndroid Build Coastguard Worker }
173*ec779b8eSAndroid Build Coastguard Worker
174*ec779b8eSAndroid Build Coastguard Worker AIBinder_linkToDeath(binder.get(), mDeathRecipient.get(), reinterpret_cast<void*>(cookieKey));
175*ec779b8eSAndroid Build Coastguard Worker
176*ec779b8eSAndroid Build Coastguard Worker ALOGD("@@@ registered observer");
177*ec779b8eSAndroid Build Coastguard Worker mRegistered = true;
178*ec779b8eSAndroid Build Coastguard Worker }
179*ec779b8eSAndroid Build Coastguard Worker
unregisterSelf()180*ec779b8eSAndroid Build Coastguard Worker void TranscodingResourcePolicy::unregisterSelf() {
181*ec779b8eSAndroid Build Coastguard Worker ALOGI("TranscodingResourcePolicy: unregisterSelf");
182*ec779b8eSAndroid Build Coastguard Worker
183*ec779b8eSAndroid Build Coastguard Worker std::scoped_lock lock{mRegisteredLock};
184*ec779b8eSAndroid Build Coastguard Worker
185*ec779b8eSAndroid Build Coastguard Worker if (!mRegistered) {
186*ec779b8eSAndroid Build Coastguard Worker return;
187*ec779b8eSAndroid Build Coastguard Worker }
188*ec779b8eSAndroid Build Coastguard Worker
189*ec779b8eSAndroid Build Coastguard Worker ::ndk::SpAIBinder binder = mService->asBinder();
190*ec779b8eSAndroid Build Coastguard Worker if (binder.get() != nullptr) {
191*ec779b8eSAndroid Build Coastguard Worker Status status = mService->unregisterObserver(mObserver);
192*ec779b8eSAndroid Build Coastguard Worker }
193*ec779b8eSAndroid Build Coastguard Worker
194*ec779b8eSAndroid Build Coastguard Worker mService = nullptr;
195*ec779b8eSAndroid Build Coastguard Worker mObserver = nullptr;
196*ec779b8eSAndroid Build Coastguard Worker mRegistered = false;
197*ec779b8eSAndroid Build Coastguard Worker }
198*ec779b8eSAndroid Build Coastguard Worker
setCallback(const std::shared_ptr<ResourcePolicyCallbackInterface> & cb)199*ec779b8eSAndroid Build Coastguard Worker void TranscodingResourcePolicy::setCallback(
200*ec779b8eSAndroid Build Coastguard Worker const std::shared_ptr<ResourcePolicyCallbackInterface>& cb) {
201*ec779b8eSAndroid Build Coastguard Worker std::scoped_lock lock{mCallbackLock};
202*ec779b8eSAndroid Build Coastguard Worker mResourcePolicyCallback = cb;
203*ec779b8eSAndroid Build Coastguard Worker }
204*ec779b8eSAndroid Build Coastguard Worker
setPidResourceLost(pid_t pid)205*ec779b8eSAndroid Build Coastguard Worker void TranscodingResourcePolicy::setPidResourceLost(pid_t pid) {
206*ec779b8eSAndroid Build Coastguard Worker std::scoped_lock lock{mCallbackLock};
207*ec779b8eSAndroid Build Coastguard Worker mResourceLostPid = pid;
208*ec779b8eSAndroid Build Coastguard Worker }
209*ec779b8eSAndroid Build Coastguard Worker
onResourceAvailable(pid_t pid)210*ec779b8eSAndroid Build Coastguard Worker void TranscodingResourcePolicy::onResourceAvailable(pid_t pid) {
211*ec779b8eSAndroid Build Coastguard Worker std::shared_ptr<ResourcePolicyCallbackInterface> cb;
212*ec779b8eSAndroid Build Coastguard Worker {
213*ec779b8eSAndroid Build Coastguard Worker std::scoped_lock lock{mCallbackLock};
214*ec779b8eSAndroid Build Coastguard Worker // Only callback if codec resource is released from other processes.
215*ec779b8eSAndroid Build Coastguard Worker if (mResourceLostPid != -1 && mResourceLostPid != pid) {
216*ec779b8eSAndroid Build Coastguard Worker cb = mResourcePolicyCallback.lock();
217*ec779b8eSAndroid Build Coastguard Worker mResourceLostPid = -1;
218*ec779b8eSAndroid Build Coastguard Worker }
219*ec779b8eSAndroid Build Coastguard Worker }
220*ec779b8eSAndroid Build Coastguard Worker
221*ec779b8eSAndroid Build Coastguard Worker if (cb != nullptr) {
222*ec779b8eSAndroid Build Coastguard Worker cb->onResourceAvailable();
223*ec779b8eSAndroid Build Coastguard Worker }
224*ec779b8eSAndroid Build Coastguard Worker }
225*ec779b8eSAndroid Build Coastguard Worker } // namespace android
226