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