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