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"
34 #include <dpl/utils/wrt_utility.h>
35 #include <dpl/utils/path.h>
36 #include <dpl/wrt-dao-ro/common_dao_types.h>
37 #include <dpl/wrt-dao-ro/widget_dao_read_only.h>
38 #include <dpl/wrt-dao-ro/global_config.h>
39 #include <dpl/wrt-dao-ro/config_parser_data.h>
40 #include <dpl/localization/w3c_file_localization.h>
42 #include <libiriwrapper.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_PKGID_PATTERN = "^[a-zA-Z0-9]{10}$";
68 const char* REG_NAME_PATTERN = "^[a-zA-Z0-9._-]{1,}$";
69 const size_t PACKAGE_ID_LENGTH = 10;
71 static const DPL::String SETTING_VALUE_ENCRYPTION = L"encryption";
72 static const DPL::String SETTING_VALUE_ENCRYPTION_ENABLE = L"enable";
73 static const DPL::String SETTING_VALUE_ENCRYPTION_DISABLE = L"disable";
74 const DPL::String SETTING_VALUE_INSTALLTOEXT_NAME = L"install-location";
75 const DPL::String SETTING_VALUE_INSTALLTOEXT_PREPER_EXT = L"prefer-external";
76 const DPL::String SETTING_VALUE_INSTALLTOEXT_AUTO = L"auto";
77 const std::string XML_EXTENSION = ".xml";
79 bool hasExtension(const std::string& filename, const std::string& extension)
81 _D("Looking for extension %s in %s", extension.c_str(), filename.c_str());
82 size_t fileLen = filename.length();
83 size_t extLen = extension.length();
84 if (fileLen < extLen) {
85 _E("Filename %s is shorter than extension %s", filename.c_str(), extension.c_str());
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_widgetConfig(m_context.widgetConfig.configInfo)
100 AddStep(&TaskConfiguration::StartStep);
102 AddStep(&TaskConfiguration::SetupTempDirStep);
103 AddStep(&TaskConfiguration::CheckPackageTypeStep);
105 AddStep(&TaskConfiguration::ParseXMLConfigStep);
107 AddStep(&TaskConfiguration::TizenIdStep);
108 AddStep(&TaskConfiguration::LockInstallationStep);
109 AddStep(&TaskConfiguration::CheckAppRunningStateStep);
110 AddStep(&TaskConfiguration::ApplicationTypeStep);
111 AddStep(&TaskConfiguration::ResourceEncryptionStep);
112 AddStep(&TaskConfiguration::InstallationFSLocationStep);
114 AddStep(&TaskConfiguration::DetectUpdateInstallationStep);
115 AddStep(&TaskConfiguration::CheckRDSSupportStep);
116 AddStep(&TaskConfiguration::ConfigureWidgetLocationStep);
117 AddStep(&TaskConfiguration::PkgmgrStartStep);
119 AddStep(&TaskConfiguration::AppendTasklistStep);
121 AddStep(&TaskConfiguration::EndStep);
124 void TaskConfiguration::StartStep()
126 _D("--------- <TaskConfiguration> : START ----------");
129 void TaskConfiguration::EndStep()
131 _D("--------- <TaskConfiguration> : END ----------");
134 void TaskConfiguration::PkgmgrStartStep()
136 pkgMgrInterface()->sendProgress(0);
139 void TaskConfiguration::AppendTasklistStep()
141 if (!m_context.isUpdateMode) {
142 _D("TaskConfiguration -> new installation task list");
143 m_context.job->appendNewInstallationTaskList();
145 _D("TaskConfiguration -> update installation task list");
146 m_context.job->appendUpdateInstallationTaskList();
150 std::shared_ptr<PackageManager::IPkgmgrSignal> TaskConfiguration::pkgMgrInterface()
152 return m_context.job->GetInstallerStruct().pkgmgrInterface;
155 void TaskConfiguration::SetupTempDirStep()
157 _D("widgetPath: %s", m_context.requestedPath.c_str());
158 _D("tempPath: %s", m_tempDir.c_str());
159 if (m_context.mode.extension == InstallMode::ExtensionType::DIR) {
160 if (m_context.mode.command ==
161 InstallMode::Command::REINSTALL) {
162 std::ostringstream tempPathBuilder;
163 tempPathBuilder << WrtDB::GlobalConfig::GetUserInstalledWidgetPath();
164 tempPathBuilder << WrtDB::GlobalConfig::GetTmpDirPath();
165 tempPathBuilder << "/";
166 tempPathBuilder << m_context.requestedPath;
167 m_tempDir = tempPathBuilder.str();
169 m_tempDir = m_context.requestedPath;
173 Jobs::WidgetInstall::createTempPath(
174 m_context.mode.rootPath ==
175 InstallMode::RootPath::RO);
176 if(!hasExtension(m_context.requestedPath, XML_EXTENSION)) //unzip everything except xml files
178 WidgetUnzip wgtUnzip;
179 wgtUnzip.unzipWgtFile(m_context.requestedPath, m_tempDir);
183 _D("From browser installation - unzip is not done");
188 void TaskConfiguration::ParseXMLConfigStep()
190 parseWidgetXMLConfig(
191 m_context.requestedPath, m_tempDir,
192 m_context.widgetConfig.packagingType,
193 m_context.mode.command == InstallMode::Command::REINSTALL);
194 _D("widget packaging type : %d", static_cast<WrtDB::PkgType>(m_context.widgetConfig.packagingType.pkgType));
197 void TaskConfiguration::TizenIdStep()
199 bool shouldMakeAppid = false;
200 using namespace PackageManager;
202 if (!!m_widgetConfig.tizenAppId) {
203 _D("Setting tizenAppId provided in config.xml: %s", DPL::ToUTF8String(*m_widgetConfig.tizenAppId).c_str());
205 m_context.widgetConfig.tzAppid = *m_widgetConfig.tizenAppId;
207 if (!!m_widgetConfig.tizenPkgId) {
208 _D("Setting tizenPkgId provided in config.xml: %s", DPL::ToUTF8String(*m_widgetConfig.tizenPkgId).c_str());
210 m_context.widgetConfig.tzPkgid = *m_widgetConfig.tizenPkgId;
212 DPL::String appid = *m_widgetConfig.tizenAppId;
213 if (appid.length() > PACKAGE_ID_LENGTH) {
214 m_context.widgetConfig.tzPkgid =
215 appid.substr(0, PACKAGE_ID_LENGTH);
217 //old version appid only has 10byte random character is able to install for a while.
218 //this case appid equal pkgid.
219 m_context.widgetConfig.tzPkgid =
220 *m_widgetConfig.tizenAppId;
221 shouldMakeAppid = true;
225 shouldMakeAppid = true;
226 TizenPkgId pkgId = WidgetDAOReadOnly::generatePkgId();
227 _D("Checking if pkg id is unique");
229 if (!validateTizenPackageID(pkgId)) {
230 //path exist, chose another one
231 pkgId = WidgetDAOReadOnly::generatePkgId();
236 m_context.widgetConfig.tzPkgid = pkgId;
237 _D("tizen_id name was generated by WRT: %ls", m_context.widgetConfig.tzPkgid.c_str());
240 if (shouldMakeAppid == true) {
241 DPL::OptionalString name;
242 DPL::OptionalString defaultLocale = m_widgetConfig.defaultlocale;
244 FOREACH(localizedData, m_widgetConfig.localizedDataSet)
246 Locale i = localizedData->first;
247 if (!!defaultLocale) {
248 if (defaultLocale == i) {
249 name = localizedData->second.name;
253 name = localizedData->second.name;
258 if (regcomp(®x, REG_NAME_PATTERN, REG_NOSUB | REG_EXTENDED) != 0) {
259 _D("Regcomp failed");
262 _D("Name : %ls", (*name).c_str());
263 if (!name || (regexec(®x, DPL::ToUTF8String(*name).c_str(),
264 static_cast<size_t>(0), NULL, 0) != REG_NOERROR))
266 const std::string allowedString("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
267 std::ostringstream genName;
269 gettimeofday(&tv, NULL);
270 unsigned int seed = time(NULL) + tv.tv_usec;
272 genName << "_" << allowedString[rand_r(&seed) % allowedString.length()];
273 name = DPL::FromUTF8String(genName.str());
274 _D("name was generated by WRT");
277 _D("Name : %ls", (*name).c_str());
278 std::ostringstream genid;
279 genid << m_context.widgetConfig.tzPkgid << "." << name;
280 _D("tizen appid was generated by WRT : %s", genid.str().c_str());
282 DPL::OptionalString appid = DPL::FromUTF8String(genid.str());
283 NormalizeAndTrimSpaceString(appid);
284 m_context.widgetConfig.tzAppid = *appid;
287 // send start signal of pkgmgr
288 pkgMgrInterface()->setPkgname(DPL::ToUTF8String(m_context.widgetConfig.tzPkgid));
290 _D("Tizen App Id : %ls", (m_context.widgetConfig.tzAppid).c_str());
291 _D("Tizen Pkg Id : %ls", (m_context.widgetConfig.tzPkgid).c_str());
294 void TaskConfiguration::LockInstallationStep()
296 std::string lockString = DPL::ToUTF8String(m_context.widgetConfig.tzAppid);
297 _D("Locking installation on file '%s'", lockString.c_str());
298 m_context.installationLock.reset(new DPL::FileBasedMutex(lockString));
299 _D("Installation locked");
302 void TaskConfiguration::CheckAppRunningStateStep()
304 bool isRunning = false;
306 app_manager_is_running(DPL::ToUTF8String(m_context.widgetConfig.tzAppid).c_str(),
308 if (APP_MANAGER_ERROR_NONE != ret) {
309 _E("Fail to get running state");
310 ThrowMsg(Jobs::WidgetInstall::Exceptions::WidgetRunningError,
311 "widget is running");
314 if (true == isRunning) {
315 // get app_context for running application
316 // app_context must be released with app_context_destroy
317 app_context_h appCtx = NULL;
319 app_manager_get_app_context(
320 DPL::ToUTF8String(m_context.widgetConfig.tzAppid).c_str(),
322 if (APP_MANAGER_ERROR_NONE != ret) {
323 _E("Fail to get app_context");
324 ThrowMsg(Jobs::WidgetInstall::Exceptions::WidgetRunningError,
325 "widget is running");
328 // terminate app_context_h
329 ret = app_manager_terminate_app(appCtx);
330 if (APP_MANAGER_ERROR_NONE != ret) {
331 _E("Fail to terminate running application");
332 app_context_destroy(appCtx);
333 ThrowMsg(Jobs::WidgetInstall::Exceptions::WidgetRunningError,
334 "widget is running");
336 app_context_destroy(appCtx);
337 // app_manager_terminate_app isn't sync API
338 // wait until application isn't running (50ms * 100)
339 bool isStillRunning = true;
340 int checkingloop = 100;
341 struct timespec duration = { 0, 50 * 1000 * 1000 };
342 while (--checkingloop >= 0) {
343 nanosleep(&duration, NULL);
344 int ret = app_manager_is_running(
345 DPL::ToUTF8String(m_context.widgetConfig.tzAppid).c_str(),
347 if (APP_MANAGER_ERROR_NONE != ret) {
348 _E("Fail to get running state");
349 ThrowMsg(Jobs::WidgetInstall::Exceptions::WidgetRunningError,
350 "widget is running");
352 if (!isStillRunning) {
356 if (isStillRunning) {
357 _E("Fail to terminate running application");
358 ThrowMsg(Jobs::WidgetInstall::Exceptions::WidgetRunningError,
359 "widget is running");
361 _D("terminate application");
366 void TaskConfiguration::ConfigureWidgetLocationStep()
368 m_context.locations =
369 WidgetLocation(DPL::ToUTF8String(m_context.widgetConfig.tzPkgid),
370 m_context.requestedPath, m_tempDir,
371 m_context.widgetConfig.packagingType,
372 m_context.mode.rootPath ==
373 InstallMode::RootPath::RO,
374 m_context.mode.extension);
375 m_context.locations->registerAppid(
376 DPL::ToUTF8String(m_context.widgetConfig.tzAppid));
378 _D("widgetSource %s", m_context.requestedPath.c_str());
381 void TaskConfiguration::DetectUpdateInstallationStep()
383 WidgetUpdateInfo update;
384 // checking installed web application
386 // no excpetion means, it isn't update mode
387 update = detectWidgetUpdate(m_widgetConfig,
388 m_context.widgetConfig.tzAppid);
389 checkWidgetUpdate(update);
391 m_context.isUpdateMode = true;
393 //if update, notify pkgmgr that this is update
394 pkgMgrInterface()->startJob(InstallationType::UpdateInstallation);
396 Catch(WidgetDAOReadOnly::Exception::WidgetNotExist) {
397 pkgMgrInterface()->startJob(InstallationType::NewInstallation);
399 m_context.isUpdateMode = false;
401 if (!validateTizenApplicationID(
402 m_context.widgetConfig.tzAppid))
404 _E("tizen application ID is already used");
405 ThrowMsg(Jobs::WidgetInstall::Exceptions::WidgetConfigFileInvalid,
408 if (!validateTizenPackageID(m_context.widgetConfig.tzPkgid)) {
409 _E("tizen package ID is already used");
410 ThrowMsg(Jobs::WidgetInstall::Exceptions::PackageAlreadyInstalled,
411 "package is already installed");
416 void TaskConfiguration::CheckRDSSupportStep()
418 //update needs RDS support to go ahead if REINSTALL command is given
419 if(m_context.isUpdateMode)
421 if (!checkSupportRDSUpdateIfReinstall(m_widgetConfig)) {
422 ThrowMsg(Jobs::WidgetInstall::Exceptions::NotSupportRDSUpdate,
423 "RDS update failed");
428 bool TaskConfiguration::validateTizenApplicationID(
429 const WrtDB::TizenAppId &tizenAppId)
431 _D("tizen application ID = [%ls]", tizenAppId.c_str());
434 if (regcomp(®, REG_TIZENID_PATTERN, REG_NOSUB | REG_EXTENDED) != 0) {
435 _D("Regcomp failed");
439 if (regexec(®, DPL::ToUTF8String(tizenAppId).c_str(), 0, NULL, 0)
449 bool TaskConfiguration::validateTizenPackageID(
450 const WrtDB::TizenPkgId &tizenPkgId)
452 _D("tizen application ID = [%ls]", tizenPkgId.c_str());
455 if (regcomp(®, REG_PKGID_PATTERN, REG_NOSUB | REG_EXTENDED) != 0)
457 _D("Regcomp failed");
460 if (regexec(®, DPL::ToUTF8String(tizenPkgId).c_str(), 0, NULL, 0) == REG_NOMATCH)
469 bool TaskConfiguration::checkWidgetUpdate(
470 const WidgetUpdateInfo &update)
472 if (update.existingVersion.IsNull() || update.incomingVersion.IsNull()) {
476 _D("existing version = '%ls", update.existingVersion->Raw().c_str());
477 _D("incoming version = '%ls", update.incomingVersion->Raw().c_str());
478 _D("Tizen AppID = %ls", update.tzAppId.c_str());
480 m_context.widgetConfig.tzAppid = update.tzAppId;
482 if (!!update.existingVersion ||
483 m_context.mode.extension ==
484 InstallMode::ExtensionType::DIR) {
491 void TaskConfiguration::parseWidgetXMLConfig(
492 const std::string &widgetSource,
493 const std::string &tempPath,
494 WrtDB::PackagingType pkgType,
501 if (pkgType == PKG_TYPE_HOSTED_WEB_APP) {
502 parser.Parse(widgetSource,
504 new RootParser<WidgetParser>(m_widgetConfig,
505 DPL::FromUTF32String(
508 std::string configFile;
509 configFile = tempPath + "/" + CONFIG_XML;
510 if (!WrtUtilFileExists(configFile)) {
511 configFile = tempPath + "/" + WITH_OSP_XML;
515 // checking RDS data directory
516 if (access(configFile.c_str(), F_OK) != 0) {
517 std::string tzAppId =
518 widgetSource.substr(widgetSource.find_last_of("/")+1);
519 WidgetDAOReadOnly dao(WidgetDAOReadOnly::getTzAppId(DPL::FromUTF8String(tzAppId)));
520 configFile = DPL::ToUTF8String(*dao.getWidgetInstalledPath());
522 configFile += WITH_OSP_XML;
526 if(!DPL::Utils::Path(configFile).Exists())
528 ThrowMsg(Exceptions::MissingConfig, "Config file not exists");
531 #ifdef SCHEMA_VALIDATION_ENABLED
532 if(!parser.Validate(configFilePath, WRT_WIDGETS_XML_SCHEMA))
534 _E("Invalid configuration file - schema validation failed");
535 ThrowMsg(Exceptions::WidgetConfigFileInvalid, "Failed to parse config.xml file");
538 parser.Parse(configFile,
540 new RootParser<WidgetParser>(m_widgetConfig,
546 Catch(ElementParser::Exception::ParseError)
548 _E("Failed to parse config.xml file");
549 ThrowMsg(Exceptions::WidgetConfigFileInvalid, "Parser exeption");
551 Catch(WidgetDAOReadOnly::Exception::WidgetNotExist)
553 _E("Failed to find installed widget - give proper tizenId");
554 ThrowMsg(Exceptions::RDSDeltaFailure, "WidgetNotExist");
556 Catch(Exceptions::WidgetConfigFileNotFound){
557 _E("Failed to find config.xml");
558 ThrowMsg(Exceptions::MissingConfig, "Parser exeption");
562 WidgetUpdateInfo TaskConfiguration::detectWidgetUpdate(
563 const ConfigParserData &configInfo,
564 const WrtDB::TizenAppId &tizenId)
566 _D("Checking up widget package for config.xml...");
567 OptionalWidgetVersion incomingVersion;
569 if (!configInfo.version.IsNull()) {
571 DPL::Optional<WidgetVersion>(
572 WidgetVersion(*configInfo.version));
575 WidgetDAOReadOnly dao(tizenId);
577 OptionalWidgetVersion optVersion;
578 DPL::OptionalString version = dao.getVersion();
579 if (!version.IsNull()) {
580 optVersion = OptionalWidgetVersion(WidgetVersion(*version));
583 return WidgetUpdateInfo(
589 void TaskConfiguration::CheckPackageTypeStep()
591 if (hasExtension(m_context.requestedPath, XML_EXTENSION)) {
592 _D("Hosted app installation");
593 m_context.widgetConfig.packagingType = PKG_TYPE_HOSTED_WEB_APP;
597 std::string configFile = m_tempDir + "/" + OSP_MANIFEST_XML;
598 if (WrtUtilFileExists(configFile)) {
599 m_context.widgetConfig.packagingType = PKG_TYPE_HYBRID_WEB_APP;
603 m_context.widgetConfig.packagingType = PKG_TYPE_NOMAL_WEB_APP;
606 void TaskConfiguration::ApplicationTypeStep() //TODO: is this really needed as WAC is not supported?
608 AppType widgetAppType = APP_TYPE_UNKNOWN;
609 FOREACH(iterator, m_widgetConfig.nameSpaces) {
610 _D("namespace = [%ls]", (*iterator).c_str());
612 if (*iterator == ConfigurationNamespace::TizenWebAppNamespaceName) {
613 widgetAppType = APP_TYPE_TIZENWEBAPP;
618 m_context.widgetConfig.webAppType = widgetAppType;
620 _D("type = [%s]", m_context.widgetConfig.webAppType.getApptypeToString().c_str());
623 void TaskConfiguration::ResourceEncryptionStep()
625 m_context.needEncryption = false;
626 FOREACH(it, m_widgetConfig.settingsList)
628 if (it->m_name == SETTING_VALUE_ENCRYPTION &&
629 it->m_value == SETTING_VALUE_ENCRYPTION_ENABLE)
631 _D("resource need encryption");
632 m_context.needEncryption = true;
637 bool TaskConfiguration::getMMCStatus()
640 if (vconf_get_int(VCONFKEY_SYSMAN_MMC_STATUS, &mmcStatus)) {
641 _E("vconf_get_int(VCONFKEY_SYSMAN_MMC_STATUS) failed.");
647 case VCONFKEY_SYSMAN_MMC_MOUNTED:
648 _D("mmcStatus is MMC_MOUNTED.");
650 case VCONFKEY_SYSMAN_MMC_REMOVED:
651 case VCONFKEY_SYSMAN_MMC_INSERTED_NOT_MOUNTED:
652 _D("mmcStatus is MMC_REMOVED or NOT_MOUNTED.");
655 _E("Platform is not supported, use the default settings");
660 bool TaskConfiguration::getDefaultExternalStorage()
662 // XXX NOT IMPLEMENTED.
666 void TaskConfiguration::InstallationFSLocationStep()
668 m_context.locationType = INSTALL_LOCATION_TYPE_NOMAL;
669 DPL::String locationValue;
671 if (m_context.mode.installTime != InstallMode::InstallTime::PRELOAD) {
672 FOREACH(it, m_widgetConfig.settingsList) {
673 if (it->m_name == SETTING_VALUE_INSTALLTOEXT_NAME) {
674 locationValue = it->m_value;
679 if ((SETTING_VALUE_INSTALLTOEXT_PREPER_EXT == locationValue
680 && getMMCStatus()) ||
681 (SETTING_VALUE_INSTALLTOEXT_AUTO == locationValue
682 && getDefaultExternalStorage())) {
683 _D("This webapp will be installed to sd card");
684 m_context.locationType = INSTALL_LOCATION_TYPE_EXTERNAL;
689 bool TaskConfiguration::checkSupportRDSUpdateIfReinstall(const WrtDB::ConfigParserData
692 if (m_context.mode.command ==
693 InstallMode::Command::REINSTALL)
695 DPL::String configValue = SETTING_VALUE_ENCRYPTION_DISABLE;
696 DPL::String dbValue = SETTING_VALUE_ENCRYPTION_DISABLE;
698 WidgetDAOReadOnly dao(m_context.widgetConfig.tzAppid);
699 WrtDB::WidgetSettings widgetSettings;
700 dao.getWidgetSettings(widgetSettings);
702 FOREACH(it, widgetSettings) {
703 if (it->settingName == SETTING_VALUE_ENCRYPTION) {
704 dbValue = it->settingValue;
708 FOREACH(data, configInfo.settingsList)
710 if (data->m_name == SETTING_VALUE_ENCRYPTION)
712 configValue = data->m_value;
715 if (configValue != dbValue) {
716 _E("Not Support RDS mode because of encryption setting");