Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / xwalk / application / browser / application_service.cc
index 2125599..a2ee3f0 100644 (file)
@@ -11,6 +11,8 @@
 #include "base/file_util.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.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_event_manager.h"
 #include "xwalk/application/browser/application_system.h"
 #include "xwalk/application/browser/installer/package.h"
 #include "xwalk/application/common/application_file_util.h"
-#include "xwalk/application/common/application_manifest_constants.h"
 #include "xwalk/application/common/event_names.h"
-#include "xwalk/application/common/id_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_MOBILE)
-#include "xwalk/application/browser/installer/tizen/package_installer.h"
+#if defined(OS_TIZEN)
+#include "xwalk/application/browser/installer/tizen/service_package_installer.h"
 #endif
 
-using xwalk::RuntimeContext;
+namespace xwalk {
+namespace application {
 
 namespace {
 
@@ -42,18 +44,18 @@ void CloseMessageLoop() {
 
 void WaitForEventAndClose(
     const std::string& app_id, const std::string& event_name,
-    xwalk::application::ApplicationEventManager* event_manager) {
-  class CloseOnEventArrived : public xwalk::application::EventObserver {
+    ApplicationEventManager* event_manager) {
+  class CloseOnEventArrived : public EventObserver {
    public:
     static CloseOnEventArrived* Create(const std::string& event_name,
-        xwalk::application::ApplicationEventManager* event_manager) {
+        ApplicationEventManager* event_manager) {
       return new CloseOnEventArrived(event_name, event_manager);
     }
 
     virtual void Observe(
         const std::string& app_id,
-        scoped_refptr<xwalk::application::Event> event) OVERRIDE {
-      DCHECK(xwalk::application::kOnJavaScriptEventAck == event->name());
+        scoped_refptr<Event> event) OVERRIDE {
+      DCHECK(kOnJavaScriptEventAck == event->name());
       std::string ack_event_name;
       event->args()->GetString(0, &ack_event_name);
       if (ack_event_name != event_name_)
@@ -65,8 +67,8 @@ void WaitForEventAndClose(
    private:
     CloseOnEventArrived(
         const std::string& event_name,
-        xwalk::application::ApplicationEventManager* event_manager)
-        : xwalk::application::EventObserver(event_manager),
+        ApplicationEventManager* event_manager)
+        : EventObserver(event_manager),
           event_name_(event_name) {}
 
     std::string event_name_;
@@ -76,18 +78,18 @@ void WaitForEventAndClose(
   CloseOnEventArrived* observer =
       CloseOnEventArrived::Create(event_name, event_manager);
   event_manager->AttachObserver(app_id,
-      xwalk::application::kOnJavaScriptEventAck, observer);
+      kOnJavaScriptEventAck, observer);
 }
 
 void WaitForFinishLoad(
-    scoped_refptr<xwalk::application::ApplicationData> application,
-    xwalk::application::ApplicationEventManager* event_manager,
+    scoped_refptr<ApplicationData> application,
+    ApplicationEventManager* event_manager,
     content::WebContents* contents) {
   class CloseAfterLoadObserver : public content::WebContentsObserver {
    public:
     CloseAfterLoadObserver(
-        scoped_refptr<xwalk::application::ApplicationData> application,
-        xwalk::application::ApplicationEventManager* event_manager,
+        scoped_refptr<ApplicationData> application,
+        ApplicationEventManager* event_manager,
         content::WebContents* contents)
         : content::WebContentsObserver(contents),
           application_(application),
@@ -101,13 +103,13 @@ void WaitForFinishLoad(
         const GURL& validate_url,
         bool is_main_frame,
         content::RenderViewHost* render_view_host) OVERRIDE {
-      if (!IsEventHandlerRegistered(xwalk::application::kOnInstalled)) {
+      if (!IsEventHandlerRegistered(kOnInstalled)) {
         CloseMessageLoop();
       } else {
         scoped_ptr<base::ListValue> event_args(new base::ListValue);
-        scoped_refptr<xwalk::application::Event> event =
-            xwalk::application::Event::CreateEvent(
-                xwalk::application::kOnInstalled, event_args.Pass());
+        scoped_refptr<Event> event =
+            Event::CreateEvent(
+                kOnInstalled, event_args.Pass());
         event_manager_->SendEvent(application_->ID(), event);
 
         WaitForEventAndClose(
@@ -122,53 +124,52 @@ void WaitForFinishLoad(
       return events.find(event_name) != events.end();
     }
 
-    scoped_refptr<xwalk::application::ApplicationData> application_;
-    xwalk::application::ApplicationEventManager* event_manager_;
+    scoped_refptr<ApplicationData> application_;
+    ApplicationEventManager* event_manager_;
   };
 
   // This object is self-destroyed when an event occurs.
   new CloseAfterLoadObserver(application, event_manager, contents);
 }
 
-#if defined(OS_TIZEN_MOBILE)
-bool InstallPackageOnTizen(xwalk::application::ApplicationService* service,
-                           xwalk::application::ApplicationStorage* storage,
-                           const std::string& app_id,
+void SaveSystemEventsInfo(
+    ApplicationService* application_service,
+    scoped_refptr<ApplicationData> application_data,
+    ApplicationEventManager* event_manager) {
+  // We need to run main document after installation in order to
+  // register system events.
+  if (application_data->HasMainDocument()) {
+    if (Application* application =
+        application_service->Launch(application_data->ID())) {
+      WaitForFinishLoad(application->data(), event_manager,
+                        application->GetMainDocumentRuntime()->web_contents());
+    }
+  }
+}
+
+#if defined(OS_TIZEN)
+bool InstallPackageOnTizen(ApplicationData* application_data,
                            const base::FilePath& data_dir) {
-  // FIXME(cmarcelo): The Tizen-specific steps of installation in
-  // service mode are not supported yet. Remove when this is fixed.
-  if (xwalk::XWalkRunner::GetInstance()->is_running_as_service())
-    return true;
-
-  scoped_ptr<xwalk::application::PackageInstaller> installer =
-      xwalk::application::PackageInstaller::Create(service, storage,
-                                                   app_id, data_dir);
-  if (!installer || !installer->Install()) {
-    LOG(ERROR) << "An error occurred during installation on Tizen.";
+  if (!XWalkRunner::GetInstance()->is_running_as_service()) {
+    LOG(ERROR) << "Installation on Tizen is only possible in"
+               << "service mode via 'xwalkctl' utility.";
     return false;
   }
-  return true;
+
+  return InstallApplicationForTizen(application_data, data_dir);
 }
 
-bool UninstallPackageOnTizen(xwalk::application::ApplicationService* service,
-                             xwalk::application::ApplicationStorage* storage,
-                             const std::string& app_id,
+bool UninstallPackageOnTizen(ApplicationData* application_data,
                              const base::FilePath& data_dir) {
-  // FIXME(cmarcelo): The Tizen-specific steps of installation in
-  // service mode are not supported yet. Remove when this is fixed.
-  if (xwalk::XWalkRunner::GetInstance()->is_running_as_service())
-    return true;
-
-  scoped_ptr<xwalk::application::PackageInstaller> installer =
-      xwalk::application::PackageInstaller::Create(service, storage,
-                                                   app_id, data_dir);
-  if (!installer || !installer->Uninstall()) {
-    LOG(ERROR) << "An error occurred during uninstallation on Tizen.";
+  if (!XWalkRunner::GetInstance()->is_running_as_service()) {
+    LOG(ERROR) << "Uninstallation on Tizen is only possible in"
+               << "service mode using 'xwalkctl' utility.";
     return false;
   }
-  return true;
+
+  return UninstallApplicationForTizen(application_data, data_dir);
 }
-#endif  // OS_TIZEN_MOBILE
+#endif  // OS_TIZEN
 
 bool CopyDirectoryContents(const base::FilePath& from,
     const base::FilePath& to) {
@@ -188,9 +189,6 @@ bool CopyDirectoryContents(const base::FilePath& from,
 
 }  // namespace
 
-namespace xwalk {
-namespace application {
-
 const base::FilePath::CharType kApplicationsDir[] =
     FILE_PATH_LITERAL("applications");
 
@@ -199,7 +197,8 @@ ApplicationService::ApplicationService(RuntimeContext* runtime_context,
                                        ApplicationEventManager* event_manager)
     : runtime_context_(runtime_context),
       application_storage_(app_storage),
-      event_manager_(event_manager) {
+      event_manager_(event_manager),
+      permission_policy_handler_(new PermissionPolicyManager()) {
   AddObserver(event_manager);
 }
 
@@ -219,29 +218,36 @@ bool ApplicationService::Install(const base::FilePath& path, std::string* id) {
   // the installation will always fail because of moving application
   // resources into an invalid directory.
   if (!base::DirectoryExists(data_dir) &&
-      !file_util::CreateDirectory(data_dir))
+      !base::CreateDirectory(data_dir))
     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, Manifest::COMMAND_LINE, &error);
+      unpacked_dir, app_id, Manifest::COMMAND_LINE, &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;
+    LOG(INFO) << "Already installed: " << *id;
     return false;
   }
 
@@ -251,7 +257,7 @@ bool ApplicationService::Install(const base::FilePath& path, std::string* id) {
       return false;
   }
   if (!package) {
-    if (!file_util::CreateDirectory(app_dir))
+    if (!base::CreateDirectory(app_dir))
       return false;
     if (!CopyDirectoryContents(unpacked_dir, app_dir))
       return false;
@@ -268,11 +274,12 @@ bool ApplicationService::Install(const base::FilePath& path, std::string* id) {
     return false;
   }
 
-#if defined(OS_TIZEN_MOBILE)
-  if (!InstallPackageOnTizen(this, application_storage_,
-                             application_data->ID(),
-                             runtime_context_->GetPath()))
+#if defined(OS_TIZEN)
+  if (!InstallPackageOnTizen(application_data,
+                             runtime_context_->GetPath())) {
+    application_storage_->RemoveApplication(application_data->ID());
     return false;
+  }
 #endif
 
   LOG(INFO) << "Application be installed in: " << app_dir.MaybeAsASCII();
@@ -280,32 +287,161 @@ bool ApplicationService::Install(const base::FilePath& path, std::string* id) {
             << " successfully.";
   *id = application_data->ID();
 
+  SaveSystemEventsInfo(this, application_data, event_manager_);
+
   FOR_EACH_OBSERVER(Observer, observers_,
                     OnApplicationInstalled(application_data->ID()));
 
-  // We need to run main document after installation in order to
-  // register system events.
-  if (application_data->HasMainDocument()) {
-    if (Application* application = Launch(application_data->ID())) {
-      WaitForFinishLoad(application->data(), event_manager_,
-          application->GetMainDocumentRuntime()->web_contents());
-    }
+  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,
+                      &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 (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.";
+    app->Terminate(Application::Immediate);
+  }
+
+  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,
+                                    &error);
+  if (!new_application) {
+    LOG(ERROR) << "Error during loading new package: " << error;
+    base::DeleteFile(app_dir, true);
+    base::Move(tmp_dir, app_dir);
+    return false;
+  }
+
+#if defined(OS_TIZEN)
+  if (!UninstallPackageOnTizen(old_application,
+                               runtime_context_->GetPath())) {
+    base::DeleteFile(app_dir, true);
+    base::Move(tmp_dir, app_dir);
+    return false;
+  }
+#endif
+
+  if (!application_storage_->UpdateApplication(new_application)) {
+    LOG(ERROR) << "An Error occurred when updating the application.";
+    base::DeleteFile(app_dir, true);
+    base::Move(tmp_dir, app_dir);
+#if defined(OS_TIZEN)
+    InstallPackageOnTizen(old_application,
+                          runtime_context_->GetPath());
+#endif
+    return false;
+  }
+#if defined(OS_TIZEN)
+  if (!InstallPackageOnTizen(new_application,
+                             runtime_context_->GetPath()))
+    return false;
+#endif
+  base::DeleteFile(tmp_dir, true);
+
+  SaveSystemEventsInfo(this, new_application, event_manager_);
+
+  FOR_EACH_OBSERVER(Observer, observers_,
+                    OnApplicationUpdated(app_id));
+
   return true;
 }
 
 bool ApplicationService::Uninstall(const std::string& id) {
-#if defined(OS_TIZEN_MOBILE)
-  if (!UninstallPackageOnTizen(this, application_storage_, id,
-                               runtime_context_->GetPath()))
+  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(Application::Immediate);
+  }
+
+#if defined(OS_TIZEN)
+  if (!UninstallPackageOnTizen(application,
+                               runtime_context_->GetPath()))
+    result = false;
 #endif
 
   if (!application_storage_->RemoveApplication(id)) {
     LOG(ERROR) << "Cannot uninstall application with id " << id
                << "; application is not installed.";
-    return false;
+    result = false;
   }
 
   const base::FilePath resources =
@@ -314,15 +450,55 @@ bool ApplicationService::Uninstall(const std::string& id) {
       !base::DeleteFile(resources, true)) {
     LOG(ERROR) << "Error occurred while trying to remove application with id "
                << id << "; Cannot remove all resources.";
-    return false;
+    result = false;
   }
 
+  content::StoragePartition* partition =
+      content::BrowserContext::GetStoragePartitionForSite(
+          runtime_context_, application->GetBaseURLFromApplicationId(id));
+  partition->ClearDataForOrigin(
+      content::StoragePartition::REMOVE_DATA_MASK_ALL,
+      content::StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL,
+      application->URL(),
+      partition->GetURLRequestContext());
+
   FOR_EACH_OBSERVER(Observer, observers_, OnApplicationUninstalled(id));
 
-  return true;
+  return result;
+}
+
+Application* ApplicationService::Launch(
+    scoped_refptr<ApplicationData> application_data,
+    const Application::LaunchParams& launch_params) {
+  if (GetApplicationByID(application_data->ID()) != NULL) {
+    LOG(INFO) << "Application with id: " << application_data->ID()
+              << " is already running.";
+    // FIXME: we need to notify application that it had been attempted
+    // to invoke and let the application to define the further behavior.
+    return NULL;
+  }
+
+  event_manager_->AddEventRouterForApp(application_data);
+  Application* application(new Application(application_data,
+                                           runtime_context_,
+                                           this));
+  ScopedVector<Application>::iterator app_iter =
+      applications_.insert(applications_.end(), application);
+
+  if (!application->Launch(launch_params)) {
+    event_manager_->RemoveEventRouterForApp(application_data);
+    applications_.erase(app_iter);
+    return NULL;
+  }
+
+  FOR_EACH_OBSERVER(Observer, observers_,
+                    DidLaunchApplication(application));
+
+  return application;
 }
 
-Application* ApplicationService::Launch(const std::string& id) {
+Application* ApplicationService::Launch(
+    const std::string& id, const Application::LaunchParams& params) {
   scoped_refptr<ApplicationData> application_data =
     application_storage_->GetApplicationData(id);
   if (!application_data) {
@@ -330,10 +506,11 @@ Application* ApplicationService::Launch(const std::string& id) {
     return NULL;
   }
 
-  return Launch(application_data);
+  return Launch(application_data, params);
 }
 
-Application* ApplicationService::Launch(const base::FilePath& path) {
+Application* ApplicationService::Launch(
+    const base::FilePath& path, const Application::LaunchParams& params) {
   if (!base::DirectoryExists(path))
     return NULL;
 
@@ -347,34 +524,7 @@ Application* ApplicationService::Launch(const base::FilePath& path) {
     return NULL;
   }
 
-  return Launch(application_data);
-}
-
-Application* ApplicationService::Launch(const GURL& url) {
-  namespace keys = xwalk::application_manifest_keys;
-
-  const std::string& url_spec = url.spec();
-  DCHECK(!url_spec.empty());
-  const std::string& app_id = GenerateId(url_spec);
-  // FIXME: we need to handle hash collisions.
-  DCHECK(!application_storage_->GetApplicationData(app_id));
-
-  base::DictionaryValue manifest;
-  // FIXME: define permissions!
-  manifest.SetString(keys::kLaunchWebURLKey, url_spec);
-  manifest.SetString(keys::kNameKey, "XWalk Browser");
-  manifest.SetString(keys::kVersionKey, "0");
-  manifest.SetInteger(keys::kManifestVersionKey, 1);
-  std::string error;
-  scoped_refptr<ApplicationData> application_data = ApplicationData::Create(
-            base::FilePath(), Manifest::COMMAND_LINE, manifest, app_id, &error);
-  if (!application_data) {
-    LOG(ERROR) << "Error occurred while trying to launch application: "
-               << error;
-    return NULL;
-  }
-
-  return Launch(application_data, Application::LaunchWebURLKey);
+  return Launch(application_data, params);
 }
 
 namespace {
@@ -439,35 +589,92 @@ void ApplicationService::OnApplicationTerminated(
   }
 }
 
-Application* ApplicationService::Launch(
-    scoped_refptr<ApplicationData> application_data,
-    Application::LaunchEntryPoints entry_points) {
-  if (GetApplicationByID(application_data->ID()) != NULL) {
-    LOG(INFO) << "Application with id: " << application_data->ID()
-              << " is already running.";
-    // FIXME: we need to notify application that it had been attempted
-    // to invoke and let the application to define the further behavior.
-    return NULL;
+void ApplicationService::CheckAPIAccessControl(const std::string& app_id,
+    const std::string& extension_name,
+    const std::string& api_name, const PermissionCallback& callback) {
+  Application* app = GetApplicationByID(app_id);
+  if (!app) {
+    LOG(ERROR) << "No running application found with ID: "
+      << app_id;
+    callback.Run(UNDEFINED_RUNTIME_PERM);
+    return;
   }
-
-  event_manager_->AddEventRouterForApp(application_data);
-  Application* application(new Application(application_data,
-                                           runtime_context_,
-                                           this));
-  application->set_entry_points(entry_points);
-  ScopedVector<Application>::iterator app_iter =
-      applications_.insert(applications_.end(), application);
-
-  if (!application->Launch()) {
-    event_manager_->RemoveEventRouterForApp(application_data);
-    applications_.erase(app_iter);
-    return NULL;
+  if (!app->UseExtension(extension_name)) {
+    LOG(ERROR) << "Can not find extension: "
+      << extension_name << " of Application with ID: "
+      << app_id;
+    callback.Run(UNDEFINED_RUNTIME_PERM);
+    return;
   }
+  // Permission name should have been registered at extension initialization.
+  std::string permission_name =
+      app->GetRegisteredPermissionName(extension_name, api_name);
+  if (permission_name.empty()) {
+    LOG(ERROR) << "API: " << api_name << " of extension: "
+      << extension_name << " not registered!";
+    callback.Run(UNDEFINED_RUNTIME_PERM);
+    return;
+  }
+  // Okay, since we have the permission name, let's get down to the policies.
+  // First, find out whether the permission is stored for the current session.
+  StoredPermission perm = app->GetPermission(
+      SESSION_PERMISSION, permission_name);
+  if (perm != UNDEFINED_STORED_PERM) {
+    // "PROMPT" should not be in the session storage.
+    DCHECK(perm != PROMPT);
+    if (perm == ALLOW) {
+      callback.Run(ALLOW_SESSION);
+      return;
+    }
+    if (perm == DENY) {
+      callback.Run(DENY_SESSION);
+      return;
+    }
+    NOTREACHED();
+  }
+  // Then, query the persistent policy storage.
+  perm = app->GetPermission(PERSISTENT_PERMISSION, permission_name);
+  // Permission not found in persistent permission table, normally this should
+  // not happen because all the permission needed by the application should be
+  // contained in its manifest, so it also means that the application is asking
+  // for something wasn't allowed.
+  if (perm == UNDEFINED_STORED_PERM) {
+    callback.Run(UNDEFINED_RUNTIME_PERM);
+    return;
+  }
+  if (perm == PROMPT) {
+    // TODO(Bai): We needed to pop-up a dialog asking user to chose one from
+    // either allow/deny for session/one shot/forever. Then, we need to update
+    // the session and persistent policy accordingly.
+    callback.Run(UNDEFINED_RUNTIME_PERM);
+    return;
+  }
+  if (perm == ALLOW) {
+    callback.Run(ALLOW_ALWAYS);
+    return;
+  }
+  if (perm == DENY) {
+    callback.Run(DENY_ALWAYS);
+    return;
+  }
+  NOTREACHED();
+}
 
-  FOR_EACH_OBSERVER(Observer, observers_,
-                    DidLaunchApplication(application));
-
-  return application;
+bool ApplicationService::RegisterPermissions(const std::string& app_id,
+    const std::string& extension_name,
+    const std::string& perm_table) {
+  Application* app = GetApplicationByID(app_id);
+  if (!app) {
+    LOG(ERROR) << "No running application found with ID: " << app_id;
+    return false;
+  }
+  if (!app->UseExtension(extension_name)) {
+    LOG(ERROR) << "Can not find extension: "
+               << extension_name << " of Application with ID: "
+               << app_id;
+    return false;
+  }
+  return app->RegisterPermissions(extension_name, perm_table);
 }
 
 }  // namespace application