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 "OMXMaster.h"
22 
23 #include "SoftOMXPlugin.h"
24 
25 #include <dlfcn.h>
26 #include <fcntl.h>
27 
28 #include <media/stagefright/foundation/ADebug.h>
29 
30 namespace android {
31 
OMXMaster()32 OMXMaster::OMXMaster()
33     : mVendorLibHandle(NULL) {
34 
35     mProcessName[0] = 0;
36     if (mProcessName[0] == 0) {
37         pid_t pid = getpid();
38         char filename[20];
39         snprintf(filename, sizeof(filename), "/proc/%d/comm", pid);
40         int fd = open(filename, O_RDONLY);
41         if (fd < 0) {
42             ALOGW("couldn't determine process name");
43             sprintf(mProcessName, "<unknown>");
44         } else {
45             ssize_t len = read(fd, mProcessName, sizeof(mProcessName));
46             if (len < 2) {
47                 ALOGW("couldn't determine process name");
48                 sprintf(mProcessName, "<unknown>");
49             } else {
50                 // the name is newline terminated, so erase the newline
51                 mProcessName[len - 1] = 0;
52             }
53             close(fd);
54         }
55     }
56 
57     addVendorPlugin();
58     addPlugin(new SoftOMXPlugin);
59 }
60 
~OMXMaster()61 OMXMaster::~OMXMaster() {
62     clearPlugins();
63 
64     if (mVendorLibHandle != NULL) {
65         dlclose(mVendorLibHandle);
66         mVendorLibHandle = NULL;
67     }
68 }
69 
addVendorPlugin()70 void OMXMaster::addVendorPlugin() {
71     addPlugin("libstagefrighthw.so");
72 }
73 
addPlugin(const char * libname)74 void OMXMaster::addPlugin(const char *libname) {
75     mVendorLibHandle = dlopen(libname, RTLD_NOW);
76 
77     if (mVendorLibHandle == NULL) {
78         return;
79     }
80 
81     typedef OMXPluginBase *(*CreateOMXPluginFunc)();
82     CreateOMXPluginFunc createOMXPlugin =
83         (CreateOMXPluginFunc)dlsym(
84                 mVendorLibHandle, "createOMXPlugin");
85     if (!createOMXPlugin)
86         createOMXPlugin = (CreateOMXPluginFunc)dlsym(
87                 mVendorLibHandle, "_ZN7android15createOMXPluginEv");
88 
89     if (createOMXPlugin) {
90         addPlugin((*createOMXPlugin)());
91     }
92 }
93 
addPlugin(OMXPluginBase * plugin)94 void OMXMaster::addPlugin(OMXPluginBase *plugin) {
95     Mutex::Autolock autoLock(mLock);
96 
97     mPlugins.push_back(plugin);
98 
99     OMX_U32 index = 0;
100 
101     char name[128];
102     OMX_ERRORTYPE err;
103     while ((err = plugin->enumerateComponents(
104                     name, sizeof(name), index++)) == OMX_ErrorNone) {
105         String8 name8(name);
106 
107         if (mPluginByComponentName.indexOfKey(name8) >= 0) {
108             ALOGE("A component of name '%s' already exists, ignoring this one.",
109                  name8.string());
110 
111             continue;
112         }
113 
114         mPluginByComponentName.add(name8, plugin);
115     }
116 
117     if (err != OMX_ErrorNoMore) {
118         ALOGE("OMX plugin failed w/ error 0x%08x after registering %zu "
119              "components", err, mPluginByComponentName.size());
120     }
121 }
122 
clearPlugins()123 void OMXMaster::clearPlugins() {
124     Mutex::Autolock autoLock(mLock);
125 
126     typedef void (*DestroyOMXPluginFunc)(OMXPluginBase*);
127     DestroyOMXPluginFunc destroyOMXPlugin =
128         (DestroyOMXPluginFunc)dlsym(
129                 mVendorLibHandle, "destroyOMXPlugin");
130 
131     mPluginByComponentName.clear();
132 
133     for (List<OMXPluginBase *>::iterator it = mPlugins.begin();
134             it != mPlugins.end(); ++it) {
135         if (destroyOMXPlugin)
136             destroyOMXPlugin(*it);
137         else
138             delete *it;
139         *it = NULL;
140     }
141 
142     mPlugins.clear();
143 }
144 
makeComponentInstance(const char * name,const OMX_CALLBACKTYPE * callbacks,OMX_PTR appData,OMX_COMPONENTTYPE ** component)145 OMX_ERRORTYPE OMXMaster::makeComponentInstance(
146         const char *name,
147         const OMX_CALLBACKTYPE *callbacks,
148         OMX_PTR appData,
149         OMX_COMPONENTTYPE **component) {
150     ALOGI("makeComponentInstance(%s) in %s process", name, mProcessName);
151     Mutex::Autolock autoLock(mLock);
152 
153     *component = NULL;
154 
155     ssize_t index = mPluginByComponentName.indexOfKey(String8(name));
156 
157     if (index < 0) {
158         return OMX_ErrorInvalidComponentName;
159     }
160 
161     OMXPluginBase *plugin = mPluginByComponentName.valueAt(index);
162     OMX_ERRORTYPE err =
163         plugin->makeComponentInstance(name, callbacks, appData, component);
164 
165     if (err != OMX_ErrorNone) {
166         return err;
167     }
168 
169     mPluginByInstance.add(*component, plugin);
170 
171     return err;
172 }
173 
destroyComponentInstance(OMX_COMPONENTTYPE * component)174 OMX_ERRORTYPE OMXMaster::destroyComponentInstance(
175         OMX_COMPONENTTYPE *component) {
176     Mutex::Autolock autoLock(mLock);
177 
178     ssize_t index = mPluginByInstance.indexOfKey(component);
179 
180     if (index < 0) {
181         return OMX_ErrorBadParameter;
182     }
183 
184     OMXPluginBase *plugin = mPluginByInstance.valueAt(index);
185     mPluginByInstance.removeItemsAt(index);
186 
187     return plugin->destroyComponentInstance(component);
188 }
189 
enumerateComponents(OMX_STRING name,size_t size,OMX_U32 index)190 OMX_ERRORTYPE OMXMaster::enumerateComponents(
191         OMX_STRING name,
192         size_t size,
193         OMX_U32 index) {
194     Mutex::Autolock autoLock(mLock);
195 
196     size_t numComponents = mPluginByComponentName.size();
197 
198     if (index >= numComponents) {
199         return OMX_ErrorNoMore;
200     }
201 
202     const String8 &name8 = mPluginByComponentName.keyAt(index);
203 
204     CHECK(size >= 1 + name8.size());
205     strcpy(name, name8.string());
206 
207     return OMX_ErrorNone;
208 }
209 
getRolesOfComponent(const char * name,Vector<String8> * roles)210 OMX_ERRORTYPE OMXMaster::getRolesOfComponent(
211         const char *name,
212         Vector<String8> *roles) {
213     Mutex::Autolock autoLock(mLock);
214 
215     roles->clear();
216 
217     ssize_t index = mPluginByComponentName.indexOfKey(String8(name));
218 
219     if (index < 0) {
220         return OMX_ErrorInvalidComponentName;
221     }
222 
223     OMXPluginBase *plugin = mPluginByComponentName.valueAt(index);
224     return plugin->getRolesOfComponent(name, roles);
225 }
226 
227 }  // namespace android
228