Home | History | Annotate | Download | only in src
      1 /* ------------------------------------------------------------------
      2  * Copyright (C) 1998-2009 PacketVideo
      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
     13  * express or implied.
     14  * See the License for the specific language governing permissions
     15  * and limitations under the License.
     16  * -------------------------------------------------------------------
     17  */
     18 #include "osclconfig_lib.h"
     19 #include "oscl_shared_library.h"
     20 #include "oscl_string.h"
     21 #include "pvlogger.h"
     22 #include "oscl_utf8conv.h"
     23 #include "oscl_uuid.h"
     24 #include "oscl_file_types.h"
     25 
     26 #define BUFFER_SIZE 256
     27 
     28 typedef OsclSharedLibraryInterface*(*PVGetInterface_t)();
     29 typedef void (*PVReleaseInterface_t)(OsclSharedLibraryInterface*);
     30 
     31 OSCL_EXPORT_REF OsclSharedLibrary::OsclSharedLibrary()
     32 {
     33     ipLogger = PVLogger::GetLoggerObject("oscllib");
     34 #if OSCL_LIBRARY_PERF_LOGGING
     35     iDiagnosticsLogger = PVLogger::GetLoggerObject("pvplayerdiagnostics.oscllib.osclsharedlibrary");
     36     iLibCount = 0;
     37     iLibLoadTime = 0;
     38 #endif
     39     pSharedLibInterface = NULL;
     40     iRefCount = 0;
     41     ipHandle = NULL;
     42 
     43 }
     44 
     45 OSCL_EXPORT_REF OsclSharedLibrary::OsclSharedLibrary(const OSCL_String& aPath)
     46 {
     47     ipLogger = PVLogger::GetLoggerObject("oscllib");
     48 #if OSCL_LIBRARY_PERF_LOGGING
     49     iDiagnosticsLogger = PVLogger::GetLoggerObject("pvplayerdiagnostics.oscllib.osclsharedlibrary");
     50     iLibCount = 0;
     51     iLibLoadTime = 0;
     52 #endif
     53     pSharedLibInterface = NULL;
     54 
     55     iRefCount = 0;
     56     ipHandle = NULL;
     57     iLibPath = aPath;
     58 }
     59 
     60 OSCL_EXPORT_REF OsclSharedLibrary::~OsclSharedLibrary()
     61 {
     62 #if OSCL_LIBRARY_PERF_LOGGING
     63     PVLOGGER_LOGMSG(PVLOGMSG_INST_PROF, iDiagnosticsLogger, PVLOGMSG_INFO,
     64                     (0, "OsclSharedLibrary - Loading %d libraries took %d ticks ...", iLibCount, iLibLoadTime));
     65     iDiagnosticsLogger = NULL;
     66 #endif
     67     ipLogger = NULL;
     68 
     69     if (NULL != ipHandle)
     70     {
     71         Close();
     72     }
     73 }
     74 
     75 OSCL_EXPORT_REF OsclLibStatus OsclSharedLibrary::LoadLib(const OSCL_String& aPath)
     76 {
     77     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, ipLogger, PVLOGMSG_DEBUG, (0, "OsclSharedLibrary::LoadLib %s IN", aPath.get_cstr()));
     78 #if OSCL_LIBRARY_PERF_LOGGING
     79     iLibCount++;
     80     TICK starttime;
     81     SET_TICK(starttime);
     82 #endif
     83     iLibPath = aPath;
     84     // First look for debug version of the library ending with _debug
     85     int32 dotpos = aPath.get_size() - 1;
     86     while (dotpos >= 0)
     87     {
     88         if (aPath[dotpos] == '.')
     89             break;
     90         dotpos--;
     91     }
     92     if (dotpos >= 0 && dotpos != (int32)(aPath.get_size() - 1))
     93     {   // extension exists
     94 #if OSCL_LIB_READ_DEBUG_LIBS
     95         OSCL_HeapString<OsclMemAllocator> path1(aPath.get_cstr(), dotpos);
     96         OSCL_HeapString<OsclMemAllocator> debugPath(path1);
     97         debugPath += "_debug";
     98         debugPath += (aPath.get_cstr() + dotpos);
     99         PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, ipLogger, PVLOGMSG_DEBUG, (0, "OsclSharedLibrary::LoadLib looking for Debug lib %s", debugPath.get_cstr()));
    100         // Open the library
    101         if (OsclLibSuccess == loadlibrary(debugPath))
    102         {
    103 #if OSCL_LIBRARY_PERF_LOGGING
    104             DIFF_TICK(starttime, delta);
    105             iLibLoadTime += delta;
    106             PVLOGGER_LOGMSG(PVLOGMSG_INST_PROF, iDiagnosticsLogger, PVLOGMSG_INFO,
    107                             (0, "OsclSharedLibrary - Loading library %s took %d ticks ...", debugPath.get_cstr(), delta));
    108 #endif
    109             return OsclLibSuccess;  // debug dll loaded successfully
    110         }
    111         // _debug load failed, try original
    112 #endif
    113         if (OsclLibSuccess ==  loadlibrary(aPath))
    114         {
    115 #if OSCL_LIBRARY_PERF_LOGGING
    116             DIFF_TICK(starttime, delta);
    117             iLibLoadTime += delta;
    118             PVLOGGER_LOGMSG(PVLOGMSG_INST_PROF, iDiagnosticsLogger, PVLOGMSG_INFO,
    119                             (0, "OsclSharedLibrary - Loading library %s took %d ticks ...", aPath.get_cstr(), delta));
    120 #endif
    121             return OsclLibSuccess;
    122         }
    123         return OsclLibFail;
    124     }
    125     else if (dotpos == (int32)(aPath.get_size() - 1))
    126     {   // libname ended with "." no extension
    127         OSCL_HeapString<OsclMemAllocator> path1(aPath.get_cstr(), dotpos);
    128         OSCL_HeapString<OsclMemAllocator> debugPath(path1);
    129 #if OSCL_LIB_READ_DEBUG_LIBS
    130         debugPath += "_debug.";
    131         debugPath += PV_RUNTIME_LIB_FILENAME_EXTENSION;
    132         PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, ipLogger, PVLOGMSG_DEBUG, (0, "OsclSharedLibrary::LoadLib looking for Debug lib %s", debugPath.get_cstr()));
    133         // Open the library
    134         if (OsclLibSuccess == loadlibrary(debugPath))
    135         {
    136 #if OSCL_LIBRARY_PERF_LOGGING
    137             DIFF_TICK(starttime, delta);
    138             iLibLoadTime += delta;
    139             PVLOGGER_LOGMSG(PVLOGMSG_INST_PROF, iDiagnosticsLogger, PVLOGMSG_INFO,
    140                             (0, "OsclSharedLibrary - Loading library %s took %d ticks ...", debugPath.get_cstr(), delta));
    141 #endif
    142             return OsclLibSuccess;  // debug dll loaded successfully
    143         }
    144         // _debug load failed, try original
    145         debugPath = path1;
    146 #endif
    147         debugPath += PV_RUNTIME_LIB_FILENAME_EXTENSION;
    148         if (OsclLibSuccess ==  loadlibrary(debugPath))
    149         {
    150 #if OSCL_LIBRARY_PERF_LOGGING
    151             DIFF_TICK(starttime, delta);
    152             iLibLoadTime += delta;
    153             PVLOGGER_LOGMSG(PVLOGMSG_INST_PROF, iDiagnosticsLogger, PVLOGMSG_INFO,
    154                             (0, "OsclSharedLibrary - Loading library %s took %d ticks ...", debugPath.get_cstr(), delta));
    155 #endif
    156             return OsclLibSuccess;
    157         }
    158         return OsclLibFail;
    159     }
    160     else    // libname without extension
    161     {
    162         OSCL_HeapString<OsclMemAllocator> path1(aPath.get_cstr());
    163         OSCL_HeapString<OsclMemAllocator> debugPath(path1);
    164 #if OSCL_LIB_READ_DEBUG_LIBS
    165         debugPath += "_debug.";
    166         debugPath += PV_RUNTIME_LIB_FILENAME_EXTENSION;
    167         PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, ipLogger, PVLOGMSG_DEBUG, (0, "OsclSharedLibrary::LoadLib looking for Debug lib %s", debugPath.get_cstr()));
    168         // Open the library
    169         if (OsclLibSuccess == loadlibrary(debugPath))
    170         {
    171 #if OSCL_LIBRARY_PERF_LOGGING
    172             DIFF_TICK(starttime, delta);
    173             iLibLoadTime += delta;
    174             PVLOGGER_LOGMSG(PVLOGMSG_INST_PROF, iDiagnosticsLogger, PVLOGMSG_INFO,
    175                             (0, "OsclSharedLibrary - Loading library %s took %d ticks ...", debugPath.get_cstr(), delta));
    176 #endif
    177             return OsclLibSuccess;  // debug dll loaded successfully
    178         }
    179         // _debug load failed, try original
    180         debugPath = path1;
    181 #endif
    182         debugPath += ".";
    183         debugPath += PV_RUNTIME_LIB_FILENAME_EXTENSION;
    184         if (OsclLibSuccess ==  loadlibrary(debugPath))
    185         {
    186 #if OSCL_LIBRARY_PERF_LOGGING
    187             DIFF_TICK(starttime, delta);
    188             iLibLoadTime += delta;
    189             PVLOGGER_LOGMSG(PVLOGMSG_INST_PROF, iDiagnosticsLogger, PVLOGMSG_INFO,
    190                             (0, "OsclSharedLibrary - Loading library %s took %d ticks ...", debugPath.get_cstr(), delta));
    191 #endif
    192             return OsclLibSuccess;
    193         }
    194         return OsclLibFail;
    195     }
    196 
    197 }
    198 
    199 OSCL_EXPORT_REF OsclLibStatus OsclSharedLibrary::LoadLib()
    200 {
    201     return LoadLib(iLibPath);
    202 }
    203 
    204 OSCL_EXPORT_REF void OsclSharedLibrary::SetLibPath(const OSCL_String& aPath)
    205 {
    206     iLibPath = aPath;
    207 }
    208 
    209 OSCL_EXPORT_REF OsclLibStatus OsclSharedLibrary::QueryInterface(const OsclUuid& aInterfaceId,
    210         OsclAny*& aInterfacePtr)
    211 {
    212     aInterfacePtr = NULL;
    213     // Look up the PVGetInterface method
    214     if (NULL == ipHandle)
    215     {
    216         return OsclLibNotLoaded;
    217     }
    218     PVGetInterface_t getInterface =
    219         (PVGetInterface_t)dlsym(ipHandle, "PVGetInterface");
    220     // dlsym() returns NULL if there were any issues getting the
    221     // address of the symbol
    222     if (NULL == getInterface)
    223     {
    224         // check for errors
    225         const char* pErr = dlerror();
    226         if (NULL == pErr)
    227         {
    228             // No error reported, but no symbol was found
    229             PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, ipLogger, PVLOGMSG_INFO,
    230                             (0, "OsclLib::QueryInterface: Could not access PVGetInterface "
    231                              "symbol in library but no error reported"));
    232         }
    233         else
    234         {
    235             // Error reported
    236             PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, ipLogger, PVLOGMSG_INFO,
    237                             (0, "OsclLib::QueryInterface: Could not access PVGetInterface "
    238                              "symbol in library: %s", pErr));
    239         }
    240         return OsclLibFail;
    241     }
    242 
    243     // Get the OsclSharedLibraryInterface if needed.  There can be multiple calls
    244     // to query interface so check whether the interface has already been fetched.
    245     if (!pSharedLibInterface)
    246     {
    247         pSharedLibInterface = (OsclSharedLibraryInterface*)getInterface();
    248     }
    249     if (NULL == pSharedLibInterface)
    250     {
    251         PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, ipLogger, PVLOGMSG_INFO,
    252                         (0, "OsclSharedLibrary::QueryInterface: Could not access the "
    253                          "library pointer function"));
    254         return OsclLibFail;
    255     }
    256     // Lookup the interface ID
    257     aInterfacePtr = pSharedLibInterface->SharedLibraryLookup(aInterfaceId);
    258     if (NULL == aInterfacePtr)
    259     {
    260         PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, ipLogger, PVLOGMSG_INFO,
    261                         (0, "OsclLib::QueryInterface: NO library interface found for aInterfaceId."));
    262         return OsclLibFail;
    263     }
    264     return OsclLibSuccess;
    265 }
    266 
    267 OSCL_EXPORT_REF OsclLibStatus OsclSharedLibrary::Close()
    268 {
    269     if (iRefCount > 0)
    270     {
    271         return OsclLibFail;
    272     }
    273     if (pSharedLibInterface)
    274     {
    275         PVReleaseInterface_t releaseInterface =
    276             (PVReleaseInterface_t)dlsym(ipHandle, "PVReleaseInterface");
    277         // dlsym() returns NULL if there were any issues getting the
    278         // address of the symbol
    279         if (NULL == releaseInterface)
    280         {
    281             PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, ipLogger, PVLOGMSG_ERR,
    282                             (0, "OsclLib::Close: Could not access "
    283                              "PVReleaseInterface symbol in library - Possible memory leak."));
    284             // check for errors
    285             const char* pErr = dlerror();
    286             if (NULL == pErr)
    287             {
    288                 // No error reported, but no symbol was found
    289                 PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, ipLogger, PVLOGMSG_INFO,
    290                                 (0, "OsclLib::Close: Could not access PVReleaseInterface "
    291                                  "symbol in library but no error reported"));
    292             }
    293             else
    294             {
    295                 // Error reported
    296                 PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, ipLogger, PVLOGMSG_INFO,
    297                                 (0, "OsclLib::Close: Could not access PVReleaseInterface "
    298                                  "symbol in library: %s", pErr));
    299             }
    300             dlclose(ipHandle);
    301             pSharedLibInterface = NULL;
    302         }
    303         else
    304         {
    305             releaseInterface(pSharedLibInterface);
    306             pSharedLibInterface = NULL;
    307         }
    308     }
    309 
    310     if (ipHandle)
    311     {
    312         if (0 != dlclose(ipHandle))
    313         {
    314             // dlclose() returns non-zero value if close failed, check for errors
    315             const char* pErr = dlerror();
    316             if (NULL != pErr)
    317             {
    318                 PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, ipLogger, PVLOGMSG_WARNING,
    319                                 (0, "OsclSharedLibrary::Close: Error closing library: %s", pErr));
    320             }
    321             else
    322             {
    323                 PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, ipLogger, PVLOGMSG_WARNING,
    324                                 (0, "OsclSharedLibrary::Close: Error closing library, no error reported"
    325                                  ""));
    326             }
    327             return OsclLibFail;
    328         }
    329         ipHandle = NULL;
    330     }
    331     return OsclLibSuccess;
    332 }
    333 
    334 OSCL_EXPORT_REF void OsclSharedLibrary::AddRef()
    335 {
    336     ++iRefCount;
    337 }
    338 
    339 OSCL_EXPORT_REF void OsclSharedLibrary::RemoveRef()
    340 {
    341     --iRefCount;
    342 }
    343 
    344 //
    345 //OsclSharedLibraryList
    346 //
    347 #include "oscl_configfile_list.h"
    348 #include "oscl_library_list.h"
    349 
    350 OSCL_EXPORT_REF OsclSharedLibraryList::OsclSharedLibraryList()
    351 {
    352     iLogger = PVLogger::GetLoggerObject("oscllib");
    353 }
    354 
    355 OSCL_EXPORT_REF OsclSharedLibraryList::~OsclSharedLibraryList()
    356 {
    357     CloseAll();
    358 }
    359 /*
    360 ** Give a config file path, search all config files for libraries that
    361 ** support the given interface ID.
    362 */
    363 OSCL_EXPORT_REF void OsclSharedLibraryList::Populate(const OSCL_String& aPath, const OsclUuid& aInterfaceId)
    364 {
    365     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, iLogger, PVLOGMSG_DEBUG,
    366                     (0, "OsclSharedLibraryList::Populate '%s' IN", aPath.get_cstr()));
    367 
    368     iInterfaceId = aInterfaceId;
    369     OsclConfigFileList configFileList;
    370     configFileList.Populate(aPath);
    371     for (uint32 i = 0; i < configFileList.Size(); i++)
    372     {
    373         OsclLibraryList libList;
    374         libList.Populate(aInterfaceId, configFileList.GetConfigfileAt(i));
    375         for (uint32 j = 0; j < libList.Size(); j++)
    376         {
    377             OsclSharedLibrary* sharedLib = OSCL_NEW(OsclSharedLibrary, (libList.GetLibraryPathAt(j)));
    378             iList.push_back(sharedLib);
    379         }
    380     }
    381 }
    382 
    383 /*
    384 ** Query interface for the given library.
    385 */
    386 OSCL_EXPORT_REF OsclLibStatus OsclSharedLibraryList::QueryInterfaceAt(uint32 aIndex, OsclAny*& aInterfacePtr)
    387 {
    388     aInterfacePtr = NULL;
    389     OsclLibStatus status = OsclLibFail;
    390 
    391     if (aIndex < iList.size())
    392     {
    393         status = iList[aIndex]->QueryInterface(iInterfaceId, aInterfacePtr);
    394         //Load lib if needed & repeat the query.
    395         if (status == OsclLibNotLoaded)
    396         {
    397             status = iList[aIndex]->LoadLib();
    398             if (status == OsclLibSuccess)
    399                 status = iList[aIndex]->QueryInterface(iInterfaceId, aInterfacePtr);
    400         }
    401     }
    402     return status;
    403 }
    404 
    405 /*
    406 ** Close all open libraries
    407 */
    408 OSCL_EXPORT_REF void OsclSharedLibraryList::CloseAll()
    409 {
    410     while (!iList.empty())
    411     {
    412         iList.front()->Close();
    413         OSCL_DELETE(iList.front());
    414         iList.erase(&iList.front());
    415     }
    416 }
    417 
    418 OsclLibStatus OsclSharedLibrary::loadlibrary(const OSCL_String& alib)
    419 {
    420     PVLOGGER_LOGMSG(PVLOGMSG_INST_LLDBG, ipLogger, PVLOGMSG_DEBUG, (0, "OsclSharedLibrary::loadlibrary %s IN", alib.get_cstr()));
    421     // Clear any errors
    422     dlerror();
    423     // Open the library
    424     void* library = dlopen(alib.get_cstr(), RTLD_NOW);
    425     // dlopen() returns NULL if there were any issues opening the library
    426     if (NULL == library)
    427     {
    428         // check for errors
    429         const char* pErr = dlerror();
    430         if (NULL == pErr)
    431         {
    432             // No error reported, but no handle to the library
    433             PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, ipLogger, PVLOGMSG_WARNING,
    434                             (0, "OsclLib::loadlibrary: Error opening "
    435                              "library (%s) but no error reported",
    436                              alib.get_cstr(), pErr));
    437         }
    438         else
    439         {
    440             // Error reported
    441             PVLOGGER_LOGMSG(PVLOGMSG_INST_REL, ipLogger, PVLOGMSG_WARNING,
    442                             (0, "OsclLib::loadlibrary: Error opening "
    443                              "library (%s): %s", alib.get_cstr(), pErr));
    444         }
    445         return OsclLibFail;
    446     }
    447     ipHandle = library;
    448     return OsclLibSuccess;
    449 
    450 }
    451 
    452