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.
Init()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 
TryRegisterEmojiFactory(const char * library_name)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 
~EmojiFactoryManager()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 
InitializeEmojiFactory()143 static void InitializeEmojiFactory() {
144   g_registrar.Init();
145 }
146 
147 /* static */
GetImplementation(const char * name)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 */
GetAvailableImplementation()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 
GetImplementation(const char * name)176 extern "C" android::EmojiFactory *GetImplementation(
177     const char *name) {
178   return android::EmojiFactory::GetImplementation(name);
179 }
180 
GetAvailableImplementation()181 extern "C" android::EmojiFactory *GetAvailableImplementation() {
182   return android::EmojiFactory::GetAvailableImplementation();
183 }
184