[Release] wrt-installer_0.1.54
[framework/web/wrt-installer.git] / src / jobs / widget_install / job_widget_install.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    job_widget_install.cpp
18  * @author  Radoslaw Wicik r.wicik@samsung.com
19  * @author  Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
20  * @version 1.0
21  * @brief   Implementation file for main installer task
22  */
23 #include <memory>
24 #include <string>
25 #include <sys/time.h>
26 #include <ctime>
27 #include <cstdlib>
28 #include <limits.h>
29 #include <regex.h>
30
31 #include <dpl/noncopyable.h>
32 #include <dpl/abstract_waitable_input_adapter.h>
33 #include <dpl/abstract_waitable_output_adapter.h>
34 #include <dpl/zip_input.h>
35 #include <dpl/binary_queue.h>
36 #include <dpl/copy.h>
37 #include <dpl/assert.h>
38 #include <dpl/sstream.h>
39 #include <dpl/file_input.h>
40 #include <dpl/utils/wrt_utility.h>
41 #include <dpl/wrt-dao-ro/common_dao_types.h>
42 #include <dpl/wrt-dao-ro/widget_dao_read_only.h>
43 #include <dpl/wrt-dao-ro/global_config.h>
44 #include <dpl/wrt-dao-ro/config_parser_data.h>
45 #include <dpl/wrt-dao-rw/global_dao.h> // TODO remove
46 #include <dpl/localization/w3c_file_localization.h>
47
48 #include <libiriwrapper.h>
49 #include <pkg-manager/pkgmgr_signal.h>
50 #include <app_manager.h>
51
52 #include "root_parser.h"
53 #include "widget_parser.h"
54 #include "parser_runner.h"
55 #include <widget_install/job_widget_install.h>
56 #include <widget_install/task_certify.h>
57 #include <widget_install/task_widget_config.h>
58 #include <widget_install/task_file_manipulation.h>
59 #include <widget_install/task_ace_check.h>
60 #include <widget_install/task_smack.h>
61 #include <widget_install/task_manifest_file.h>
62 #include <widget_install/task_prepare_files.h>
63 #include <widget_install/task_recovery.h>
64 #include <widget_install/task_install_ospsvc.h>
65 #include <widget_install/task_update_files.h>
66 #include <widget_install/task_database.h>
67 #include <widget_install/task_remove_backup.h>
68 #include <widget_install/task_encrypt_resource.h>
69 #include <widget_install/task_certificates.h>
70 #include <widget_install/task_unzip.h>
71 #include <widget_install/task_commons.h>
72 #include <widget_install/task_prepare_reinstall.h>
73
74 #include <widget_install/widget_install_errors.h>
75 #include <widget_install/widget_install_context.h>
76 #include <widget_install_to_external.h>
77
78 using namespace WrtDB;
79 using namespace Jobs::Exceptions;
80
81 namespace // anonymous
82 {
83 const char * const CONFIG_XML = "config.xml";
84 const char * const WITH_OSP_XML = "res/wgt/config.xml";
85
86 //allowed: a-z, A-Z, 0-9
87 const char* REG_TIZENID_PATTERN = "^[a-zA-Z0-9]{10}.{1,}$";
88 const char* REG_NAME_PATTERN = "^[a-zA-Z0-9._-]{1,}$";
89 const size_t PACKAGE_ID_LENGTH = 10;
90
91 static const DPL::String SETTING_VALUE_ENCRYPTION = L"encryption";
92 static const DPL::String SETTING_VALUE_ENCRYPTION_ENABLE = L"enable";
93 static const DPL::String SETTING_VALUE_ENCRYPTION_DISABLE = L"disable";
94 const DPL::String SETTING_VALUE_INSTALLTOEXT_NAME =
95     L"install-location";
96 const DPL::String SETTING_VALUE_INSTALLTOEXT_PREPER_EXT =
97     L"prefer-external";
98
99 const std::string XML_EXTENSION = ".xml";
100
101 bool hasExtension(const std::string& filename, const std::string& extension)
102 {
103     LogDebug("Looking for extension " << extension << " in: " << filename);
104     size_t fileLen = filename.length();
105     size_t extLen = extension.length();
106     if (fileLen < extLen) {
107         LogError("Filename " << filename << " is shorter than extension "
108                              << extension);
109         return false;
110     }
111     return (0 == filename.compare(fileLen - extLen, extLen, extension));
112 }
113 } // namespace anonymous
114
115 namespace Jobs {
116 namespace WidgetInstall {
117 class InstallerTaskFail :
118     public DPL::TaskDecl<InstallerTaskFail>
119 {
120   private:
121     ConfigureResult m_result;
122
123     void StepFail()
124     {
125         if (m_result == ConfigureResult::Deferred) {
126             ThrowMsg(Jobs::WidgetInstall::Exceptions::Deferred,
127                     "widget installation or update deferred!");
128         } else if (m_result == ConfigureResult::Failed_InvalidConfig) {
129             ThrowMsg(Jobs::WidgetInstall::Exceptions::WidgetConfigFileInvalid,
130                     "invalid config");
131         } else if (m_result == ConfigureResult::Failed_LowerVersion) {
132             ThrowMsg(Jobs::WidgetInstall::Exceptions::PackageLowerVersion,
133                     "package version is lower than installed version");
134         } else if (m_result == ConfigureResult::Failed_AlreadyInstalled) {
135             ThrowMsg(Jobs::WidgetInstall::Exceptions::PackageAlreadyInstalled,
136                     "package is already installed");
137         } else if (m_result == ConfigureResult::Failed_WidgetRunning) {
138             ThrowMsg(Jobs::WidgetInstall::Exceptions::WidgetRunningError,
139                     "widget is running");
140         } else if (m_result == ConfigureResult::Failed_DrmError) {
141             ThrowMsg(Jobs::WidgetInstall::Exceptions::DRMFailed,
142                     "drm failed");
143         } else if (m_result == ConfigureResult::Failed_NotSupportRDSUpdate) {
144             ThrowMsg(Jobs::WidgetInstall::Exceptions::NotSupportRDSUpdate,
145                     "RDS update failed");
146         } else {
147             ThrowMsg(Jobs::WidgetInstall::Exceptions::NotAllowed,
148                     "widget installation or update not allowed!");
149         }
150     }
151
152   public:
153     InstallerTaskFail(ConfigureResult result) :
154         DPL::TaskDecl<InstallerTaskFail>(this),
155         m_result(result)
156     {
157         AddStep(&InstallerTaskFail::StepFail);
158     }
159 };
160
161 JobWidgetInstall::JobWidgetInstall(
162     std::string const &widgetPath,
163     const WidgetInstallationStruct &
164     installerStruct) :
165     Job(Installation),
166     JobContextBase<WidgetInstallationStruct>(installerStruct),
167     m_exceptionCaught(Jobs::Exceptions::Success)
168 {
169     m_installerContext.mode = m_jobStruct.m_installMode;
170     ConfigureResult result = PrePareInstallation(widgetPath);
171
172     if (result == ConfigureResult::Ok) {
173         LogInfo("Configure installation succeeded");
174         m_installerContext.job->SetProgressFlag(true);
175
176         AddTask(new TaskRecovery(m_installerContext));
177
178         // Create installation tasks
179         if (m_installerContext.widgetConfig.packagingType !=
180             WrtDB::PKG_TYPE_DIRECTORY_WEB_APP &&
181             m_installerContext.widgetConfig.packagingType !=
182             WrtDB::PKG_TYPE_HOSTED_WEB_APP &&
183             !m_isDRM)
184         {
185             AddTask(new TaskUnzip(m_installerContext));
186         }
187
188         AddTask(new TaskWidgetConfig(m_installerContext));
189         if (m_installerContext.widgetConfig.packagingType ==
190             WrtDB::PKG_TYPE_HOSTED_WEB_APP)
191         {
192             AddTask(new TaskPrepareFiles(m_installerContext));
193         }
194         AddTask(new TaskCertify(m_installerContext));
195         if (m_needEncryption) {
196             AddTask(new TaskEncryptResource(m_installerContext));
197         }
198
199         AddTask(new TaskFileManipulation(m_installerContext));
200
201         AddTask(new TaskManifestFile(m_installerContext));
202         if (m_installerContext.widgetConfig.packagingType ==
203             PKG_TYPE_HYBRID_WEB_APP)
204         {
205             AddTask(new TaskInstallOspsvc(m_installerContext));
206         }
207         AddTask(new TaskCertificates(m_installerContext));
208         AddTask(new TaskDatabase(m_installerContext));
209         AddTask(new TaskAceCheck(m_installerContext));
210         AddTask(new TaskSmack(m_installerContext));
211     } else if (result == ConfigureResult::Updated) {
212         LogInfo("Configure installation updated");
213         LogInfo("Widget Update");
214         m_installerContext.job->SetProgressFlag(true);
215
216         if (m_installerContext.mode.command ==
217             InstallMode::Command::REINSTALL)
218         {
219             AddTask(new TaskPrepareReinstall(m_installerContext));
220         }
221
222         if (m_installerContext.widgetConfig.packagingType !=
223             WrtDB::PKG_TYPE_HOSTED_WEB_APP &&
224             m_installerContext.widgetConfig.packagingType !=
225             WrtDB::PKG_TYPE_DIRECTORY_WEB_APP &&
226             !m_isDRM)
227         {
228             AddTask(new TaskUnzip(m_installerContext));
229         }
230
231         AddTask(new TaskWidgetConfig(m_installerContext));
232
233         if (m_installerContext.widgetConfig.packagingType ==
234             WrtDB::PKG_TYPE_HOSTED_WEB_APP)
235         {
236             AddTask(new TaskPrepareFiles(m_installerContext));
237         }
238
239         AddTask(new TaskCertify(m_installerContext));
240         if (m_needEncryption) {
241             AddTask(new TaskEncryptResource(m_installerContext));
242         }
243
244         if (m_installerContext.widgetConfig.packagingType !=
245             WrtDB::PKG_TYPE_DIRECTORY_WEB_APP)
246         {
247             AddTask(new TaskUpdateFiles(m_installerContext));
248             AddTask(new TaskFileManipulation(m_installerContext));
249         }
250
251         AddTask(new TaskManifestFile(m_installerContext));
252         if (m_installerContext.widgetConfig.packagingType ==
253             PKG_TYPE_HYBRID_WEB_APP)
254         {
255             AddTask(new TaskInstallOspsvc(m_installerContext));
256         }
257         AddTask(new TaskCertificates(m_installerContext));
258         AddTask(new TaskDatabase(m_installerContext));
259         AddTask(new TaskAceCheck(m_installerContext));
260         //TODO: remove widgetHandle from this task and move before database task
261         // by now widget handle is needed in ace check
262         // Any error in acecheck while update will break widget
263         AddTask(new TaskSmack(m_installerContext));
264         AddTask(new TaskRemoveBackupFiles(m_installerContext));
265     } else if (result == ConfigureResult::Deferred) {
266         // Installation is deferred
267         LogInfo("Configure installation deferred");
268
269         AddTask(new InstallerTaskFail(result));
270     } else if (result >= ConfigureResult::Failed &&
271             result <= ConfigureResult::Failed_DrmError) {
272         // Installation is not allowed to proceed due to widget update policy
273         LogWarning("Configure installation failed!");
274
275         AddTask(new InstallerTaskFail(result));
276     } else {
277         Assert(false && "Invalid configure result!");
278     }
279 }
280
281 ConfigureResult JobWidgetInstall::PrePareInstallation(
282     const std::string &widgetPath)
283 {
284     ConfigureResult result;
285     m_needEncryption = false;
286
287     Try
288     {
289         std::string tempDir;
290         if (m_installerContext.mode.extension == InstallMode::ExtensionType::DIR) {
291             std::ostringstream tempPathBuilder;
292             tempPathBuilder << WrtDB::GlobalConfig::GetUserInstalledWidgetPath();
293             tempPathBuilder << WrtDB::GlobalConfig::GetTmpDirPath();
294             tempPathBuilder << "/";
295             tempPathBuilder << widgetPath;
296             tempDir = tempPathBuilder.str();;
297         } else {
298             tempDir =
299                 Jobs::WidgetInstall::createTempPath(
300                         m_installerContext.mode.rootPath ==
301                             InstallMode::RootPath::RO);
302         }
303
304         m_isDRM = isDRMWidget(widgetPath);
305         if (true == m_isDRM) {
306             LogDebug("decrypt DRM widget");
307             if (DecryptDRMWidget(widgetPath, tempDir)) {
308                 LogDebug("Failed decrypt DRM widget");
309                 return ConfigureResult::Failed_DrmError;
310             }
311         }
312
313         LogDebug("widgetPath:" << widgetPath);
314
315         m_installerContext.widgetConfig.packagingType =
316             checkPackageType(widgetPath, tempDir);
317         ConfigParserData configData = getWidgetDataFromXML(
318                 widgetPath,
319                 tempDir,
320                 m_installerContext.widgetConfig.packagingType,
321                 m_isDRM,
322                 m_installerContext.mode.command == InstallMode::Command::REINSTALL);
323         LogDebug("widget packaging type : " <<
324                  m_installerContext.widgetConfig.packagingType.pkgType);
325
326         setTizenId(configData);
327         setApplicationType(configData);
328         m_needEncryption = detectResourceEncryption(configData);
329         setInstallLocationType(configData);
330
331         // Configure installation
332         result = ConfigureInstallation(widgetPath, configData, tempDir);
333     }
334     Catch(Exceptions::ExtractFileFailed)
335     {
336         LogError("Failed to create temporary path for widget");
337         result = ConfigureResult::Failed_InvalidConfig;
338     }
339
340     return result;
341 }
342
343 void JobWidgetInstall::setTizenId(
344     const WrtDB::ConfigParserData &configInfo)
345 {
346     bool shouldMakeAppid = false;
347     using namespace PackageManager;
348     if (!!configInfo.tizenAppId) {
349         LogDebug("Setting tizenAppId provided in config.xml: " <<
350                  configInfo.tizenAppId);
351
352         m_installerContext.widgetConfig.tzAppid = *configInfo.tizenAppId;
353         //check package id.
354         if (!!configInfo.tizenPkgId) {
355             LogDebug("Setting tizenPkgId provided in config.xml: " <<
356                      configInfo.tizenPkgId);
357
358             m_installerContext.widgetConfig.tzPkgid = *configInfo.tizenPkgId;
359         } else {
360             DPL::String appid = *configInfo.tizenAppId;
361             if (appid.length() > PACKAGE_ID_LENGTH) {
362                 m_installerContext.widgetConfig.tzPkgid =
363                     appid.substr(0, PACKAGE_ID_LENGTH);
364             } else {
365                 //old version appid only has 10byte random character is able to install for a while.
366                 //this case appid equal pkgid.
367                 m_installerContext.widgetConfig.tzPkgid =
368                     *configInfo.tizenAppId;
369                 shouldMakeAppid = true;
370             }
371         }
372     } else {
373         shouldMakeAppid = true;
374         TizenPkgId pkgId = WidgetDAOReadOnly::generatePkgId();
375         LogDebug("Checking if pkg id is unique");
376         while (true) {
377             if (!validateTizenPackageID(pkgId)) {
378                 //path exist, chose another one
379                 pkgId = WidgetDAOReadOnly::generatePkgId();
380                 continue;
381             }
382             break;
383         }
384         m_installerContext.widgetConfig.tzPkgid = pkgId;
385         LogInfo("tizen_id name was generated by WRT: " <<
386                 m_installerContext.widgetConfig.tzPkgid);
387     }
388
389     if (shouldMakeAppid == true) {
390         DPL::OptionalString name;
391         DPL::OptionalString defaultLocale = configInfo.defaultlocale;
392
393         FOREACH(localizedData, configInfo.localizedDataSet)
394         {
395             Locale i = localizedData->first;
396             if (!!defaultLocale) {
397                 if (defaultLocale == i) {
398                     name = localizedData->second.name;
399                     break;
400                 }
401             } else {
402                 name = localizedData->second.name;
403                 break;
404             }
405         }
406         regex_t regx;
407         if (regcomp(&regx, REG_NAME_PATTERN, REG_NOSUB | REG_EXTENDED) != 0) {
408             LogDebug("Regcomp failed");
409         }
410
411         LogDebug("Name : " << name);
412         if (!name || (regexec(&regx, DPL::ToUTF8String(*name).c_str(),
413                               static_cast<size_t>(0), NULL, 0) != REG_NOERROR))
414         {
415             // TODO : generate name move to wrt-commons
416             std::string allowedString("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
417             std::ostringstream genName;
418             struct timeval tv;
419             gettimeofday(&tv, NULL);
420             unsigned int seed = time(NULL) + tv.tv_usec;
421
422             genName << "_" << allowedString[rand_r(&seed) % allowedString.length()];
423             name = DPL::FromUTF8String(genName.str());
424             LogDebug("name was generated by WRT");
425         }
426         regfree(&regx);
427         LogDebug("Name : " << name);
428         std::ostringstream genid;
429         genid << m_installerContext.widgetConfig.tzPkgid << "." << name;
430         LogDebug("tizen appid was generated by WRT : " << genid.str());
431
432         DPL::OptionalString appid = DPL::FromUTF8String(genid.str());
433         NormalizeAndTrimSpaceString(appid);
434         m_installerContext.widgetConfig.tzAppid = *appid;
435     }
436
437     // send start signal of pkgmgr
438     getInstallerStruct().pkgmgrInterface->setPkgname(DPL::ToUTF8String(
439                                                          m_installerContext.
440                                                              widgetConfig.
441                                                              tzPkgid));
442     LogInfo("Tizen App Id : " << m_installerContext.widgetConfig.tzAppid);
443     LogInfo("Tizen Pkg Id : " << m_installerContext.widgetConfig.tzPkgid);
444     LogInfo("W3C Widget GUID : " << m_installerContext.widgetConfig.guid);
445 }
446
447 void JobWidgetInstall::configureWidgetLocation(const std::string & widgetPath,
448                                                const std::string& tempPath)
449 {
450     m_installerContext.locations =
451         WidgetLocation(DPL::ToUTF8String(m_installerContext.widgetConfig.
452                                              tzPkgid),
453                        widgetPath, tempPath,
454                        m_installerContext.widgetConfig.packagingType,
455                        m_installerContext.mode.rootPath ==
456                            InstallMode::RootPath::RO);
457     m_installerContext.locations->registerAppid(
458         DPL::ToUTF8String(m_installerContext.widgetConfig.tzAppid));
459
460     LogInfo("widgetSource " << widgetPath);
461 }
462
463 ConfigureResult JobWidgetInstall::ConfigureInstallation(
464     const std::string &widgetSource,
465     const WrtDB::ConfigParserData &configData,
466     const std::string &tempPath)
467 {
468     ConfigureResult result = ConfigureResult::Failed;
469     WidgetUpdateInfo update;
470
471     // checking installed web application
472     Try {
473         // checking existing application is installed
474         WidgetDAOReadOnly dao(m_installerContext.widgetConfig.tzAppid);
475         // no excpetion means, it isn't update mode
476         getInstallerStruct().pkgmgrInterface->sendSignal(
477                 PKGMGR_START_KEY,
478                 PKGMGR_START_UPDATE);
479
480         update = detectWidgetUpdate(configData,
481                                     m_installerContext.widgetConfig.tzAppid);
482         result = checkWidgetUpdate(update);
483         if (result != ConfigureResult::Updated) {
484             // Already installed TizenAppId. return failed
485             return ConfigureResult::Failed_AlreadyInstalled;
486         }
487         if (!checkSupportRDSUpdate(configData)) {
488             return ConfigureResult::Failed_NotSupportRDSUpdate;
489         }
490         m_installerContext.isUpdateMode = true;
491     }
492     Catch(WidgetDAOReadOnly::Exception::WidgetNotExist) {
493         result = ConfigureResult::Ok;
494         getInstallerStruct().pkgmgrInterface->sendSignal(
495                 PKGMGR_START_KEY,
496                 PKGMGR_START_INSTALL);
497         m_installerContext.isUpdateMode = false;
498
499         if (!validateTizenApplicationID(
500             m_installerContext.widgetConfig.tzAppid))
501         {
502             LogError("tizen application ID is already used");
503             return ConfigureResult::Failed_InvalidConfig;
504         }
505         if (!validateTizenPackageID(m_installerContext.widgetConfig.tzPkgid)) {
506             LogError("tizen package ID is already used");
507             return ConfigureResult::Failed_AlreadyInstalled;
508         }
509     }
510
511     configureWidgetLocation(widgetSource, tempPath);
512
513     // Init installer context
514     m_installerContext.installStep = InstallerContext::INSTALL_START;
515     m_installerContext.job = this;
516     m_installerContext.widgetConfig.shareHref = std::string();
517
518     return result;
519 }
520
521 bool JobWidgetInstall::validateTizenApplicationID(
522     const WrtDB::TizenAppId &tizenAppId)
523 {
524     LogInfo("tizen application ID = [" << tizenAppId << "]");
525
526     regex_t reg;
527     if (regcomp(&reg, REG_TIZENID_PATTERN, REG_NOSUB | REG_EXTENDED) != 0) {
528         LogDebug("Regcomp failed");
529     }
530
531     if (regexec(&reg, DPL::ToUTF8String(tizenAppId).c_str(), 0, NULL, 0)
532         == REG_NOMATCH)
533     {
534         regfree(&reg);
535         return false;
536     }
537     regfree(&reg);
538     return true;
539 }
540
541 bool JobWidgetInstall::validateTizenPackageID(
542     const WrtDB::TizenPkgId &tizenPkgId)
543 {
544     std::string pkgId = DPL::ToUTF8String(tizenPkgId);
545
546     std::string installPath =
547         std::string(GlobalConfig::GetUserInstalledWidgetPath()) +
548         "/" + pkgId;
549     std::string preinstallPath =
550         std::string(GlobalConfig::GetUserPreloadedWidgetPath()) +
551         "/" + pkgId;
552
553     struct stat dirStat;
554     if ((stat(installPath.c_str(), &dirStat) == 0) ||
555         (stat(preinstallPath.c_str(), &dirStat) == 0))
556     {
557         return false;
558     }
559     return true;
560 }
561
562 ConfigureResult JobWidgetInstall::checkWidgetUpdate(
563     const WidgetUpdateInfo &update)
564 {
565     if (update.existingVersion.IsNull() || update.incomingVersion.IsNull()) {
566         return ConfigureResult::Failed;
567     }
568
569     LogInfo("existing version = '" << update.existingVersion);
570     LogInfo("incoming version = '" << update.incomingVersion);
571     LogInfo("Tizen AppID = " << update.tzAppId);
572
573     // Check running state
574     bool isRunning = false;
575     int ret =
576         app_manager_is_running(DPL::ToUTF8String(update.tzAppId).c_str(),
577                                &isRunning);
578     if (APP_MANAGER_ERROR_NONE != ret) {
579         LogError("Fail to get running state");
580         return ConfigureResult::Failed_WidgetRunning;
581     }
582
583     if (true == isRunning) {
584         // get app_context for running application
585         // app_context must be released with app_context_destroy
586         app_context_h appCtx = NULL;
587         ret =
588             app_manager_get_app_context(
589                 DPL::ToUTF8String(update.tzAppId).c_str(),
590                 &appCtx);
591         if (APP_MANAGER_ERROR_NONE != ret) {
592             LogError("Fail to get app_context");
593             return ConfigureResult::Failed_WidgetRunning;
594         }
595
596         // terminate app_context_h
597         ret = app_manager_terminate_app(appCtx);
598         if (APP_MANAGER_ERROR_NONE != ret) {
599             LogError("Fail to terminate running application");
600             app_context_destroy(appCtx);
601             return ConfigureResult::Failed_WidgetRunning;
602         } else {
603             app_context_destroy(appCtx);
604             // app_manager_terminate_app isn't sync API
605             // wait until application isn't running (50ms * 100)
606             bool isStillRunning = true;
607             int checkingloop = 100;
608             struct timespec duration = { 0, 50 * 1000 * 1000 };
609             while (--checkingloop >= 0) {
610                 nanosleep(&duration, NULL);
611                 int ret =
612                     app_manager_is_running(
613                         DPL::ToUTF8String(update.tzAppId).c_str(),
614                         &isStillRunning);
615                 if (APP_MANAGER_ERROR_NONE != ret) {
616                     LogError("Fail to get running state");
617                     return ConfigureResult::Failed_WidgetRunning;
618                 }
619                 if (!isStillRunning) {
620                     break;
621                 }
622             }
623             if (isStillRunning) {
624                 LogError("Fail to terminate running application");
625                 return ConfigureResult::Failed_WidgetRunning;
626             }
627             LogInfo("terminate application");
628         }
629     }
630
631     m_installerContext.widgetConfig.tzAppid = update.tzAppId;
632
633     if (!!update.existingVersion ||
634             m_installerContext.mode.extension ==
635             InstallMode::ExtensionType::DIR) {
636         return ConfigureResult::Updated;
637     }
638
639     return ConfigureResult::Failed;
640 }
641
642 ConfigParserData JobWidgetInstall::getWidgetDataFromXML(
643     const std::string &widgetSource,
644     const std::string &tempPath,
645     WrtDB::PackagingType pkgType,
646     bool isDRM,
647     bool isReinstall)
648 {
649     // Parse config
650     ParserRunner parser;
651     ConfigParserData configInfo;
652
653     Try
654     {
655         if (pkgType == PKG_TYPE_HOSTED_WEB_APP) {
656             parser.Parse(widgetSource,
657                          ElementParserPtr(
658                              new RootParser<WidgetParser>(configInfo,
659                                                           DPL::FromUTF32String(
660                                                               L"widget"))));
661         } else if (pkgType == PKG_TYPE_DIRECTORY_WEB_APP) {
662             std::string configPath;
663             configPath = tempPath;
664             configPath += "/";
665             configPath += WITH_OSP_XML;
666
667             if (isReinstall) {
668                 // checking RDS data directory
669                 if (access(configPath.c_str(), F_OK) != 0) {
670                     std::string tzAppId =
671                         widgetSource.substr(widgetSource.find_last_of("/")+1);
672                     WidgetDAOReadOnly dao(WidgetDAOReadOnly::getTzAppId(DPL::FromUTF8String(tzAppId)));
673                     configPath = DPL::ToUTF8String(*dao.getWidgetInstalledPath());
674                     configPath += "/";
675                     configPath += WITH_OSP_XML;
676                 }
677             }
678             parser.Parse(configPath,
679                          ElementParserPtr(
680                              new RootParser<WidgetParser>(
681                                  configInfo,
682                                  DPL::FromUTF32String(L"widget"))));
683         } else {
684             if (!isDRM) {
685                 std::unique_ptr<DPL::ZipInput> zipFile(
686                     new DPL::ZipInput(widgetSource));
687
688                 std::unique_ptr<DPL::ZipInput::File> configFile;
689
690                 // Open config.xml file
691                 if (pkgType == PKG_TYPE_HYBRID_WEB_APP) {
692                     configFile.reset(zipFile->OpenFile(WITH_OSP_XML));
693                 } else {
694                     configFile.reset(zipFile->OpenFile(CONFIG_XML));
695                 }
696
697                 // Extract config
698                 DPL::BinaryQueue buffer;
699                 DPL::AbstractWaitableInputAdapter inputAdapter(configFile.get());
700                 DPL::AbstractWaitableOutputAdapter outputAdapter(&buffer);
701                 DPL::Copy(&inputAdapter, &outputAdapter);
702                 parser.Parse(&buffer,
703                              ElementParserPtr(
704                                  new RootParser<WidgetParser>(configInfo,
705                                                               DPL::
706                                                                   FromUTF32String(
707                                                                   L"widget"))));
708             } else {
709                 // DRM widget
710                 std::string configFile;
711                 if (pkgType == PKG_TYPE_HYBRID_WEB_APP) {
712                     configFile = tempPath + "/" + WITH_OSP_XML;
713                 } else {
714                     configFile = tempPath + "/" + CONFIG_XML;
715                 }
716
717                 parser.Parse(configFile,
718                              ElementParserPtr(
719                                  new RootParser<WidgetParser>(configInfo,
720                                                               DPL::
721                                                                   FromUTF32String(
722                                                                   L"widget"))));
723             }
724         }
725     }
726     Catch(DPL::ZipInput::Exception::OpenFailed)
727     {
728         LogError("Failed to open widget package");
729         return ConfigParserData();
730     }
731     Catch(DPL::ZipInput::Exception::OpenFileFailed)
732     {
733         LogError("Failed to open config.xml file");
734         return ConfigParserData();
735     }
736     Catch(DPL::CopyFailed)
737     {
738         LogError("Failed to extract config.xml file");
739         return ConfigParserData();
740     }
741     Catch(DPL::FileInput::Exception::OpenFailed)
742     {
743         LogError("Failed to open config.xml file");
744         return ConfigParserData();
745     }
746     Catch(ElementParser::Exception::ParseError)
747     {
748         LogError("Failed to parse config.xml file");
749         return ConfigParserData();
750     }
751     Catch(DPL::ZipInput::Exception::SeekFileFailed)
752     {
753         LogError("Failed to seek widget archive - corrupted package?");
754         return ConfigParserData();
755     }
756     return configInfo;
757 }
758
759 WidgetUpdateInfo JobWidgetInstall::detectWidgetUpdate(
760     const ConfigParserData &configInfo,
761     const WrtDB::TizenAppId &tizenId)
762 {
763     LogInfo("Checking up widget package for config.xml...");
764     OptionalWidgetVersion incomingVersion;
765
766     if (!configInfo.version.IsNull()) {
767         incomingVersion =
768             DPL::Optional<WidgetVersion>(
769                 WidgetVersion(*configInfo.version));
770     }
771
772     WidgetDAOReadOnly dao(tizenId);
773
774     OptionalWidgetVersion optVersion;
775     DPL::OptionalString version = dao.getVersion();
776     if (!version.IsNull()) {
777         optVersion = OptionalWidgetVersion(WidgetVersion(*version));
778     }
779
780     return WidgetUpdateInfo(
781         dao.getTzAppId(),
782         optVersion,
783         incomingVersion);
784 }
785
786 void JobWidgetInstall::SendProgress()
787 {
788     using namespace PackageManager;
789     if (GetProgressFlag() != false) {
790         if (getInstallerStruct().progressCallback != NULL) {
791             // send progress signal of pkgmgr
792             std::ostringstream percent;
793             percent << static_cast<int>(GetProgressPercent());
794             getInstallerStruct().pkgmgrInterface->sendSignal(
795                 PKGMGR_PROGRESS_KEY,
796                 percent.str());
797
798             LogDebug("Call widget install progressCallbak");
799             getInstallerStruct().progressCallback(
800                 getInstallerStruct().userParam,
801                 GetProgressPercent(),
802                 GetProgressDescription());
803         }
804     }
805 }
806
807 void JobWidgetInstall::SendProgressIconPath(const std::string &path)
808 {
809     using namespace PackageManager;
810     if (GetProgressFlag() != false) {
811         if (getInstallerStruct().progressCallback != NULL) {
812             // send progress signal of pkgmgr
813             getInstallerStruct().pkgmgrInterface->sendSignal(
814                 PKGMGR_ICON_PATH,
815                 path);
816         }
817     }
818 }
819
820 void JobWidgetInstall::SendFinishedSuccess()
821 {
822     using namespace PackageManager;
823     // TODO : sync should move to separate task.
824     sync();
825
826     if (INSTALL_LOCATION_TYPE_EXTERNAL == m_installerContext.locationType) {
827         if (m_installerContext.isUpdateMode) {
828             WidgetInstallToExtSingleton::Instance().postUpgrade(true);
829         } else {
830             WidgetInstallToExtSingleton::Instance().postInstallation(true);
831         }
832         WidgetInstallToExtSingleton::Instance().deinitialize();
833     }
834
835     // remove widget install information file
836     unlink(m_installerContext.installInfo.c_str());
837
838     //inform widget info
839     JobWidgetInstall::displayWidgetInfo();
840
841     TizenAppId& tizenId = m_installerContext.widgetConfig.tzAppid;
842
843     // send signal of pkgmgr
844     getInstallerStruct().pkgmgrInterface->sendSignal(
845         PKGMGR_END_KEY,
846         PKGMGR_END_SUCCESS);
847
848     LogDebug("Call widget install successfinishedCallback");
849     getInstallerStruct().finishedCallback(getInstallerStruct().userParam,
850                                           DPL::ToUTF8String(
851                                               tizenId), Jobs::Exceptions::Success);
852 }
853
854 void JobWidgetInstall::SendFinishedFailure()
855 {
856     using namespace PackageManager;
857     // remove widget install information file
858     unlink(m_installerContext.installInfo.c_str());
859
860     LogError("Error number: " << m_exceptionCaught);
861     LogError("Message: " << m_exceptionMessage);
862     TizenAppId & tizenId = m_installerContext.widgetConfig.tzAppid;
863
864     LogDebug("Call widget install failure finishedCallback");
865     std::stringstream errorNum;
866     errorNum << m_exceptionCaught;
867
868     // send signal of pkgmgr
869     getInstallerStruct().pkgmgrInterface->sendSignal(
870         PKGMGR_ERROR,
871         errorNum.str());
872
873     getInstallerStruct().pkgmgrInterface->sendSignal(
874         PKGMGR_END_KEY,
875         PKGMGR_END_FAILURE);
876
877     getInstallerStruct().finishedCallback(getInstallerStruct().userParam,
878                                           DPL::ToUTF8String(
879                                               tizenId), m_exceptionCaught);
880 }
881
882 void JobWidgetInstall::SaveExceptionData(const Jobs::JobExceptionBase &e)
883 {
884     m_exceptionCaught = static_cast<Jobs::Exceptions::Type>(e.getParam());
885     m_exceptionMessage = e.GetMessage();
886 }
887
888 void JobWidgetInstall::displayWidgetInfo()
889 {
890     WidgetDAOReadOnly dao(m_installerContext.widgetConfig.tzAppid);
891
892     std::ostringstream out;
893     WidgetLocalizedInfo localizedInfo =
894         W3CFileLocalization::getLocalizedInfo(dao.getTzAppId());
895
896     out << std::endl <<
897     "===================================== INSTALLED WIDGET INFO =========" \
898     "============================";
899     out << std::endl << "Name:                        " << localizedInfo.name;
900     out << std::endl << "AppId:                     " << dao.getTzAppId();
901     WidgetSize size = dao.getPreferredSize();
902     out << std::endl << "Width:                       " << size.width;
903     out << std::endl << "Height:                      " << size.height;
904     out << std::endl << "Start File:                  " <<
905     W3CFileLocalization::getStartFile(dao.getTzAppId());
906     out << std::endl << "Version:                     " << dao.getVersion();
907     out << std::endl << "Licence:                     " <<
908     localizedInfo.license;
909     out << std::endl << "Licence Href:                " <<
910     localizedInfo.licenseHref;
911     out << std::endl << "Description:                 " <<
912     localizedInfo.description;
913     out << std::endl << "Widget Id:                   " << dao.getGUID();
914     out << std::endl << "Widget recognized:           " << dao.isRecognized();
915     out << std::endl << "Widget distributor signed:   " <<
916     dao.isDistributorSigned();
917     out << std::endl << "Widget trusted:              " << dao.isTrusted();
918
919     OptionalWidgetIcon icon = W3CFileLocalization::getIcon(dao.getTzAppId());
920     DPL::OptionalString iconSrc =
921         !!icon ? icon->src : DPL::OptionalString::Null;
922     out << std::endl << "Icon:                        " << iconSrc;
923
924     out << std::endl << "Preferences:";
925     {
926         PropertyDAOReadOnly::WidgetPreferenceList list = dao.getPropertyList();
927         FOREACH(it, list)
928         {
929             out << std::endl << "  Key:                       " <<
930             it->key_name;
931             out << std::endl << "      Readonly:              " <<
932             it->readonly;
933         }
934     }
935
936     out << std::endl << "Features:";
937     {
938         WidgetFeatureSet list = dao.getFeaturesList();
939         FOREACH(it, list)
940         {
941             out << std::endl << "  Name:                      " << it->name;
942         }
943     }
944
945     out << std::endl;
946
947     LogInfo(out.str());
948 }
949
950 WrtDB::PackagingType JobWidgetInstall::checkPackageType(
951     const std::string &widgetSource,
952     const std::string &tempPath)
953 {
954     // Check installation type (direcotory/ or config.xml or widget.wgt)
955     if (m_installerContext.mode.extension == InstallMode::ExtensionType::DIR) {
956         LogDebug("Install directly from directory");
957         return PKG_TYPE_DIRECTORY_WEB_APP;
958     }
959     if (hasExtension(widgetSource, XML_EXTENSION)) {
960         LogInfo("Hosted app installation");
961         return PKG_TYPE_HOSTED_WEB_APP;
962     }
963
964     if (m_isDRM) {
965         std::string configFile = tempPath + "/" + CONFIG_XML;
966         if (WrtUtilFileExists(configFile)) {
967             return PKG_TYPE_NOMAL_WEB_APP;
968         }
969
970         configFile = tempPath + "/" + WITH_OSP_XML;
971         if (WrtUtilFileExists(configFile)) {
972             return PKG_TYPE_HYBRID_WEB_APP;
973         }
974     } else {
975         std::unique_ptr<DPL::ZipInput> zipFile;
976
977         Try
978         {
979             // Open zip file
980             zipFile.reset(new DPL::ZipInput(widgetSource));
981         }
982         Catch(DPL::ZipInput::Exception::OpenFailed)
983         {
984             LogDebug("Failed to open widget package");
985             return PKG_TYPE_UNKNOWN;
986         }
987         Catch(DPL::ZipInput::Exception::SeekFileFailed)
988         {
989             LogError("Failed to seek widget package file");
990             return PKG_TYPE_UNKNOWN;
991         }
992
993         Try
994         {
995             // Open config.xml file in package root
996             std::unique_ptr<DPL::ZipInput::File> configFile(
997                 zipFile->OpenFile(CONFIG_XML));
998             return PKG_TYPE_NOMAL_WEB_APP;
999         }
1000         Catch(DPL::ZipInput::Exception::OpenFileFailed)
1001         {
1002             LogDebug("Could not find config.xml");
1003         }
1004
1005         Try
1006         {
1007             // Open config.xml file in package root
1008             std::unique_ptr<DPL::ZipInput::File> configFile(
1009                 zipFile->OpenFile(WITH_OSP_XML));
1010
1011             return PKG_TYPE_HYBRID_WEB_APP;
1012         }
1013         Catch(DPL::ZipInput::Exception::OpenFileFailed)
1014         {
1015             LogDebug("Could not find wgt/config.xml");
1016             return PKG_TYPE_UNKNOWN;
1017         }
1018     }
1019
1020     return PKG_TYPE_UNKNOWN;
1021 }
1022
1023 void JobWidgetInstall::setApplicationType(
1024     const WrtDB::ConfigParserData &configInfo)
1025 {
1026     FOREACH(iterator, configInfo.nameSpaces) {
1027         LogInfo("namespace = [" << *iterator << "]");
1028         AppType currentAppType = APP_TYPE_UNKNOWN;
1029
1030         if (*iterator == ConfigurationNamespace::W3CWidgetNamespaceName) {
1031             continue;
1032         } else if (
1033             *iterator ==
1034             ConfigurationNamespace::WacWidgetNamespaceNameForLinkElement ||
1035             *iterator ==
1036             ConfigurationNamespace::WacWidgetNamespaceName)
1037         {
1038             currentAppType = APP_TYPE_WAC20;
1039         } else if (*iterator ==
1040                    ConfigurationNamespace::TizenWebAppNamespaceName)
1041         {
1042             currentAppType = APP_TYPE_TIZENWEBAPP;
1043         }
1044
1045         if (m_installerContext.widgetConfig.webAppType ==
1046             APP_TYPE_UNKNOWN)
1047         {
1048             m_installerContext.widgetConfig.webAppType = currentAppType;
1049         } else if (m_installerContext.widgetConfig.webAppType ==
1050                    currentAppType)
1051         {
1052             continue;
1053         } else {
1054             ThrowMsg(Exceptions::WidgetConfigFileInvalid,
1055                      "Config.xml has more than one namespace");
1056         }
1057     }
1058
1059     // If there is no define, type set to WAC 2.0
1060     if (m_installerContext.widgetConfig.webAppType == APP_TYPE_UNKNOWN) {
1061         m_installerContext.widgetConfig.webAppType = APP_TYPE_WAC20;
1062     }
1063
1064     LogInfo("type = [" <<
1065             m_installerContext.widgetConfig.webAppType.getApptypeToString() <<
1066             "]");
1067 }
1068
1069 bool JobWidgetInstall::detectResourceEncryption(
1070     const WrtDB::ConfigParserData &configData)
1071 {
1072     FOREACH(it, configData.settingsList)
1073     {
1074         if (it->m_name == SETTING_VALUE_ENCRYPTION &&
1075             it->m_value == SETTING_VALUE_ENCRYPTION_ENABLE)
1076         {
1077             LogDebug("resource need encryption");
1078             return true;
1079         }
1080     }
1081     return false;
1082 }
1083
1084 void JobWidgetInstall::setInstallLocationType(
1085     const WrtDB::ConfigParserData & configData)
1086 {
1087     m_installerContext.locationType = INSTALL_LOCATION_TYPE_NOMAL;
1088     if (m_installerContext.mode.installTime != InstallMode::InstallTime::PRELOAD) {
1089         FOREACH(it, configData.settingsList) {
1090             if (it->m_name == SETTING_VALUE_INSTALLTOEXT_NAME &&
1091                 it->m_value ==
1092                 SETTING_VALUE_INSTALLTOEXT_PREPER_EXT)
1093             {
1094                 LogDebug("This widget will be installed to sd card");
1095                 m_installerContext.locationType =
1096                     INSTALL_LOCATION_TYPE_EXTERNAL;
1097             }
1098         }
1099     }
1100 }
1101
1102 bool JobWidgetInstall::isDRMWidget(std::string /*widgetPath*/)
1103 {
1104     /* TODO */
1105     return false;
1106 }
1107
1108 bool JobWidgetInstall::DecryptDRMWidget(std::string /*widgetPath*/,
1109                                         std::string /*destPath*/)
1110 {
1111     /* TODO */
1112     return false;
1113 }
1114
1115 bool JobWidgetInstall::checkSupportRDSUpdate(const WrtDB::ConfigParserData
1116         &configInfo)
1117 {
1118     if (m_installerContext.mode.command ==
1119             InstallMode::Command::REINSTALL)
1120     {
1121         DPL::String configValue = SETTING_VALUE_ENCRYPTION_DISABLE;
1122         DPL::String dbValue = SETTING_VALUE_ENCRYPTION_DISABLE;
1123
1124         WidgetDAOReadOnly dao(m_installerContext.widgetConfig.tzAppid);
1125         WrtDB::WidgetSettings widgetSettings;
1126         dao.getWidgetSettings(widgetSettings);
1127
1128         FOREACH(it, widgetSettings) {
1129             if (it->settingName == SETTING_VALUE_ENCRYPTION) {
1130                 dbValue = it->settingValue;
1131             }
1132         }
1133
1134         FOREACH(data, configInfo.settingsList)
1135         {
1136             if (data->m_name == SETTING_VALUE_ENCRYPTION) 
1137             {
1138                 configValue = data->m_value;
1139             }
1140         }
1141         if (configValue != dbValue) {
1142             LogError("Not Support RDS mode because of encryption setting");
1143             return false;
1144         }
1145     }
1146
1147     return true;
1148 }
1149 } //namespace WidgetInstall
1150 } //namespace Jobs