blob: 3693314c0278937a5ce9abb1a9248e070f10546c [file] [log] [blame]
The Android Open Source Project7d814fb2009-03-10 16:20:55 -07001/*
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
31namespace android {
32
33static pthread_once_t g_once = PTHREAD_ONCE_INIT;
34static Vector<EmojiFactory *> *g_factories = NULL;
35static Vector<void *> *g_handles = NULL;
36
37class EmojiFactoryManager {
38 public:
Daisuke Miyakawae77fc972009-05-26 14:54:46 +090039 void Init();
The Android Open Source Project7d814fb2009-03-10 16:20:55 -070040 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.
Daisuke Miyakawae77fc972009-05-26 14:54:46 +090052void EmojiFactoryManager::Init() {
The Android Open Source Project7d814fb2009-03-10 16:20:55 -070053 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, "");
Steve Block4fa03562011-12-20 16:22:43 +000058 // ALOGD("ro.config.libemoji: %s", emoji_libraries);
The Android Open Source Project7d814fb2009-03-10 16:20:55 -070059 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
75void EmojiFactoryManager::TryRegisterEmojiFactory(const char *library_name) {
76 void *handle = dlopen(library_name, RTLD_LAZY | RTLD_LOCAL);
Daisuke Miyakawae77fc972009-05-26 14:54:46 +090077 if (handle == NULL) {
78 const char* error_str = dlerror();
79 if (error_str) {
80 error_str = "Unknown reason";
81 }
Steve Block0805d752012-01-06 19:18:46 +000082 ALOGE("Failed to load shared library %s: %s", library_name, error_str);
The Android Open Source Project7d814fb2009-03-10 16:20:55 -070083 return;
84 }
85 EmojiFactory *(*get_emoji_factory)() =
86 reinterpret_cast<EmojiFactory *(*)()>(dlsym(handle,
87 "GetEmojiFactory"));
Daisuke Miyakawae77fc972009-05-26 14:54:46 +090088 if (get_emoji_factory == NULL) {
89 const char* error_str = dlerror();
90 if (error_str) {
91 error_str = "Unknown reason";
92 }
Steve Block0805d752012-01-06 19:18:46 +000093 ALOGE("Failed to call GetEmojiFactory: %s", error_str);
The Android Open Source Project7d814fb2009-03-10 16:20:55 -070094 dlclose(handle);
95 return;
96 }
97
98 EmojiFactory *factory = (*get_emoji_factory)();
99 if (NULL == factory) {
Steve Block0805d752012-01-06 19:18:46 +0000100 ALOGE("Returned factory is NULL");
The Android Open Source Project7d814fb2009-03-10 16:20:55 -0700101 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())) {
Steve Block0805d752012-01-06 19:18:46 +0000111 ALOGE("Same EmojiFactory was found: %s", name);
The Android Open Source Project7d814fb2009-03-10 16:20:55 -0700112 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);
The Android Open Source Project7d814fb2009-03-10 16:20:55 -0700121}
122
123EmojiFactoryManager::~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
141static EmojiFactoryManager g_registrar;
142
143static void InitializeEmojiFactory() {
Daisuke Miyakawae77fc972009-05-26 14:54:46 +0900144 g_registrar.Init();
The Android Open Source Project7d814fb2009-03-10 16:20:55 -0700145}
146
147/* static */
148EmojiFactory *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 */
164EmojiFactory *EmojiFactory::GetAvailableImplementation() {
165 pthread_once(&g_once, InitializeEmojiFactory);
166 size_t size = g_factories->size();
The Android Open Source Project7d814fb2009-03-10 16:20:55 -0700167 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
The Android Open Source Project7d814fb2009-03-10 16:20:55 -0700176extern "C" android::EmojiFactory *GetImplementation(
177 const char *name) {
178 return android::EmojiFactory::GetImplementation(name);
179}
180
181extern "C" android::EmojiFactory *GetAvailableImplementation() {
182 return android::EmojiFactory::GetAvailableImplementation();
183}