Tizen 2.4.0 rev3 SDK Public Release
[framework/location/maps-service.git] / src / plugin / module.cpp
1 /* Copyright (c) 2010-2014 Samsung Electronics Co., Ltd. All rights reserved.
2  *
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 "module.h"
18 #include "maps_util.h"
19 #include <glib/gstdio.h>
20 #include "thread.h"
21 #include "command.h"
22 #include "command_queue.h"
23 #include "empty_module.h"
24
25 extern const char *MAPS_PLUGINS_PATH_PREFIX;
26
27 plugin::scope_mutex::scope_mutex(GMutex *m) : mutex(m)
28 {
29         g_mutex_lock(mutex);
30 }
31
32 plugin::scope_mutex::~scope_mutex()
33 {
34         g_mutex_unlock(mutex);
35 }
36
37 plugin::binary_extractor::binary_extractor()
38 {
39 }
40
41 plugin::provider_info plugin::binary_extractor::get_plugin_info(const
42                                                         string &file_name) const
43 {
44
45         if (file_name.empty())
46                 return provider_info::empty_instance;
47
48         /* 1.Initialize plugin */
49         GMod *plugin = gmod_new(file_name, FALSE);
50         if (!plugin)
51                 return provider_info::empty_instance;
52
53         provider_info info;
54
55         /* 2. Get plugin info */
56         maps_plugin_get_info_f func =
57                 (maps_plugin_get_info_f) gmod_find_sym(plugin,
58                 "maps_plugin_get_info");
59         if (func) {
60                 maps_plugin_info_h i;
61                 if (func(&i) == MAPS_ERROR_NONE) {
62                         char *provider_name = NULL;
63                         maps_plugin_info_get_provider_name(i, &provider_name);
64
65                         /* Convert plugin info to provider info */
66                         info.construct(string(provider_name), file_name);
67
68                         g_free(provider_name);
69                 }
70                 maps_plugin_info_destroy(i);
71         }
72
73         /* 3. shutdown plugin */
74         gmod_free(plugin);
75
76         return info;
77 }
78
79 maps_plugin_h plugin::binary_extractor::init(const provider_info &info,
80                                              int *init_error)
81 {
82         /* 1.Initialize plugin */
83         if (info.file.empty() || !init_error)
84                 return NULL;
85
86         *init_error = MAPS_ERROR_NONE;
87
88         GMod *plugin = gmod_new(info.file, TRUE);
89         if (!plugin) {
90                 MAPS_LOGE("Open Module Failed: %s", info.file.c_str());
91                 gmod_free(plugin);
92                 return NULL;
93         }
94
95         /* 2.1 Create new plugin interface */
96         plugin_s* new_plugin = g_slice_new0(plugin_s);
97
98         /* 2. Perform steps to completely initialize a plugin */
99         do {
100
101                 if (!new_plugin) {
102                         MAPS_LOGE("OUT_OF_MEMORY(0x%08x)",
103                                 MAPS_ERROR_OUT_OF_MEMORY);
104                         break;
105                 }
106
107                 /* 2.1 Set plugin module handle */
108                 new_plugin->module = plugin;
109
110                 /* 2.2 Set plugin interface */
111                 new_plugin->interface = get_empty_interface();
112
113                 /* Plugin dedicated functions */
114                 new_plugin->interface.maps_plugin_init =
115                         (maps_plugin_init_f) gmod_find_sym(plugin,
116                         "maps_plugin_init");
117                 new_plugin->interface.maps_plugin_shutdown =
118                         (maps_plugin_shutdown_f) gmod_find_sym(plugin,
119                         "maps_plugin_shutdown");
120                 new_plugin->interface.maps_plugin_get_info =
121                         (maps_plugin_get_info_f) gmod_find_sym(plugin,
122                         "maps_plugin_get_info");
123
124                 /* Maps Provider access key, preference and capabilities */
125                 new_plugin->interface.maps_plugin_set_provider_key =
126                         (maps_plugin_set_provider_key_f) gmod_find_sym(plugin,
127                         "maps_plugin_set_provider_key");
128                 new_plugin->interface.maps_plugin_get_provider_key =
129                         (maps_plugin_get_provider_key_f) gmod_find_sym(plugin,
130                         "maps_plugin_get_provider_key");
131                 new_plugin->interface.maps_plugin_set_preference =
132                         (maps_plugin_set_preference_f) gmod_find_sym(plugin,
133                         "maps_plugin_set_preference");
134                 new_plugin->interface.maps_plugin_get_preference =
135                         (maps_plugin_get_preference_f) gmod_find_sym(plugin,
136                         "maps_plugin_get_preference");
137                 new_plugin->interface.maps_plugin_is_service_supported =
138                         (maps_plugin_is_service_supported_f)
139                         gmod_find_sym(plugin,
140                         "maps_plugin_is_service_supported");
141                 new_plugin->interface.maps_plugin_is_data_supported =
142                         (maps_plugin_is_data_supported_f) gmod_find_sym(plugin,
143                         "maps_plugin_is_data_supported");
144
145                 /* Geocode */
146                 new_plugin->interface.maps_plugin_geocode =
147                         (maps_plugin_geocode_f) gmod_find_sym(plugin,
148                         "maps_plugin_geocode");
149                 new_plugin->interface.maps_plugin_geocode_inside_area =
150                         (maps_plugin_geocode_inside_area_f)
151                         gmod_find_sym(plugin,
152                         "maps_plugin_geocode_inside_area");
153                 new_plugin->interface.
154                         maps_plugin_geocode_by_structured_address =
155                         (maps_plugin_geocode_by_structured_address_f)
156                         gmod_find_sym(plugin,
157                         "maps_plugin_geocode_by_structured_address");
158                 new_plugin->interface.maps_plugin_reverse_geocode =
159                         (maps_plugin_reverse_geocode_f) gmod_find_sym(plugin,
160                         "maps_plugin_reverse_geocode");
161
162                 /* Place */
163                 new_plugin->interface.maps_plugin_search_place =
164                         (maps_plugin_search_place_f) gmod_find_sym(plugin,
165                         "maps_plugin_search_place");
166                 new_plugin->interface.maps_plugin_search_place_by_area =
167                         (maps_plugin_search_place_by_area_f)
168                         gmod_find_sym(plugin,
169                         "maps_plugin_search_place_by_area");
170                 new_plugin->interface.maps_plugin_search_place_by_address =
171                         (maps_plugin_search_place_by_address_f)
172                         gmod_find_sym(plugin,
173                         "maps_plugin_search_place_by_address");
174
175                 /* Route */
176                 new_plugin->interface.maps_plugin_search_route =
177                         (maps_plugin_search_route_f) gmod_find_sym(plugin,
178                         "maps_plugin_search_route");
179                 new_plugin->interface.maps_plugin_search_route_waypoints =
180                         (maps_plugin_search_route_waypoints_f)
181                         gmod_find_sym(plugin,
182                         "maps_plugin_search_route_waypoints");
183
184                 /* Cancel Request */
185                 new_plugin->interface.maps_plugin_cancel_request =
186                         (maps_plugin_cancel_request_f) gmod_find_sym(plugin,
187                         "maps_plugin_cancel_request");
188
189                 /* 2.3 Check whether the plugin init function is valid */
190                 if (!new_plugin->interface.maps_plugin_init) {
191                         MAPS_LOGE("ERROR! Plugin initialization function is "
192                                   "invalid");
193                         break;
194                 }
195
196                 /* 2.4 Call a plugin to initialize itself, send to the plugin
197                 *  its pointer */
198                 int ret =
199                         new_plugin->interface.
200                         maps_plugin_init((maps_plugin_h *) (&new_plugin));
201                 *init_error = ret; /* Remember the error of plugin init */
202                 if (ret != MAPS_ERROR_NONE) {
203                         MAPS_LOGE("ERROR! Plugin initialization function "
204                                   "failed: %d", ret);
205                         break;
206                 }
207
208                 if (!new_plugin->interface.maps_plugin_set_provider_key) {
209                         MAPS_LOGE("ERROR! Plugin set_provider_key function "
210                                   "is NULL: %d", ret);
211                         break;
212                 }
213
214                 if (!new_plugin->interface.maps_plugin_get_provider_key) {
215                         MAPS_LOGE("ERROR! Plugin set_provider_key function is "
216                                   "NULL: %d", ret);
217                         break;
218                 }
219
220                 if (!new_plugin->interface.maps_plugin_set_preference) {
221                         MAPS_LOGE("ERROR! Plugin set_preference function is "
222                                   "NULL: %d", ret);
223                         break;
224                 }
225
226                 if (!new_plugin->interface.maps_plugin_get_preference) {
227                         MAPS_LOGE("ERROR! Plugin get_preference function is "
228                                   "NULL: %d", ret);
229                         break;
230                 }
231
232                 if (!new_plugin->interface.maps_plugin_is_data_supported) {
233                         MAPS_LOGE("ERROR! Plugin support_is_data_supported "
234                                   "function is NULL: %d", ret);
235                         break;
236                 }
237
238                 if (!new_plugin->interface.maps_plugin_is_service_supported) {
239                         MAPS_LOGE("ERROR! Plugin support_is_service_supported "
240                                   "function is NULL: %d", ret);
241                         break;
242                 }
243
244                 /* 2.7 Create a queue with asynchronous requests to plugin */
245                 if (session::command_queue::is_async())
246                         new_plugin->request_queue = g_async_queue_new();
247
248                 /* 2.8 Initialize the mutex for the map of pending requests */
249                 new_plugin->pending_request_maps =
250                         g_hash_table_new_full(g_int_hash, g_int_equal, g_free,
251                         session::command_handler::destroy);
252                 if (!new_plugin->pending_request_maps) {
253                         MAPS_LOGE("OUT_OF_MEMORY(0x%08x)",
254                                 MAPS_ERROR_OUT_OF_MEMORY);
255                         break;
256                 }
257                 g_mutex_init(&new_plugin->pending_request_mutex);
258
259                 /* DEBUG TRACE */
260                 trace_dbg(new_plugin);
261
262                 /* 2.5 Return newly initialized plugin */
263                 return new_plugin;
264
265         } while (FALSE);
266
267         MAPS_LOGE("Shut down the plugin because of error");
268
269         /* 3. shutdown plugin in case of problem */
270         shutdown(new_plugin);
271         return NULL;
272 }
273
274 void plugin::binary_extractor::shutdown(maps_plugin_h plugin_h)
275 {
276         if (!plugin_h)
277                 return;
278
279         plugin_s *plugin = (plugin_s *) plugin_h;
280         g_return_if_fail(plugin->module);
281
282         /* 0. shutdown plugin */
283         if (plugin->interface.maps_plugin_shutdown)
284                 plugin->interface.maps_plugin_shutdown(plugin);
285
286         /* 1. Stop the thread, processing the request queue */
287         session::thread().stop(plugin);
288
289         /* 2. Destroy the request queue */
290         if (plugin->request_queue)
291                 g_async_queue_unref(plugin->request_queue);
292
293         /* 3. Destroy the map of pending requests */
294         if (plugin->pending_request_maps) {
295                 g_hash_table_unref(plugin->pending_request_maps);
296
297                 /* Clear the mutex for the map of pending requests */
298                 g_mutex_clear(&plugin->pending_request_mutex);
299         }
300
301         /* 4. Unload plugin from memory */
302         gmod_free((GMod *) plugin->module);
303
304         /* 5. Destroying the table with plugin capabilities */
305         /*maps_string_hashtable_destroy(plugin->capabilities); */
306
307         /* 6. Release memory used by plugin structure */
308         g_slice_free(plugin_s, plugin);
309 }
310
311 /* Open the binary (which contains a plugin) */
312 plugin::GMod *plugin::binary_extractor::gmod_new(const string &module_file,
313                                                  gboolean is_resident) const
314 {
315
316         if (!g_module_supported()) {
317                 MAPS_LOGE("ERROR! g_module_supported is false\n\n");
318                 return NULL;
319         }
320
321         if (module_file.empty())
322                 return NULL;
323
324         GMod *gmod = g_new0(GMod, 1);
325
326         gmod->name = g_strdup(module_file.c_str());
327         if (!gmod->name) {
328                 g_free(gmod);
329                 return NULL;
330         }
331
332         /*gmod->path = g_module_build_path(MAPS_PLUGINS_PATH_PREFIX,
333         * gmod->name); */
334         gmod->path = g_strnfill(100, 0);
335         g_sprintf(gmod->path, "%s/%s", MAPS_PLUGINS_PATH_PREFIX, gmod->name);
336         if (!gmod->path) {
337                 g_free(gmod->name);
338                 g_free(gmod);
339                 return NULL;
340         }
341
342         gmod->module = g_module_open(gmod->path, G_MODULE_BIND_LAZY);
343         if (!gmod->module) {
344                 MAPS_LOGE("module path not found: %s", gmod->path);
345
346                 const gchar *last_error = g_module_error();
347                 MAPS_LOGE("last module error: %s", last_error);
348
349                 g_free(gmod->name);
350                 g_free(gmod->path);
351                 g_free(gmod);
352                 return NULL;
353         }
354         MAPS_LOGD("open module");
355         /*if (is_resident)
356                 g_module_make_resident(gmod->module);*/
357
358         return gmod;
359 }
360
361 /* Close the binary (which contains a plugin) */
362 void plugin::binary_extractor::gmod_free(GMod *gmod) const
363 {
364         /*g_return_if_fail(gmod); */
365         if (!gmod)
366                 return;
367
368         if (gmod->name)
369                 g_free(gmod->name);
370         if (gmod->path)
371                 g_free(gmod->path);
372         if (gmod->module)
373                 g_module_close(gmod->module);
374         g_free(gmod);
375
376         MAPS_LOGD("close module");
377         MAPS_LOGD("last module error: %s", g_module_error());
378 }
379
380 /* Find the address of a function in a binary (which contains a plugin) */
381 gpointer plugin::binary_extractor::gmod_find_sym(GMod *gmod,
382                                                  const gchar *func_name) const
383 {
384         g_return_val_if_fail(gmod, NULL);
385         g_return_val_if_fail(func_name, NULL);
386
387         gpointer func_ptr = NULL;
388         if (!g_module_symbol(gmod->module, func_name, &func_ptr)) {
389                 MAPS_LOGE("function symbol not found");
390                 MAPS_LOGE("%s", g_module_error());
391                 func_ptr = NULL;
392         }
393         return func_ptr;
394 }
395
396 void plugin::binary_extractor::trace_dbg(const plugin_s *plugin) const
397 {
398
399         MAPS_LOGD("*********************************************");
400         MAPS_LOGD("PLUGIN INFO");
401         if (!plugin) {
402                 MAPS_LOGD("PLUGIN is NULL");
403                 MAPS_LOGD("*********************************************");
404                 return;
405         }
406
407         const GMod *mod = (const GMod *) plugin->module;
408         if (!mod) {
409                 MAPS_LOGD("PLUGIN module is NULL");
410         }
411         else {
412                 MAPS_LOGD("module address:\t\t\t%p", mod->module);
413                 MAPS_LOGD("module name:\t\t\t%s", mod->name);
414                 MAPS_LOGD("module path:\t\t\t%s", mod->path);
415         }
416
417         if (!plugin->request_queue) {
418                 MAPS_LOGD("PLUGIN request queue is NULL");
419         }
420         else {
421                 MAPS_LOGD("plugin request queue:\t\t\t%p",
422                         plugin->request_queue);
423         }
424
425         const interface_s *itf = &plugin->interface;
426         MAPS_LOGD("maps_plugin_init:\t\t\t%p", itf->maps_plugin_init);
427         MAPS_LOGD("maps_plugin_shutdown:\t\t\t%p", itf->maps_plugin_shutdown);
428         MAPS_LOGD("maps_plugin_get_info:\t\t\t%p", itf->maps_plugin_get_info);
429
430         /* Maps Provider access key */
431         MAPS_LOGD("maps_plugin_set_provider_key:\t\t%p",
432                 itf->maps_plugin_set_provider_key);
433         MAPS_LOGD("maps_plugin_get_provider_key:\t\t%p",
434                 itf->maps_plugin_get_provider_key);
435         MAPS_LOGD("maps_plugin_is_service_supported:\t%p",
436                 itf->maps_plugin_is_service_supported);
437         MAPS_LOGD("maps_plugin_is_data_supported:\t\t%p",
438                 itf->maps_plugin_is_data_supported);
439
440         MAPS_LOGD("maps_plugin_geocode:\t\t\t%p", itf->maps_plugin_geocode);
441         MAPS_LOGD("maps_plugin_geocode_inside_area:\t%p",
442                 itf->maps_plugin_geocode_inside_area);
443         MAPS_LOGD("maps_plugin_geocode_by_structured_address: %p",
444                 itf->maps_plugin_geocode_by_structured_address);
445         MAPS_LOGD("maps_plugin_reverse_geocode:\t\t%p",
446                 itf->maps_plugin_reverse_geocode);
447
448         MAPS_LOGD("maps_plugin_search_place:\t\t%p",
449                 itf->maps_plugin_search_place);
450         MAPS_LOGD("maps_plugin_search_place_by_area:\t%p",
451                 itf->maps_plugin_search_place_by_area);
452         MAPS_LOGD("maps_plugin_search_place_by_address:\t%p",
453                 itf->maps_plugin_search_place_by_address);
454
455         MAPS_LOGD("maps_plugin_search_route:\t\t%p",
456                 itf->maps_plugin_search_route);
457         MAPS_LOGD("maps_plugin_search_route_waypoints:\t%p",
458                 itf->maps_plugin_search_route_waypoints);
459
460         MAPS_LOGD("maps_plugin_cancel_request:\t\t%p",
461                 itf->maps_plugin_cancel_request);
462         MAPS_LOGD("*********************************************");
463 }