1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "OMXMaster"
19 #include <utils/Log.h>
20 
21 #include <media/stagefright/omx/OMXMaster.h>
22 #include <media/stagefright/omx/SoftOMXPlugin.h>
23 #include <media/stagefright/foundation/ADebug.h>
24 
25 #include <vndksupport/linker.h>
26 
27 #include <dlfcn.h>
28 #include <fcntl.h>
29 
30 namespace android {
31 
OMXMaster()32 OMXMaster::OMXMaster()
33     : mVendorLibHandle(NULL) {
34 
35     pid_t pid = getpid();
36     char filename[20];
37     snprintf(filename, sizeof(filename), "/proc/%d/comm", pid);
38     int fd = open(filename, O_RDONLY);
39     if (fd < 0) {
40       ALOGW("couldn't determine process name");
41       strlcpy(mProcessName, "<unknown>", sizeof(mProcessName));
42     } else {
43       ssize_t len = read(fd, mProcessName, sizeof(mProcessName));
44       if (len < 2) {
45         ALOGW("couldn't determine process name");
46         strlcpy(mProcessName, "<unknown>", sizeof(mProcessName));
47       } else {
48         // the name is newline terminated, so erase the newline
49         mProcessName[len - 1] = 0;
50       }
51       close(fd);
52     }
53 
54     addVendorPlugin();
55     addPlugin(new SoftOMXPlugin);
56 }
57 
~OMXMaster()58 OMXMaster::~OMXMaster() {
59     clearPlugins();
60 
61     if (mVendorLibHandle != NULL) {
62         dlclose(mVendorLibHandle);
63         mVendorLibHandle = NULL;
64     }
65 }
66 
addVendorPlugin()67 void OMXMaster::addVendorPlugin() {
68     addPlugin("libstagefrighthw.so");
69 }
70 
addPlugin(const char * libname)71 void OMXMaster::addPlugin(const char *libname) {
72     mVendorLibHandle = android_load_sphal_library(libname, RTLD_NOW);
73 
74     if (mVendorLibHandle == NULL) {
75         return;
76     }
77 
78     typedef OMXPluginBase *(*CreateOMXPluginFunc)();
79     CreateOMXPluginFunc createOMXPlugin =
80         (CreateOMXPluginFunc)dlsym(
81                 mVendorLibHandle, "createOMXPlugin");
82     if (!createOMXPlugin)
83         createOMXPlugin = (CreateOMXPluginFunc)dlsym(
84                 mVendorLibHandle, "_ZN7android15createOMXPluginEv");
85 
86     if (createOMXPlugin) {
87         addPlugin((*createOMXPlugin)());
88     }
89 }
90 
addPlugin(OMXPluginBase * plugin)91 void OMXMaster::addPlugin(OMXPluginBase *plugin) {
92     Mutex::Autolock autoLock(mLock);
93 
94     mPlugins.push_back(plugin);
95 
96     OMX_U32 index = 0;
97 
98     char name[128];
99     OMX_ERRORTYPE err;
100     while ((err = plugin->enumerateComponents(
101                     name, sizeof(name), index++)) == OMX_ErrorNone) {
102         String8 name8(name);
103 
104         if (mPluginByComponentName.indexOfKey(name8) >= 0) {
105             ALOGE("A component of name '%s' already exists, ignoring this one.",
106                  name8.string());
107 
108             continue;
109         }
110 
111         mPluginByComponentName.add(name8, plugin);
112     }
113 
114     if (err != OMX_ErrorNoMore) {
115         ALOGE("OMX plugin failed w/ error 0x%08x after registering %zu "
116              "components", err, mPluginByComponentName.size());
117     }
118 }
119 
clearPlugins()120 void OMXMaster::clearPlugins() {
121     Mutex::Autolock autoLock(mLock);
122 
123     typedef void (*DestroyOMXPluginFunc)(OMXPluginBase*);
124     DestroyOMXPluginFunc destroyOMXPlugin =
125         (DestroyOMXPluginFunc)dlsym(
126                 mVendorLibHandle, "destroyOMXPlugin");
127 
128     mPluginByComponentName.clear();
129 
130     for (List<OMXPluginBase *>::iterator it = mPlugins.begin();
131             it != mPlugins.end(); ++it) {
132         if (destroyOMXPlugin)
133             destroyOMXPlugin(*it);
134         else
135             delete *it;
136         *it = NULL;
137     }
138 
139     mPlugins.clear();
140 }
141 
makeComponentInstance(const char * name,const OMX_CALLBACKTYPE * callbacks,OMX_PTR appData,OMX_COMPONENTTYPE ** component)142 OMX_ERRORTYPE OMXMaster::makeComponentInstance(
143         const char *name,
144         const OMX_CALLBACKTYPE *callbacks,
145         OMX_PTR appData,
146         OMX_COMPONENTTYPE **component) {
147     ALOGI("makeComponentInstance(%s) in %s process", name, mProcessName);
148     Mutex::Autolock autoLock(mLock);
149 
150     *component = NULL;
151 
152     ssize_t index = mPluginByComponentName.indexOfKey(String8(name));
153 
154     if (index < 0) {
155         return OMX_ErrorInvalidComponentName;
156     }
157 
158     OMXPluginBase *plugin = mPluginByComponentName.valueAt(index);
159     OMX_ERRORTYPE err =
160         plugin->makeComponentInstance(name, callbacks, appData, component);
161 
162     if (err != OMX_ErrorNone) {
163         return err;
164     }
165 
166     mPluginByInstance.add(*component, plugin);
167 
168     return err;
169 }
170 
destroyComponentInstance(OMX_COMPONENTTYPE * component)171 OMX_ERRORTYPE OMXMaster::destroyComponentInstance(
172         OMX_COMPONENTTYPE *component) {
173     Mutex::Autolock autoLock(mLock);
174 
175     ssize_t index = mPluginByInstance.indexOfKey(component);
176 
177     if (index < 0) {
178         return OMX_ErrorBadParameter;
179     }
180 
181     OMXPluginBase *plugin = mPluginByInstance.valueAt(index);
182     mPluginByInstance.removeItemsAt(index);
183 
184     return plugin->destroyComponentInstance(component);
185 }
186 
enumerateComponents(OMX_STRING name,size_t size,OMX_U32 index)187 OMX_ERRORTYPE OMXMaster::enumerateComponents(
188         OMX_STRING name,
189         size_t size,
190         OMX_U32 index) {
191     Mutex::Autolock autoLock(mLock);
192 
193     size_t numComponents = mPluginByComponentName.size();
194 
195     if (index >= numComponents) {
196         return OMX_ErrorNoMore;
197     }
198 
199     const String8 &name8 = mPluginByComponentName.keyAt(index);
200 
201     CHECK(size >= 1 + name8.size());
202     strcpy(name, name8.string());
203 
204     return OMX_ErrorNone;
205 }
206 
getRolesOfComponent(const char * name,Vector<String8> * roles)207 OMX_ERRORTYPE OMXMaster::getRolesOfComponent(
208         const char *name,
209         Vector<String8> *roles) {
210     Mutex::Autolock autoLock(mLock);
211 
212     roles->clear();
213 
214     ssize_t index = mPluginByComponentName.indexOfKey(String8(name));
215 
216     if (index < 0) {
217         return OMX_ErrorInvalidComponentName;
218     }
219 
220     OMXPluginBase *plugin = mPluginByComponentName.valueAt(index);
221     return plugin->getRolesOfComponent(name, roles);
222 }
223 
224 }  // namespace android
225