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