Upstream version 8.36.161.0
[platform/framework/web/crosswalk.git] / src / xwalk / application / browser / application_service.cc
index 6316ce1..c4fa85a 100644 (file)
@@ -4,24 +4,24 @@
 
 #include "xwalk/application/browser/application_service.h"
 
+#include <hash_set>
 #include <set>
 #include <string>
+#include <vector>
 
 #include "base/files/file_enumerator.h"
 #include "base/file_util.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/path_service.h"
-#include "base/version.h"
-#include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "xwalk/application/browser/application.h"
-#include "xwalk/application/browser/application_storage.h"
 #include "xwalk/application/browser/application_system.h"
-#include "xwalk/application/browser/installer/package.h"
+#include "xwalk/application/common/application_storage.h"
+#include "xwalk/application/common/installer/package.h"
+#include "xwalk/application/common/installer/package_installer.h"
 #include "xwalk/application/common/application_file_util.h"
-#include "xwalk/application/common/permission_policy_manager.h"
 #include "xwalk/runtime/browser/runtime_context.h"
 #include "xwalk/runtime/browser/runtime.h"
 #include "xwalk/runtime/browser/xwalk_runner.h"
 
 #if defined(OS_TIZEN)
 #include "xwalk/application/browser/application_tizen.h"
-#include "xwalk/application/browser/installer/tizen/package_installer.h"
 #endif
 
 namespace xwalk {
+
 namespace application {
 
 namespace {
 
-bool CopyDirectoryContents(const base::FilePath& from,
-    const base::FilePath& to) {
-  base::FileEnumerator iter(from, false,
-      base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
-  for (base::FilePath path = iter.Next(); !path.empty(); path = iter.Next()) {
-    if (iter.GetInfo().IsDirectory()) {
-      if (!base::CopyDirectory(path, to, true))
-        return false;
-    } else if (!base::CopyFile(path, to.Append(path.BaseName()))) {
-        return false;
-    }
-  }
+const base::FilePath::CharType kApplicationDataDirName[] =
+    FILE_PATH_LITERAL("Storage/ext");
 
-  return true;
+base::FilePath GetStoragePartitionPath(
+    const base::FilePath& base_path, const std::string& app_id) {
+  return base_path.Append(kApplicationDataDirName).Append(app_id);
 }
 
-void RemoveWidgetStorageFiles(const base::FilePath& storage_path,
-                              const std::string& app_id) {
-  base::FileEnumerator iter(storage_path, true,
-                            base::FileEnumerator::FILES);
-  for (base::FilePath file = iter.Next(); !file.empty(); file = iter.Next()) {
-    if (file.MaybeAsASCII().find(app_id) != std::string::npos)
-      base::DeleteFile(file, false);
+void CollectUnusedStoragePartitions(RuntimeContext* context,
+                                    ApplicationStorage* storage) {
+  std::vector<std::string> app_ids;
+  if (!storage->GetInstalledApplicationIDs(app_ids))
+    return;
+
+  scoped_ptr<base::hash_set<base::FilePath> > active_paths(
+      new base::hash_set<base::FilePath>());
+
+  for (unsigned i = 0; i < app_ids.size(); ++i) {
+    active_paths->insert(
+        GetStoragePartitionPath(context->GetPath(), app_ids.at(i)));
   }
+
+  content::BrowserContext::GarbageCollectStoragePartitions(
+      context, active_paths.Pass(), base::Bind(&base::DoNothing));
 }
 
 }  // namespace
 
-const base::FilePath::CharType kApplicationsDir[] =
-    FILE_PATH_LITERAL("applications");
-
 ApplicationService::ApplicationService(RuntimeContext* runtime_context,
                                        ApplicationStorage* app_storage)
     : runtime_context_(runtime_context),
       application_storage_(app_storage),
-      permission_policy_handler_(new PermissionPolicyManager()) {
+      package_installer_(PackageInstaller::Create(app_storage)) {
+  CollectUnusedStoragePartitions(runtime_context, app_storage);
 }
 
 ApplicationService::~ApplicationService() {
 }
 
 bool ApplicationService::Install(const base::FilePath& path, std::string* id) {
-  // FIXME(leandro): Installation is not robust enough -- should any step
-  // fail, it can't roll back to a consistent state.
-  if (!base::PathExists(path))
-    return false;
-
-  const base::FilePath data_dir =
-      runtime_context_->GetPath().Append(kApplicationsDir);
-
-  // Make sure the kApplicationsDir exists under data_path, otherwise,
-  // the installation will always fail because of moving application
-  // resources into an invalid directory.
-  if (!base::DirectoryExists(data_dir) &&
-      !base::CreateDirectory(data_dir))
+  if (!package_installer_->Install(path, id))
     return false;
 
-  std::string app_id;
-  base::FilePath unpacked_dir;
-  scoped_ptr<Package> package;
-  if (!base::DirectoryExists(path)) {
-    package = Package::Create(path);
-    package->Extract(&unpacked_dir);
-    app_id = package->Id();
-  } else {
-    unpacked_dir = path;
-  }
-
-  std::string error;
-  scoped_refptr<ApplicationData> application_data = LoadApplication(
-      unpacked_dir, app_id, Manifest::COMMAND_LINE,
-      package->type(), &error);
-  if (!application_data) {
-    LOG(ERROR) << "Error during application installation: " << error;
-    return false;
-  }
-  if (!permission_policy_handler_->
-      InitApplicationPermission(application_data)) {
-    LOG(ERROR) << "Application permission data is invalid";
-    return false;
-  }
-
-  if (application_storage_->Contains(application_data->ID())) {
-    *id = application_data->ID();
-    LOG(INFO) << "Already installed: " << *id;
-    return false;
-  }
-
-  base::FilePath app_dir = data_dir.AppendASCII(application_data->ID());
-  if (base::DirectoryExists(app_dir)) {
-    if (!base::DeleteFile(app_dir, true))
-      return false;
-  }
-  if (!package) {
-    if (!base::CreateDirectory(app_dir))
-      return false;
-    if (!CopyDirectoryContents(unpacked_dir, app_dir))
-      return false;
-  } else {
-    if (!base::Move(unpacked_dir, app_dir))
-      return false;
-  }
-
-  application_data->SetPath(app_dir);
-
-  if (!application_storage_->AddApplication(application_data)) {
-    LOG(ERROR) << "Application with id " << application_data->ID()
-               << " couldn't be installed.";
-    return false;
-  }
-
-#if defined(OS_TIZEN)
-  if (!PackageInstaller::InstallApplication(
-        application_data, runtime_context_->GetPath())) {
-    application_storage_->RemoveApplication(application_data->ID());
-    return false;
-  }
-#endif
-
-  LOG(INFO) << "Application be installed in: " << app_dir.MaybeAsASCII();
-  LOG(INFO) << "Installed application with id: " << application_data->ID()
-            << " successfully.";
-  *id = application_data->ID();
-
   FOR_EACH_OBSERVER(Observer, observers_,
-                    OnApplicationInstalled(application_data->ID()));
+                    OnApplicationInstalled(*id));
 
   return true;
 }
 
 bool ApplicationService::Update(const std::string& id,
                                 const base::FilePath& path) {
-  if (!base::PathExists(path)) {
-    LOG(ERROR) << "The XPK/WGT package file " << path.value() << " is invalid.";
-    return false;
-  }
-
-  if (base::DirectoryExists(path)) {
-    LOG(WARNING) << "Can not update an unpacked XPK/WGT package.";
-    return false;
-  }
-
-  base::FilePath unpacked_dir;
-  base::FilePath origin_dir;
-  std::string app_id;
-  scoped_ptr<Package> package = Package::Create(path);
-  if (!package) {
-    LOG(ERROR) << "XPK/WGT file is invalid.";
-    return false;
-  }
-
-  app_id = package->Id();
-
-  if (app_id.empty()) {
-    LOG(ERROR) << "XPK/WGT file is invalid, and the application id is empty.";
-    return false;
-  }
-
-  if (id.empty() ||
-      id.compare(app_id) != 0) {
-    LOG(ERROR) << "The XPK/WGT file is not the same as expecting.";
-    return false;
-  }
-
-  if (!package->Extract(&unpacked_dir))
-    return false;
-
-  std::string error;
-  scoped_refptr<ApplicationData> new_application =
-      LoadApplication(unpacked_dir,
-                      app_id,
-                      Manifest::COMMAND_LINE,
-                      package->type(),
-                      &error);
-  if (!new_application) {
-    LOG(ERROR) << "An error occurred during application updating: " << error;
-    return false;
-  }
-
-  scoped_refptr<ApplicationData> old_application =
-      application_storage_->GetApplicationData(app_id);
-  if (!old_application) {
-    LOG(INFO) << "Application haven't installed yet: " << app_id;
-    return false;
-  }
-
-  if (
-#if defined(OS_TIZEN)
-      // For Tizen WGT package, downgrade to a lower version or reinstall
-      // is permitted when using Tizen WRT, Crosswalk runtime need to follow
-      // this behavior on Tizen platform.
-      package->type() != Package::WGT &&
-#endif
-      old_application->Version()->CompareTo(
-          *(new_application->Version())) >= 0) {
-    LOG(INFO) << "The version number of new XPK/WGT package "
-                 "should be higher than "
-              << old_application->VersionString();
-    return false;
-  }
-
-  const base::FilePath& app_dir = old_application->Path();
-  const base::FilePath tmp_dir(app_dir.value()
-                               + FILE_PATH_LITERAL(".tmp"));
-
-  if (Application* app = GetApplicationByID(app_id)) {
-    LOG(INFO) << "Try to terminate the running application before update.";
+  if (Application* app = GetApplicationByID(id)) {
+    LOG(INFO) << "Try to terminate the running application before uninstall.";
     app->Terminate();
   }
 
-  if (!base::Move(app_dir, tmp_dir) ||
-      !base::Move(unpacked_dir, app_dir))
-    return false;
-
-  new_application = LoadApplication(app_dir,
-                                    app_id,
-                                    Manifest::COMMAND_LINE,
-                                    package->type(),
-                                    &error);
-  if (!new_application) {
-    LOG(ERROR) << "Error during loading new package: " << error;
-    base::DeleteFile(app_dir, true);
-    base::Move(tmp_dir, app_dir);
+  if (!package_installer_->Update(id, path))
     return false;
-  }
-
-  if (!application_storage_->UpdateApplication(new_application)) {
-    LOG(ERROR) << "Fail to update application, roll back to the old one.";
-    base::DeleteFile(app_dir, true);
-    base::Move(tmp_dir, app_dir);
-    return false;
-  }
-
-#if defined(OS_TIZEN)
-  if (!PackageInstaller::UpdateApplication(
-        new_application, runtime_context_->GetPath())) {
-    LOG(ERROR) << "Fail to update package on Tizen, roll back to the old one.";
-    base::DeleteFile(app_dir, true);
-    if (!application_storage_->UpdateApplication(old_application)) {
-      LOG(ERROR) << "Fail to revert old application info, "
-                 << "remove the application as a last resort.";
-      application_storage_->RemoveApplication(old_application->ID());
-      return false;
-    }
-    base::Move(tmp_dir, app_dir);
-    return false;
-  }
-#endif
-
-  base::DeleteFile(tmp_dir, true);
 
   FOR_EACH_OBSERVER(Observer, observers_,
-                    OnApplicationUpdated(app_id));
+                    OnApplicationUpdated(id));
 
   return true;
 }
 
 bool ApplicationService::Uninstall(const std::string& id) {
-  bool result = true;
-
-  scoped_refptr<ApplicationData> application =
-      application_storage_->GetApplicationData(id);
-  if (!application) {
-    LOG(ERROR) << "Cannot uninstall application with id " << id
-               << "; invalid application id";
-    return false;
-  }
-
   if (Application* app = GetApplicationByID(id)) {
     LOG(INFO) << "Try to terminate the running application before uninstall.";
     app->Terminate();
   }
 
-#if defined(OS_TIZEN)
-  if (!PackageInstaller::UninstallApplication(
-        application, runtime_context_->GetPath()))
-    result = false;
-#endif
-
-  if (!application_storage_->RemoveApplication(id)) {
-    LOG(ERROR) << "Cannot uninstall application with id " << id
-               << "; application is not installed.";
-    result = false;
-  }
-
-  const base::FilePath resources =
-      runtime_context_->GetPath().Append(kApplicationsDir).AppendASCII(id);
-  if (base::DirectoryExists(resources) &&
-      !base::DeleteFile(resources, true)) {
-    LOG(ERROR) << "Error occurred while trying to remove application with id "
-               << id << "; Cannot remove all resources.";
-    result = false;
-  }
-
-  // Clear databases, the directory clean up will happen next time Crosswalk
-  // startup by ApplicationStorageImpl::CollectGarbageApplications.
-  content::BrowserContext::AsyncObliterateStoragePartition(
-      runtime_context_,
-      application->GetBaseURLFromApplicationId(id),
-      base::Bind(&base::DoNothing));
+  if (!package_installer_->Uninstall(id))
+    return false;
 
   FOR_EACH_OBSERVER(Observer, observers_, OnApplicationUninstalled(id));
 
-  return result;
+  return true;
 }
 
 void ApplicationService::ChangeLocale(const std::string& locale) {
-  const ApplicationData::ApplicationDataMap& apps =
-      application_storage_->GetInstalledApplications();
+  ApplicationData::ApplicationDataMap apps;
+  if (!application_storage_->GetInstalledApplications(apps))
+    return;
+
   ApplicationData::ApplicationDataMap::const_iterator it;
   for (it = apps.begin(); it != apps.end(); ++it) {
     base::string16 error;