/* * 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, ""); // LOGD("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"; } LOGE("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"; } LOGE("Failed to call GetEmojiFactory: %s", error_str); dlclose(handle); return; } EmojiFactory *factory = (*get_emoji_factory)(); if (NULL == factory) { LOGE("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())) { LOGE("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(); }