9a5ac69c204e701d2cb58d317ed9860b650ecf9c
[framework/web/wearable/wrt-installer.git] / src / jobs / widget_uninstall / job_widget_uninstall.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 #include <regex.h>
18 #include <sys/stat.h>
19 #include <widget_uninstall/job_widget_uninstall.h>
20 #include <widget_uninstall/widget_uninstall_errors.h>
21 #include <widget_uninstall/task_check.h>
22 #include <widget_uninstall/task_db_update.h>
23 #include <widget_uninstall/task_remove_files.h>
24 #include <widget_uninstall/task_remove_custom_handlers.h>
25 #include <widget_uninstall/task_smack.h>
26 #include <widget_uninstall/task_uninstall_ospsvc.h>
27 #include <widget_uninstall/task_delete_pkginfo.h>
28 #include <dpl/wrt-dao-ro/global_config.h>
29 #include <pkg-manager/pkgmgr_signal.h>
30 #include <app2ext_interface.h>
31 #include <dpl/utils/path.h>
32 #include <installer_log.h>
33
34 using namespace WrtDB;
35
36 namespace { //anonymous
37 const char* REG_TIZEN_PKGID_PATTERN = "^[a-zA-Z0-9]{10}$";
38 const int PKGID_LENTH = 10;
39 const DPL::Utils::Path PRELOAD_INSTALLED_PATH("/usr/apps");
40
41 bool checkDirectoryExist(const std::string& pkgId)
42 {
43     DPL::Utils::Path installPath(GlobalConfig::GetUserInstalledWidgetPath());
44     installPath /= pkgId;
45     return installPath.Exists();
46 }
47 }
48
49 namespace Jobs {
50 namespace WidgetUninstall {
51
52 class UninstallerTaskFail :
53     public DPL::TaskDecl<UninstallerTaskFail>
54 {
55   private:
56     WidgetStatus m_status;
57
58     void StepFail()
59     {
60         if (WidgetStatus::NOT_INSTALLED == m_status) {
61             ThrowMsg(Jobs::WidgetUninstall::Exceptions::WidgetNotExist,
62                      "Widget does not exist");
63         } else if (WidgetStatus::PREALOAD == m_status) {
64             ThrowMsg(Jobs::WidgetUninstall::Exceptions::Unremovable,
65                      "Widget cann't uninstall");
66         } else {
67             Throw(Jobs::WidgetUninstall::Exceptions::Base);
68         }
69     }
70
71   public:
72     UninstallerTaskFail(WidgetStatus status) :
73         DPL::TaskDecl<UninstallerTaskFail>(this),
74         m_status(status)
75
76     {
77         AddStep(&UninstallerTaskFail::StepFail);
78     }
79 };
80
81 JobWidgetUninstall::JobWidgetUninstall(
82     const std::string & tizenPkgId,
83     const WidgetUninstallationStruct &
84     uninstallerStruct) :
85     Job(Uninstallation),
86     JobContextBase<WidgetUninstallationStruct>(uninstallerStruct),
87     m_exceptionCaught(Jobs::Exceptions::Success),
88     m_id(tizenPkgId)
89 {
90     using namespace PackageManager;
91     m_context.removeStarted = false;
92     m_context.removeFinished = false;
93     m_context.removeAbnormal = false;
94     m_context.uninstallStep = UninstallerContext::UNINSTALL_START;
95     m_context.job = this;
96
97     Try
98     {
99         WidgetStatus status = getWidgetStatus(tizenPkgId);
100
101         if (WidgetStatus::Ok == status) {
102             //TODO: check and save type
103
104             WrtDB::WidgetDAOReadOnly dao(*m_context.tzAppIdList.begin());
105             m_context.tzPkgid = DPL::ToUTF8String(dao.getTizenPkgId());
106             m_context.locations = WidgetLocation(m_context.tzPkgid);
107             m_context.locations->registerAppid(DPL::ToUTF8String(*m_context.tzAppIdList.begin()));
108             m_context.installedPath =
109                 DPL::Utils::Path(*dao.getWidgetInstalledPath());
110             m_context.manifestFile = getManifestFile();
111             PackagingType packagingType = dao.getPackagingType();
112
113             _D("Widget model exists. Pkg id : %s", m_context.tzPkgid.c_str());
114
115             // send start signal of pkgmgr
116             if (GetInstallerStruct().pkgmgrInterface->setPkgname(m_context.tzPkgid))
117             {
118                 GetInstallerStruct().pkgmgrInterface->startJob(InstallationType::Uninstallation);
119             }
120
121             AddTask(new TaskCheck(m_context));
122             if (packagingType == PKG_TYPE_HYBRID_WEB_APP) {
123                 AddTask(new TaskUninstallOspsvc(m_context));
124             }
125             AddTask(new TaskDeletePkgInfo(m_context));
126             AddTask(new TaskDbUpdate(m_context));
127             AddTask(new TaskSmack(m_context));
128
129             AddTask(new TaskRemoveCustomHandlers(m_context));
130             AddTask(new TaskRemoveFiles(m_context));
131         } else if (WidgetStatus::NOT_INSTALLED == status ||
132                 WidgetStatus::PREALOAD == status) {
133             AddTask(new UninstallerTaskFail(status));
134         } else if (WidgetStatus::ABNORMAL == status) {
135             m_context.locations = WidgetLocation(m_context.tzPkgid);
136             m_context.removeAbnormal = true;
137             AddTask(new TaskRemoveFiles(m_context));
138         } else {
139             AddTask(new UninstallerTaskFail(WidgetStatus::UNRECOGNIZED));
140         }
141     } Catch(WidgetDAOReadOnly::Exception::Base) {
142         AddTask(new UninstallerTaskFail(WidgetStatus::UNRECOGNIZED));
143     }
144 }
145
146 // regexec() function does not work properly in specific locale (ex, Estonian)
147 // So, change locale temporally before call regcomp and regexec
148 class ScopeLocale {
149 public:
150     ScopeLocale(){
151         currentLocale = setlocale(LC_ALL , NULL);
152         if (NULL == setlocale(LC_ALL, "C")) {
153             _W("Failed to change locale to \"C\"");
154         }
155     }
156
157     ~ScopeLocale() {
158         if (NULL == setlocale(LC_ALL, currentLocale.c_str())) {
159             _W("Failed to set previous locale");
160         }
161     }
162
163 private:
164     std::string currentLocale;
165 };
166
167 WidgetStatus JobWidgetUninstall::getWidgetStatus(const std::string &id)
168 {
169     ScopeLocale locale;
170
171     regex_t regx;
172     if(regcomp(&regx, REG_TIZEN_PKGID_PATTERN, REG_NOSUB | REG_EXTENDED)!=0){
173         _D("Regcomp failed");
174     }
175     std::string pkgId = id;
176     DPL::Utils::Path installPath;
177
178     if ((regexec(&regx, id.c_str(),
179             static_cast<size_t>(0), NULL, 0) != REG_NOERROR)) {
180         //appid was passed
181         pkgId = id.substr(0, PKGID_LENTH);
182
183         //Service app cannot uninstall by appid
184         WrtDB::WidgetDAOReadOnly dao(DPL::FromUTF8String(id));
185         if( dao.getWidgetType().appType == APP_TYPE_TIZENWEBSERVICE ){
186             _E("Service app cannot uninstall by appid");
187             return WidgetStatus::NOT_INSTALLED;
188         }
189     }
190
191     m_context.tzAppIdList = WrtDB::WidgetDAOReadOnly::getTzAppIdList(DPL::FromUTF8String(pkgId));
192     if( m_context.tzAppIdList.empty() ){
193         if(checkDirectoryExist(pkgId)) {
194             _E("installed widget status is abnormal");
195
196             return WidgetStatus::ABNORMAL;
197         }
198         return WidgetStatus::NOT_INSTALLED;
199     }
200
201     return WidgetStatus::Ok;
202 }
203
204 std::string JobWidgetUninstall::getRemovedTizenId() const
205 {
206     return m_id;
207 }
208
209 bool JobWidgetUninstall::getRemoveStartedFlag() const
210 {
211     return m_context.removeStarted;
212 }
213
214 bool JobWidgetUninstall::getRemoveFinishedFlag() const
215 {
216     return m_context.removeFinished;
217 }
218
219 DPL::Utils::Path JobWidgetUninstall::getManifestFile() const
220 {
221     std::ostringstream manifest_name;
222     manifest_name << m_context.tzPkgid << ".xml";
223     DPL::Utils::Path manifestFile;
224
225     const DPL::Utils::Path PRELOAD_INSTALLED_PATH("/usr/apps/" + m_context.tzPkgid);
226     const DPL::Utils::Path USR_PACKAGES_PATH("/usr/share/packages");
227     const DPL::Utils::Path OPT_PACKAGES_PATH("/opt/share/packages");
228
229     if (PRELOAD_INSTALLED_PATH == m_context.installedPath) {
230         _D("This widget is preloaded.");
231         manifestFile = USR_PACKAGES_PATH;
232     } else {
233         manifestFile = OPT_PACKAGES_PATH;
234     }
235
236     manifestFile /= manifest_name.str();
237     _D("Manifest file : %s", manifestFile.Fullpath().c_str());
238
239     return manifestFile;
240 }
241
242 void JobWidgetUninstall::SendProgress()
243 {
244     using namespace PackageManager;
245     if (!getRemoveStartedFlag() ||
246         (getRemoveStartedFlag() && getRemoveFinishedFlag()))
247     {
248         if (NULL != GetInstallerStruct().progressCallback) {
249             // send progress signal of pkgmgr
250             std::ostringstream percent;
251             percent << static_cast<int>(GetProgressPercent());
252
253             _D("Call widget uninstall progressCallback");
254             GetInstallerStruct().progressCallback(
255                 GetInstallerStruct().userParam,
256                 GetProgressPercent(), GetProgressDescription());
257         }
258     }
259 }
260
261 void JobWidgetUninstall::SendFinishedSuccess()
262 {
263     using namespace PackageManager;
264     // send signal of pkgmgr
265     GetInstallerStruct().pkgmgrInterface->endJob(m_exceptionCaught);
266
267     _D("Call widget uninstall success finishedCallback");
268     GetInstallerStruct().finishedCallback(GetInstallerStruct().userParam,
269                                           getRemovedTizenId(),
270                                           Jobs::Exceptions::Success);
271 }
272
273 void JobWidgetUninstall::SendFinishedFailure()
274 {
275     using namespace PackageManager;
276
277     LOGE(COLOR_ERROR "Error in uninstallation step: %d" COLOR_END, m_exceptionCaught);
278     LOGE(COLOR_ERROR "Message: %s" COLOR_END, m_exceptionMessage.c_str());
279     fprintf(stderr, "[Err:%d] %s", m_exceptionCaught, m_exceptionMessage.c_str());
280
281     // send signal of pkgmgr
282     GetInstallerStruct().pkgmgrInterface->endJob(m_exceptionCaught);
283
284     _D("Call widget uninstall failure finishedCallback");
285     GetInstallerStruct().finishedCallback(GetInstallerStruct().userParam,
286                                           getRemovedTizenId(),
287                                           m_exceptionCaught);
288     _D("[JobWidgetUninstall] Asynchronous failure callback status sent");
289 }
290
291 void JobWidgetUninstall::SaveExceptionData(const Jobs::JobExceptionBase &e)
292 {
293     m_exceptionCaught = static_cast<Jobs::Exceptions::Type>(e.getParam());
294     m_exceptionMessage = e.GetMessage();
295 }
296 } //namespace WidgetUninstall
297 } //namespace Jobs