Tizen 2.4.0 rev3 SDK Public Release
[framework/web/wrt-installer.git] / src / jobs / widget_install / job_widget_install.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 /*
17  * @file    job_widget_install.cpp
18  * @author  Radoslaw Wicik r.wicik@samsung.com
19  * @author  Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
20  * @version 1.0
21  * @brief   Implementation file for main installer task
22  */
23 #include <string>
24 #include <sys/time.h>
25 #include <ctime>
26 #include <cstdlib>
27 #include <limits.h>
28 #include <regex.h>
29
30 #include <dpl/platform.h>
31 #include <dpl/utils/wrt_utility.h>
32 #include <dpl/utils/path.h>
33 #include <dpl/localization/w3c_file_localization.h>
34
35 #include <pkg-manager/pkgmgr_signal.h>
36 #include <app_manager.h>
37 #include <privilege-control.h>
38 #include "root_parser.h"
39 #include "widget_parser.h"
40 #include "parser_runner.h"
41 #include <widget_install/job_widget_install.h>
42 #include <widget_install/task_certify.h>
43 #include <widget_install/task_process_config.h>
44 #include <widget_install/task_file_manipulation.h>
45 #include <widget_install/task_ace_check.h>
46 #include <widget_install/task_smack.h>
47 #include <widget_install/task_manifest_file.h>
48 #include <widget_install/task_prepare_files.h>
49 #include <widget_install/task_recovery.h>
50 #include <widget_install/task_install_ospsvc.h>
51 #include <widget_install/task_update_files.h>
52 #include <widget_install/task_database.h>
53 #include <widget_install/task_remove_backup.h>
54 #include <widget_install/task_encrypt_resource.h>
55 #include <widget_install/task_pkg_info_update.h>
56 #include <widget_install/task_commons.h>
57 #include <widget_install/task_prepare_reinstall.h>
58 #include <widget_install/task_configuration.h>
59 #include <widget_install/task_user_data_manipulation.h>
60 #include <widget_install/task_status_check.h>
61 #if ENABLE(PRE_LAUNCH)
62 #include <widget_install/task_prelaunching_registration.h>
63 #endif
64 #include <widget_install_to_external.h>
65 #include <boost/filesystem.hpp>
66 #include <dpl/log/secure_log.h>
67
68 namespace bf = boost::filesystem;
69
70 using namespace WrtDB;
71 using namespace Jobs::Exceptions;
72
73 namespace Jobs {
74 namespace WidgetInstall {
75
76 JobWidgetInstall::JobWidgetInstall(
77     std::string const &widgetPath,
78     std::string const &tzPkgId,
79     const Jobs::WidgetInstall::WidgetInstallationStruct &
80     installerStruct) :
81     Job(UnknownInstallation),
82     JobContextBase<Jobs::WidgetInstall::WidgetInstallationStruct>(installerStruct),
83     m_exceptionCaught(Jobs::Exceptions::Success)
84 {
85     m_installerContext.mode = m_jobStruct.m_installMode;
86     m_installerContext.requestedPath = widgetPath;
87     m_jobStruct.pkgmgrInterface->setPkgname(tzPkgId);
88
89     if (InstallMode::Command::RECOVERY == m_installerContext.mode.command) {
90         m_installerContext.widgetConfig.tzPkgid = DPL::FromUTF8String(tzPkgId);
91         AddTask(new TaskRecovery(this));
92     }
93
94     //start configuration of installation
95     AddTask(new TaskConfiguration(this));
96
97     m_installerContext.callerPkgId
98             = DPL::FromUTF8String(m_jobStruct.pkgmgrInterface->getCallerId());
99     _D("Caller Package Id : %s", DPL::ToUTF8String(m_installerContext.callerPkgId).c_str());
100 }
101
102 void JobWidgetInstall::appendNewInstallationTaskList()
103 {
104     _D("Configure installation succeeded");
105     SetProgressFlag(true);
106
107     AddTask(new TaskFileManipulation(this));
108     AddTask(new TaskProcessConfig(this));
109     if (m_installerContext.widgetConfig.packagingType ==
110         WrtDB::PKG_TYPE_HOSTED_WEB_APP)
111     {
112         AddTask(new TaskPrepareFiles(this));
113     }
114     AddTask(new TaskCertify(this));
115     AddTask(new TaskUserDataManipulation(this));
116     if (m_installerContext.needEncryption) {
117         AddTask(new TaskEncryptResource(this));
118     }
119     AddTask(new TaskManifestFile(this));
120     if (m_installerContext.widgetConfig.packagingType ==
121         PKG_TYPE_HYBRID_WEB_APP) {
122         AddTask(new TaskInstallOspsvc(this));
123     }
124     AddTask(new TaskDatabase(this));
125     AddTask(new TaskAceCheck(this));
126     AddTask(new TaskSmack(this));
127     AddTask(new TaskPkgInfoUpdate(this));
128 #if ENABLE(PRE_LAUNCH)
129     if (m_installerContext.isNeedPreLaunching) {
130         AddTask(new TaskPreLaunchingRegistration(this));
131     }
132 #endif
133 }
134
135 void JobWidgetInstall::appendUpdateInstallationTaskList()
136 {
137     _D("Configure installation updated");
138     _D("Widget Update");
139     SetProgressFlag(true);
140     AddTask(new TaskStatusCheck(this));
141
142     if (m_installerContext.mode.command ==
143         InstallMode::Command::REINSTALL) {
144         AddTask(new TaskPrepareReinstall(this));
145     }
146
147     if (m_installerContext.mode.extension !=
148             InstallMode::ExtensionType::DIRECTORY) {
149         AddTask(new TaskUpdateFiles(this));
150         AddTask(new TaskFileManipulation(this));
151     }
152
153     AddTask(new TaskProcessConfig(this));
154
155     if (m_installerContext.widgetConfig.packagingType ==
156         WrtDB::PKG_TYPE_HOSTED_WEB_APP) {
157         AddTask(new TaskPrepareFiles(this));
158     }
159
160     AddTask(new TaskCertify(this));
161     AddTask(new TaskUserDataManipulation(this));
162     if (m_installerContext.needEncryption) {
163         AddTask(new TaskEncryptResource(this));
164     }
165     AddTask(new TaskManifestFile(this));
166     if (m_installerContext.widgetConfig.packagingType ==
167         PKG_TYPE_HYBRID_WEB_APP) {
168         AddTask(new TaskInstallOspsvc(this));
169     }
170
171     AddTask(new TaskDatabase(this));
172     AddTask(new TaskAceCheck(this));
173     //TODO: remove widgetHandle from this task and move before database task
174     // by now widget handle is needed in ace check
175     // Any error in acecheck while update will break widget
176     AddTask(new TaskSmack(this));
177     AddTask(new TaskRemoveBackupFiles(this));
178     AddTask(new TaskPkgInfoUpdate(this));
179 }
180
181 void JobWidgetInstall::appendRDSUpdateTaskList()
182 {
183     _D("Configure installation RDS updated");
184     SetProgressFlag(true);
185     AddTask(new TaskStatusCheck(this));
186     AddTask(new TaskPrepareReinstall(this));
187     AddTask(new TaskCertify(this));
188 }
189
190 void JobWidgetInstall::appendRecoveryTaskList()
191 {
192     _D("Recovery Task");
193     SetProgressFlag(true);
194
195     AddTask(new TaskProcessConfig(this));
196
197     AddTask(new TaskCertify(this));
198     AddTask(new TaskManifestFile(this));
199     if (m_installerContext.widgetConfig.packagingType ==
200         PKG_TYPE_HYBRID_WEB_APP) {
201         AddTask(new TaskInstallOspsvc(this));
202     }
203     AddTask(new TaskSmack(this));
204 }
205
206 void JobWidgetInstall::appendFotaInstallationTaskList()
207 {
208     /* TODO */
209     _D("Configure installation succeeded");
210     SetProgressFlag(true);
211
212     AddTask(new TaskProcessConfig(this));
213     AddTask(new TaskCertify(this));
214     AddTask(new TaskUserDataManipulation(this));
215     if (m_installerContext.needEncryption) {
216         AddTask(new TaskEncryptResource(this));
217     }
218     AddTask(new TaskManifestFile(this));
219     if (m_installerContext.widgetConfig.packagingType ==
220         PKG_TYPE_HYBRID_WEB_APP)
221     {
222         AddTask(new TaskInstallOspsvc(this));
223     }
224     AddTask(new TaskDatabase(this));
225     AddTask(new TaskAceCheck(this));
226     AddTask(new TaskSmack(this));
227     AddTask(new TaskPkgInfoUpdate(this));
228 }
229
230 void JobWidgetInstall::appendFotaUpdateTaskList()
231 {
232     _D("Configure installation updated");
233     _D("Widget Update");
234     SetProgressFlag(true);
235
236     AddTask(new TaskProcessConfig(this));
237     AddTask(new TaskCertify(this));
238     AddTask(new TaskUserDataManipulation(this));
239     if (m_installerContext.needEncryption) {
240         AddTask(new TaskEncryptResource(this));
241     }
242
243     AddTask(new TaskManifestFile(this));
244     if (m_installerContext.widgetConfig.packagingType ==
245         PKG_TYPE_HYBRID_WEB_APP)
246     {
247         AddTask(new TaskInstallOspsvc(this));
248     }
249
250     AddTask(new TaskDatabase(this));
251     AddTask(new TaskAceCheck(this));
252     //TODO: remove widgetHandle from this task and move before database task
253     // by now widget handle is needed in ace check
254     // Any error in acecheck while update will break widget
255     AddTask(new TaskSmack(this));
256     AddTask(new TaskPkgInfoUpdate(this));
257 #if ENABLE(PRE_LAUNCH)
258     if (m_installerContext.isNeedPreLaunching) {
259         AddTask(new TaskPreLaunchingRegistration(this));
260     }
261 #endif
262 }
263
264 void JobWidgetInstall::SendProgress()
265 {
266     using namespace PackageManager;
267     if (GetProgressFlag() != false) {
268         if (GetInstallerStruct().progressCallback != NULL) {
269             // send progress signal of pkgmgr
270             GetInstallerStruct().pkgmgrInterface->sendProgressInstall(GetProgressPercent());
271
272             _D("Call widget install progressCallback");
273             GetInstallerStruct().progressCallback(
274                 GetInstallerStruct().userParam,
275                 GetProgressPercent(),
276                 GetProgressDescription());
277         }
278     }
279 }
280
281 void JobWidgetInstall::SendProgressIconPath(const std::string &path)
282 {
283     using namespace PackageManager;
284     if (GetProgressFlag() != false) {
285         if (GetInstallerStruct().progressCallback != NULL) {
286             // send progress signal of pkgmgr
287             GetInstallerStruct().pkgmgrInterface->sendIconPath(path);
288         }
289     }
290 }
291
292 void JobWidgetInstall::SendFinishedSuccess()
293 {
294     using namespace PackageManager;
295     // TODO : sync should move to separate task.
296     sync();
297
298     if (INSTALL_LOCATION_TYPE_PREFER_EXTERNAL == m_installerContext.locationType) {
299         if (m_installerContext.isUpdateMode) {
300             WidgetInstallToExtSingleton::Instance().postUpgrade(true);
301         } else {
302             WidgetInstallToExtSingleton::Instance().postInstallation(true);
303         }
304         WidgetInstallToExtSingleton::Instance().deinitialize();
305     }
306
307     /* smack label of ".mmc" is changed to "wrt-installer" after calling above function.
308        smack label of ".mmc" must be set to [pkgid] to success uninstallation by app2ext. */
309     std::string mmcDir = m_installerContext.locations->getPackageInstallationDir() + "/.mmc";
310     std::string pkgid = DPL::ToUTF8String(m_installerContext.widgetConfig.tzPkgid);
311     if (PC_OPERATION_SUCCESS != perm_app_setup_path(pkgid.c_str(), mmcDir.c_str(), APP_PATH_PRIVATE)) {
312         _W("change to wrt-installer label to %s", mmcDir.c_str());
313     }
314
315     //inform widget info
316     JobWidgetInstall::displayWidgetInfo();
317
318     TizenAppId& tizenId = m_installerContext.widgetConfig.tzAppid;
319
320     // send signal of pkgmgr
321     GetInstallerStruct().pkgmgrInterface->endJob(m_exceptionCaught);
322
323     _D("Call widget install successfinishedCallback");
324     GetInstallerStruct().finishedCallback(GetInstallerStruct().userParam,
325                                           DPL::ToUTF8String(
326                                               tizenId), Jobs::Exceptions::Success);
327 }
328
329 void JobWidgetInstall::SendFinishedFailure()
330 {
331     using namespace PackageManager;
332
333     // print error message
334     LOGE("Error number: %d", m_exceptionCaught);
335     LOGE("Error message: %s", m_exceptionMessage.c_str());
336     fprintf(stderr, "[Err:%d] %s", m_exceptionCaught, m_exceptionMessage.c_str());
337
338     TizenAppId & tizenId = m_installerContext.widgetConfig.tzAppid;
339
340     _D("Call widget install failure finishedCallback");
341
342     // send signal of pkgmgr
343     GetInstallerStruct().pkgmgrInterface->endJob(m_exceptionCaught, m_exceptionMessage.c_str());
344
345     GetInstallerStruct().finishedCallback(GetInstallerStruct().userParam,
346                                           DPL::ToUTF8String(
347                                               tizenId), m_exceptionCaught);
348 }
349
350 void JobWidgetInstall::SaveExceptionData(const Jobs::JobExceptionBase &e)
351 {
352     m_exceptionCaught = static_cast<Jobs::Exceptions::Type>(e.getParam());
353     m_exceptionMessage = e.GetMessage();
354 }
355
356 void JobWidgetInstall::displayWidgetInfo()
357 {
358     if (m_installerContext.widgetConfig.webAppType.appType == WrtDB::APP_TYPE_TIZENWEBAPP)
359     {
360         WidgetDAOReadOnly dao(m_installerContext.widgetConfig.tzAppid);
361
362         std::ostringstream out;
363         WidgetLocalizedInfo localizedInfo =
364         W3CFileLocalization::getLocalizedInfo(dao.getTizenAppId());
365
366         out << std::endl <<
367         "===================================== INSTALLED WIDGET INFO =========" \
368         "============================";
369         out << std::endl << "Name:                        " << localizedInfo.name;
370     out << std::endl << "AppId:                     " << dao.getTizenAppId();
371         WidgetSize size = dao.getPreferredSize();
372         out << std::endl << "Width:                       " << size.width;
373         out << std::endl << "Height:                      " << size.height;
374         out << std::endl << "Start File:                  " <<
375     W3CFileLocalization::getStartFile(dao.getTizenAppId());
376         out << std::endl << "Version:                     " << dao.getVersion();
377         out << std::endl << "Licence:                     " <<
378         localizedInfo.license;
379         out << std::endl << "Licence Href:                " <<
380         localizedInfo.licenseHref;
381         out << std::endl << "Description:                 " <<
382         localizedInfo.description;
383         out << std::endl << "Widget Id:                   " << dao.getGUID();
384
385     OptionalWidgetIcon icon = W3CFileLocalization::getIcon(dao.getTizenAppId());
386         DPL::OptionalString iconSrc =
387             !!icon ? icon->src : DPL::OptionalString();
388         out << std::endl << "Icon:                        " << iconSrc;
389
390         out << std::endl << "Preferences:";
391         {
392             PropertyDAOReadOnly::WidgetPreferenceList list = dao.getPropertyList();
393             FOREACH(it, list)
394             {
395                 out << std::endl << "  Key:                       " <<
396                 it->key_name;
397                 out << std::endl << "      Readonly:              " <<
398                 it->readonly;
399             }
400         }
401
402         out << std::endl;
403
404         _D("%s", out.str().c_str());
405     }
406 }
407
408 void JobWidgetInstall::SecureRemove(const bf::path& path)
409 {
410     if (path.empty()) {
411         _E("error for get path");
412         ThrowMsg(Jobs::WidgetInstall::Exceptions::RemovingFileFailure, "Try to remove insecure location");
413         return;
414     }
415
416     const char* blacklist[] = {
417         "/",
418         "/opt",
419         "/opt/",
420         "/opt/share",
421         "/opt/share/",
422         "/opt/share/widget",
423         "/opt/share/widget/",
424         "/opt/share/widget/temp_info",
425         "/opt/share/widget/temp_info/",
426         "/opt/share/packages",
427         "/opt/share/packages/",
428         "/opt/share/applications",
429         "/opt/share/applications/",
430         "/opt/usr",
431         "/opt/usr/",
432         "/opt/usr/apps",
433         "/opt/usr/apps/",
434         NULL
435     };
436
437     char* canonicalizeFilePath = canonicalize_file_name(path.c_str());
438     if (!canonicalizeFilePath) {
439         _E("error : a pathname[%s] component is unreadable or does not exist", path.c_str());
440         //ThrowMsg(Jobs::WidgetInstall::Exceptions::RemovingFileFailure, "Try to remove insecure location");
441         return;
442     }
443
444     int idx = 0;
445     while(blacklist[idx]){
446         char* cmpFilePath = canonicalize_file_name(blacklist[idx]);
447         if (cmpFilePath) {
448             if(!strcmp(canonicalizeFilePath, cmpFilePath)) {
449                 _E("illegal access : %s", path.c_str());
450                 free(cmpFilePath);
451                 free(canonicalizeFilePath);
452                 ThrowMsg(Jobs::WidgetInstall::Exceptions::RemovingFileFailure, "Try to remove insecure location");
453                 return;
454             }
455             free(cmpFilePath);
456         }
457         idx++;
458     }
459     free(canonicalizeFilePath);
460     bf::remove_all(path);
461 }
462 } //namespace WidgetInstall
463 } //namespace Jobs