| /* |
| * Copyright (C) 2009 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "EmojiFactory.h" |
| |
| #define LOG_TAG "EmojiFactory" |
| #include <utils/Log.h> |
| #include <utils/Vector.h> |
| |
| #include <cutils/properties.h> |
| |
| #include <dlfcn.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <pthread.h> |
| |
| |
| namespace android { |
| |
| static pthread_once_t g_once = PTHREAD_ONCE_INIT; |
| static Vector<EmojiFactory *> *g_factories = NULL; |
| static Vector<void *> *g_handles = NULL; |
| |
| class EmojiFactoryManager { |
| public: |
| void Init(); |
| virtual ~EmojiFactoryManager(); |
| private: |
| void TryRegisterEmojiFactory(const char *library_name); |
| }; |
| |
| // Note: I previously did this procedure in the construcor. However, |
| // property_get() didn't return a correct value in that context. I guess |
| // property_get() does not return correct values before AndroidRuntime |
| // instance (or exactly, AppRuntime in instance app_main.cpp) is |
| // fully ready (see AndroidRunitem.cpp and app_main.cpp). |
| // So, instead of doing this in constructor, I decided this shoud be done |
| // when a user requires to EmojiFactory, which makes better sense to me. |
| void EmojiFactoryManager::Init() { |
| g_handles = new Vector<void *>(); |
| g_factories = new Vector<EmojiFactory *>(); |
| |
| char *emoji_libraries = new char[PROPERTY_VALUE_MAX]; |
| int len = property_get("ro.config.libemoji", emoji_libraries, ""); |
| // ALOGD("ro.config.libemoji: %s", emoji_libraries); |
| if (len > 0) { |
| char *saveptr, *ptr; |
| ptr = emoji_libraries; |
| while (true) { |
| ptr = strtok_r(ptr, ":", &saveptr); |
| if (NULL == ptr) { |
| break; |
| } |
| TryRegisterEmojiFactory(ptr); |
| ptr = NULL; |
| } |
| } |
| |
| delete [] emoji_libraries; |
| } |
| |
| void EmojiFactoryManager::TryRegisterEmojiFactory(const char *library_name) { |
| void *handle = dlopen(library_name, RTLD_LAZY | RTLD_LOCAL); |
| if (handle == NULL) { |
| const char* error_str = dlerror(); |
| if (error_str) { |
| error_str = "Unknown reason"; |
| } |
| ALOGE("Failed to load shared library %s: %s", library_name, error_str); |
| return; |
| } |
| EmojiFactory *(*get_emoji_factory)() = |
| reinterpret_cast<EmojiFactory *(*)()>(dlsym(handle, |
| "GetEmojiFactory")); |
| if (get_emoji_factory == NULL) { |
| const char* error_str = dlerror(); |
| if (error_str) { |
| error_str = "Unknown reason"; |
| } |
| ALOGE("Failed to call GetEmojiFactory: %s", error_str); |
| dlclose(handle); |
| return; |
| } |
| |
| EmojiFactory *factory = (*get_emoji_factory)(); |
| if (NULL == factory) { |
| ALOGE("Returned factory is NULL"); |
| dlclose(handle); |
| return; |
| } |
| |
| const char *name = factory->Name(); |
| |
| size_t size = g_factories->size(); |
| for (size_t i = 0; i < size; ++i) { |
| EmojiFactory *f = g_factories->itemAt(i); |
| if (!strcmp(name, f->Name())) { |
| ALOGE("Same EmojiFactory was found: %s", name); |
| delete factory; |
| dlclose(handle); |
| return; |
| } |
| } |
| g_factories->push(factory); |
| // dlclose() must not be called here, since returned factory may point to |
| // static data in the shared library (like "static const char* = "emoji";") |
| g_handles->push(handle); |
| } |
| |
| EmojiFactoryManager::~EmojiFactoryManager() { |
| if (g_factories != NULL) { |
| size_t size = g_factories->size(); |
| for (size_t i = 0; i < size; ++i) { |
| delete g_factories->itemAt(i); |
| } |
| delete g_factories; |
| } |
| |
| if (g_handles != NULL) { |
| size_t size = g_handles->size(); |
| for (size_t i = 0; i < size; ++i) { |
| dlclose(g_handles->itemAt(i)); |
| } |
| delete g_handles; |
| } |
| } |
| |
| static EmojiFactoryManager g_registrar; |
| |
| static void InitializeEmojiFactory() { |
| g_registrar.Init(); |
| } |
| |
| /* static */ |
| EmojiFactory *EmojiFactory::GetImplementation(const char *name) { |
| pthread_once(&g_once, InitializeEmojiFactory); |
| if (NULL == name) { |
| return NULL; |
| } |
| size_t size = g_factories->size(); |
| for (size_t i = 0; i < size; ++i) { |
| EmojiFactory *factory = g_factories->itemAt(i); |
| if (!strcmp(name, factory->Name())) { |
| return factory; |
| } |
| } |
| return NULL; |
| } |
| |
| /* static */ |
| EmojiFactory *EmojiFactory::GetAvailableImplementation() { |
| pthread_once(&g_once, InitializeEmojiFactory); |
| size_t size = g_factories->size(); |
| for (size_t i = 0; i < size; ++i) { |
| EmojiFactory *factory = g_factories->itemAt(i); |
| return factory; |
| } |
| return NULL; |
| } |
| |
| } // namespace android |
| |
| extern "C" android::EmojiFactory *GetImplementation( |
| const char *name) { |
| return android::EmojiFactory::GetImplementation(name); |
| } |
| |
| extern "C" android::EmojiFactory *GetAvailableImplementation() { |
| return android::EmojiFactory::GetAvailableImplementation(); |
| } |