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
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:
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.
52void 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
75void 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
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() {
144  g_registrar.Init();
145}
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();
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
176extern "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}
184