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),
100 AddStep(&TaskConfiguration::StartStep);
101 AddStep(&TaskConfiguration::PrepareInstallationStep);
102 AddStep(&TaskConfiguration::AppendTasklistStep);
103 AddStep(&TaskConfiguration::EndStep);
106 void TaskConfiguration::StartStep()
108 _D("--------- <TaskConfiguration> : START ----------");
111 void TaskConfiguration::EndStep()
113 _D("--------- <TaskConfiguration> : END ----------");
116 void TaskConfiguration::AppendTasklistStep()
118 if (!m_context.isUpdateMode) {
119 _D("TaskConfiguration -> new installation task list");
120 m_context.job->appendNewInstallationTaskList();
122 _D("TaskConfiguration -> update installation task list");
123 m_context.job->appendUpdateInstallationTaskList();
127 void TaskConfiguration::PrepareInstallationStep()
129 // TODO: (job_install_refactoring) clean up this task
130 std::string widgetPath = m_context.requestedPath;
132 m_context.needEncryption = false;
134 if (m_context.mode.extension == InstallMode::ExtensionType::DIR) {
135 if (m_context.mode.command ==
136 InstallMode::Command::REINSTALL) {
137 std::ostringstream tempPathBuilder;
138 tempPathBuilder << WrtDB::GlobalConfig::GetUserInstalledWidgetPath();
139 tempPathBuilder << WrtDB::GlobalConfig::GetTmpDirPath();
140 tempPathBuilder << "/";
141 tempPathBuilder << widgetPath;
142 tempDir = tempPathBuilder.str();
144 tempDir = widgetPath;
148 Jobs::WidgetInstall::createTempPath(
149 m_context.mode.rootPath ==
150 InstallMode::RootPath::RO);
151 WidgetUnzip wgtUnzip;
152 wgtUnzip.unzipWgtFile(widgetPath, tempDir);
155 _D("widgetPath: %s", widgetPath.c_str());
156 _D("tempPath: %s", tempDir.c_str());
158 m_context.widgetConfig.packagingType =
159 checkPackageType(widgetPath, tempDir);
160 ConfigParserData configData = getWidgetDataFromXML(
163 m_context.widgetConfig.packagingType,
164 m_context.mode.command == InstallMode::Command::REINSTALL);
165 _D("widget packaging type : %d", static_cast<WrtDB::PkgType>(m_context.widgetConfig.packagingType.pkgType));
167 setTizenId(configData);
168 setApplicationType(configData);
169 m_context.needEncryption = detectResourceEncryption(configData);
170 setInstallLocationType(configData);
171 // TODO: (job_install_refactoring) hide this call
172 m_context.callerPkgId =
173 DPL::FromUTF8String(m_context.job->GetInstallerStruct().pkgmgrInterface->getCallerId());
174 _D("Caller Package Id : %s", DPL::ToUTF8String(m_context.callerPkgId).c_str());
176 // Configure installation
177 result = ConfigureInstallation(widgetPath, configData, tempDir);
178 // TODO: (job_install_refactoring) hide this call
179 m_context.job->GetInstallerStruct().pkgmgrInterface->sendSignal(
183 m_context.isUpdateMode = result;
186 void TaskConfiguration::setTizenId(
187 const WrtDB::ConfigParserData &configInfo)
189 bool shouldMakeAppid = false;
190 using namespace PackageManager;
191 if (!!configInfo.tizenAppId) {
192 _D("Setting tizenAppId provided in config.xml: %ls", (*configInfo.tizenAppId).c_str());
193 m_context.widgetConfig.tzAppid = *configInfo.tizenAppId;
195 if (!!configInfo.tizenPkgId) {
196 _D("Setting tizenPkgId provided in config.xml: %ls", (*configInfo.tizenPkgId).c_str());
197 m_context.widgetConfig.tzPkgid = *configInfo.tizenPkgId;
199 DPL::String appid = *configInfo.tizenAppId;
200 if (appid.length() > PACKAGE_ID_LENGTH) {
201 m_context.widgetConfig.tzPkgid =
202 appid.substr(0, PACKAGE_ID_LENGTH);
204 //old version appid only has 10byte random character is able to install for a while.
205 //this case appid equal pkgid.
206 m_context.widgetConfig.tzPkgid =
207 *configInfo.tizenAppId;
208 shouldMakeAppid = true;
212 shouldMakeAppid = true;
213 TizenPkgId pkgId = WidgetDAOReadOnly::generatePkgId();
214 _D("Checking if pkg id is unique");
216 if (!validateTizenPackageID(pkgId)) {
217 //path exist, chose another one
218 pkgId = WidgetDAOReadOnly::generatePkgId();
223 m_context.widgetConfig.tzPkgid = pkgId;
224 _D("tizen_id name was generated by WRT: %ls", m_context.widgetConfig.tzPkgid.c_str());
227 if (shouldMakeAppid == true) {
228 DPL::OptionalString name;
229 DPL::OptionalString defaultLocale = configInfo.defaultlocale;
231 FOREACH(localizedData, configInfo.localizedDataSet)
233 Locale i = localizedData->first;
234 if (!!defaultLocale) {
235 if (defaultLocale == i) {
236 name = localizedData->second.name;
240 name = localizedData->second.name;
245 if (regcomp(®x, REG_NAME_PATTERN, REG_NOSUB | REG_EXTENDED) != 0) {
246 _D("Regcomp failed");
249 _D("Name : %ls", (*name).c_str());
250 if (!name || (regexec(®x, DPL::ToUTF8String(*name).c_str(),
251 static_cast<size_t>(0), NULL, 0) != REG_NOERROR))
253 // TODO : (job_install_refactoring) generate name move to wrt-commons
254 std::string allowedString("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
255 std::ostringstream genName;
257 gettimeofday(&tv, NULL);
258 unsigned int seed = time(NULL) + tv.tv_usec;
260 genName << "_" << allowedString[rand_r(&seed) % allowedString.length()];
261 name = DPL::FromUTF8String(genName.str());
262 _D("name was generated by WRT");
265 _D("Name : %ls", (*name).c_str());
266 std::ostringstream genid;
267 genid << m_context.widgetConfig.tzPkgid << "." << name;
268 _D("tizen appid was generated by WRT : %s", genid.str().c_str());
270 DPL::OptionalString appid = DPL::FromUTF8String(genid.str());
271 NormalizeAndTrimSpaceString(appid);
272 m_context.widgetConfig.tzAppid = *appid;
275 // send start signal of pkgmgr
276 // TODO: (job_install_refactoring) hide this call
277 m_context.job->GetInstallerStruct().pkgmgrInterface->setPkgname(DPL::ToUTF8String(
281 _D("Tizen App Id : %ls", m_context.widgetConfig.tzAppid.c_str());
282 _D("Tizen Pkg Id : %ls", m_context.widgetConfig.tzPkgid.c_str());
285 void TaskConfiguration::configureWidgetLocation(const std::string & widgetPath,
286 const std::string& tempPath)
288 m_context.locations =
289 WidgetLocation(DPL::ToUTF8String(m_context.widgetConfig.
291 widgetPath, tempPath,
292 m_context.widgetConfig.packagingType,
293 m_context.mode.rootPath ==
294 InstallMode::RootPath::RO,
295 m_context.mode.extension);
296 m_context.locations->registerAppid(
297 DPL::ToUTF8String(m_context.widgetConfig.tzAppid));
299 _D("widgetSource %s", widgetPath.c_str());
302 bool TaskConfiguration::ConfigureInstallation(
303 const std::string &widgetSource,
304 const WrtDB::ConfigParserData &configData,
305 const std::string &tempPath)
309 WidgetUpdateInfo update;
311 // checking installed web application
313 // no excpetion means, it isn't update mode
314 // TODO: (job_install_refactoring) hide this call/
315 m_context.job->GetInstallerStruct().pkgmgrInterface->sendSignal(
317 PKGMGR_START_UPDATE);
319 update = detectWidgetUpdate(configData,
320 m_context.widgetConfig.tzAppid);
321 result = checkWidgetUpdate(update);
323 // Already installed TizenAppId. return failed
324 ThrowMsg(Jobs::WidgetInstall::Exceptions::PackageAlreadyInstalled,
325 "package is already installed");
327 if (!checkSupportRDSUpdate(configData)) {
328 ThrowMsg(Jobs::WidgetInstall::Exceptions::NotSupportRDSUpdate,
329 "RDS update failed");
333 Catch(WidgetDAOReadOnly::Exception::WidgetNotExist) {
334 // TODO: (job_install_refactoring) hide this call
335 m_context.job->GetInstallerStruct().pkgmgrInterface->sendSignal(
337 PKGMGR_START_INSTALL);
340 if (!validateTizenApplicationID(
341 m_context.widgetConfig.tzAppid))
343 _E("tizen application ID is already used");
344 ThrowMsg(Jobs::WidgetInstall::Exceptions::WidgetConfigFileInvalid,
347 if (!validateTizenPackageID(m_context.widgetConfig.tzPkgid)) {
348 _E("tizen package ID is already used");
349 ThrowMsg(Jobs::WidgetInstall::Exceptions::PackageAlreadyInstalled,
350 "package is already installed");
354 configureWidgetLocation(widgetSource, tempPath);
359 bool TaskConfiguration::validateTizenApplicationID(
360 const WrtDB::TizenAppId &tizenAppId)
362 _D("tizen application ID = [%ls]", tizenAppId.c_str());
365 if (regcomp(®, REG_TIZENID_PATTERN, REG_NOSUB | REG_EXTENDED) != 0) {
366 _D("Regcomp failed");
369 if (regexec(®, DPL::ToUTF8String(tizenAppId).c_str(), 0, NULL, 0)
379 bool TaskConfiguration::validateTizenPackageID(
380 const WrtDB::TizenPkgId &tizenPkgId)
382 std::string pkgId = DPL::ToUTF8String(tizenPkgId);
384 std::string installPath =
385 std::string(GlobalConfig::GetUserInstalledWidgetPath()) +
389 if ((stat(installPath.c_str(), &dirStat) == 0))
396 bool TaskConfiguration::checkWidgetUpdate(
397 const WidgetUpdateInfo &update)
399 if (update.existingVersion.IsNull() || update.incomingVersion.IsNull()) {
403 _D("existing version = '%ls", update.existingVersion->Raw().c_str());
404 _D("incoming version = '%ls", update.incomingVersion->Raw().c_str());
405 _D("Tizen AppID = %ls", update.tzAppId.c_str());
407 // Check running state
408 bool isRunning = false;
410 app_manager_is_running(DPL::ToUTF8String(update.tzAppId).c_str(),
412 if (APP_MANAGER_ERROR_NONE != ret) {
413 _E("Fail to get running state");
414 ThrowMsg(Jobs::WidgetInstall::Exceptions::WidgetRunningError,
415 "widget is running");
418 if (true == isRunning) {
419 // get app_context for running application
420 // app_context must be released with app_context_destroy
421 app_context_h appCtx = NULL;
423 app_manager_get_app_context(
424 DPL::ToUTF8String(update.tzAppId).c_str(),
426 if (APP_MANAGER_ERROR_NONE != ret) {
427 _E("Fail to get app_context");
428 ThrowMsg(Jobs::WidgetInstall::Exceptions::WidgetRunningError,
429 "widget is running");
432 // terminate app_context_h
433 ret = app_manager_terminate_app(appCtx);
434 if (APP_MANAGER_ERROR_NONE != ret) {
435 _E("Fail to terminate running application");
436 app_context_destroy(appCtx);
437 ThrowMsg(Jobs::WidgetInstall::Exceptions::WidgetRunningError,
438 "widget is running");
440 app_context_destroy(appCtx);
441 // app_manager_terminate_app isn't sync API
442 // wait until application isn't running (50ms * 100)
443 bool isStillRunning = true;
444 int checkingloop = 100;
445 struct timespec duration = { 0, 50 * 1000 * 1000 };
446 while (--checkingloop >= 0) {
447 nanosleep(&duration, NULL);
449 app_manager_is_running(
450 DPL::ToUTF8String(update.tzAppId).c_str(),
452 if (APP_MANAGER_ERROR_NONE != ret) {
453 _E("Fail to get running state");
454 ThrowMsg(Jobs::WidgetInstall::Exceptions::WidgetRunningError,
455 "widget is running");
457 if (!isStillRunning) {
461 if (isStillRunning) {
462 _E("Fail to terminate running application");
463 ThrowMsg(Jobs::WidgetInstall::Exceptions::WidgetRunningError,
464 "widget is running");
466 _D("terminate application");
470 m_context.widgetConfig.tzAppid = update.tzAppId;
472 if (!!update.existingVersion ||
473 m_context.mode.extension ==
474 InstallMode::ExtensionType::DIR) {
481 ConfigParserData TaskConfiguration::getWidgetDataFromXML(
482 const std::string &widgetSource,
483 const std::string &tempPath,
484 WrtDB::PackagingType pkgType,
489 ConfigParserData configInfo;
492 if (pkgType == PKG_TYPE_HOSTED_WEB_APP) {
493 parser.Parse(widgetSource,
495 new RootParser<WidgetParser>(configInfo,
496 DPL::FromUTF32String(
499 std::string configFile;
500 configFile = tempPath + "/" + CONFIG_XML;
501 if (!WrtUtilFileExists(configFile)) {
502 configFile = tempPath + "/" + WITH_OSP_XML;
506 // checking RDS data directory
507 if (access(configFile.c_str(), F_OK) != 0) {
508 std::string tzAppId =
509 widgetSource.substr(widgetSource.find_last_of("/")+1);
510 WidgetDAOReadOnly dao(WidgetDAOReadOnly::getTzAppId(DPL::FromUTF8String(tzAppId)));
511 configFile = DPL::ToUTF8String(*dao.getWidgetInstalledPath());
513 configFile += WITH_OSP_XML;
517 if(!DPL::Utils::Path(configFile).Exists())
519 ThrowMsg(Exceptions::MissingConfig, "Config file not exists");
522 parser.Parse(configFile,
524 new RootParser<WidgetParser>(configInfo,
530 Catch(ElementParser::Exception::ParseError)
532 _E("Failed to parse config.xml file");
533 ThrowMsg(Exceptions::WidgetConfigFileInvalid, "Parser exeption");
535 Catch(WidgetDAOReadOnly::Exception::WidgetNotExist)
537 _E("Failed to find installed widget - give proper tizenId");
538 ThrowMsg(Exceptions::RDSDeltaFailure, "WidgetNotExist");
540 Catch(Exceptions::WidgetConfigFileNotFound){
541 _E("Failed to find config.xml");
542 ThrowMsg(Exceptions::MissingConfig, "Parser exeption");
548 WidgetUpdateInfo TaskConfiguration::detectWidgetUpdate(
549 const ConfigParserData &configInfo,
550 const WrtDB::TizenAppId &tizenId)
552 _D("Checking up widget package for config.xml...");
553 OptionalWidgetVersion incomingVersion;
555 if (!configInfo.version.IsNull()) {
557 DPL::Optional<WidgetVersion>(
558 WidgetVersion(*configInfo.version));
561 WidgetDAOReadOnly dao(tizenId);
563 OptionalWidgetVersion optVersion;
564 DPL::OptionalString version = dao.getVersion();
565 if (!version.IsNull()) {
566 optVersion = OptionalWidgetVersion(WidgetVersion(*version));
569 return WidgetUpdateInfo(
576 WrtDB::PackagingType TaskConfiguration::checkPackageType(
577 const std::string &widgetSource,
578 const std::string &tempPath)
580 if (hasExtension(widgetSource, XML_EXTENSION)) {
581 _D("Hosted app installation");
582 return PKG_TYPE_HOSTED_WEB_APP;
585 std::string configFile = tempPath + "/" + OSP_MANIFEST_XML;
586 if (WrtUtilFileExists(configFile)) {
587 return PKG_TYPE_HYBRID_WEB_APP;
590 return PKG_TYPE_NOMAL_WEB_APP;
593 void TaskConfiguration::setApplicationType(
594 const WrtDB::ConfigParserData &configInfo)
596 AppType widgetAppType = APP_TYPE_UNKNOWN;
597 FOREACH(iterator, configInfo.nameSpaces) {
598 _D("namespace = [%ls]", (*iterator).c_str());
600 if (*iterator == ConfigurationNamespace::TizenWebAppNamespaceName) {
601 widgetAppType = APP_TYPE_TIZENWEBAPP;
606 m_context.widgetConfig.webAppType = widgetAppType;
608 _D("type = [%s]", m_context.widgetConfig.webAppType.getApptypeToString().c_str());
611 bool TaskConfiguration::detectResourceEncryption(
612 const WrtDB::ConfigParserData &configData)
614 FOREACH(it, configData.settingsList)
616 if (it->m_name == SETTING_VALUE_ENCRYPTION &&
617 it->m_value == SETTING_VALUE_ENCRYPTION_ENABLE)
619 _D("resource need encryption");
626 void TaskConfiguration::setInstallLocationType(
627 const WrtDB::ConfigParserData & configData)
629 m_context.locationType = INSTALL_LOCATION_TYPE_NOMAL;
630 if (m_context.mode.installTime != InstallMode::InstallTime::PRELOAD) {
631 FOREACH(it, configData.settingsList) {
632 if (it->m_name == SETTING_VALUE_INSTALLTOEXT_NAME &&
634 SETTING_VALUE_INSTALLTOEXT_PREPER_EXT)
636 _D("This widget will be installed to sd card");
637 m_context.locationType =
638 INSTALL_LOCATION_TYPE_EXTERNAL;
644 bool TaskConfiguration::checkSupportRDSUpdate(const WrtDB::ConfigParserData
647 if (m_context.mode.command ==
648 InstallMode::Command::REINSTALL)
650 DPL::String configValue = SETTING_VALUE_ENCRYPTION_DISABLE;
651 DPL::String dbValue = SETTING_VALUE_ENCRYPTION_DISABLE;
653 WidgetDAOReadOnly dao(m_context.widgetConfig.tzAppid);
654 WrtDB::WidgetSettings widgetSettings;
655 dao.getWidgetSettings(widgetSettings);
657 FOREACH(it, widgetSettings) {
658 if (it->settingName == SETTING_VALUE_ENCRYPTION) {
659 dbValue = it->settingValue;
663 FOREACH(data, configInfo.settingsList)
665 if (data->m_name == SETTING_VALUE_ENCRYPTION)
667 configValue = data->m_value;
670 if (configValue != dbValue) {
671 _E("Not Support RDS mode because of encryption setting");