Upstream version 11.39.258.0
[platform/framework/web/crosswalk.git] / src / xwalk / application / tools / tizen / xwalk_package_installer.cc
1 // Copyright (c) 2014 Intel Corporation. All rights reserved.
2 // Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5
6 #include "xwalk/application/tools/tizen/xwalk_package_installer.h"
7
8 #include <pwd.h>
9 #include <ss_manager.h>
10 #include <sys/types.h>
11 #include <unistd.h>
12
13 #include <pkgmgr/pkgmgr_parser.h>
14
15 #include <algorithm>
16 #include <cctype>
17 #include <map>
18 #include <string>
19
20 #include "base/file_util.h"
21 #include "base/files/file_enumerator.h"
22 #include "base/logging.h"
23 #include "base/path_service.h"
24 #include "base/version.h"
25 #include "crypto/symmetric_key.h"
26 #include "third_party/libxml/chromium/libxml_utils.h"
27 #include "xwalk/application/common/application_data.h"
28 #include "xwalk/application/common/application_file_util.h"
29 #include "xwalk/application/common/application_manifest_constants.h"
30 #include "xwalk/application/common/id_util.h"
31 #include "xwalk/application/common/manifest_handlers/tizen_app_control_handler.h"
32 #include "xwalk/application/common/manifest_handlers/tizen_application_handler.h"
33 #include "xwalk/application/common/manifest_handlers/tizen_metadata_handler.h"
34 #include "xwalk/application/common/manifest_handlers/tizen_setting_handler.h"
35 #include "xwalk/application/common/permission_policy_manager.h"
36 #include "xwalk/application/common/tizen/application_storage.h"
37 #include "xwalk/application/common/tizen/encryption.h"
38 #include "xwalk/application/common/tizen/package_query.h"
39 #include "xwalk/application/tools/tizen/xwalk_packageinfo_constants.h"
40 #include "xwalk/application/tools/tizen/xwalk_platform_installer.h"
41 #include "xwalk/application/tools/tizen/xwalk_rds_delta_parser.h"
42 #include "xwalk/runtime/common/xwalk_paths.h"
43
44 namespace info = application_packageinfo_constants;
45
46 using xwalk::application::ApplicationData;
47 using xwalk::application::ApplicationStorage;
48 using xwalk::application::FileDeleter;
49 using xwalk::application::Manifest;
50 using xwalk::application::Package;
51
52 namespace {
53
54 const base::FilePath::CharType kApplicationsDir[] =
55     FILE_PATH_LITERAL("applications");
56
57 const base::FilePath::CharType kInstallTempDir[] =
58     FILE_PATH_LITERAL("install_temp");
59
60 const base::FilePath::CharType kUpdateTempDir[] =
61     FILE_PATH_LITERAL("update_temp");
62
63 namespace widget_keys = xwalk::application_widget_keys;
64
65 const base::FilePath kXWalkLauncherBinary("/usr/bin/xwalk-launcher");
66
67 const base::FilePath kDefaultIcon(
68     "/usr/share/icons/default/small/crosswalk.png");
69
70 const std::string kServicePrefix("xwalk-service.");
71 const std::string kAppIdPrefix("xwalk.");
72
73 bool CopyDirectoryContents(const base::FilePath& from,
74     const base::FilePath& to) {
75   base::FileEnumerator iter(from, false,
76       base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
77   for (base::FilePath path = iter.Next(); !path.empty(); path = iter.Next()) {
78     if (iter.GetInfo().IsDirectory()) {
79       if (!base::CopyDirectory(path, to, true))
80         return false;
81     } else if (!base::CopyFile(path, to.Append(path.BaseName()))) {
82         return false;
83     }
84   }
85
86   return true;
87 }
88
89 void WriteMetaDataElement(
90     XmlWriter& writer, // NOLINT
91     xwalk::application::TizenMetaDataInfo* info) {
92   if (!info)
93     return;
94
95   const std::map<std::string, std::string>& metadata = info->metadata();
96   std::map<std::string, std::string>::const_iterator it;
97   for (it = metadata.begin(); it != metadata.end(); ++it) {
98     writer.StartElement("metadata");
99     writer.AddAttribute("key", it->first);
100     writer.AddAttribute("value", it->second);
101     writer.EndElement();
102   }
103 }
104
105 bool GeneratePkgInfoXml(xwalk::application::ApplicationData* application,
106                         const std::string& icon_name,
107                         const base::FilePath& app_dir,
108                         const base::FilePath& xml_path) {
109   if (!base::PathExists(app_dir) &&
110       !base::CreateDirectory(app_dir))
111     return false;
112
113   std::string package_id =
114       xwalk::application::AppIdToPkgId(application->ID());
115
116   base::FilePath execute_path =
117       app_dir.AppendASCII("bin/").AppendASCII(application->ID());
118   std::string stripped_name = application->Name();
119
120   FILE* file = base::OpenFile(xml_path, "w");
121
122   XmlWriter xml_writer;
123   xml_writer.StartWriting();
124   xml_writer.StartElement("manifest");
125   xml_writer.AddAttribute("xmlns", "http://tizen.org/ns/packages");
126   xml_writer.AddAttribute("package", package_id);
127   xml_writer.AddAttribute("type",
128       application->GetManifest()->type() == Manifest::TYPE_MANIFEST
129       ? "xpk" : "wgt");
130   xml_writer.AddAttribute("version", application->VersionString());
131   xml_writer.WriteElement("label", application->Name());
132   xml_writer.WriteElement("description", application->Description());
133
134   xml_writer.StartElement("ui-application");
135   xml_writer.AddAttribute("appid", application->ID());
136   xml_writer.AddAttribute("exec", execute_path.MaybeAsASCII());
137   xml_writer.AddAttribute("type", "webapp");
138   xml_writer.AddAttribute("taskmanage", "true");
139
140   const xwalk::application::AppControlInfoList* aplist =
141       static_cast<const xwalk::application::AppControlInfoList*>(
142           application->GetManifestData(
143               widget_keys::kTizenApplicationAppControlsKey));
144   if (aplist) {
145     for (const auto& item : aplist->controls) {
146       xml_writer.StartElement("app-control");
147
148       xml_writer.StartElement("operation");
149       xml_writer.AddAttribute("name", item.operation());
150       xml_writer.EndElement();
151
152       xml_writer.StartElement("uri");
153       if (!item.uri().empty()) {
154         xml_writer.AddAttribute("name", item.uri());
155       } else {
156         xml_writer.AddAttribute("name", "*/*");
157       }
158       xml_writer.EndElement();
159
160       xml_writer.StartElement("mime");
161       if (!item.mime().empty()) {
162         xml_writer.AddAttribute("name", item.mime());
163       } else {
164         xml_writer.AddAttribute("name", "*/*");
165       }
166       xml_writer.EndElement();
167
168       xml_writer.EndElement();
169     }
170   }
171
172   xml_writer.WriteElement("label", application->Name());
173
174   xwalk::application::TizenMetaDataInfo* info =
175       static_cast<xwalk::application::TizenMetaDataInfo*>(
176       application->GetManifestData(widget_keys::kTizenMetaDataKey));
177   WriteMetaDataElement(xml_writer, info);
178
179   if (icon_name.empty())
180     xml_writer.WriteElement("icon", info::kDefaultIconName);
181   else
182     xml_writer.WriteElement("icon",
183                             kServicePrefix + application->ID() + ".png");
184   xml_writer.EndElement();  // Ends "ui-application"
185
186   xml_writer.EndElement();  // Ends "manifest" element.
187   xml_writer.StopWriting();
188
189   base::WriteFile(xml_path,
190                   xml_writer.GetWrittenString().c_str(),
191                   xml_writer.GetWrittenString().size());
192
193   base::CloseFile(file);
194   LOG(INFO) << "Converting manifest.json into "
195             << xml_path.BaseName().MaybeAsASCII()
196             << " for installation. [DONE]";
197   return true;
198 }
199
200 bool CreateAppSymbolicLink(const base::FilePath& app_dir,
201                            const std::string& app_id) {
202   base::FilePath execute_path =
203       app_dir.AppendASCII("bin/").AppendASCII(app_id);
204
205   if (!base::CreateDirectory(execute_path.DirName())) {
206     LOG(ERROR) << "Could not create directory '"
207                << execute_path.DirName().value() << "'.";
208     return false;
209   }
210
211   if (!base::CreateSymbolicLink(kXWalkLauncherBinary, execute_path)) {
212     LOG(ERROR) << "Could not create symbolic link to launcher from '"
213                << execute_path.value() << "'.";
214     return false;
215   }
216   return true;
217 }
218
219 }  // namespace
220
221 PackageInstaller::PackageInstaller(ApplicationStorage* storage)
222   : storage_(storage),
223     quiet_(false) {
224 }
225
226 PackageInstaller::~PackageInstaller() {
227 }
228
229 scoped_ptr<PackageInstaller> PackageInstaller::Create(
230     ApplicationStorage* storage) {
231   return scoped_ptr<PackageInstaller>(new PackageInstaller(storage));
232 }
233
234 void PackageInstaller::SetQuiet(bool quiet) {
235   quiet_ = quiet;
236 }
237
238 void PackageInstaller::SetInstallationKey(const std::string& key) {
239   key_ = key;
240 }
241
242 std::string PackageInstaller::PrepareUninstallationID(
243     const std::string& id) {
244   // this function fix pkg_id to app_id
245   // if installer was launched with pkg_id
246   if (xwalk::application::IsValidPkgID(id)) {
247     LOG(INFO) << "The package id is given " << id << " Will find app_id...";
248     std::string appid = xwalk::application::PkgIdToAppId(id);
249     if (!appid.empty())
250       return appid;
251   }
252   return id;
253 }
254
255 bool PackageInstaller::PlatformInstall(ApplicationData* app_data) {
256   std::string app_id(app_data->ID());
257   base::FilePath data_dir;
258   CHECK(PathService::Get(xwalk::DIR_DATA_PATH, &data_dir));
259
260   base::FilePath app_dir =
261       data_dir.AppendASCII(info::kAppDir).AppendASCII(app_id);
262   base::FilePath xml_path = data_dir.AppendASCII(info::kAppDir).AppendASCII(
263       app_id + std::string(info::kXmlExtension));
264
265   std::string icon_name;
266   if (!app_data->GetManifest()->GetString(
267       GetIcon128Key(app_data->manifest_type()), &icon_name))
268     LOG(WARNING) << "'icon' not included in manifest";
269
270   // This will clean everything inside '<data dir>/<app id>'.
271   FileDeleter app_dir_cleaner(app_dir, true);
272
273   if (!GeneratePkgInfoXml(app_data, icon_name, app_dir, xml_path)) {
274     LOG(ERROR) << "Failed to create XML metadata file '"
275                << xml_path.value() << "'.";
276     return false;
277   }
278
279   if (!CreateAppSymbolicLink(app_dir, app_id)) {
280     LOG(ERROR) << "Failed to create symbolic link for " << app_id;
281     return false;
282   }
283
284   base::FilePath icon =
285       icon_name.empty() ? kDefaultIcon : app_dir.AppendASCII(icon_name);
286
287   if (xml_path.empty() || icon.empty()) {
288     LOG(ERROR) << "Xml or icon path is empty";
289     return false;
290   }
291
292   PlatformInstaller platform_installer(app_id);
293
294   InitializePkgmgrSignal(&platform_installer, "-i", app_id);
295
296   if (!platform_installer.InstallApplication(xml_path, icon))
297     return false;
298
299   app_dir_cleaner.Dismiss();
300
301   return true;
302 }
303
304 bool PackageInstaller::PlatformUninstall(const std::string& app_id) {
305   PlatformInstaller platform_installer(app_id);
306
307   InitializePkgmgrSignal(&platform_installer, "-d", app_id);
308
309   return platform_installer.UninstallApplication();
310 }
311
312 bool PackageInstaller::PlatformUpdate(ApplicationData* app_data) {
313   std::string app_id(app_data->ID());
314   base::FilePath data_dir;
315   CHECK(PathService::Get(xwalk::DIR_DATA_PATH, &data_dir));
316
317   base::FilePath app_dir =
318       data_dir.AppendASCII(info::kAppDir).AppendASCII(app_id);
319   base::FilePath new_xml_path = data_dir.AppendASCII(info::kAppDir).AppendASCII(
320       app_id + ".new" + std::string(info::kXmlExtension));
321
322   std::string icon_name;
323   if (!app_data->GetManifest()->GetString(
324       GetIcon128Key(app_data->manifest_type()), &icon_name))
325     LOG(WARNING) << "'icon' not included in manifest";
326
327   // This will clean everything inside '<data dir>/<app id>' and the new XML.
328   FileDeleter app_dir_cleaner(app_dir, true);
329   FileDeleter new_xml_cleaner(new_xml_path, true);
330
331   if (!GeneratePkgInfoXml(app_data, icon_name, app_dir, new_xml_path)) {
332     LOG(ERROR) << "Could not create new XML metadata file '"
333                << new_xml_path.value() << "'.";
334     return false;
335   }
336
337   if (!CreateAppSymbolicLink(app_dir, app_id))
338     return false;
339
340   base::FilePath icon =
341       icon_name.empty() ? kDefaultIcon : app_dir.AppendASCII(icon_name);
342
343   PlatformInstaller platform_installer(app_id);
344
345   InitializePkgmgrSignal(&platform_installer, "-i", app_id);
346
347   if (!platform_installer.UpdateApplication(new_xml_path, icon))
348     return false;
349
350   app_dir_cleaner.Dismiss();
351   return true;
352 }
353
354 bool PackageInstaller::PlatformReinstall(const std::string& pkgid) {
355   PlatformInstaller platform_installer;
356   InitializePkgmgrSignal(&platform_installer, "-r", pkgid);
357
358   return platform_installer.ReinstallApplication(pkgid);
359 }
360
361 bool PackageInstaller::Install(const base::FilePath& path, std::string* id) {
362   // FIXME(leandro): Installation is not robust enough -- should any step
363   // fail, it can't roll back to a consistent state.
364   if (!base::PathExists(path)) {
365     LOG(ERROR) << "The specified XPK/WGT package file is invalid.";
366     return false;
367   }
368   if (base::DirectoryExists(path)) {
369     LOG(WARNING) << "Cannot install from directory.";
370     return false;
371   }
372
373   base::FilePath data_dir, install_temp_dir;
374   CHECK(PathService::Get(xwalk::DIR_DATA_PATH, &data_dir));
375   install_temp_dir = data_dir.Append(kInstallTempDir);
376   data_dir = data_dir.Append(kApplicationsDir);
377
378   // Make sure the kApplicationsDir exists under data_path, otherwise,
379   // the installation will always fail because of moving application
380   // resources into an invalid directory.
381   if (!base::DirectoryExists(data_dir) &&
382       !base::CreateDirectory(data_dir))
383     return false;
384
385   if (!base::DirectoryExists(install_temp_dir) &&
386       !base::CreateDirectory(install_temp_dir))
387     return false;
388
389   std::string app_id;
390   base::FilePath unpacked_dir;
391   scoped_ptr<Package> package;
392   FileDeleter tmp_path(install_temp_dir.Append(path.BaseName()), false);
393   if (!base::DirectoryExists(path)) {
394     if (tmp_path.path() != path &&
395         !base::CopyFile(path, tmp_path.path()))
396       return false;
397     package = Package::Create(tmp_path.path());
398     if (!package || !package->IsValid())
399       return false;
400     package->ExtractToTemporaryDir(&unpacked_dir);
401     app_id = package->Id();
402   } else {
403     unpacked_dir = path;
404   }
405
406   base::FilePath app_dir = data_dir.AppendASCII(app_id);
407   base::FilePath manifest_path =
408       xwalk::application::GetManifestPath(app_dir, package->manifest_type());
409   if (!base::PathExists(manifest_path)) {
410     if (!base::DirectoryExists(app_dir))
411       if (!base::CreateDirectory(app_dir))
412         return false;
413     if (!base::CopyFile(
414         xwalk::application::GetManifestPath(
415             unpacked_dir, package->manifest_type()), manifest_path))
416       return false;
417   }
418
419   std::string error;
420   scoped_refptr<ApplicationData> app_data = LoadApplication(
421       app_dir, app_id, ApplicationData::LOCAL_DIRECTORY,
422       package->manifest_type(), &error);
423   if (!app_data.get()) {
424     LOG(ERROR) << "Error during application installation: " << error;
425     return false;
426   }
427
428   // FIXME: Probably should be removed, as we should not handle permissions
429   // inside XWalk.
430   xwalk::application::PermissionPolicyManager permission_policy_handler;
431   if (!permission_policy_handler.
432       InitApplicationPermission(app_data.get())) {
433     LOG(ERROR) << "Application permission data is invalid";
434     return false;
435   }
436
437   if (storage_->Contains(app_data->ID())) {
438     *id = app_data->ID();
439     LOG(INFO) << "Already installed: " << *id;
440     return false;
441   }
442
443   if (base::DirectoryExists(app_dir)) {
444     if (!base::DeleteFile(app_dir, true))
445       return false;
446   }
447   if (!package) {
448     if (!base::CreateDirectory(app_dir))
449       return false;
450     if (!CopyDirectoryContents(unpacked_dir, app_dir))
451       return false;
452   } else {
453     if (!base::Move(unpacked_dir, app_dir))
454       return false;
455   }
456
457   xwalk::application::TizenSettingInfo* info =
458       static_cast<xwalk::application::TizenSettingInfo*>(
459           app_data->GetManifestData(widget_keys::kTizenSettingKey));
460   if (info && info->encryption_enabled()) {
461     // Generate encryption key.
462     scoped_ptr<crypto::SymmetricKey> key(
463         crypto::SymmetricKey::GenerateRandomKey(
464             crypto::SymmetricKey::AES, 256));
465
466     std::string str_key;
467     key->GetRawKey(&str_key);
468
469     std::string appId = app_data->ID();
470     std::transform(appId.begin(), appId.end(), appId.begin(), tolower);
471     scoped_ptr<char[], base::FreeDeleter> buffer =
472         scoped_ptr<char[], base::FreeDeleter>(strdup(str_key.c_str()));
473     const char* filename = appId.c_str();
474     int ret = ssm_write_buffer(
475         buffer.get(), str_key.size(),
476         filename,
477         SSM_FLAG_SECRET_OPERATION,
478         filename);
479     // Encrypt the resources if needed.
480     base::FileEnumerator iter(app_dir, true, base::FileEnumerator::FILES);
481     for (base::FilePath file_path = iter.Next();
482          !file_path.empty();
483          file_path = iter.Next()) {
484       if (!ret && xwalk::application::RequiresEncryption(file_path) &&
485           base::PathIsWritable(file_path)) {
486         std::string content;
487         std::string encrypted;
488         if (!base::ReadFileToString(file_path, &content)) {
489           LOG(ERROR) << "Failed to read " << file_path.MaybeAsASCII();
490           return false;
491         }
492         if (!xwalk::application::EncryptData(content.data(),
493                                              content.size(),
494                                              str_key,
495                                              &encrypted)
496             || !base::WriteFile(file_path,
497                                 encrypted.data(),
498                                 encrypted.size())) {
499           LOG(ERROR) << "Failed to encrypt " << file_path.MaybeAsASCII();
500           return false;
501         }
502       }
503     }
504   }
505
506   if (!storage_->AddApplication(app_data)) {
507     LOG(ERROR) << "Application with id " << app_data->ID()
508                << " couldn't be installed due to a Storage error";
509     base::DeleteFile(app_dir, true);
510     return false;
511   }
512
513   if (!PlatformInstall(app_data.get())) {
514     LOG(ERROR) << "Application with id " << app_data->ID()
515                << " couldn't be installed due to a platform error";
516     storage_->RemoveApplication(app_data->ID());
517     base::DeleteFile(app_dir, true);
518     return false;
519   }
520
521   LOG(INFO) << "Installed application with id: " << app_data->ID()
522             << " to " << app_dir.MaybeAsASCII() << " successfully.";
523   *id = app_data->ID();
524
525   return true;
526 }
527
528 bool PackageInstaller::Update(const std::string& app_id,
529                               const base::FilePath& path) {
530   if (!xwalk::application::IsValidApplicationID(app_id)) {
531     LOG(ERROR) << "The given application id " << app_id << " is invalid.";
532     return false;
533   }
534
535   if (!base::PathExists(path)) {
536     LOG(ERROR) << "The specified XPK/WGT package file is invalid.";
537     return false;
538   }
539
540   if (base::DirectoryExists(path)) {
541     LOG(WARNING) << "Cannot update from directory.";
542     return false;
543   }
544
545   base::FilePath unpacked_dir, update_temp_dir;
546   CHECK(PathService::Get(xwalk::DIR_DATA_PATH, &update_temp_dir));
547   update_temp_dir = update_temp_dir.Append(kUpdateTempDir);
548   if (!base::DirectoryExists(update_temp_dir) &&
549       !base::CreateDirectory(update_temp_dir))
550     return false;
551
552   FileDeleter tmp_path(update_temp_dir.Append(path.BaseName()), false);
553   if (tmp_path.path() != path &&
554       !base::CopyFile(path, tmp_path.path()))
555     return false;
556
557   scoped_ptr<Package> package = Package::Create(tmp_path.path());
558   if (!package) {
559     LOG(ERROR) << "XPK/WGT file is invalid.";
560     return false;
561   }
562
563   if (app_id.compare(package->Id()) != 0) {
564     LOG(ERROR) << "The XPK/WGT file is invalid, the application id is not the"
565                << "same as the installed application has.";
566     return false;
567   }
568
569   if (!package->ExtractToTemporaryDir(&unpacked_dir))
570     return false;
571
572   std::string error;
573   scoped_refptr<ApplicationData> new_app_data =
574       LoadApplication(unpacked_dir, app_id, ApplicationData::TEMP_DIRECTORY,
575                       package->manifest_type(), &error);
576   if (!new_app_data.get()) {
577     LOG(ERROR) << "An error occurred during application updating: " << error;
578     return false;
579   }
580
581   scoped_refptr<ApplicationData> old_app_data =
582       storage_->GetApplicationData(app_id);
583   if (!old_app_data.get()) {
584     LOG(INFO) << "Application haven't installed yet: " << app_id;
585     return false;
586   }
587
588   // For Tizen WGT package, downgrade to a lower version or reinstall
589   // is permitted when using Tizen WRT, Crosswalk runtime need to follow
590   // this behavior on Tizen platform.
591   if (package->manifest_type() != Manifest::TYPE_WIDGET &&
592       old_app_data->Version()->CompareTo(
593           *(new_app_data->Version())) >= 0) {
594     LOG(INFO) << "The version number of new XPK/WGT package "
595                  "should be higher than "
596               << old_app_data->VersionString();
597     return false;
598   }
599
600   const base::FilePath& app_dir = old_app_data->path();
601   const base::FilePath tmp_dir(app_dir.value()
602                                + FILE_PATH_LITERAL(".tmp"));
603
604   if (!base::Move(app_dir, tmp_dir) ||
605       !base::Move(unpacked_dir, app_dir))
606     return false;
607
608   new_app_data = LoadApplication(
609       app_dir, app_id, ApplicationData::LOCAL_DIRECTORY,
610       package->manifest_type(), &error);
611   if (!new_app_data.get()) {
612     LOG(ERROR) << "Error during loading new package: " << error;
613     base::DeleteFile(app_dir, true);
614     base::Move(tmp_dir, app_dir);
615     return false;
616   }
617
618   if (!storage_->UpdateApplication(new_app_data)) {
619     LOG(ERROR) << "Fail to update application, roll back to the old one.";
620     base::DeleteFile(app_dir, true);
621     base::Move(tmp_dir, app_dir);
622     return false;
623   }
624
625   if (!PlatformUpdate(new_app_data.get())) {
626     LOG(ERROR) << "Fail to update application, roll back to the old one.";
627     base::DeleteFile(app_dir, true);
628     if (!storage_->UpdateApplication(old_app_data)) {
629       LOG(ERROR) << "Fail to revert old application info, "
630                  << "remove the application as a last resort.";
631       storage_->RemoveApplication(old_app_data->ID());
632       base::DeleteFile(tmp_dir, true);
633       return false;
634     }
635     base::Move(tmp_dir, app_dir);
636     return false;
637   }
638
639   base::DeleteFile(tmp_dir, true);
640
641   return true;
642 }
643
644 bool PackageInstaller::Uninstall(const std::string& id) {
645   std::string app_id = PrepareUninstallationID(id);
646
647   if (!xwalk::application::IsValidApplicationID(app_id)) {
648     LOG(ERROR) << "The given application id '" << app_id << "' is invalid.";
649     return false;
650   }
651
652   bool result = true;
653   if (!storage_->RemoveApplication(app_id)) {
654     LOG(ERROR) << "Cannot uninstall application with id " << app_id
655                << "; application is not installed.";
656     result = false;
657   }
658
659   base::FilePath resources;
660   CHECK(PathService::Get(xwalk::DIR_DATA_PATH, &resources));
661   resources = resources.Append(kApplicationsDir).AppendASCII(app_id);
662   if (base::DirectoryExists(resources) &&
663       !base::DeleteFile(resources, true)) {
664     LOG(ERROR) << "Error occurred while trying to remove application with id "
665                << app_id << "; Cannot remove all resources.";
666     result = false;
667   }
668
669   if (!PlatformUninstall(app_id))
670     result = false;
671
672   return result;
673 }
674
675 bool PackageInstaller::Reinstall(const std::string& pkgid) {
676   if (!xwalk::application::IsValidPkgID(pkgid)) {
677     LOG(ERROR) << "The given package id '" << pkgid << "' is invalid.";
678     return false;
679   }
680
681   base::FilePath app_dir = xwalk::application::GetPackagePath(pkgid);
682   if (!base::DirectoryExists(app_dir)) {
683     LOG(ERROR) << "Application directory " << app_dir.value()
684                << " does not exist!";
685     return false;
686   }
687
688   RDSDeltaParser rds_parser(app_dir, pkgid);
689   if (!rds_parser.Parse())
690     return false;
691
692   if (!rds_parser.ApplyParsedData())
693     return false;
694
695   if (!PlatformReinstall(pkgid)) {
696     LOG(ERROR) << "Reinstallation of package " << pkgid
697                << " has failed due to a platform error!";
698     return false;
699   }
700
701   LOG(INFO) << "Package " << pkgid << " has been reinstalled successfully";
702   return true;
703 }
704
705 void PackageInstaller::ContinueUnfinishedTasks() {
706   base::FilePath config_dir;
707   CHECK(PathService::Get(xwalk::DIR_DATA_PATH, &config_dir));
708
709   base::FilePath install_temp_dir = config_dir.Append(kInstallTempDir),
710       update_temp_dir = config_dir.Append(kUpdateTempDir);
711   FileDeleter install_cleaner(install_temp_dir, true),
712       update_cleaner(update_temp_dir, true);
713
714   if (base::DirectoryExists(install_temp_dir)) {
715     base::FileEnumerator install_iter(
716         install_temp_dir, false, base::FileEnumerator::FILES);
717     for (base::FilePath file = install_iter.Next();
718          !file.empty(); file = install_iter.Next()) {
719       std::string app_id;
720       Install(file, &app_id);
721     }
722   }
723
724   if (base::DirectoryExists(update_temp_dir)) {
725     base::FileEnumerator update_iter(
726         update_temp_dir, false, base::FileEnumerator::FILES);
727     for (base::FilePath file = update_iter.Next();
728          !file.empty(); file = update_iter.Next()) {
729       std::string app_id;
730       if (!Install(file, &app_id) && storage_->Contains(app_id)) {
731         LOG(INFO) << "trying to update %s" << app_id;
732         Update(app_id, file);
733       }
734     }
735   }
736 }
737
738 void PackageInstaller::InitializePkgmgrSignal(
739     PlatformInstaller* platform_installer, const std::string& action,
740     const std::string& action_arg) {
741   DCHECK(platform_installer);
742   DCHECK(!action.empty());
743   DCHECK(!action_arg.empty());
744
745   if (key_.empty())
746     return;
747
748   const char* pkgmgr_argv[5];
749   pkgmgr_argv[0] = action.c_str();
750   pkgmgr_argv[1] = action_arg.c_str();  // this value is ignored by pkgmgr
751   pkgmgr_argv[2] = "-k";
752   pkgmgr_argv[3] = key_.c_str();
753   pkgmgr_argv[4] = "-q";
754
755   platform_installer->InitializePkgmgrSignal((quiet_ ? 5 : 4), pkgmgr_argv);
756 }