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