xref: /aosp_15_r20/hardware/interfaces/cas/aidl/default/FactoryLoader.h (revision 4d7e907c777eeecc4c5bd7cf640a754fac206ff7)
1*4d7e907cSAndroid Build Coastguard Worker /*
2*4d7e907cSAndroid Build Coastguard Worker  * Copyright (C) 2022 The Android Open Source Project
3*4d7e907cSAndroid Build Coastguard Worker  *
4*4d7e907cSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*4d7e907cSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*4d7e907cSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*4d7e907cSAndroid Build Coastguard Worker  *
8*4d7e907cSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*4d7e907cSAndroid Build Coastguard Worker  *
10*4d7e907cSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*4d7e907cSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*4d7e907cSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*4d7e907cSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*4d7e907cSAndroid Build Coastguard Worker  * limitations under the License.
15*4d7e907cSAndroid Build Coastguard Worker  */
16*4d7e907cSAndroid Build Coastguard Worker 
17*4d7e907cSAndroid Build Coastguard Worker #include <android-base/strings.h>
18*4d7e907cSAndroid Build Coastguard Worker #include <dirent.h>
19*4d7e907cSAndroid Build Coastguard Worker #include <dlfcn.h>
20*4d7e907cSAndroid Build Coastguard Worker #include <media/cas/CasAPI.h>
21*4d7e907cSAndroid Build Coastguard Worker #include <utils/KeyedVector.h>
22*4d7e907cSAndroid Build Coastguard Worker #include <utils/Mutex.h>
23*4d7e907cSAndroid Build Coastguard Worker #include "SharedLibrary.h"
24*4d7e907cSAndroid Build Coastguard Worker 
25*4d7e907cSAndroid Build Coastguard Worker using namespace std;
26*4d7e907cSAndroid Build Coastguard Worker 
27*4d7e907cSAndroid Build Coastguard Worker namespace aidl {
28*4d7e907cSAndroid Build Coastguard Worker namespace android {
29*4d7e907cSAndroid Build Coastguard Worker namespace hardware {
30*4d7e907cSAndroid Build Coastguard Worker namespace cas {
31*4d7e907cSAndroid Build Coastguard Worker 
32*4d7e907cSAndroid Build Coastguard Worker using namespace ::android;
33*4d7e907cSAndroid Build Coastguard Worker 
34*4d7e907cSAndroid Build Coastguard Worker template <class T>
35*4d7e907cSAndroid Build Coastguard Worker class FactoryLoader {
36*4d7e907cSAndroid Build Coastguard Worker   public:
FactoryLoader(const char * name)37*4d7e907cSAndroid Build Coastguard Worker     FactoryLoader(const char* name) : mFactory(NULL), mCreateFactoryFuncName(name) {}
38*4d7e907cSAndroid Build Coastguard Worker 
~FactoryLoader()39*4d7e907cSAndroid Build Coastguard Worker     virtual ~FactoryLoader() { closeFactory(); }
40*4d7e907cSAndroid Build Coastguard Worker 
41*4d7e907cSAndroid Build Coastguard Worker     bool findFactoryForScheme(int32_t CA_system_id, shared_ptr<SharedLibrary>* library = NULL,
42*4d7e907cSAndroid Build Coastguard Worker                               T** factory = NULL);
43*4d7e907cSAndroid Build Coastguard Worker 
44*4d7e907cSAndroid Build Coastguard Worker     bool enumeratePlugins(vector<AidlCasPluginDescriptor>* results);
45*4d7e907cSAndroid Build Coastguard Worker 
46*4d7e907cSAndroid Build Coastguard Worker   private:
47*4d7e907cSAndroid Build Coastguard Worker     typedef T* (*CreateFactoryFunc)();
48*4d7e907cSAndroid Build Coastguard Worker 
49*4d7e907cSAndroid Build Coastguard Worker     Mutex mMapLock;
50*4d7e907cSAndroid Build Coastguard Worker     T* mFactory;
51*4d7e907cSAndroid Build Coastguard Worker     const char* mCreateFactoryFuncName;
52*4d7e907cSAndroid Build Coastguard Worker     shared_ptr<SharedLibrary> mLibrary;
53*4d7e907cSAndroid Build Coastguard Worker     KeyedVector<int32_t, String8> mCASystemIdToLibraryPathMap;
54*4d7e907cSAndroid Build Coastguard Worker     KeyedVector<String8, shared_ptr<SharedLibrary>> mLibraryPathToOpenLibraryMap;
55*4d7e907cSAndroid Build Coastguard Worker 
56*4d7e907cSAndroid Build Coastguard Worker     bool loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id,
57*4d7e907cSAndroid Build Coastguard Worker                                       shared_ptr<SharedLibrary>* library, T** factory);
58*4d7e907cSAndroid Build Coastguard Worker 
59*4d7e907cSAndroid Build Coastguard Worker     bool queryPluginsFromPath(const String8& path, vector<AidlCasPluginDescriptor>* results);
60*4d7e907cSAndroid Build Coastguard Worker 
61*4d7e907cSAndroid Build Coastguard Worker     bool openFactory(const String8& path);
62*4d7e907cSAndroid Build Coastguard Worker     void closeFactory();
63*4d7e907cSAndroid Build Coastguard Worker };
64*4d7e907cSAndroid Build Coastguard Worker 
65*4d7e907cSAndroid Build Coastguard Worker template <class T>
findFactoryForScheme(int32_t CA_system_id,shared_ptr<SharedLibrary> * library,T ** factory)66*4d7e907cSAndroid Build Coastguard Worker bool FactoryLoader<T>::findFactoryForScheme(int32_t CA_system_id,
67*4d7e907cSAndroid Build Coastguard Worker                                             shared_ptr<SharedLibrary>* library, T** factory) {
68*4d7e907cSAndroid Build Coastguard Worker     if (library != NULL) {
69*4d7e907cSAndroid Build Coastguard Worker         library->reset();
70*4d7e907cSAndroid Build Coastguard Worker     }
71*4d7e907cSAndroid Build Coastguard Worker     if (factory != NULL) {
72*4d7e907cSAndroid Build Coastguard Worker         *factory = NULL;
73*4d7e907cSAndroid Build Coastguard Worker     }
74*4d7e907cSAndroid Build Coastguard Worker 
75*4d7e907cSAndroid Build Coastguard Worker     Mutex::Autolock autoLock(mMapLock);
76*4d7e907cSAndroid Build Coastguard Worker 
77*4d7e907cSAndroid Build Coastguard Worker     // first check cache
78*4d7e907cSAndroid Build Coastguard Worker     ssize_t index = mCASystemIdToLibraryPathMap.indexOfKey(CA_system_id);
79*4d7e907cSAndroid Build Coastguard Worker     if (index >= 0) {
80*4d7e907cSAndroid Build Coastguard Worker         return loadFactoryForSchemeFromPath(mCASystemIdToLibraryPathMap[index], CA_system_id,
81*4d7e907cSAndroid Build Coastguard Worker                                             library, factory);
82*4d7e907cSAndroid Build Coastguard Worker     }
83*4d7e907cSAndroid Build Coastguard Worker 
84*4d7e907cSAndroid Build Coastguard Worker     // no luck, have to search
85*4d7e907cSAndroid Build Coastguard Worker #ifdef __LP64__
86*4d7e907cSAndroid Build Coastguard Worker     String8 dirPath("/vendor/lib64/mediacas");
87*4d7e907cSAndroid Build Coastguard Worker #else
88*4d7e907cSAndroid Build Coastguard Worker     String8 dirPath("/vendor/lib/mediacas");
89*4d7e907cSAndroid Build Coastguard Worker #endif
90*4d7e907cSAndroid Build Coastguard Worker     DIR* pDir = opendir(dirPath.c_str());
91*4d7e907cSAndroid Build Coastguard Worker 
92*4d7e907cSAndroid Build Coastguard Worker     if (pDir == NULL) {
93*4d7e907cSAndroid Build Coastguard Worker         ALOGE("Failed to open plugin directory %s", dirPath.c_str());
94*4d7e907cSAndroid Build Coastguard Worker         return false;
95*4d7e907cSAndroid Build Coastguard Worker     }
96*4d7e907cSAndroid Build Coastguard Worker 
97*4d7e907cSAndroid Build Coastguard Worker     struct dirent* pEntry;
98*4d7e907cSAndroid Build Coastguard Worker     while ((pEntry = readdir(pDir))) {
99*4d7e907cSAndroid Build Coastguard Worker         String8 pluginPath = dirPath + "/" + pEntry->d_name;
100*4d7e907cSAndroid Build Coastguard Worker         if (base::EndsWith(pluginPath.c_str(), ".so")) {
101*4d7e907cSAndroid Build Coastguard Worker             if (loadFactoryForSchemeFromPath(pluginPath, CA_system_id, library, factory)) {
102*4d7e907cSAndroid Build Coastguard Worker                 mCASystemIdToLibraryPathMap.add(CA_system_id, pluginPath);
103*4d7e907cSAndroid Build Coastguard Worker                 closedir(pDir);
104*4d7e907cSAndroid Build Coastguard Worker 
105*4d7e907cSAndroid Build Coastguard Worker                 return true;
106*4d7e907cSAndroid Build Coastguard Worker             }
107*4d7e907cSAndroid Build Coastguard Worker         }
108*4d7e907cSAndroid Build Coastguard Worker     }
109*4d7e907cSAndroid Build Coastguard Worker 
110*4d7e907cSAndroid Build Coastguard Worker     closedir(pDir);
111*4d7e907cSAndroid Build Coastguard Worker 
112*4d7e907cSAndroid Build Coastguard Worker     ALOGE("Failed to find plugin");
113*4d7e907cSAndroid Build Coastguard Worker     return false;
114*4d7e907cSAndroid Build Coastguard Worker }
115*4d7e907cSAndroid Build Coastguard Worker 
116*4d7e907cSAndroid Build Coastguard Worker template <class T>
enumeratePlugins(vector<AidlCasPluginDescriptor> * results)117*4d7e907cSAndroid Build Coastguard Worker bool FactoryLoader<T>::enumeratePlugins(vector<AidlCasPluginDescriptor>* results) {
118*4d7e907cSAndroid Build Coastguard Worker     ALOGI("enumeratePlugins");
119*4d7e907cSAndroid Build Coastguard Worker 
120*4d7e907cSAndroid Build Coastguard Worker     results->clear();
121*4d7e907cSAndroid Build Coastguard Worker 
122*4d7e907cSAndroid Build Coastguard Worker #ifdef __LP64__
123*4d7e907cSAndroid Build Coastguard Worker     String8 dirPath("/vendor/lib64/mediacas");
124*4d7e907cSAndroid Build Coastguard Worker #else
125*4d7e907cSAndroid Build Coastguard Worker     String8 dirPath("/vendor/lib/mediacas");
126*4d7e907cSAndroid Build Coastguard Worker #endif
127*4d7e907cSAndroid Build Coastguard Worker     DIR* pDir = opendir(dirPath.c_str());
128*4d7e907cSAndroid Build Coastguard Worker 
129*4d7e907cSAndroid Build Coastguard Worker     if (pDir == NULL) {
130*4d7e907cSAndroid Build Coastguard Worker         ALOGE("Failed to open plugin directory %s", dirPath.c_str());
131*4d7e907cSAndroid Build Coastguard Worker         return false;
132*4d7e907cSAndroid Build Coastguard Worker     }
133*4d7e907cSAndroid Build Coastguard Worker 
134*4d7e907cSAndroid Build Coastguard Worker     Mutex::Autolock autoLock(mMapLock);
135*4d7e907cSAndroid Build Coastguard Worker 
136*4d7e907cSAndroid Build Coastguard Worker     struct dirent* pEntry;
137*4d7e907cSAndroid Build Coastguard Worker     while ((pEntry = readdir(pDir))) {
138*4d7e907cSAndroid Build Coastguard Worker         String8 pluginPath = dirPath + "/" + pEntry->d_name;
139*4d7e907cSAndroid Build Coastguard Worker         if (base::EndsWith(pluginPath.c_str(), ".so")) {
140*4d7e907cSAndroid Build Coastguard Worker             queryPluginsFromPath(pluginPath, results);
141*4d7e907cSAndroid Build Coastguard Worker         }
142*4d7e907cSAndroid Build Coastguard Worker     }
143*4d7e907cSAndroid Build Coastguard Worker     closedir(pDir);
144*4d7e907cSAndroid Build Coastguard Worker     return true;
145*4d7e907cSAndroid Build Coastguard Worker }
146*4d7e907cSAndroid Build Coastguard Worker 
147*4d7e907cSAndroid Build Coastguard Worker template <class T>
loadFactoryForSchemeFromPath(const String8 & path,int32_t CA_system_id,shared_ptr<SharedLibrary> * library,T ** factory)148*4d7e907cSAndroid Build Coastguard Worker bool FactoryLoader<T>::loadFactoryForSchemeFromPath(const String8& path, int32_t CA_system_id,
149*4d7e907cSAndroid Build Coastguard Worker                                                     shared_ptr<SharedLibrary>* library,
150*4d7e907cSAndroid Build Coastguard Worker                                                     T** factory) {
151*4d7e907cSAndroid Build Coastguard Worker     closeFactory();
152*4d7e907cSAndroid Build Coastguard Worker 
153*4d7e907cSAndroid Build Coastguard Worker     if (!openFactory(path) || !mFactory->isSystemIdSupported(CA_system_id)) {
154*4d7e907cSAndroid Build Coastguard Worker         closeFactory();
155*4d7e907cSAndroid Build Coastguard Worker         return false;
156*4d7e907cSAndroid Build Coastguard Worker     }
157*4d7e907cSAndroid Build Coastguard Worker 
158*4d7e907cSAndroid Build Coastguard Worker     if (library != NULL) {
159*4d7e907cSAndroid Build Coastguard Worker         *library = mLibrary;
160*4d7e907cSAndroid Build Coastguard Worker     }
161*4d7e907cSAndroid Build Coastguard Worker     if (factory != NULL) {
162*4d7e907cSAndroid Build Coastguard Worker         *factory = mFactory;
163*4d7e907cSAndroid Build Coastguard Worker     }
164*4d7e907cSAndroid Build Coastguard Worker     return true;
165*4d7e907cSAndroid Build Coastguard Worker }
166*4d7e907cSAndroid Build Coastguard Worker 
167*4d7e907cSAndroid Build Coastguard Worker template <class T>
queryPluginsFromPath(const String8 & path,vector<AidlCasPluginDescriptor> * results)168*4d7e907cSAndroid Build Coastguard Worker bool FactoryLoader<T>::queryPluginsFromPath(const String8& path,
169*4d7e907cSAndroid Build Coastguard Worker                                             vector<AidlCasPluginDescriptor>* results) {
170*4d7e907cSAndroid Build Coastguard Worker     closeFactory();
171*4d7e907cSAndroid Build Coastguard Worker 
172*4d7e907cSAndroid Build Coastguard Worker     vector<CasPluginDescriptor> descriptors;
173*4d7e907cSAndroid Build Coastguard Worker     if (!openFactory(path) || mFactory->queryPlugins(&descriptors) != OK) {
174*4d7e907cSAndroid Build Coastguard Worker         closeFactory();
175*4d7e907cSAndroid Build Coastguard Worker         return false;
176*4d7e907cSAndroid Build Coastguard Worker     }
177*4d7e907cSAndroid Build Coastguard Worker 
178*4d7e907cSAndroid Build Coastguard Worker     for (auto it = descriptors.begin(); it != descriptors.end(); it++) {
179*4d7e907cSAndroid Build Coastguard Worker         results->push_back(
180*4d7e907cSAndroid Build Coastguard Worker                 AidlCasPluginDescriptor{.caSystemId = it->CA_system_id, .name = it->name.c_str()});
181*4d7e907cSAndroid Build Coastguard Worker     }
182*4d7e907cSAndroid Build Coastguard Worker     return true;
183*4d7e907cSAndroid Build Coastguard Worker }
184*4d7e907cSAndroid Build Coastguard Worker 
185*4d7e907cSAndroid Build Coastguard Worker template <class T>
openFactory(const String8 & path)186*4d7e907cSAndroid Build Coastguard Worker bool FactoryLoader<T>::openFactory(const String8& path) {
187*4d7e907cSAndroid Build Coastguard Worker     // get strong pointer to open shared library
188*4d7e907cSAndroid Build Coastguard Worker     ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
189*4d7e907cSAndroid Build Coastguard Worker     if (index >= 0) {
190*4d7e907cSAndroid Build Coastguard Worker         mLibrary = mLibraryPathToOpenLibraryMap[index];
191*4d7e907cSAndroid Build Coastguard Worker     } else {
192*4d7e907cSAndroid Build Coastguard Worker         index = mLibraryPathToOpenLibraryMap.add(path, NULL);
193*4d7e907cSAndroid Build Coastguard Worker     }
194*4d7e907cSAndroid Build Coastguard Worker 
195*4d7e907cSAndroid Build Coastguard Worker     if (!mLibrary.get()) {
196*4d7e907cSAndroid Build Coastguard Worker         mLibrary = ::ndk::SharedRefBase::make<SharedLibrary>(path);
197*4d7e907cSAndroid Build Coastguard Worker         if (!*mLibrary) {
198*4d7e907cSAndroid Build Coastguard Worker             return false;
199*4d7e907cSAndroid Build Coastguard Worker         }
200*4d7e907cSAndroid Build Coastguard Worker 
201*4d7e907cSAndroid Build Coastguard Worker         mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
202*4d7e907cSAndroid Build Coastguard Worker     }
203*4d7e907cSAndroid Build Coastguard Worker 
204*4d7e907cSAndroid Build Coastguard Worker     CreateFactoryFunc createFactory = (CreateFactoryFunc)mLibrary->lookup(mCreateFactoryFuncName);
205*4d7e907cSAndroid Build Coastguard Worker     if (createFactory == NULL || (mFactory = createFactory()) == NULL) {
206*4d7e907cSAndroid Build Coastguard Worker         return false;
207*4d7e907cSAndroid Build Coastguard Worker     }
208*4d7e907cSAndroid Build Coastguard Worker     return true;
209*4d7e907cSAndroid Build Coastguard Worker }
210*4d7e907cSAndroid Build Coastguard Worker 
211*4d7e907cSAndroid Build Coastguard Worker template <class T>
closeFactory()212*4d7e907cSAndroid Build Coastguard Worker void FactoryLoader<T>::closeFactory() {
213*4d7e907cSAndroid Build Coastguard Worker     delete mFactory;
214*4d7e907cSAndroid Build Coastguard Worker     mFactory = NULL;
215*4d7e907cSAndroid Build Coastguard Worker     mLibrary.reset();
216*4d7e907cSAndroid Build Coastguard Worker }
217*4d7e907cSAndroid Build Coastguard Worker 
218*4d7e907cSAndroid Build Coastguard Worker }  // namespace cas
219*4d7e907cSAndroid Build Coastguard Worker }  // namespace hardware
220*4d7e907cSAndroid Build Coastguard Worker }  // namespace android
221*4d7e907cSAndroid Build Coastguard Worker }  // namespace aidl
222