2 * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * @file task_configuration.cpp
19 * @author Tomasz Iwanek
20 * @brief implementation file for configuration task
22 #include "task_configuration.h"
33 #include <dpl/utils/wrt_utility.h>
34 #include <dpl/utils/path.h>
35 #include <dpl/wrt-dao-ro/common_dao_types.h>
36 #include <dpl/wrt-dao-ro/widget_dao_read_only.h>
37 #include <dpl/wrt-dao-ro/global_config.h>
38 #include <dpl/wrt-dao-ro/config_parser_data.h>
39 #include <dpl/localization/w3c_file_localization.h>
41 #include <libiriwrapper.h>
42 #include <pkg-manager/pkgmgr_signal.h>
43 #include <app_manager.h>
45 #include "root_parser.h"
46 #include "widget_parser.h"
47 #include "parser_runner.h"
49 #include <widget_install/widget_install_errors.h>
50 #include <widget_install/widget_install_context.h>
51 #include <widget_install_to_external.h>
52 #include <widget_install/widget_unzip.h>
53 #include <widget_install/job_widget_install.h>
54 #include <widget_install/task_commons.h>
56 #include <installer_log.h>
58 using namespace WrtDB;
61 const char* const CONFIG_XML = "config.xml";
62 const char* const WITH_OSP_XML = "res/wgt/config.xml";
63 const char* const OSP_MANIFEST_XML = "info/manifest.xml";
65 //allowed: a-z, A-Z, 0-9
66 const char* REG_TIZENID_PATTERN = "^[a-zA-Z0-9]{10}.{1,}$";
67 const char* REG_NAME_PATTERN = "^[a-zA-Z0-9._-]{1,}$";
68 const size_t PACKAGE_ID_LENGTH = 10;
70 static const DPL::String SETTING_VALUE_ENCRYPTION = L"encryption";
71 static const DPL::String SETTING_VALUE_ENCRYPTION_ENABLE = L"enable";
72 static const DPL::String SETTING_VALUE_ENCRYPTION_DISABLE = L"disable";
73 const DPL::String SETTING_VALUE_INSTALLTOEXT_NAME =
75 const DPL::String SETTING_VALUE_INSTALLTOEXT_PREPER_EXT =
78 const std::string XML_EXTENSION = ".xml";
80 bool hasExtension(const std::string& filename, const std::string& extension)
82 _D("Looking for extension %s in %s", extension.c_str(), filename.c_str());
83 size_t fileLen = filename.length();
84 size_t extLen = extension.length();
85 if (fileLen < extLen) {
86 _E("Filename %s is shorter than extension %s", filename.c_str(), extension.c_str());
89 return (0 == filename.compare(fileLen - extLen, extLen, extension));
91 } // namespace anonymous
94 namespace WidgetInstall {
96 TaskConfiguration::TaskConfiguration(InstallerContext& context) :
97 DPL::TaskDecl<TaskConfiguration>(this),
99 m_result(ConfigureResult::Unknown)
101 AddStep(&TaskConfiguration::StartStep);
102 AddStep(&TaskConfiguration::PrepareInstallationStep);
103 AddStep(&TaskConfiguration::AppendTasklistStep);
104 AddStep(&TaskConfiguration::EndStep);
107 void TaskConfiguration::StartStep()
109 _D("--------- <TaskConfiguration> : START ----------");
112 void TaskConfiguration::EndStep()
114 _D("--------- <TaskConfiguration> : END ----------");
117 void TaskConfiguration::AppendTasklistStep()
119 // TODO: (job_install_refactoring) do not store config result anywhere
120 m_context.confResult = m_result;
122 if (m_result == ConfigureResult::Ok) {
123 _D("TaskConfiguration -> new installation task list");
124 m_context.job->appendNewInstallationTaskList();
125 } else if (m_result == ConfigureResult::Updated) {
126 _D("TaskConfiguration -> update installation task list");
127 m_context.job->appendUpdateInstallationTaskList();
129 _D("TaskConfiguration -> failure task list");
130 m_context.job->appendFailureTaskList();
134 void TaskConfiguration::PrepareInstallationStep()
136 // TODO: (job_install_refactoring) clean up this task
137 std::string widgetPath = m_context.requestedPath;
138 ConfigureResult result;
139 m_context.needEncryption = false;
143 if (m_context.mode.extension == InstallMode::ExtensionType::DIR) {
144 if (m_context.mode.command ==
145 InstallMode::Command::REINSTALL) {
146 std::ostringstream tempPathBuilder;
147 tempPathBuilder << WrtDB::GlobalConfig::GetUserInstalledWidgetPath();
148 tempPathBuilder << WrtDB::GlobalConfig::GetTmpDirPath();
149 tempPathBuilder << "/";
150 tempPathBuilder << widgetPath;
151 tempDir = tempPathBuilder.str();
153 tempDir = widgetPath;
157 Jobs::WidgetInstall::createTempPath(
158 m_context.mode.rootPath ==
159 InstallMode::RootPath::RO);
160 WidgetUnzip wgtUnzip;
161 wgtUnzip.unzipWgtFile(widgetPath, tempDir);
164 _D("widgetPath:%s", widgetPath.c_str());
165 _D("tempPath:%s", tempDir.c_str());
167 m_context.widgetConfig.packagingType =
168 checkPackageType(widgetPath, tempDir);
169 ConfigParserData configData = getWidgetDataFromXML(
172 m_context.widgetConfig.packagingType,
173 m_context.mode.command == InstallMode::Command::REINSTALL);
174 _D("widget packaging type : %d", m_context.widgetConfig.packagingType.pkgType);
176 setTizenId(configData);
177 setApplicationType(configData);
178 m_context.needEncryption = detectResourceEncryption(configData);
179 setInstallLocationType(configData);
180 // TODO: (job_install_refactoring) hide this call
181 m_context.callerPkgId =
182 DPL::FromUTF8String(m_context.job->GetInstallerStruct().pkgmgrInterface->getCallerId());
183 _D("Caller Package Id : %ls", m_context.callerPkgId.c_str());
185 // Configure installation
186 result = ConfigureInstallation(widgetPath, configData, tempDir);
187 // TODO: (job_install_refactoring) hide this call
188 m_context.job->GetInstallerStruct().pkgmgrInterface->sendSignal(
192 Catch(Exceptions::OpenZipFailed)
194 _E("Failed to unzip for widget");
195 result = ConfigureResult::Failed_OpenZipError;
197 Catch(Exceptions::ExtractFileFailed)
199 _E("Failed to unzip for widget");
200 result = ConfigureResult::Failed_UnzipError;
202 Catch(Exceptions::DrmDecryptFailed)
204 _E("Failed to unzip for widget");
205 result = ConfigureResult::Failed_DrmError;
207 Catch(Exceptions::MissingConfig)
209 _E("Failed to localize config.xml");
210 result = ConfigureResult::Failed_InvalidConfig;
212 Catch(Exceptions::WidgetConfigFileInvalid)
214 _E("Invalid configuration file");
215 result = ConfigureResult::Failed_InvalidConfig;
217 Catch(DPL::Exception)
219 _E("Unknown exception");
220 result = ConfigureResult::Failed;
226 void TaskConfiguration::setTizenId(
227 const WrtDB::ConfigParserData &configInfo)
229 bool shouldMakeAppid = false;
230 using namespace PackageManager;
231 if (!!configInfo.tizenAppId) {
232 _D("Setting tizenAppId provided in config.xml: %ls", (*configInfo.tizenAppId).c_str());
233 m_context.widgetConfig.tzAppid = *configInfo.tizenAppId;
235 if (!!configInfo.tizenPkgId) {
236 _D("Setting tizenPkgId provided in config.xml: %ls", (*configInfo.tizenPkgId).c_str());
237 m_context.widgetConfig.tzPkgid = *configInfo.tizenPkgId;
239 DPL::String appid = *configInfo.tizenAppId;
240 if (appid.length() > PACKAGE_ID_LENGTH) {
241 m_context.widgetConfig.tzPkgid =
242 appid.substr(0, PACKAGE_ID_LENGTH);
244 //old version appid only has 10byte random character is able to install for a while.
245 //this case appid equal pkgid.
246 m_context.widgetConfig.tzPkgid =
247 *configInfo.tizenAppId;
248 shouldMakeAppid = true;
252 shouldMakeAppid = true;
253 TizenPkgId pkgId = WidgetDAOReadOnly::generatePkgId();
254 _D("Checking if pkg id is unique");
256 if (!validateTizenPackageID(pkgId)) {
257 //path exist, chose another one
258 pkgId = WidgetDAOReadOnly::generatePkgId();
263 m_context.widgetConfig.tzPkgid = pkgId;
264 _D("tizen_id name was generated by WRT: %ls", m_context.widgetConfig.tzPkgid.c_str());
267 if (shouldMakeAppid == true) {
268 DPL::OptionalString name;
269 DPL::OptionalString defaultLocale = configInfo.defaultlocale;
271 FOREACH(localizedData, configInfo.localizedDataSet)
273 Locale i = localizedData->first;
274 if (!!defaultLocale) {
275 if (defaultLocale == i) {
276 name = localizedData->second.name;
280 name = localizedData->second.name;
285 if (regcomp(®x, REG_NAME_PATTERN, REG_NOSUB | REG_EXTENDED) != 0) {
286 _D("Regcomp failed");
289 _D("Name : %ls", (*name).c_str());
290 if (!name || (regexec(®x, DPL::ToUTF8String(*name).c_str(),
291 static_cast<size_t>(0), NULL, 0) != REG_NOERROR))
293 // TODO : (job_install_refactoring) generate name move to wrt-commons
294 std::string allowedString("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
295 std::ostringstream genName;
297 gettimeofday(&tv, NULL);
298 unsigned int seed = time(NULL) + tv.tv_usec;
300 genName << "_" << allowedString[rand_r(&seed) % allowedString.length()];
301 name = DPL::FromUTF8String(genName.str());
302 _D("name was generated by WRT");
305 _D("Name : %ls", (*name).c_str());
306 std::ostringstream genid;
307 genid << m_context.widgetConfig.tzPkgid << "." << name;
308 _D("tizen appid was generated by WRT : %s", genid.str().c_str());
310 DPL::OptionalString appid = DPL::FromUTF8String(genid.str());
311 NormalizeAndTrimSpaceString(appid);
312 m_context.widgetConfig.tzAppid = *appid;
315 // send start signal of pkgmgr
316 // TODO: (job_install_refactoring) hide this call
317 m_context.job->GetInstallerStruct().pkgmgrInterface->setPkgname(DPL::ToUTF8String(
321 _D("Tizen App Id : %ls", (m_context.widgetConfig.tzAppid).c_str());
322 _D("Tizen Pkg Id : %ls", (m_context.widgetConfig.tzPkgid).c_str());
323 _D("W3C Widget GUID : %ls", (*m_context.widgetConfig.guid).c_str());
327 void TaskConfiguration::configureWidgetLocation(const std::string & widgetPath,
328 const std::string& tempPath)
330 m_context.locations =
331 WidgetLocation(DPL::ToUTF8String(m_context.widgetConfig.
333 widgetPath, tempPath,
334 m_context.widgetConfig.packagingType,
335 m_context.mode.rootPath ==
336 InstallMode::RootPath::RO,
337 m_context.mode.extension);
338 m_context.locations->registerAppid(
339 DPL::ToUTF8String(m_context.widgetConfig.tzAppid));
341 _D("widgetSource %s", widgetPath.c_str());
344 ConfigureResult TaskConfiguration::ConfigureInstallation(
345 const std::string &widgetSource,
346 const WrtDB::ConfigParserData &configData,
347 const std::string &tempPath)
349 ConfigureResult result = ConfigureResult::Failed;
350 WidgetUpdateInfo update;
352 // checking installed web application
354 // checking existing application is installed
355 WidgetDAOReadOnly dao(m_context.widgetConfig.tzAppid);
356 // no excpetion means, it isn't update mode
357 // TODO: (job_install_refactoring) hide this call/
358 m_context.job->GetInstallerStruct().pkgmgrInterface->sendSignal(
360 PKGMGR_START_UPDATE);
362 update = detectWidgetUpdate(configData,
363 m_context.widgetConfig.tzAppid);
364 result = checkWidgetUpdate(update);
365 if (result != ConfigureResult::Updated) {
366 // Already installed TizenAppId. return failed
367 return ConfigureResult::Failed_AlreadyInstalled;
369 if (!checkSupportRDSUpdate(configData)) {
370 return ConfigureResult::Failed_NotSupportRDSUpdate;
372 m_context.isUpdateMode = true;
374 Catch(WidgetDAOReadOnly::Exception::WidgetNotExist) {
375 // TODO: (job_install_refactoring) hide this call
376 m_context.job->GetInstallerStruct().pkgmgrInterface->sendSignal(
378 PKGMGR_START_INSTALL);
379 result = ConfigureResult::Ok;
380 m_context.isUpdateMode = false;
382 if (!validateTizenApplicationID(
383 m_context.widgetConfig.tzAppid))
385 _E("tizen application ID is already used");
386 return ConfigureResult::Failed_InvalidConfig;
388 if (!validateTizenPackageID(m_context.widgetConfig.tzPkgid)) {
389 _E("tizen package ID is already used");
390 return ConfigureResult::Failed_AlreadyInstalled;
394 configureWidgetLocation(widgetSource, tempPath);
399 bool TaskConfiguration::validateTizenApplicationID(
400 const WrtDB::TizenAppId &tizenAppId)
402 _D("tizen application ID = [%ls]", tizenAppId.c_str());
405 if (regcomp(®, REG_TIZENID_PATTERN, REG_NOSUB | REG_EXTENDED) != 0) {
406 _D("Regcomp failed");
409 if (regexec(®, DPL::ToUTF8String(tizenAppId).c_str(), 0, NULL, 0)
419 bool TaskConfiguration::validateTizenPackageID(
420 const WrtDB::TizenPkgId &tizenPkgId)
422 std::string pkgId = DPL::ToUTF8String(tizenPkgId);
424 std::string installPath =
425 std::string(GlobalConfig::GetUserInstalledWidgetPath()) +
429 if ((stat(installPath.c_str(), &dirStat) == 0))
436 ConfigureResult TaskConfiguration::checkWidgetUpdate(
437 const WidgetUpdateInfo &update)
439 if (update.existingVersion.IsNull() || update.incomingVersion.IsNull()) {
440 return ConfigureResult::Failed;
443 _D("existing version = '%ls", update.existingVersion->Raw().c_str());
444 _D("incoming version = '%ls", update.incomingVersion->Raw().c_str());
445 _D("Tizen AppID = %ls", update.tzAppId.c_str());
447 // Check running state
448 bool isRunning = false;
450 app_manager_is_running(DPL::ToUTF8String(update.tzAppId).c_str(),
452 if (APP_MANAGER_ERROR_NONE != ret) {
453 _E("Fail to get running state");
454 return ConfigureResult::Failed_WidgetRunning;
457 if (true == isRunning) {
458 // get app_context for running application
459 // app_context must be released with app_context_destroy
460 app_context_h appCtx = NULL;
462 app_manager_get_app_context(
463 DPL::ToUTF8String(update.tzAppId).c_str(),
465 if (APP_MANAGER_ERROR_NONE != ret) {
466 _E("Fail to get app_context");
467 return ConfigureResult::Failed_WidgetRunning;
470 // terminate app_context_h
471 ret = app_manager_terminate_app(appCtx);
472 if (APP_MANAGER_ERROR_NONE != ret) {
473 _E("Fail to terminate running application");
474 app_context_destroy(appCtx);
475 return ConfigureResult::Failed_WidgetRunning;
477 app_context_destroy(appCtx);
478 // app_manager_terminate_app isn't sync API
479 // wait until application isn't running (50ms * 100)
480 bool isStillRunning = true;
481 int checkingloop = 100;
482 struct timespec duration = { 0, 50 * 1000 * 1000 };
483 while (--checkingloop >= 0) {
484 nanosleep(&duration, NULL);
486 app_manager_is_running(
487 DPL::ToUTF8String(update.tzAppId).c_str(),
489 if (APP_MANAGER_ERROR_NONE != ret) {
490 _E("Fail to get running state");
491 return ConfigureResult::Failed_WidgetRunning;
493 if (!isStillRunning) {
497 if (isStillRunning) {
498 _E("Fail to terminate running application");
499 return ConfigureResult::Failed_WidgetRunning;
501 _D("terminate application");
505 m_context.widgetConfig.tzAppid = update.tzAppId;
507 if (!!update.existingVersion ||
508 m_context.mode.extension ==
509 InstallMode::ExtensionType::DIR) {
510 return ConfigureResult::Updated;
513 return ConfigureResult::Failed;
516 ConfigParserData TaskConfiguration::getWidgetDataFromXML(
517 const std::string &widgetSource,
518 const std::string &tempPath,
519 WrtDB::PackagingType pkgType,
524 ConfigParserData configInfo;
527 if (pkgType == PKG_TYPE_HOSTED_WEB_APP) {
528 parser.Parse(widgetSource,
530 new RootParser<WidgetParser>(configInfo,
531 DPL::FromUTF32String(
534 std::string configFile;
535 configFile = tempPath + "/" + CONFIG_XML;
536 if (!WrtUtilFileExists(configFile)) {
537 configFile = tempPath + "/" + WITH_OSP_XML;
541 // checking RDS data directory
542 if (access(configFile.c_str(), F_OK) != 0) {
543 std::string tzAppId =
544 widgetSource.substr(widgetSource.find_last_of("/")+1);
545 WidgetDAOReadOnly dao(WidgetDAOReadOnly::getTzAppId(DPL::FromUTF8String(tzAppId)));
546 configFile = DPL::ToUTF8String(*dao.getWidgetInstalledPath());
548 configFile += WITH_OSP_XML;
552 if(!DPL::Utils::Path(configFile).Exists())
554 ThrowMsg(Exceptions::MissingConfig, "Config file not exists");
557 parser.Parse(configFile,
559 new RootParser<WidgetParser>(configInfo,
565 Catch(ElementParser::Exception::ParseError)
567 _E("Failed to parse config.xml file");
568 return ConfigParserData();
570 Catch(WidgetDAOReadOnly::Exception::WidgetNotExist)
572 _E("Failed to find installed widget - give proper tizenId");
573 return ConfigParserData();
575 Catch(Exceptions::WidgetConfigFileNotFound){
576 _E("Failed to find config.xml");
577 return ConfigParserData();
583 WidgetUpdateInfo TaskConfiguration::detectWidgetUpdate(
584 const ConfigParserData &configInfo,
585 const WrtDB::TizenAppId &tizenId)
587 _D("Checking up widget package for config.xml...");
588 OptionalWidgetVersion incomingVersion;
590 if (!configInfo.version.IsNull()) {
592 DPL::Optional<WidgetVersion>(
593 WidgetVersion(*configInfo.version));
596 WidgetDAOReadOnly dao(tizenId);
598 OptionalWidgetVersion optVersion;
599 DPL::OptionalString version = dao.getVersion();
600 if (!version.IsNull()) {
601 optVersion = OptionalWidgetVersion(WidgetVersion(*version));
604 return WidgetUpdateInfo(
611 WrtDB::PackagingType TaskConfiguration::checkPackageType(
612 const std::string &widgetSource,
613 const std::string &tempPath)
615 if (hasExtension(widgetSource, XML_EXTENSION)) {
616 _D("Hosted app installation");
617 return PKG_TYPE_HOSTED_WEB_APP;
620 std::string configFile = tempPath + "/" + OSP_MANIFEST_XML;
621 if (WrtUtilFileExists(configFile)) {
622 return PKG_TYPE_HYBRID_WEB_APP;
625 return PKG_TYPE_NOMAL_WEB_APP;
628 void TaskConfiguration::setApplicationType(
629 const WrtDB::ConfigParserData &configInfo)
631 AppType widgetAppType = APP_TYPE_UNKNOWN;
632 FOREACH(iterator, configInfo.nameSpaces) {
633 _D("namespace = [%ls]", (*iterator).c_str());
635 if (*iterator == ConfigurationNamespace::TizenWebAppNamespaceName) {
636 widgetAppType = APP_TYPE_TIZENWEBAPP;
641 m_context.widgetConfig.webAppType = widgetAppType;
643 _D("type = [%s]", m_context.widgetConfig.webAppType.getApptypeToString().c_str());
646 bool TaskConfiguration::detectResourceEncryption(
647 const WrtDB::ConfigParserData &configData)
649 FOREACH(it, configData.settingsList)
651 if (it->m_name == SETTING_VALUE_ENCRYPTION &&
652 it->m_value == SETTING_VALUE_ENCRYPTION_ENABLE)
654 _D("resource need encryption");
661 void TaskConfiguration::setInstallLocationType(
662 const WrtDB::ConfigParserData & configData)
664 m_context.locationType = INSTALL_LOCATION_TYPE_NOMAL;
665 if (m_context.mode.installTime != InstallMode::InstallTime::PRELOAD) {
666 FOREACH(it, configData.settingsList) {
667 if (it->m_name == SETTING_VALUE_INSTALLTOEXT_NAME &&
669 SETTING_VALUE_INSTALLTOEXT_PREPER_EXT)
671 _D("This widget will be installed to sd card");
672 m_context.locationType =
673 INSTALL_LOCATION_TYPE_EXTERNAL;
679 bool TaskConfiguration::checkSupportRDSUpdate(const WrtDB::ConfigParserData
682 if (m_context.mode.command ==
683 InstallMode::Command::REINSTALL)
685 DPL::String configValue = SETTING_VALUE_ENCRYPTION_DISABLE;
686 DPL::String dbValue = SETTING_VALUE_ENCRYPTION_DISABLE;
688 WidgetDAOReadOnly dao(m_context.widgetConfig.tzAppid);
689 WrtDB::WidgetSettings widgetSettings;
690 dao.getWidgetSettings(widgetSettings);
692 FOREACH(it, widgetSettings) {
693 if (it->settingName == SETTING_VALUE_ENCRYPTION) {
694 dbValue = it->settingValue;
698 FOREACH(data, configInfo.settingsList)
700 if (data->m_name == SETTING_VALUE_ENCRYPTION)
702 configValue = data->m_value;
705 if (configValue != dbValue) {
706 _E("Not Support RDS mode because of encryption setting");