1 /*
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 #ifndef ANDROID_MEDIA_RESOURCEMANAGERSERVICEUTILS_H_
19 #define ANDROID_MEDIA_RESOURCEMANAGERSERVICEUTILS_H_
20 
21 #include <map>
22 #include <set>
23 #include <memory>
24 #include <vector>
25 
26 #include <aidl/android/media/BnResourceManagerService.h>
27 #include <media/MediaResource.h>
28 #include <utils/String8.h>
29 
30 namespace android {
31 
32 class ResourceManagerService;
33 
34 /*
35  * Death Notifier to track IResourceManagerClient's death.
36  */
37 class DeathNotifier : public std::enable_shared_from_this<DeathNotifier> {
38 
39     // BinderDiedContext defines the cookie that is passed as DeathRecipient.
40     // Since this can maintain more context than a raw pointer, we can
41     // validate the scope of DeathNotifier, before deferencing it upon the binder death.
42     struct BinderDiedContext {
43         std::weak_ptr<DeathNotifier> mDeathNotifier;
44     };
45 public:
46     static std::shared_ptr<DeathNotifier> Create(
47         const std::shared_ptr<::aidl::android::media::IResourceManagerClient>& client,
48         const std::weak_ptr<ResourceManagerService>& service,
49         const ::aidl::android::media::ClientInfoParcel& clientInfo,
50         bool overrideProcessInfo = false);
51 
52     DeathNotifier(const std::shared_ptr<::aidl::android::media::IResourceManagerClient>& client,
53                   const std::weak_ptr<ResourceManagerService>& service,
54                   const ::aidl::android::media::ClientInfoParcel& clientInfo);
55 
~DeathNotifier()56     virtual ~DeathNotifier() {
57         unlink();
58     }
59 
60     // Implement death recipient
61     static void BinderDiedCallback(void* cookie);
62     static void BinderUnlinkedCallback(void* cookie);
63     virtual void binderDied();
64 
65 private:
link()66     void link() {
67         // Create the context that is passed as cookie to the binder death notification.
68         // The context gets deleted at BinderUnlinkedCallback.
69         mCookie = new BinderDiedContext{.mDeathNotifier = weak_from_this()};
70         // Register for the callbacks by linking to death notification.
71         AIBinder_linkToDeath(mClient->asBinder().get(), mDeathRecipient.get(), mCookie);
72     }
73 
unlink()74     void unlink() {
75         if (mClient != nullptr) {
76             // Unlink from the death notification.
77             AIBinder_unlinkToDeath(mClient->asBinder().get(), mDeathRecipient.get(), mCookie);
78             mClient = nullptr;
79         }
80     }
81 
82 protected:
83     std::shared_ptr<::aidl::android::media::IResourceManagerClient> mClient;
84     std::weak_ptr<ResourceManagerService> mService;
85     const ::aidl::android::media::ClientInfoParcel mClientInfo;
86     BinderDiedContext* mCookie;
87     ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
88 };
89 
90 class OverrideProcessInfoDeathNotifier : public DeathNotifier {
91 public:
OverrideProcessInfoDeathNotifier(const std::shared_ptr<::aidl::android::media::IResourceManagerClient> & client,const std::weak_ptr<ResourceManagerService> & service,const::aidl::android::media::ClientInfoParcel & clientInfo)92     OverrideProcessInfoDeathNotifier(
93         const std::shared_ptr<::aidl::android::media::IResourceManagerClient>& client,
94         const std::weak_ptr<ResourceManagerService>& service,
95         const ::aidl::android::media::ClientInfoParcel& clientInfo)
96             : DeathNotifier(client, service, clientInfo) {}
97 
~OverrideProcessInfoDeathNotifier()98     virtual ~OverrideProcessInfoDeathNotifier() {}
99 
100     virtual void binderDied();
101 };
102 
103 // Encapsulate Resource List as vector of resources instead of map.
104 // Since the number of resource is very limited, maintaining it as
105 // std::vector helps with both performance and memory requiremnts.
106 struct ResourceList {
107     // Add or Update an entry into ResourceList.
108     // If a new entry is added, isNewEntry will be set to true upon return
109     // returns true on successful update, false otherwise.
110     bool add(const ::aidl::android::media::MediaResourceParcel& res, bool* isNewEntry = nullptr);
111 
112     // reduce the resource usage by subtracting the resource value.
113     // If the resource value is 0 after reducing the resource usage,
114     // that entry will be removed and removedEntryValue is set to the
115     // value before it was removed upon return otherwise it will be set to -1.
116     // returns true on successful removal of the resource, false otherwise.
117     bool remove(const ::aidl::android::media::MediaResourceParcel& res,
118                 long* removedEntryValue = nullptr);
119 
120     // Returns true if there aren't any resource entries.
emptyResourceList121     bool empty() const {
122         return mResourceList.empty();
123     }
124 
125     // Returns resource list as a non-modifiable vectors
getResourcesResourceList126     const std::vector<::aidl::android::media::MediaResourceParcel>& getResources() const {
127         return mResourceList;
128     }
129 
130     // Converts resource list into string format
131     std::string toString() const;
132 
133     // BEGIN: Test only function
134     // Check if two resource lists are the same.
135     bool operator==(const ResourceList& rhs) const;
136 
137     // Add or Update an entry into ResourceList.
138     void addOrUpdate(const ::aidl::android::media::MediaResourceParcel& res);
139     // END: Test only function
140 
141 private:
142     std::vector<::aidl::android::media::MediaResourceParcel> mResourceList;
143 };
144 
145 // Encapsulation for Resource Info, that contains
146 // - pid of the app
147 // - uid of the app
148 // - client id
149 // - name of the client (specifically for the codec)
150 // - the client associted with it
151 // - death notifier for the (above) client
152 // - list of resources associated with it
153 // - A flag that marks whether this resource is pending to be removed.
154 struct ResourceInfo {
155     pid_t pid;
156     uid_t uid;
157     int64_t clientId;
158     std::string name;
159     std::shared_ptr<::aidl::android::media::IResourceManagerClient> client;
160     std::shared_ptr<DeathNotifier> deathNotifier = nullptr;
161     ResourceList resources;
162     bool pendingRemoval{false};
163     uint32_t importance = 0;
164 };
165 
166 /*
167  * Resource Reclaim request info that encapsulates
168  *  - the calling/requesting process pid.
169  *  - id of the client that made reclaim request.
170  *  - the calling/requesting client's importance.
171  *  - the list of resources requesting (to be reclaimed from others)
172  */
173 struct ReclaimRequestInfo {
174     int mCallingPid = -1;
175     int64_t mClientId = 0;
176     uint32_t mCallingClientImportance = 0;
177     const std::vector<::aidl::android::media::MediaResourceParcel>& mResources;
178 };
179 
180 /*
181  * Resource request info that encapsulates
182  *  - the calling/requesting process pid.
183  *  - the calling/requesting client's id.
184  *  - the resource requesting (to be reclaimed from others)
185  */
186 struct ResourceRequestInfo {
187     // pid of the calling/requesting process.
188     int mCallingPid = -1;
189     // id of the calling/requesting client.
190     int64_t mClientId = 0;
191     // resources requested.
192     const ::aidl::android::media::MediaResourceParcel* mResource;
193 };
194 
195 /*
196  * Structure that defines the Client - a possible target to relcaim from.
197  * This encapsulates pid, uid of the process and the client id
198  * based on the reclaim policy.
199  */
200 struct ClientInfo {
201     // pid of the process.
202     pid_t mPid = -1;
203     // uid of the process.
204     uid_t mUid = -1;
205     // Client Id.
206     int64_t mClientId = -1;
207     ClientInfo(pid_t pid = -1, uid_t uid = -1, const int64_t& clientId = -1)
mPidClientInfo208         : mPid(pid), mUid(uid), mClientId(clientId) {}
209 };
210 
211 // Map of Resource information index through the client id.
212 typedef std::map<int64_t, ResourceInfo> ResourceInfos;
213 
214 // Map of Resource information indexed through the process id.
215 typedef std::map<int, ResourceInfos> PidResourceInfosMap;
216 
217 // templated function to stringify the given vector of items.
218 template <typename T>
getString(const std::vector<T> & items)219 String8 getString(const std::vector<T>& items) {
220     String8 itemsStr;
221     for (size_t i = 0; i < items.size(); ++i) {
222         itemsStr.appendFormat("%s ", toString(items[i]).c_str());
223     }
224     return itemsStr;
225 }
226 
227 // Bunch of utility functions that looks for a specific Resource.
228 
229 //Check whether a given resource (of type and subtype) is found in given resource parcel.
230 bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
231                      const ::aidl::android::media::MediaResourceParcel& resource);
232 
233 //Check whether a given resource (of type and subtype) is found in given resource list.
234 bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
235                      const ResourceList& resources);
236 
237 //Check whether a given resource (of type and subtype) is found in given resource info list.
238 bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
239                      const ResourceInfos& infos);
240 
241 // Return modifiable list of ResourceInfo for a given process (look up by pid)
242 // from the map of ResourceInfos.
243 ResourceInfos& getResourceInfosForEdit(int pid, PidResourceInfosMap& map);
244 
245 // Return modifiable ResourceInfo for a given process (look up by pid)
246 // from the map of ResourceInfos.
247 // If the item is not in the map, create one and add it to the map.
248 ResourceInfo& getResourceInfoForEdit(
249         const aidl::android::media::ClientInfoParcel& clientInfo,
250         const std::shared_ptr<aidl::android::media::IResourceManagerClient>& client,
251         ResourceInfos& infos);
252 
253 // Merge resources from r2 into r1.
254 void mergeResources(::aidl::android::media::MediaResourceParcel& r1,
255                     const ::aidl::android::media::MediaResourceParcel& r2);
256 
257 // To notify the media_resource_monitor about the resource being granted.
258 void notifyResourceGranted(
259         int pid,
260         const std::vector<::aidl::android::media::MediaResourceParcel>& resources);
261 
262 } // namespace android
263 
264 #endif //ANDROID_MEDIA_RESOURCEMANAGERSERVICEUTILS_H_
265