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 using namespace WrtDB;
59 const char* const CONFIG_XML = "config.xml";
60 const char* const WITH_OSP_XML = "res/wgt/config.xml";
61 const char* const OSP_MANIFEST_XML = "info/manifest.xml";
63 //allowed: a-z, A-Z, 0-9
64 const char* REG_TIZENID_PATTERN = "^[a-zA-Z0-9]{10}.{1,}$";
65 const char* REG_NAME_PATTERN = "^[a-zA-Z0-9._-]{1,}$";
66 const size_t PACKAGE_ID_LENGTH = 10;
68 static const DPL::String SETTING_VALUE_ENCRYPTION = L"encryption";
69 static const DPL::String SETTING_VALUE_ENCRYPTION_ENABLE = L"enable";
70 static const DPL::String SETTING_VALUE_ENCRYPTION_DISABLE = L"disable";
71 const DPL::String SETTING_VALUE_INSTALLTOEXT_NAME =
73 const DPL::String SETTING_VALUE_INSTALLTOEXT_PREPER_EXT =
76 const std::string XML_EXTENSION = ".xml";
78 bool hasExtension(const std::string& filename, const std::string& extension)
80 LogDebug("Looking for extension " << extension << " in: " << filename);
81 size_t fileLen = filename.length();
82 size_t extLen = extension.length();
83 if (fileLen < extLen) {
84 LogError("Filename " << filename << " is shorter than extension "
88 return (0 == filename.compare(fileLen - extLen, extLen, extension));
90 } // namespace anonymous
93 namespace WidgetInstall {
95 TaskConfiguration::TaskConfiguration(InstallerContext& context) :
96 DPL::TaskDecl<TaskConfiguration>(this),
98 m_result(ConfigureResult::Unknown)
100 AddStep(&TaskConfiguration::StartStep);
101 AddStep(&TaskConfiguration::PrepareInstallationStep);
102 AddStep(&TaskConfiguration::AppendTasklistStep);
103 AddStep(&TaskConfiguration::EndStep);
106 void TaskConfiguration::StartStep()
108 LogDebug("--------- <TaskConfiguration> : START ----------");
111 void TaskConfiguration::EndStep()
113 LogDebug("--------- <TaskConfiguration> : END ----------");
116 void TaskConfiguration::AppendTasklistStep()
118 // TODO: (job_install_refactoring) do not store config result anywhere
119 m_context.confResult = m_result;
121 if (m_result == ConfigureResult::Ok) {
122 LogInfo("TaskConfiguration -> new installation task list");
123 m_context.job->appendNewInstallationTaskList();
124 } else if (m_result == ConfigureResult::Updated) {
125 LogInfo("TaskConfiguration -> update installation task list");
126 m_context.job->appendUpdateInstallationTaskList();
128 LogInfo("TaskConfiguration -> failure task list");
129 m_context.job->appendFailureTaskList();
133 void TaskConfiguration::PrepareInstallationStep()
135 // TODO: (job_install_refactoring) clean up this task
136 std::string widgetPath = m_context.requestedPath;
137 ConfigureResult result;
138 m_context.needEncryption = false;
142 if (m_context.mode.extension == InstallMode::ExtensionType::DIR) {
143 if (m_context.mode.command ==
144 InstallMode::Command::REINSTALL) {
145 std::ostringstream tempPathBuilder;
146 tempPathBuilder << WrtDB::GlobalConfig::GetUserInstalledWidgetPath();
147 tempPathBuilder << WrtDB::GlobalConfig::GetTmpDirPath();
148 tempPathBuilder << "/";
149 tempPathBuilder << widgetPath;
150 tempDir = tempPathBuilder.str();
152 tempDir = widgetPath;
156 Jobs::WidgetInstall::createTempPath(
157 m_context.mode.rootPath ==
158 InstallMode::RootPath::RO);
159 WidgetUnzip wgtUnzip;
160 wgtUnzip.unzipWgtFile(widgetPath, tempDir);
163 LogDebug("widgetPath:" << widgetPath);
164 LogDebug("tempPath:" << tempDir);
166 m_context.widgetConfig.packagingType =
167 checkPackageType(widgetPath, tempDir);
168 ConfigParserData configData = getWidgetDataFromXML(
171 m_context.widgetConfig.packagingType,
172 m_context.mode.command == InstallMode::Command::REINSTALL);
173 LogDebug("widget packaging type : " <<
174 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 LogDebug("Caller Package Id : " << m_context.callerPkgId);
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 LogError("Failed to unzip for widget");
195 result = ConfigureResult::Failed_OpenZipError;
197 Catch(Exceptions::ExtractFileFailed)
199 LogError("Failed to unzip for widget");
200 result = ConfigureResult::Failed_UnzipError;
202 Catch(Exceptions::DrmDecryptFailed)
204 LogError("Failed to unzip for widget");
205 result = ConfigureResult::Failed_DrmError;
207 Catch(Exceptions::MissingConfig)
209 LogError("Failed to localize config.xml");
210 result = ConfigureResult::Failed_InvalidConfig;
212 Catch(Exceptions::WidgetConfigFileInvalid)
214 LogError("Invalid configuration file");
215 result = ConfigureResult::Failed_InvalidConfig;
217 Catch(DPL::Exception)
219 LogError("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 LogDebug("Setting tizenAppId provided in config.xml: " <<
233 configInfo.tizenAppId);
235 m_context.widgetConfig.tzAppid = *configInfo.tizenAppId;
237 if (!!configInfo.tizenPkgId) {
238 LogDebug("Setting tizenPkgId provided in config.xml: " <<
239 configInfo.tizenPkgId);
241 m_context.widgetConfig.tzPkgid = *configInfo.tizenPkgId;
243 DPL::String appid = *configInfo.tizenAppId;
244 if (appid.length() > PACKAGE_ID_LENGTH) {
245 m_context.widgetConfig.tzPkgid =
246 appid.substr(0, PACKAGE_ID_LENGTH);
248 //old version appid only has 10byte random character is able to install for a while.
249 //this case appid equal pkgid.
250 m_context.widgetConfig.tzPkgid =
251 *configInfo.tizenAppId;
252 shouldMakeAppid = true;
256 shouldMakeAppid = true;
257 TizenPkgId pkgId = WidgetDAOReadOnly::generatePkgId();
258 LogDebug("Checking if pkg id is unique");
260 if (!validateTizenPackageID(pkgId)) {
261 //path exist, chose another one
262 pkgId = WidgetDAOReadOnly::generatePkgId();
267 m_context.widgetConfig.tzPkgid = pkgId;
268 LogDebug("tizen_id name was generated by WRT: " <<
269 m_context.widgetConfig.tzPkgid);
272 if (shouldMakeAppid == true) {
273 DPL::OptionalString name;
274 DPL::OptionalString defaultLocale = configInfo.defaultlocale;
276 FOREACH(localizedData, configInfo.localizedDataSet)
278 Locale i = localizedData->first;
279 if (!!defaultLocale) {
280 if (defaultLocale == i) {
281 name = localizedData->second.name;
285 name = localizedData->second.name;
290 if (regcomp(®x, REG_NAME_PATTERN, REG_NOSUB | REG_EXTENDED) != 0) {
291 LogDebug("Regcomp failed");
294 LogDebug("Name : " << name);
295 if (!name || (regexec(®x, DPL::ToUTF8String(*name).c_str(),
296 static_cast<size_t>(0), NULL, 0) != REG_NOERROR))
298 // TODO : (job_install_refactoring) generate name move to wrt-commons
299 std::string allowedString("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
300 std::ostringstream genName;
302 gettimeofday(&tv, NULL);
303 unsigned int seed = time(NULL) + tv.tv_usec;
305 genName << "_" << allowedString[rand_r(&seed) % allowedString.length()];
306 name = DPL::FromUTF8String(genName.str());
307 LogDebug("name was generated by WRT");
310 LogDebug("Name : " << name);
311 std::ostringstream genid;
312 genid << m_context.widgetConfig.tzPkgid << "." << name;
313 LogDebug("tizen appid was generated by WRT : " << genid.str());
315 DPL::OptionalString appid = DPL::FromUTF8String(genid.str());
316 NormalizeAndTrimSpaceString(appid);
317 m_context.widgetConfig.tzAppid = *appid;
320 // send start signal of pkgmgr
321 // TODO: (job_install_refactoring) hide this call
322 m_context.job->GetInstallerStruct().pkgmgrInterface->setPkgname(DPL::ToUTF8String(
326 LogDebug("Tizen App Id : " << m_context.widgetConfig.tzAppid);
327 LogDebug("Tizen Pkg Id : " << m_context.widgetConfig.tzPkgid);
328 LogDebug("W3C Widget GUID : " << m_context.widgetConfig.guid);
331 void TaskConfiguration::configureWidgetLocation(const std::string & widgetPath,
332 const std::string& tempPath)
334 m_context.locations =
335 WidgetLocation(DPL::ToUTF8String(m_context.widgetConfig.
337 widgetPath, tempPath,
338 m_context.widgetConfig.packagingType,
339 m_context.mode.rootPath ==
340 InstallMode::RootPath::RO,
341 m_context.mode.extension);
342 m_context.locations->registerAppid(
343 DPL::ToUTF8String(m_context.widgetConfig.tzAppid));
345 LogDebug("widgetSource " << widgetPath);
348 ConfigureResult TaskConfiguration::ConfigureInstallation(
349 const std::string &widgetSource,
350 const WrtDB::ConfigParserData &configData,
351 const std::string &tempPath)
353 ConfigureResult result = ConfigureResult::Failed;
354 WidgetUpdateInfo update;
356 // checking installed web application
358 // checking existing application is installed
359 WidgetDAOReadOnly dao(m_context.widgetConfig.tzAppid);
360 // no excpetion means, it isn't update mode
361 // TODO: (job_install_refactoring) hide this call/
362 m_context.job->GetInstallerStruct().pkgmgrInterface->sendSignal(
364 PKGMGR_START_UPDATE);
366 update = detectWidgetUpdate(configData,
367 m_context.widgetConfig.tzAppid);
368 result = checkWidgetUpdate(update);
369 if (result != ConfigureResult::Updated) {
370 // Already installed TizenAppId. return failed
371 return ConfigureResult::Failed_AlreadyInstalled;
373 if (!checkSupportRDSUpdate(configData)) {
374 return ConfigureResult::Failed_NotSupportRDSUpdate;
376 m_context.isUpdateMode = true;
378 Catch(WidgetDAOReadOnly::Exception::WidgetNotExist) {
379 // TODO: (job_install_refactoring) hide this call
380 m_context.job->GetInstallerStruct().pkgmgrInterface->sendSignal(
382 PKGMGR_START_INSTALL);
383 result = ConfigureResult::Ok;
384 m_context.isUpdateMode = false;
386 if (!validateTizenApplicationID(
387 m_context.widgetConfig.tzAppid))
389 LogError("tizen application ID is already used");
390 return ConfigureResult::Failed_InvalidConfig;
392 if (!validateTizenPackageID(m_context.widgetConfig.tzPkgid)) {
393 LogError("tizen package ID is already used");
394 return ConfigureResult::Failed_AlreadyInstalled;
398 configureWidgetLocation(widgetSource, tempPath);
403 bool TaskConfiguration::validateTizenApplicationID(
404 const WrtDB::TizenAppId &tizenAppId)
406 LogDebug("tizen application ID = [" << tizenAppId << "]");
409 if (regcomp(®, REG_TIZENID_PATTERN, REG_NOSUB | REG_EXTENDED) != 0) {
410 LogDebug("Regcomp failed");
413 if (regexec(®, DPL::ToUTF8String(tizenAppId).c_str(), 0, NULL, 0)
423 bool TaskConfiguration::validateTizenPackageID(
424 const WrtDB::TizenPkgId &tizenPkgId)
426 std::string pkgId = DPL::ToUTF8String(tizenPkgId);
428 std::string installPath =
429 std::string(GlobalConfig::GetUserInstalledWidgetPath()) +
433 if ((stat(installPath.c_str(), &dirStat) == 0))
440 ConfigureResult TaskConfiguration::checkWidgetUpdate(
441 const WidgetUpdateInfo &update)
443 if (update.existingVersion.IsNull() || update.incomingVersion.IsNull()) {
444 return ConfigureResult::Failed;
447 LogDebug("existing version = '" << update.existingVersion);
448 LogDebug("incoming version = '" << update.incomingVersion);
449 LogDebug("Tizen AppID = " << update.tzAppId);
451 // Check running state
452 bool isRunning = false;
454 app_manager_is_running(DPL::ToUTF8String(update.tzAppId).c_str(),
456 if (APP_MANAGER_ERROR_NONE != ret) {
457 LogError("Fail to get running state");
458 return ConfigureResult::Failed_WidgetRunning;
461 if (true == isRunning) {
462 // get app_context for running application
463 // app_context must be released with app_context_destroy
464 app_context_h appCtx = NULL;
466 app_manager_get_app_context(
467 DPL::ToUTF8String(update.tzAppId).c_str(),
469 if (APP_MANAGER_ERROR_NONE != ret) {
470 LogError("Fail to get app_context");
471 return ConfigureResult::Failed_WidgetRunning;
474 // terminate app_context_h
475 ret = app_manager_terminate_app(appCtx);
476 if (APP_MANAGER_ERROR_NONE != ret) {
477 LogError("Fail to terminate running application");
478 app_context_destroy(appCtx);
479 return ConfigureResult::Failed_WidgetRunning;
481 app_context_destroy(appCtx);
482 // app_manager_terminate_app isn't sync API
483 // wait until application isn't running (50ms * 100)
484 bool isStillRunning = true;
485 int checkingloop = 100;
486 struct timespec duration = { 0, 50 * 1000 * 1000 };
487 while (--checkingloop >= 0) {
488 nanosleep(&duration, NULL);
490 app_manager_is_running(
491 DPL::ToUTF8String(update.tzAppId).c_str(),
493 if (APP_MANAGER_ERROR_NONE != ret) {
494 LogError("Fail to get running state");
495 return ConfigureResult::Failed_WidgetRunning;
497 if (!isStillRunning) {
501 if (isStillRunning) {
502 LogError("Fail to terminate running application");
503 return ConfigureResult::Failed_WidgetRunning;
505 LogDebug("terminate application");
509 m_context.widgetConfig.tzAppid = update.tzAppId;
511 if (!!update.existingVersion ||
512 m_context.mode.extension ==
513 InstallMode::ExtensionType::DIR) {
514 return ConfigureResult::Updated;
517 return ConfigureResult::Failed;
520 ConfigParserData TaskConfiguration::getWidgetDataFromXML(
521 const std::string &widgetSource,
522 const std::string &tempPath,
523 WrtDB::PackagingType pkgType,
528 ConfigParserData configInfo;
531 if (pkgType == PKG_TYPE_HOSTED_WEB_APP) {
532 parser.Parse(widgetSource,
534 new RootParser<WidgetParser>(configInfo,
535 DPL::FromUTF32String(
538 std::string configFile;
539 configFile = tempPath + "/" + CONFIG_XML;
540 if (!WrtUtilFileExists(configFile)) {
541 configFile = tempPath + "/" + WITH_OSP_XML;
545 // checking RDS data directory
546 if (access(configFile.c_str(), F_OK) != 0) {
547 std::string tzAppId =
548 widgetSource.substr(widgetSource.find_last_of("/")+1);
549 WidgetDAOReadOnly dao(WidgetDAOReadOnly::getTzAppId(DPL::FromUTF8String(tzAppId)));
550 configFile = DPL::ToUTF8String(*dao.getWidgetInstalledPath());
552 configFile += WITH_OSP_XML;
556 if(!DPL::Utils::Path(configFile).Exists())
558 ThrowMsg(Exceptions::MissingConfig, "Config file not exists");
561 parser.Parse(configFile,
563 new RootParser<WidgetParser>(configInfo,
569 Catch(ElementParser::Exception::ParseError)
571 LogError("Failed to parse config.xml file");
572 return ConfigParserData();
574 Catch(WidgetDAOReadOnly::Exception::WidgetNotExist)
576 LogError("Failed to find installed widget - give proper tizenId");
577 return ConfigParserData();
579 Catch(Exceptions::WidgetConfigFileNotFound){
580 LogError("Failed to find config.xml");
581 return ConfigParserData();
587 WidgetUpdateInfo TaskConfiguration::detectWidgetUpdate(
588 const ConfigParserData &configInfo,
589 const WrtDB::TizenAppId &tizenId)
591 LogDebug("Checking up widget package for config.xml...");
592 OptionalWidgetVersion incomingVersion;
594 if (!configInfo.version.IsNull()) {
596 DPL::Optional<WidgetVersion>(
597 WidgetVersion(*configInfo.version));
600 WidgetDAOReadOnly dao(tizenId);
602 OptionalWidgetVersion optVersion;
603 DPL::OptionalString version = dao.getVersion();
604 if (!version.IsNull()) {
605 optVersion = OptionalWidgetVersion(WidgetVersion(*version));
608 return WidgetUpdateInfo(
615 WrtDB::PackagingType TaskConfiguration::checkPackageType(
616 const std::string &widgetSource,
617 const std::string &tempPath)
619 if (hasExtension(widgetSource, XML_EXTENSION)) {
620 LogDebug("Hosted app installation");
621 return PKG_TYPE_HOSTED_WEB_APP;
624 std::string configFile = tempPath + "/" + OSP_MANIFEST_XML;
625 if (WrtUtilFileExists(configFile)) {
626 return PKG_TYPE_HYBRID_WEB_APP;
629 return PKG_TYPE_NOMAL_WEB_APP;
632 void TaskConfiguration::setApplicationType(
633 const WrtDB::ConfigParserData &configInfo)
635 AppType widgetAppType = APP_TYPE_UNKNOWN;
636 FOREACH(iterator, configInfo.nameSpaces) {
637 LogDebug("namespace = [" << *iterator << "]");
639 if (*iterator == ConfigurationNamespace::TizenWebAppNamespaceName) {
640 if (widgetAppType != APP_TYPE_UNKNOWN &&
641 widgetAppType != APP_TYPE_TIZENWEBAPP)
643 LogError("To many namespaces declared in configuration fileA.");
644 ThrowMsg(Exceptions::WidgetConfigFileInvalid,
645 "Config.xml has more than one valid namespace");
647 widgetAppType = APP_TYPE_TIZENWEBAPP;
649 LogDebug("Namespace ignored.");
653 m_context.widgetConfig.webAppType = widgetAppType;
655 LogDebug("type = [" <<
656 m_context.widgetConfig.webAppType.getApptypeToString() <<
660 bool TaskConfiguration::detectResourceEncryption(
661 const WrtDB::ConfigParserData &configData)
663 FOREACH(it, configData.settingsList)
665 if (it->m_name == SETTING_VALUE_ENCRYPTION &&
666 it->m_value == SETTING_VALUE_ENCRYPTION_ENABLE)
668 LogDebug("resource need encryption");
675 void TaskConfiguration::setInstallLocationType(
676 const WrtDB::ConfigParserData & configData)
678 m_context.locationType = INSTALL_LOCATION_TYPE_NOMAL;
679 if (m_context.mode.installTime != InstallMode::InstallTime::PRELOAD) {
680 FOREACH(it, configData.settingsList) {
681 if (it->m_name == SETTING_VALUE_INSTALLTOEXT_NAME &&
683 SETTING_VALUE_INSTALLTOEXT_PREPER_EXT)
685 LogDebug("This widget will be installed to sd card");
686 m_context.locationType =
687 INSTALL_LOCATION_TYPE_EXTERNAL;
693 bool TaskConfiguration::checkSupportRDSUpdate(const WrtDB::ConfigParserData
696 if (m_context.mode.command ==
697 InstallMode::Command::REINSTALL)
699 DPL::String configValue = SETTING_VALUE_ENCRYPTION_DISABLE;
700 DPL::String dbValue = SETTING_VALUE_ENCRYPTION_DISABLE;
702 WidgetDAOReadOnly dao(m_context.widgetConfig.tzAppid);
703 WrtDB::WidgetSettings widgetSettings;
704 dao.getWidgetSettings(widgetSettings);
706 FOREACH(it, widgetSettings) {
707 if (it->settingName == SETTING_VALUE_ENCRYPTION) {
708 dbValue = it->settingValue;
712 FOREACH(data, configInfo.settingsList)
714 if (data->m_name == SETTING_VALUE_ENCRYPTION)
716 configValue = data->m_value;
719 if (configValue != dbValue) {
720 LogError("Not Support RDS mode because of encryption setting");