2 * Copyright (c) 2011 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 job_widget_install.cpp
18 * @author Radoslaw Wicik r.wicik@samsung.com
19 * @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
21 * @brief Implementation file for main installer task
23 #include <dpl/noncopyable.h>
24 #include <dpl/abstract_waitable_input_adapter.h>
25 #include <dpl/abstract_waitable_output_adapter.h>
26 #include <dpl/zip_input.h>
27 #include <dpl/scoped_ptr.h>
28 #include <dpl/binary_queue.h>
30 #include <dpl/assert.h>
31 #include <dpl/sstream.h>
32 #include "root_parser.h"
33 #include "widget_parser.h"
34 #include "parser_runner.h"
35 #include <widget_install/job_widget_install.h>
36 #include <widget_install/task_parental_mode.h>
37 #include <widget_install/task_unzip.h>
38 #include <widget_install/task_certify.h>
39 #include <widget_install/task_widget_config.h>
40 #include <widget_install/task_db_update.h>
41 #include <widget_install/task_ace_check.h>
42 #include <widget_install/task_smack.h>
43 #include <widget_install/task_desktop_file.h>
44 #include <widget_install/task_private_storage.h>
45 #include <widget_install/widget_install_errors.h>
46 #include <widget_install/widget_install_context.h>
48 #include <dpl/wrt-dao-rw/widget_dao.h> //TODO remove
49 #include <dpl/wrt-dao-ro/widget_dao_read_only.h>
50 #include <dpl/wrt-dao-rw/global_dao.h> // TODO remove
52 #include <dpl/localization/w3c_file_localization.h>
54 using namespace WrtDB;
56 namespace // anonymous
58 const char * const CONFIG_XML = "config.xml";
60 struct PathAndFilePair
65 PathAndFilePair(const std::string &p,
66 const std::string &f) :
73 PathAndFilePair SplitFileAndPath(const std::string &filePath)
75 std::string::size_type position = filePath.rfind('/');
77 // Is this only a file without a path ?
78 if (position == std::string::npos) {
79 return PathAndFilePair(std::string(), filePath);
82 // This is full file-path pair
83 return PathAndFilePair(filePath.substr(0,
85 filePath.substr(position + 1));
88 class InstallerTaskFail :
89 public DPL::TaskDecl<InstallerTaskFail>
97 ThrowMsg(Jobs::WidgetInstall::Exceptions::Deferred,
98 "Widget installation or update deferred!");
100 ThrowMsg(Jobs::WidgetInstall::Exceptions::NotAllowed,
101 "Widget installation or update not allowed!");
106 InstallerTaskFail(bool deferred) :
107 DPL::TaskDecl<InstallerTaskFail>(this),
110 AddStep(&InstallerTaskFail::StepFail);
113 } // namespace anonymous
116 namespace WidgetInstall {
117 JobWidgetInstall::JobWidgetInstall(std::string const &widgetPath,
118 const WidgetInstallationStruct &installerStruct) :
120 JobContextBase<WidgetInstallationStruct>(installerStruct),
121 m_exceptionCaught(Exceptions::Success)
123 // Configure installation
124 ConfigureResult result = ConfigureInstallation(widgetPath);
126 if (result == ConfigureResult::Ok) {
127 LogInfo("Configure installation succeeded");
129 // Create installation tasks
130 AddTask(new TaskParentalMode(m_installerContext));
131 AddTask(new TaskUnzip(m_installerContext));
132 AddTask(new TaskWidgetConfig(m_installerContext));
133 AddTask(new TaskCertify(m_installerContext));
134 AddTask(new TaskDbUpdate(m_installerContext));
135 // TODO: Update progress information for this task
137 AddTask(new TaskAceCheck(m_installerContext));
138 //This is sort of quick solution, because ACE verdicts are based upon
139 //data from DAO (DB). So AceCheck for now has to be AFTER DbUpdate
141 AddTask(new TaskSmack(m_installerContext));
143 AddTask(new TaskDesktopFile(m_installerContext));
144 AddTask(new TaskPrivateStorage(m_installerContext));
145 } else if (result == ConfigureResult::Deferred) {
146 // Installation is deferred
147 LogInfo("Configure installation deferred");
149 AddTask(new InstallerTaskFail(true));
150 } else if (result == ConfigureResult::Failed) {
151 // Installation is not allowed to proceed due to widget update policy
152 LogWarning("Configure installation failed!");
154 AddTask(new InstallerTaskFail(false));
156 Assert(false && "Invalid configure result!");
160 DPL::Optional<WidgetHandle> JobWidgetInstall::getNewWidgetHandle() const
162 return m_installerContext.widgetHandle;
165 bool JobWidgetInstall::getUnzipStartedFlag() const
167 return m_installerContext.unzipStarted;
170 bool JobWidgetInstall::getUnzipFinishedFlag() const
172 return m_installerContext.unzipFinished;
175 JobWidgetInstall::ConfigureResult JobWidgetInstall::ConfigureInstallation(
176 const std::string &widgetPath)
178 // Detect widget update
179 WidgetUpdateInfo update = detectWidgetUpdate(widgetPath);
182 "Widget install/update: incoming guid = '" <<
183 update.incomingGUID << "'");
185 "Widget install/update: incoming version = '" <<
186 update.incomingVersion << "'");
189 WidgetUpdateMode::Type updateTypeCheckBit;
191 if (update.existingWidgetInfo.isExist == false) {
192 LogInfo("Widget info does not exist");
193 updateTypeCheckBit = WidgetUpdateMode::NotInstalled;
195 LogInfo("Widget info exists. Handle: " <<
196 update.existingWidgetInfo.existingHandle);
198 DPL::OStringStream pkgName;
199 DPL::OptionalString pkgname =
200 WidgetDAOReadOnly(update.existingWidgetInfo.existingHandle).getPkgname();
202 if(pkgname.IsNull()) {
203 LogInfo("But widget package name doesn't exist");
204 return ConfigureResult::Failed;
207 LogInfo("Widget model exists. Package name: " << pkgName);
208 if (aul_app_is_running(DPL::ToUTF8String(*pkgname).c_str())) {
209 // Must be deferred when update in progress
210 if (m_jobStruct.updateMode == WidgetUpdateMode::PolicyWac) {
212 "Widget is already running. Policy is update according to WAC");
213 LogInfo("Installation deferred: " << widgetPath);
215 GlobalDAO::AddDefferedWidgetPackageInstallation(
216 DPL::FromUTF8String(widgetPath));
218 return ConfigureResult::Deferred;
221 "Widget is already running. Policy is not update according to WAC");
222 LogInfo("Installation aborted: " << widgetPath);
224 return ConfigureResult::Failed;
228 OptionalWidgetVersion existingVersion;
229 existingVersion = update.existingWidgetInfo.existingVersion;
230 OptionalWidgetVersion incomingVersion = update.incomingVersion;
232 updateTypeCheckBit = CalcWidgetUpdatePolicy(existingVersion,
237 bool canProceed = (m_jobStruct.updateMode & updateTypeCheckBit) > 0;
239 LogInfo("Whether widget policy allow proceed: " << canProceed);
241 // Init installer context
242 m_installerContext.widgetFilePath = widgetPath;
243 m_installerContext.tempWidgetPath = std::string();
244 m_installerContext.widgetConfig = WidgetRegisterInfo();
245 m_installerContext.unzipStarted = false;
246 m_installerContext.unzipFinished = false;
247 m_installerContext.installStep = InstallerContext::INSTALL_START;
248 m_installerContext.job = this;
249 m_installerContext.existingWidgetInfo = update.existingWidgetInfo;
250 m_installerContext.widgetConfig.shareHref = std::string();
253 return canProceed ? ConfigureResult::Ok : ConfigureResult::Failed;
256 WidgetUpdateMode::Type JobWidgetInstall::CalcWidgetUpdatePolicy(
257 const OptionalWidgetVersion &existingVersion,
258 const OptionalWidgetVersion &incomingVersion) const
260 // Widget is installed, check versions
261 if (!existingVersion && !incomingVersion) {
262 return WidgetUpdateMode::ExistingVersionEqual;
263 } else if (!existingVersion && !!incomingVersion) {
264 return WidgetUpdateMode::ExistingVersionNewer;
265 } else if (!!existingVersion && !incomingVersion) {
266 return WidgetUpdateMode::ExistingVersionOlder;
268 LogInfo("Existing widget: version = '" << *existingVersion << "'");
270 if (!existingVersion->IsWac() && !incomingVersion->IsWac()) {
271 return WidgetUpdateMode::BothVersionsNotStd;
272 } else if (!existingVersion->IsWac()) {
273 return WidgetUpdateMode::ExistingVersionNotStd;
274 } else if (!incomingVersion->IsWac()) {
275 return WidgetUpdateMode::IncomingVersionNotStd;
277 // Both versions are WAC-comparable. Do compare.
278 if (*incomingVersion == *existingVersion) {
279 return WidgetUpdateMode::ExistingVersionEqual;
280 } else if (*incomingVersion > *existingVersion) {
281 return WidgetUpdateMode::ExistingVersionOlder;
283 return WidgetUpdateMode::ExistingVersionNewer;
289 WidgetUpdateInfo JobWidgetInstall::detectWidgetUpdate(
290 const std::string &widgetPath)
292 LogInfo("Checking up widget package for config.xml...");
297 DPL::ScopedPtr<DPL::ZipInput> zipFile(
298 new DPL::ZipInput(widgetPath));
300 // Open config.xml file
301 DPL::ScopedPtr<DPL::ZipInput::File> configFile(
302 zipFile->OpenFile(CONFIG_XML));
305 DPL::BinaryQueue buffer;
306 DPL::AbstractWaitableInputAdapter inputAdapter(configFile.Get());
307 DPL::AbstractWaitableOutputAdapter outputAdapter(&buffer);
308 DPL::Copy(&inputAdapter, &outputAdapter);
312 ConfigParserData configInfo;
314 parser.Parse(&buffer,
316 new RootParser<WidgetParser>(configInfo,
317 DPL::FromUTF32String(
321 DPL::OptionalString widgetGUID = configInfo.widget_id;
323 if (widgetGUID.IsNull()) {
324 LogDebug("Installed widget has no GUID");
325 return WidgetUpdateInfo();
328 LogDebug("Installed widget GUID: " << *widgetGUID);
330 // Locate widget ID with this GUID
331 // Incoming widget version
332 OptionalWidgetVersion widgetVersion;
333 if (!configInfo.version.IsNull()) {
335 DPL::Optional<WidgetVersion>(
336 WidgetVersion(*configInfo.version));
341 // Search widget handle by GUID
342 WidgetDAO dao(widgetGUID);
343 return WidgetUpdateInfo(
346 WidgetUpdateInfo::ExistingWidgetInfo(
347 dao.getHandle(), dao.getVersion()));
349 Catch(WidgetDAO::Exception::WidgetNotExist){
350 // GUID isn't installed
351 return WidgetUpdateInfo(
354 WidgetUpdateInfo::ExistingWidgetInfo());
357 Catch(DPL::ZipInput::Exception::OpenFailed)
359 LogDebug("Failed to open widget package");
360 return WidgetUpdateInfo();
362 Catch(DPL::ZipInput::Exception::OpenFileFailed)
364 LogDebug("Failed to open config.xml file");
365 return WidgetUpdateInfo();
367 Catch(DPL::CopyFailed)
369 LogDebug("Failed to extract config.xml file");
370 return WidgetUpdateInfo();
372 Catch(ElementParser::Exception::ParseError)
374 LogDebug("Failed to parse config.xml file");
375 return WidgetUpdateInfo();
379 void JobWidgetInstall::SendProgress()
381 if (GetProgressFlag() != false) {
382 if (getInstallerStruct().progressCallback != NULL) {
384 LogDebug("Call widget install progressCallbak");
385 getInstallerStruct().progressCallback(getInstallerStruct().userParam,
386 GetProgressPercent(),GetProgressDescription());
391 void JobWidgetInstall::SendFinishedSuccess()
394 JobWidgetInstall::displayWidgetInfo();
396 DPL::Optional<WidgetHandle> handle = getNewWidgetHandle();
397 const WidgetHandle INVALID_WIDGET_HANDLE = 0;
399 LogDebug("Call widget install successfinishedCallback");
400 getInstallerStruct().finishedCallback(getInstallerStruct().userParam,
401 !!handle ? *handle : INVALID_WIDGET_HANDLE, Exceptions::Success);
404 void JobWidgetInstall::SendFinishedFailure()
406 LogError("Error in installation step: " << m_exceptionCaught);
407 LogError("Message: " << m_exceptionMessage);
408 DPL::Optional<WidgetHandle> handle = getNewWidgetHandle();
409 const WidgetHandle INVALID_WIDGET_HANDLE = 0;
411 LogDebug("Call widget install failure finishedCallback");
412 getInstallerStruct().finishedCallback(getInstallerStruct().userParam,
413 !!handle ? *handle : INVALID_WIDGET_HANDLE, m_exceptionCaught);
416 void JobWidgetInstall::SaveExceptionData(const Jobs::JobExceptionBase &e)
418 m_exceptionCaught = static_cast<Exceptions::Type>(e.getParam());
419 m_exceptionMessage = e.GetMessage();
422 void JobWidgetInstall::displayWidgetInfo()
424 DPL::Optional<WidgetHandle> handle = getNewWidgetHandle();
427 WidgetDAO dao(*handle);
429 std::ostringstream out;
430 WidgetLocalizedInfo localizedInfo =
431 W3CFileLocalization::getLocalizedInfo(*handle);
434 "===================================== INSTALLED WIDGET INFO ========="\
435 "============================";
436 out << std::endl << "Name: " << localizedInfo.name;
437 WidgetSize size = dao.getPreferredSize();
438 out << std::endl << "Width: " << size.width;
439 out << std::endl << "Height: " << size.height;
440 out << std::endl << "Start File: " <<
441 W3CFileLocalization::getStartFile(*handle);
442 out << std::endl << "Version: " << dao.getVersion();
443 out << std::endl << "Licence: " <<
444 localizedInfo.license;
445 out << std::endl << "Licence Href: " <<
446 localizedInfo.licenseHref;
447 out << std::endl << "Description: " <<
448 localizedInfo.description;
449 out << std::endl << "Widget Id: " << dao.getGUID();
450 out << std::endl << "Widget recognized: " << dao.isRecognized();
451 out << std::endl << "Widget wac signed: " << dao.isWacSigned();
452 out << std::endl << "Widget distributor signed: " <<
453 dao.isDistributorSigned();
454 out << std::endl << "Widget trusted: " << dao.isTrusted();
456 OptionalWidgetIcon icon = W3CFileLocalization::getIcon(*handle);
457 DPL::OptionalString iconSrc =
458 !!icon ? icon->src : DPL::OptionalString::Null;
459 out << std::endl << "Icon: " << iconSrc;
461 out << std::endl << "Preferences:";
463 PropertyDAOReadOnly::WidgetPreferenceList list = dao.getPropertyList();
466 out << std::endl << " Key: " <<
468 out << std::endl << " Readonly: " <<
473 out << std::endl << "Features:";
475 WidgetFeatureSet list = dao.getFeaturesList();
478 out << std::endl << " Name: " << it->name;
479 out << std::endl << " Required: " << it->required;
480 out << std::endl << " Params:";
484 out << std::endl << "Back Supported: " <<
485 (dao.getBackSupported() ? "YES" : "NO");
491 } //namespace WidgetInstall