f6bb4fb4b571df0590c3f09da44a5188368116dd
[framework/web/wrt-installer.git] / src / wrt-installer / wrt_installer_api.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
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  * @file        wrt_installer_api.cpp
18  * @author      Chung Jihoon (jihoon.chung@samsung.com)
19  * @version     1.0
20  * @brief       This file contains definitions of wrt installer api
21  */
22 #include <stdlib.h>
23 #include <list>
24 #include <string>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #include <dpl/exception.h>
29 #include <dpl/log/log.h>
30 #include <dpl/assert.h>
31 #include <dpl/semaphore.h>
32 #include <dpl/sstream.h>
33 #include <dpl/errno_string.h>
34 #include <libxml/parser.h>
35 #include <vconf.h>
36
37 #include <wrt_installer_api.h>
38 #include <installer_callbacks_translate.h>
39 #include <installer_controller.h>
40 #include <language_subtag_rst_tree.h>
41 #include <dpl/wrt-dao-ro/global_config.h>
42 #include <dpl/utils/widget_version.h>
43 #include <wrt_type.h>
44 #include <dpl/localization/w3c_file_localization.h>
45 #include <dpl/wrt-dao-ro/WrtDatabase.h>
46 #include <vcore/VCore.h>
47 #include <installer_main_thread.h>
48
49 using namespace WrtDB;
50
51 #undef TRUE
52 #undef FALSE
53 #define TRUE 0
54 #define FALSE -1
55
56 #ifdef __cplusplus
57
58 #define EXPORT_API __attribute__((visibility("default")))
59 extern "C"
60 {
61 #endif
62 inline WidgetUpdateMode::Type translateWidgetUpdateMode(
63     wrt_widget_update_mode_t updateMode)
64 {
65     if (updateMode == WRT_WIM_POLICY_DIRECTORY_FORCE_INSTALL) {
66         return WidgetUpdateMode::PolicyDirectoryForceInstall;
67     }
68
69     WidgetUpdateMode::Type result = WidgetUpdateMode::Zero;
70     if (updateMode & WRT_WIM_NOT_INSTALLED) {
71         result = result | WidgetUpdateMode::NotInstalled;
72     }
73
74     if (updateMode & WRT_WIM_INCOMING_VERSION_NOT_STD) {
75         result = result | WidgetUpdateMode::IncomingVersionNotStd;
76     }
77
78     if (updateMode & WRT_WIM_EXISTING_VERSION_NOT_STD) {
79         result = result | WidgetUpdateMode::ExistingVersionNotStd;
80     }
81
82     if (updateMode & WRT_WIM_BOTH_VERSIONS_NOT_STD) {
83         result = result | WidgetUpdateMode::BothVersionsNotStd;
84     }
85
86     if (updateMode & WRT_WIM_EXISTING_VERSION_OLDER) {
87         result = result | WidgetUpdateMode::ExistingVersionOlder;
88     }
89
90     if (updateMode & WRT_WIM_EXISTING_VERSION_EQUAL) {
91         result = result | WidgetUpdateMode::ExistingVersionEqual;
92     }
93
94     if (updateMode & WRT_WIM_EXISTING_VERSION_NEWER) {
95         result = result | WidgetUpdateMode::ExistingVersionNewer;
96     }
97
98     return result;
99 }
100
101 const char PLUGIN_INSTALL_SEMAPHORE[] = "/.wrt_plugin_install_lock";
102 static int wrt_count_plugin;
103
104 static std::string cutOffFileName(const std::string& path)
105 {
106     size_t found = path.find_last_of("/");
107     if (found == std::string::npos) {
108         return path;
109     } else {
110         return path.substr(0, found);
111     }
112 }
113
114 static bool checkPath(const std::string& path)
115 {
116     struct stat st;
117     if (0 == stat(path.c_str(), &st) && S_ISDIR(st.st_mode)) {
118         return true;
119     }
120     LogError("Cannot access directory [ " << path << " ]");
121     return false;
122 }
123
124 static bool checkPaths()
125 {
126     bool if_ok = true;
127     if_ok &= (checkPath(cutOffFileName(
128                             GlobalConfig::GetWrtDatabaseFilePath())));
129     if (!if_ok) {
130         LogError(
131             "Path <" << GlobalConfig::GetWrtDatabaseFilePath() <<
132             "> does not exist.");
133     }
134
135     if_ok &= (checkPath(GlobalConfig::GetDevicePluginPath()));
136     if (!if_ok) {
137         LogError(
138             "Path <" << GlobalConfig::GetDevicePluginPath() <<
139             "> does not exist.");
140     }
141
142     if_ok &= (checkPath(GlobalConfig::GetUserInstalledWidgetPath()));
143     if (!if_ok) {
144         LogError(
145             "Path <" << GlobalConfig::GetUserInstalledWidgetPath() <<
146             "> does not exist.");
147     }
148
149     if_ok &= (checkPath(GlobalConfig::GetUserPreloadedWidgetPath()));
150     if (!if_ok) {
151         LogError(
152             "Path <" << GlobalConfig::GetUserPreloadedWidgetPath() <<
153             "> does not exist.");
154     }
155     return if_ok;
156 }
157
158 void plugin_install_status_cb(WrtErrStatus status,
159                               void* userparam)
160 {
161     Assert(userparam);
162
163     wrt_plugin_data *plugin_data = static_cast<wrt_plugin_data*>(userparam);
164
165     if (--wrt_count_plugin < 1) {
166         LogDebug("All plugins installation completed");
167
168         LogDebug("Call SetAllinstallpluginsCallback");
169         plugin_data->plugin_installed_cb(plugin_data->user_data);
170     }
171
172     if (status == WRT_SUCCESS) {
173         LogInfo(
174             "plugin installation is successful: " <<
175             plugin_data->plugin_path);
176         return;
177     }
178
179     LogError("Fail to install plugin : " << plugin_data->plugin_path);
180
181     switch (status) {
182     case WRT_PLUGIN_INSTALLER_ERROR_WRONG_PATH:
183         LogError("Failed : Plugin install path is wrong");
184         break;
185     case WRT_PLUGIN_INSTALLER_ERROR_METAFILE:
186         LogError("Failed : Plugin Metafile Error");
187         break;
188     case WRT_PLUGIN_INSTALLER_ERROR_ALREADY_INSTALLED:
189         LogError("Failed : This Plugin is already installed");
190         break;
191     case WRT_PLUGIN_INSTALLER_ERROR_LIBRARY_ERROR:
192         LogError("Failed : Library Error. Missing symbol or structures");
193         break;
194     case WRT_PLUGIN_INSTALLER_ERROR_WAITING:
195         LogError("Failed : Waiting for plugin dependencies");
196         break;
197     case WRT_PLUGIN_INSTALLER_ERROR_LOCK:
198         LogError("Failed : Lock Error");
199         break;
200     case WRT_PLUGIN_INSTALLER_ERROR_UNKNOWN:
201         LogError("Failed : Unkown Error");
202         break;
203     default:
204         break;
205     }
206 }
207
208 void plugin_install_progress_cb(float percent,
209                                 const char* description,
210                                 void* userdata)
211 {
212     char *plugin_path = static_cast<char*>(userdata);
213
214     LogInfo("Install plugin : " << plugin_path <<
215             ", Progress : " << percent <<
216             ", Description : " << description);
217 }
218
219 EXPORT_API int wrt_installer_init(void *userdata,
220                                   WrtInstallerInitCallback callback)
221 {
222     // Set DPL/LOG MID
223     DPL::Log::LogSystemSingleton::Instance().SetTag("WRT");
224
225     try {
226         LogInfo("[WRT-API] INITIALIZING WRT INSTALLER...");
227         LogInfo("[WRT-API] BUILD: " << __TIMESTAMP__);
228
229         // Touch InstallerController Singleton
230         InstallerMainThreadSingleton::Instance().TouchArchitecture();
231
232         // Check paths
233         if (!checkPaths()) {
234             if (callback) {
235                 callback(WRT_ERROR_NO_PATH, userdata);
236             }
237             return TRUE;
238         }
239
240         // Initialize ValidationCore - this must be done before AttachDatabases
241         ValidationCore::VCoreInit(
242             std::string(GlobalConfig::GetFingerprintListFile()),
243             std::string(GlobalConfig::GetFingerprintListSchema()),
244             std::string(GlobalConfig::GetVCoreDatabaseFilePath()));
245
246         InstallerMainThreadSingleton::Instance().AttachDatabases();
247
248         //checking for correct DB version
249         //            if (!WrtDB::WrtDatabase::CheckTableExist(DB_CHECKSUM_STR))
250         // {
251         //                LogError("WRONG VERSION OF WRT DATABASE");
252         //                Assert(false && "WRONG VERSION OF WRT DATABASE");
253         //                return FALSE;
254         //            }
255         LogWarning("Database check not implemented!");
256
257         LogInfo("Prepare libxml2 to work in multithreaded program.");
258         xmlInitParser();
259
260         // Initialize Language Subtag registry
261         LanguageSubtagRstTreeSingleton::Instance().Initialize();
262
263         // Installer init
264         CONTROLLER_POST_SYNC_EVENT(
265             Logic::InstallerController,
266             InstallerControllerEvents::
267                 InitializeEvent());
268
269         // Install deferred widget packages
270         CONTROLLER_POST_EVENT(
271             Logic::InstallerController,
272             InstallerControllerEvents::
273                 InstallDeferredWidgetPackagesEvent());
274
275         if (callback) {
276             LogInfo("[WRT-API] WRT INSTALLER INITIALIZATION CALLBACK");
277             callback(WRT_SUCCESS, userdata);
278         }
279     } catch (const DPL::Exception& ex) {
280         LogError("Internal Error during Init:");
281         DPL::Exception::DisplayKnownException(ex);
282         if (callback) {
283             callback(WRT_ERROR_INTERNAL, userdata);
284         }
285         return FALSE;
286     }
287     // OK
288     return TRUE;
289 }
290
291 EXPORT_API void wrt_installer_shutdown()
292 {
293     try {
294         LogInfo("[WRT-API] DEINITIALIZING WRT INSTALLER...");
295
296         // Installer termination
297         CONTROLLER_POST_SYNC_EVENT(
298             Logic::InstallerController,
299             InstallerControllerEvents::
300                 TerminateEvent());
301
302         InstallerMainThreadSingleton::Instance().DetachDatabases();
303
304         // This must be done after DetachDatabase
305         ValidationCore::VCoreDeinit();
306
307         // Global deinit check
308         LogInfo("Cleanup libxml2 global values.");
309         xmlCleanupParser();
310     } catch (const DPL::Exception& ex) {
311         LogError("Internal Error during Shutdown:");
312         DPL::Exception::DisplayKnownException(ex);
313     }
314 }
315
316 EXPORT_API void wrt_install_widget(
317     const char *path,
318     void* userdata,
319     WrtInstallerStatusCallback status_cb,
320     WrtProgressCallback progress_cb,
321     wrt_widget_update_mode_t update_mode,
322     bool quiet,
323     bool preload,
324     std::shared_ptr<PackageManager::
325                         IPkgmgrSignal> pkgmgrInterface
326     )
327 {
328     UNHANDLED_EXCEPTION_HANDLER_BEGIN
329     {
330         LogInfo("[WRT-API] INSTALL WIDGET: " << path);
331         // Post installation event
332         CONTROLLER_POST_EVENT(
333             Logic::InstallerController,
334             InstallerControllerEvents::InstallWidgetEvent(
335                 path, WidgetInstallationStruct(
336                     InstallerCallbacksTranslate::installFinishedCallback,
337                     InstallerCallbacksTranslate::installProgressCallback,
338                     new InstallerCallbacksTranslate::StatusCallbackStruct(
339                         userdata, status_cb, progress_cb),
340                     translateWidgetUpdateMode(update_mode),
341                     quiet,
342                     preload,
343                     pkgmgrInterface)));
344     }
345     UNHANDLED_EXCEPTION_HANDLER_END
346 }
347
348 EXPORT_API void wrt_uninstall_widget(
349     const char * const tzAppid,
350     void* userdata,
351     WrtInstallerStatusCallback status_cb,
352     WrtProgressCallback progress_cb,
353     std::shared_ptr<PackageManager::
354                         IPkgmgrSignal> pkgmgrSignalInterface)
355 {
356     UNHANDLED_EXCEPTION_HANDLER_BEGIN
357     {
358         std::string tizenAppid(tzAppid);
359         LogInfo("[WRT-API] UNINSTALL WIDGET: " << tizenAppid);
360         // Post uninstallation event
361         CONTROLLER_POST_EVENT(
362             Logic::InstallerController,
363             InstallerControllerEvents::UninstallWidgetEvent(
364                 tizenAppid,
365                 WidgetUninstallationStruct(
366                     InstallerCallbacksTranslate::uninstallFinishedCallback,
367                     InstallerCallbacksTranslate::installProgressCallback,
368                     new InstallerCallbacksTranslate::StatusCallbackStruct(
369                         userdata, status_cb, progress_cb),
370                     pkgmgrSignalInterface
371                     )
372                 )
373             );
374     }
375     UNHANDLED_EXCEPTION_HANDLER_END
376 }
377
378 EXPORT_API void wrt_install_plugin(
379     const char *pluginDir,
380     void *user_param,
381     WrtPluginInstallerStatusCallback status_cb,
382     WrtProgressCallback progress_cb)
383 {
384     UNHANDLED_EXCEPTION_HANDLER_BEGIN
385     {
386         LogInfo("[WRT-API] INSTALL PLUGIN: " << pluginDir);
387         //Private data for status callback
388         //Resource is free in pluginInstallFinishedCallback
389         InstallerCallbacksTranslate::PluginStatusCallbackStruct*
390         callbackStruct =
391             new InstallerCallbacksTranslate::PluginStatusCallbackStruct(
392                 user_param, status_cb, progress_cb);
393
394         CONTROLLER_POST_EVENT(
395             Logic::InstallerController,
396             InstallerControllerEvents::InstallPluginEvent(
397                 std::string(pluginDir),
398                 PluginInstallerStruct(
399                     InstallerCallbacksTranslate::
400                         pluginInstallFinishedCallback,
401                     InstallerCallbacksTranslate::
402                         installProgressCallback, callbackStruct)));
403     }
404     UNHANDLED_EXCEPTION_HANDLER_END
405 }
406
407 EXPORT_API void wrt_install_all_plugins(
408     WrtAllPluginInstalledCallback installed_cb,
409     void *user_param)
410 {
411     UNHANDLED_EXCEPTION_HANDLER_BEGIN
412     {
413         std::string installRequest =
414             std::string(GlobalConfig::GetPluginInstallInitializerName());
415
416         LogDebug("Install new plugins");
417
418         Try {
419             DPL::Semaphore lock(PLUGIN_INSTALL_SEMAPHORE);
420         }
421         Catch(DPL::Semaphore::Exception::Base){
422             LogError("Failed to create installation lock");
423             return;
424         }
425
426         struct stat tmp;
427
428         if (-1 == stat(installRequest.c_str(), &tmp) ||
429             !S_ISREG(tmp.st_mode))
430         {
431             if (ENOENT == errno) {
432                 LogDebug("Plugin installation not required");
433
434                 LogDebug("Call SetAllinstallPluginCallback");
435                 installed_cb(user_param);
436
437                 DPL::Semaphore::Remove(PLUGIN_INSTALL_SEMAPHORE);
438                 return;
439             }
440             LogWarning("Opening installation request file failed");
441         }
442
443         std::string PLUGIN_PATH =
444             std::string(GlobalConfig::GetDevicePluginPath());
445
446         DIR *dir;
447         dir = opendir(PLUGIN_PATH.c_str());
448         if (!dir) {
449             DPL::Semaphore::Remove(PLUGIN_INSTALL_SEMAPHORE);
450             return;
451         }
452
453         LogInfo("Plugin DIRECTORY IS" << PLUGIN_PATH);
454         struct dirent libdir;
455         struct dirent *result;
456         int return_code;
457
458         errno = 0;
459
460         std::list<std::string> pluginsPaths;
461
462         for (return_code = readdir_r(dir, &libdir, &result);
463                     result != NULL && return_code == 0;
464                     return_code = readdir_r(dir, &libdir, &result))
465         {
466             if (strcmp(libdir.d_name, ".") == 0 ||
467                 strcmp(libdir.d_name, "..") == 0)
468             {
469                 continue;
470             }
471
472             std::string path = PLUGIN_PATH;
473             path += "/";
474             path += libdir.d_name;
475
476             struct stat tmp;
477
478             if (stat(path.c_str(), &tmp) == -1) {
479                 LogError("Failed to open file" << path);
480                 continue;
481             }
482
483             if (!S_ISDIR(tmp.st_mode)) {
484                 LogError("Not a directory" << path);
485                 continue;
486             }
487
488             pluginsPaths.push_back(path);
489         }
490
491         wrt_count_plugin = pluginsPaths.size();
492
493         FOREACH(it, pluginsPaths) {
494             wrt_plugin_data *plugin_data = new wrt_plugin_data;
495
496             plugin_data->plugin_installed_cb = installed_cb;
497             plugin_data->plugin_path = const_cast<char*>(it->c_str());
498             plugin_data->user_data = user_param;
499
500             wrt_install_plugin(
501                 it->c_str(), static_cast<void*>(plugin_data),
502                 plugin_install_status_cb,
503                 plugin_install_progress_cb);
504         }
505
506         if (return_code != 0 || errno != 0) {
507             LogError("readdir_r() failed with " << DPL::GetErrnoString());
508         }
509
510         errno = 0;
511         if (-1 == TEMP_FAILURE_RETRY(closedir(dir))) {
512             LogError("Failed to close dir: " << PLUGIN_PATH << " with error: "
513                                              << DPL::GetErrnoString());
514         }
515
516         if (0 != unlink(installRequest.c_str())) {
517             LogError("Failed to remove file initializing plugin "
518                      "installation");
519         }
520
521         Try {
522             DPL::Semaphore::Remove(PLUGIN_INSTALL_SEMAPHORE);
523         }
524         Catch(DPL::Semaphore::Exception::Base){
525             LogInfo("Failed to remove installation lock");
526         }
527     }
528     UNHANDLED_EXCEPTION_HANDLER_END
529 }
530
531 EXPORT_API int wrt_installer_init_for_tests(void *userdata,
532                                             WrtInstallerInitCallback callback)
533 {
534     // Set DPL/LOG MID
535     DPL::Log::LogSystemSingleton::Instance().SetTag("WRT");
536
537     try {
538         LogInfo("[WRT-API] INITIALIZING WRT INSTALLER...");
539         LogInfo("[WRT-API] BUILD: " << __TIMESTAMP__);
540
541         // Touch InstallerController Singleton
542         InstallerMainThreadSingleton::Instance().
543             TouchArchitectureOnlyInstaller();
544
545         // Check paths
546         if (!checkPaths()) {
547             if (callback) {
548                 callback(WRT_ERROR_NO_PATH, userdata);
549             }
550             return TRUE;
551         }
552
553         CONTROLLER_POST_SYNC_EVENT(
554             Logic::InstallerController,
555             InstallerControllerEvents::
556                 InitializeEvent());
557
558         if (callback) {
559             LogInfo("[WRT-API] WRT INSTALLER INITIALIZATION CALLBACK");
560             callback(WRT_SUCCESS, userdata);
561         }
562     } catch (const DPL::Exception& ex) {
563         LogError("Internal Error during Init:");
564         DPL::Exception::DisplayKnownException(ex);
565         if (callback) {
566             callback(WRT_ERROR_INTERNAL, userdata);
567         }
568         return FALSE;
569     }
570
571     // OK
572     return TRUE;
573 }
574
575 EXPORT_API void wrt_installer_shutdown_for_tests()
576 {
577     try {
578         LogInfo("[WRT-API] DEINITIALIZING WRT INSTALLER...");
579
580         // Installer termination
581         CONTROLLER_POST_SYNC_EVENT(
582             Logic::InstallerController,
583             InstallerControllerEvents::
584                 TerminateEvent());
585
586         // Global deinit check
587         LogInfo("Cleanup libxml2 global values.");
588         xmlCleanupParser();
589     } catch (const DPL::Exception& ex) {
590         LogError("Internal Error during Shutdown:");
591         DPL::Exception::DisplayKnownException(ex);
592     }
593 }
594
595 EXPORT_API WrtErrStatus wrt_get_widget_by_guid(std::string & tzAppid,
596                                                const std::string & guid)
597 {
598     try {
599         LogInfo("[WRT-API] GETTING WIDGET PACKAGE NAME BY WidgetID : "
600                 << guid);
601
602         WidgetGUID widget_guid = DPL::FromUTF8String(guid);
603         WrtDB::WidgetDAOReadOnly dao(widget_guid);
604         tzAppid = DPL::ToUTF8String(dao.getTzAppId());
605         return WRT_SUCCESS;
606     } catch (WidgetDAOReadOnly::Exception::WidgetNotExist&) {
607         LogError("Error package name is not found");
608         return WRT_ERROR_PKGNAME_NOT_FOUND;
609     } catch (const DPL::Exception& ex) {
610         LogError("Internal Error during get widget id by package name");
611         DPL::Exception::DisplayKnownException(ex);
612         return WRT_ERROR_INTERNAL;
613     }
614 }
615 #ifdef __cplusplus
616 }
617 #endif