Home | History | Annotate | Download | only in emoji
      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 #include "EmojiFactory.h"
     18 
     19 #define LOG_TAG "EmojiFactory"
     20 #include <utils/Log.h>
     21 #include <utils/Vector.h>
     22 
     23 #include <cutils/properties.h>
     24 
     25 #include <dlfcn.h>
     26 #include <stdlib.h>
     27 #include <string.h>
     28 #include <pthread.h>
     29 
     30 
     31 namespace android {
     32 
     33 static pthread_once_t g_once = PTHREAD_ONCE_INIT;
     34 static Vector<EmojiFactory *> *g_factories = NULL;
     35 static Vector<void *> *g_handles = NULL;
     36 
     37 class EmojiFactoryManager {
     38  public:
     39   void Init();
     40   virtual ~EmojiFactoryManager();
     41  private:
     42   void TryRegisterEmojiFactory(const char *library_name);
     43 };
     44 
     45 // Note: I previously did this procedure in the construcor. However,
     46 // property_get() didn't return a correct value in that context. I guess
     47 // property_get() does not return correct values before AndroidRuntime
     48 // instance (or exactly, AppRuntime in instance app_main.cpp) is
     49 // fully ready (see AndroidRunitem.cpp and app_main.cpp).
     50 // So, instead of doing this in constructor, I decided this shoud be done
     51 // when a user requires to EmojiFactory, which makes better sense to me.
     52 void EmojiFactoryManager::Init() {
     53   g_handles = new Vector<void *>();
     54   g_factories = new Vector<EmojiFactory *>();
     55 
     56   char *emoji_libraries = new char[PROPERTY_VALUE_MAX];
     57   int len = property_get("ro.config.libemoji", emoji_libraries, "");
     58   // ALOGD("ro.config.libemoji: %s", emoji_libraries);
     59   if (len > 0) {
     60     char *saveptr, *ptr;
     61     ptr = emoji_libraries;
     62     while (true) {
     63       ptr = strtok_r(ptr, ":", &saveptr);
     64       if (NULL == ptr) {
     65         break;
     66       }
     67       TryRegisterEmojiFactory(ptr);
     68       ptr = NULL;
     69     }
     70   }
     71 
     72   delete [] emoji_libraries;
     73 }
     74 
     75 void EmojiFactoryManager::TryRegisterEmojiFactory(const char *library_name) {
     76   void *handle = dlopen(library_name, RTLD_LAZY | RTLD_LOCAL);
     77   if (handle == NULL) {
     78     const char* error_str = dlerror();
     79     if (error_str) {
     80       error_str = "Unknown reason";
     81     }
     82     ALOGE("Failed to load shared library %s: %s", library_name, error_str);
     83     return;
     84   }
     85   EmojiFactory *(*get_emoji_factory)() =
     86       reinterpret_cast<EmojiFactory *(*)()>(dlsym(handle,
     87                                                   "GetEmojiFactory"));
     88   if (get_emoji_factory == NULL) {
     89     const char* error_str = dlerror();
     90     if (error_str) {
     91       error_str = "Unknown reason";
     92     }
     93     ALOGE("Failed to call GetEmojiFactory: %s", error_str);
     94     dlclose(handle);
     95     return;
     96   }
     97 
     98   EmojiFactory *factory = (*get_emoji_factory)();
     99   if (NULL == factory) {
    100     ALOGE("Returned factory is NULL");
    101     dlclose(handle);
    102     return;
    103   }
    104 
    105   const char *name = factory->Name();
    106 
    107   size_t size = g_factories->size();
    108   for (size_t i = 0; i < size; ++i) {
    109     EmojiFactory *f = g_factories->itemAt(i);
    110     if (!strcmp(name, f->Name())) {
    111       ALOGE("Same EmojiFactory was found: %s", name);
    112       delete factory;
    113       dlclose(handle);
    114       return;
    115     }
    116   }
    117   g_factories->push(factory);
    118   // dlclose() must not be called here, since returned factory may point to
    119   // static data in the shared library (like "static const char* = "emoji";")
    120   g_handles->push(handle);
    121 }
    122 
    123 EmojiFactoryManager::~EmojiFactoryManager() {
    124   if (g_factories != NULL) {
    125     size_t size = g_factories->size();
    126     for (size_t i = 0; i < size; ++i) {
    127       delete g_factories->itemAt(i);
    128     }
    129     delete g_factories;
    130   }
    131 
    132   if (g_handles != NULL) {
    133     size_t size = g_handles->size();
    134     for (size_t i = 0; i < size; ++i) {
    135       dlclose(g_handles->itemAt(i));
    136     }
    137     delete g_handles;
    138   }
    139 }
    140 
    141 static EmojiFactoryManager g_registrar;
    142 
    143 static void InitializeEmojiFactory() {
    144   g_registrar.Init();
    145 }
    146 
    147 /* static */
    148 EmojiFactory *EmojiFactory::GetImplementation(const char *name) {
    149   pthread_once(&g_once, InitializeEmojiFactory);
    150   if (NULL == name) {
    151     return NULL;
    152   }
    153   size_t size = g_factories->size();
    154   for (size_t i = 0; i < size; ++i) {
    155     EmojiFactory *factory = g_factories->itemAt(i);
    156     if (!strcmp(name, factory->Name())) {
    157       return factory;
    158     }
    159   }
    160   return NULL;
    161 }
    162 
    163 /* static */
    164 EmojiFactory *EmojiFactory::GetAvailableImplementation() {
    165   pthread_once(&g_once, InitializeEmojiFactory);
    166   size_t size = g_factories->size();
    167   for (size_t i = 0; i < size; ++i) {
    168     EmojiFactory *factory = g_factories->itemAt(i);
    169     return factory;
    170   }
    171   return NULL;
    172 }
    173 
    174 }  // namespace android
    175 
    176 extern "C" android::EmojiFactory *GetImplementation(
    177     const char *name) {
    178   return android::EmojiFactory::GetImplementation(name);
    179 }
    180 
    181 extern "C" android::EmojiFactory *GetAvailableImplementation() {
    182   return android::EmojiFactory::GetAvailableImplementation();
    183 }
    184