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