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