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.
19 #include <dpl/platform.h>
20 #include <widget_uninstall/job_widget_uninstall.h>
21 #include <widget_uninstall/widget_uninstall_errors.h>
22 #include <widget_uninstall/task_check.h>
23 #include <widget_uninstall/task_db_update.h>
24 #if ENABLE(PRE_LAUNCH)
25 #include <widget_uninstall/task_delete_prelaunching_info.h>
27 #include <widget_uninstall/task_remove_files.h>
28 #include <widget_uninstall/task_remove_custom_handlers.h>
29 #include <widget_uninstall/task_smack.h>
30 #include <widget_uninstall/task_uninstall_ospsvc.h>
31 #include <widget_uninstall/task_delete_pkginfo.h>
32 #include <dpl/wrt-dao-ro/global_config.h>
33 #include <pkg-manager/pkgmgr_signal.h>
34 #include <app2ext_interface.h>
35 #include <boost/filesystem.hpp>
36 #include <dpl/log/secure_log.h>
38 using namespace WrtDB;
39 namespace bf = boost::filesystem;
41 namespace { //anonymous
42 const char* REG_TIZEN_PKGID_PATTERN = "^[a-zA-Z0-9]{10}$";
43 const int PKGID_LENTH = 10;
44 const bf::path PRELOAD_INSTALLED_PATH("/usr/apps");
48 namespace WidgetUninstall {
50 class UninstallerTaskFail :
51 public DPL::TaskDecl<UninstallerTaskFail>
54 WidgetStatus m_status;
58 if (WidgetStatus::NOT_INSTALLED == m_status) {
59 ThrowMsg(Jobs::WidgetUninstall::Exceptions::WidgetNotExist,
60 "Widget does not exist");
61 } else if (WidgetStatus::PREALOAD == m_status) {
62 ThrowMsg(Jobs::WidgetUninstall::Exceptions::Unremovable,
63 "Widget cann't uninstall");
65 Throw(Jobs::WidgetUninstall::Exceptions::Base);
70 UninstallerTaskFail(WidgetStatus status) :
71 DPL::TaskDecl<UninstallerTaskFail>(this),
75 AddStep(&UninstallerTaskFail::StepFail);
79 JobWidgetUninstall::JobWidgetUninstall(
80 const std::string & tizenPkgId,
81 const WidgetUninstallationStruct &
84 JobContextBase<WidgetUninstallationStruct>(uninstallerStruct),
85 m_exceptionCaught(Jobs::Exceptions::Success),
88 using namespace PackageManager;
89 m_context.removeStarted = false;
90 m_context.removeFinished = false;
91 m_context.removeAbnormal = false;
96 WidgetStatus status = getWidgetStatus(tizenPkgId);
98 if (WidgetStatus::Ok == status) {
99 WrtDB::WidgetDAOReadOnly dao(*m_context.tzAppIdList.begin());
100 m_context.tzPkgid = DPL::ToUTF8String(dao.getTizenPkgId());
101 m_context.locations = WidgetLocation(m_context.tzPkgid);
102 m_context.locations->registerAppid(DPL::ToUTF8String(*m_context.tzAppIdList.begin()));
103 m_context.installedPath =
104 bf::path(*dao.getWidgetInstalledPath());
105 m_context.manifestFile = getManifestFile();
106 PackagingType packagingType = dao.getPackagingType();
108 _D("Widget model exists. Pkg id : %s", m_context.tzPkgid.c_str());
110 // send start signal of pkgmgr
111 if (GetInstallerStruct().pkgmgrInterface->setPkgname(m_context.tzPkgid))
113 GetAppIdsFromPackage(m_context.tzPkgid.c_str(), appIdsList);
115 GetInstallerStruct().pkgmgrInterface->startJob(InstallationType::Uninstallation);
117 #if ENABLE(PRE_LAUNCH)
118 // Fundamentally, the pre-launching mechanism is based on
119 // re-launching target webapp on every termination.
120 // So the un-registration of pre-launching flag step
121 // should be processed firstly than step of killing those webapp.
122 AddTask(new TaskDeletePreLaunchingInfo(m_context));
124 AddTask(new TaskCheck(m_context));
125 if (packagingType == PKG_TYPE_HYBRID_WEB_APP) {
126 AddTask(new TaskUninstallOspsvc(m_context));
128 AddTask(new TaskDeletePkgInfo(m_context));
129 AddTask(new TaskDbUpdate(m_context));
131 AddTask(new TaskRemoveCustomHandlers(m_context));
132 AddTask(new TaskRemoveFiles(m_context));
133 AddTask(new TaskSmack(m_context));
134 } else if (WidgetStatus::NOT_INSTALLED == status ||
135 WidgetStatus::PREALOAD == status) {
136 AddTask(new UninstallerTaskFail(status));
137 } else if (WidgetStatus::ABNORMAL == status) {
138 m_context.tzPkgid = tizenPkgId;
139 m_context.manifestFile = getManifestFile();
141 m_context.locations = WidgetLocation(m_context.tzPkgid);
142 m_context.removeAbnormal = true;
144 AddTask(new TaskRemoveFiles(m_context));
145 AddTask(new TaskDeletePkgInfo(m_context));
147 AddTask(new UninstallerTaskFail(WidgetStatus::UNRECOGNIZED));
149 } Catch(WidgetDAOReadOnly::Exception::Base) {
150 AddTask(new UninstallerTaskFail(WidgetStatus::UNRECOGNIZED));
154 // regexec() function does not work properly in specific locale (ex, Estonian)
155 // So, change locale temporally before call regcomp and regexec
159 currentLocale = setlocale(LC_ALL , NULL);
160 if (NULL == setlocale(LC_ALL, "C")) {
161 _W("Failed to change locale to \"C\"");
166 if (NULL == setlocale(LC_ALL, currentLocale.c_str())) {
167 _W("Failed to set previous locale");
172 std::string currentLocale;
175 WidgetStatus JobWidgetUninstall::getWidgetStatus(const std::string &id)
180 if(regcomp(®x, REG_TIZEN_PKGID_PATTERN, REG_NOSUB | REG_EXTENDED)!=0){
181 _D("Regcomp failed");
183 std::string pkgId = id;
185 if ((regexec(®x, id.c_str(),
186 static_cast<size_t>(0), NULL, 0) != REG_NOERROR)) {
188 pkgId = id.substr(0, PKGID_LENTH);
190 //Service app cannot uninstall by appid
191 WrtDB::WidgetDAOReadOnly dao(DPL::FromUTF8String(id));
192 if (dao.getWidgetType().appType == APP_TYPE_TIZENWEBSERVICE) {
193 _E("Service app cannot uninstall by appid");
194 return WidgetStatus::NOT_INSTALLED;
198 m_context.tzAppIdList = WrtDB::WidgetDAOReadOnly::getTzAppIdList(DPL::FromUTF8String(pkgId));
199 if (m_context.tzAppIdList.empty()) {
201 std::string installPath = std::string(GlobalConfig::GetUserInstalledWidgetPath()) + "/" + pkgId;
202 if (bf::exists(bf::path(installPath))) {
203 _E("installed widget status is abnormal");
204 return WidgetStatus::ABNORMAL;
206 } catch (const bf::filesystem_error& ex) {
207 _E("boost::filesystem::error: %s", ex.what());
209 return WidgetStatus::NOT_INSTALLED;
211 return WidgetStatus::Ok;
214 std::string JobWidgetUninstall::getRemovedTizenId() const
219 bool JobWidgetUninstall::getRemoveStartedFlag() const
221 return m_context.removeStarted;
224 bool JobWidgetUninstall::getRemoveFinishedFlag() const
226 return m_context.removeFinished;
229 bf::path JobWidgetUninstall::getManifestFile() const
231 std::ostringstream manifest_name;
232 manifest_name << m_context.tzPkgid << ".xml";
233 bf::path manifestFile;
235 const bf::path PRELOAD_INSTALLED_PATH("/usr/apps/" + m_context.tzPkgid);
236 const bf::path USR_PACKAGES_PATH("/usr/share/packages");
237 const bf::path OPT_PACKAGES_PATH("/opt/share/packages");
239 if (PRELOAD_INSTALLED_PATH == m_context.installedPath) {
240 _D("This widget is preloaded.");
241 manifestFile = USR_PACKAGES_PATH;
243 manifestFile = OPT_PACKAGES_PATH;
246 manifestFile /= manifest_name.str();
247 _D("Manifest file : %s", manifestFile.c_str());
252 void JobWidgetUninstall::SendProgress()
254 using namespace PackageManager;
255 if (!getRemoveStartedFlag() ||
256 (getRemoveStartedFlag() && getRemoveFinishedFlag()))
258 if (NULL != GetInstallerStruct().progressCallback) {
259 // send progress signal of pkgmgr
260 GetInstallerStruct().pkgmgrInterface->sendProgressUninstall(GetProgressPercent());
262 _D("Call widget uninstall progressCallback");
263 GetInstallerStruct().progressCallback(
264 GetInstallerStruct().userParam,
265 GetProgressPercent(), GetProgressDescription());
270 void JobWidgetUninstall::GetAppIdsFromPackage(const char* package, std::vector<std::string>& appIdsList)
272 package_info_h package_info;
275 int ret = package_info_create(package, &package_info);
276 if (PACKAGE_MANAGER_ERROR_NONE != ret) {
277 _E("Failed to create package info");
281 ret = package_info_foreach_app_from_package(package_info,
285 if (PACKAGE_MANAGER_ERROR_NONE != ret) {
286 _E("Failed to get application IDs");
289 ret = package_info_destroy(package_info);
290 if (PACKAGE_MANAGER_ERROR_NONE != ret) {
291 _E("Failed to destroy package info");
297 bool JobWidgetUninstall::AppIdCallback(package_info_app_component_type_e /*comp_type*/,
298 const char *app_id, void *user_data)
300 if (app_id == NULL) {
301 _E("app_id is NULL");
305 if (user_data == NULL) {
306 _E("user data is NULL");
310 std::vector<std::string>* appList = static_cast<std::vector<std::string>*>(user_data);
311 appList->push_back(app_id);
316 void JobWidgetUninstall::SendFinishedSuccess()
318 using namespace PackageManager;
320 GetInstallerStruct().pkgmgrInterface->preEndJob(appIdsList);
322 // send signal of pkgmgr
323 GetInstallerStruct().pkgmgrInterface->endJob(m_exceptionCaught);
325 _D("Call widget uninstall success finishedCallback");
326 GetInstallerStruct().finishedCallback(GetInstallerStruct().userParam,
328 Jobs::Exceptions::Success);
331 void JobWidgetUninstall::SendFinishedFailure()
333 using namespace PackageManager;
335 LOGE("Error in uninstallation step: %d", m_exceptionCaught);
336 LOGE("Error message: %s", m_exceptionMessage.c_str());
337 fprintf(stderr, "[Err:%d] %s", m_exceptionCaught, m_exceptionMessage.c_str());
339 // send signal of pkgmgr
340 GetInstallerStruct().pkgmgrInterface->endJob(m_exceptionCaught, m_exceptionMessage.c_str());
342 _D("Call widget uninstall failure finishedCallback");
343 GetInstallerStruct().finishedCallback(GetInstallerStruct().userParam,
346 _D("[JobWidgetUninstall] Asynchronous failure callback status sent");
349 void JobWidgetUninstall::SaveExceptionData(const Jobs::JobExceptionBase &e)
351 m_exceptionCaught = static_cast<Jobs::Exceptions::Type>(e.getParam());
352 m_exceptionMessage = e.GetMessage();
355 void JobWidgetUninstall::SecureRemove(const bf::path& path)
358 _E("error for get path");
359 ThrowMsg(Jobs::WidgetUninstall::Exceptions::RemoveFileFailure, "Try to remove insecure location");
363 const char* blacklist[] = {
370 "/opt/share/widget/",
371 "/opt/share/widget/temp_info",
372 "/opt/share/widget/temp_info/",
373 "/opt/share/packages",
374 "/opt/share/packages/",
375 "/opt/share/applications",
376 "/opt/share/applications/",
384 char* canonicalizeFilePath = canonicalize_file_name(path.c_str());
385 if (!canonicalizeFilePath) {
386 _E("error : a pathname[%s] component is unreadable or does not exist", path.c_str());
387 //Do NOT throw exception for defense code (remove directory again that removed before)
392 while(blacklist[idx]){
393 char* cmpFilePath = canonicalize_file_name(blacklist[idx]);
395 if(!strcmp(canonicalizeFilePath, cmpFilePath)) {
396 _E("illegal access : %s", path.c_str());
398 free(canonicalizeFilePath);
399 ThrowMsg(Jobs::WidgetUninstall::Exceptions::RemoveFileFailure, "Try to remove insecure location");
406 free(canonicalizeFilePath);
407 bf::remove_all(path);
409 } //namespace WidgetUninstall