Upstream version 6.35.131.0
[platform/framework/web/crosswalk.git] / src / xwalk / application / browser / application_service.cc
1 // Copyright (c) 2013 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/browser/application_service.h"
6
7 #include <set>
8 #include <string>
9
10 #include "base/files/file_enumerator.h"
11 #include "base/file_util.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/path_service.h"
15 #include "base/version.h"
16 #include "content/public/browser/storage_partition.h"
17 #include "content/public/browser/web_contents.h"
18 #include "content/public/browser/web_contents_observer.h"
19 #include "xwalk/application/browser/application_event_manager.h"
20 #include "xwalk/application/browser/application.h"
21 #include "xwalk/application/browser/application_storage.h"
22 #include "xwalk/application/browser/application_system.h"
23 #include "xwalk/application/browser/installer/package.h"
24 #include "xwalk/application/common/application_file_util.h"
25 #include "xwalk/application/common/event_names.h"
26 #include "xwalk/application/common/permission_policy_manager.h"
27 #include "xwalk/runtime/browser/runtime_context.h"
28 #include "xwalk/runtime/browser/runtime.h"
29 #include "xwalk/runtime/browser/xwalk_runner.h"
30 #include "xwalk/runtime/common/xwalk_paths.h"
31
32 #if defined(OS_TIZEN)
33 #include "xwalk/application/browser/installer/tizen/service_package_installer.h"
34 #endif
35
36 namespace xwalk {
37 namespace application {
38
39 namespace {
40
41 void WaitForEventAndClose(
42     const std::string& app_id,
43     const std::string& event_name,
44     ApplicationService* application_service,
45     ApplicationEventManager* event_manager) {
46
47   class CloseOnEventArrived : public EventObserver {
48    public:
49     CloseOnEventArrived(
50         const std::string& event_name,
51         ApplicationService* application_service,
52         ApplicationEventManager* event_manager)
53         : EventObserver(event_manager),
54           event_name_(event_name),
55           application_service_(application_service) {}
56
57     virtual void Observe(
58         const std::string& app_id,
59         scoped_refptr<Event> event) OVERRIDE {
60       DCHECK(kOnJavaScriptEventAck == event->name());
61       std::string ack_event_name;
62       event->args()->GetString(0, &ack_event_name);
63       if (ack_event_name != event_name_)
64         return;
65
66       if (Application* app = application_service_->GetApplicationByID(app_id))
67         app->Terminate(Application::Immediate);
68
69       delete this;
70     }
71
72    private:
73     std::string event_name_;
74     ApplicationService* application_service_;
75   };
76
77   DCHECK(event_manager);
78   CloseOnEventArrived* observer =
79       new CloseOnEventArrived(event_name, application_service, event_manager);
80   event_manager->AttachObserver(app_id,
81       kOnJavaScriptEventAck, observer);
82 }
83
84 void WaitForFinishLoad(
85     const std::string& app_id,
86     ApplicationService* application_service,
87     ApplicationEventManager* event_manager,
88     content::WebContents* contents) {
89   class CloseAfterLoadObserver : public content::WebContentsObserver {
90    public:
91     CloseAfterLoadObserver(
92         const std::string& app_id,
93         ApplicationService* application_service,
94         ApplicationEventManager* event_manager,
95         content::WebContents* contents)
96         : content::WebContentsObserver(contents),
97           id_(app_id),
98           application_service_(application_service),
99           event_manager_(event_manager) {
100       DCHECK(application_service_);
101       DCHECK(event_manager_);
102     }
103
104     virtual void DidFinishLoad(
105         int64 frame_id,
106         const GURL& validate_url,
107         bool is_main_frame,
108         content::RenderViewHost* render_view_host) OVERRIDE {
109       Application* app = application_service_->GetApplicationByID(id_);
110       if (!app) {
111         delete this;
112         return;
113       }
114
115       if (!IsEventHandlerRegistered(app->data(), kOnInstalled)) {
116           app->Terminate(Application::Immediate);
117       } else {
118         scoped_ptr<base::ListValue> event_args(new base::ListValue);
119         scoped_refptr<Event> event =
120             Event::CreateEvent(kOnInstalled, event_args.Pass());
121         event_manager_->SendEvent(id_, event);
122
123         WaitForEventAndClose(
124             id_, event->name(), application_service_, event_manager_);
125       }
126       delete this;
127     }
128
129    private:
130     bool IsEventHandlerRegistered(scoped_refptr<ApplicationData> app_data,
131                                   const std::string& event_name) const {
132       const std::set<std::string>& events = app_data->GetEvents();
133       return events.find(event_name) != events.end();
134     }
135
136     std::string id_;
137     ApplicationService* application_service_;
138     ApplicationEventManager* event_manager_;
139   };
140
141   // This object is self-destroyed when an event occurs.
142   new CloseAfterLoadObserver(
143       app_id, application_service, event_manager, contents);
144 }
145
146 void SaveSystemEventsInfo(
147     scoped_refptr<ApplicationData> application_data,
148     ApplicationService* application_service,
149     ApplicationEventManager* event_manager) {
150   // We need to run main document after installation in order to
151   // register system events.
152   if (application_data->HasMainDocument()) {
153     if (Application* application =
154         application_service->Launch(application_data->ID())) {
155       WaitForFinishLoad(application->id(), application_service, event_manager,
156                         application->GetMainDocumentRuntime()->web_contents());
157     }
158   }
159 }
160
161 #if defined(OS_TIZEN)
162 bool InstallPackageOnTizen(ApplicationData* application_data,
163                            const base::FilePath& data_dir) {
164   if (!XWalkRunner::GetInstance()->is_running_as_service()) {
165     LOG(ERROR) << "Installation on Tizen is only possible in"
166                << "service mode via 'xwalkctl' utility.";
167     return false;
168   }
169
170   return InstallApplicationForTizen(application_data, data_dir);
171 }
172
173 bool UninstallPackageOnTizen(ApplicationData* application_data,
174                              const base::FilePath& data_dir) {
175   if (!XWalkRunner::GetInstance()->is_running_as_service()) {
176     LOG(ERROR) << "Uninstallation on Tizen is only possible in"
177                << "service mode using 'xwalkctl' utility.";
178     return false;
179   }
180
181   return UninstallApplicationForTizen(application_data, data_dir);
182 }
183 #endif  // OS_TIZEN
184
185 bool CopyDirectoryContents(const base::FilePath& from,
186     const base::FilePath& to) {
187   base::FileEnumerator iter(from, false,
188       base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
189   for (base::FilePath path = iter.Next(); !path.empty(); path = iter.Next()) {
190     if (iter.GetInfo().IsDirectory()) {
191       if (!base::CopyDirectory(path, to, true))
192         return false;
193     } else if (!base::CopyFile(path, to.Append(path.BaseName()))) {
194         return false;
195     }
196   }
197
198   return true;
199 }
200
201 void RemoveWidgetStorageFiles(const base::FilePath& storage_path,
202                               const std::string& app_id) {
203   base::FileEnumerator iter(storage_path, true,
204                             base::FileEnumerator::FILES);
205   for (base::FilePath file = iter.Next(); !file.empty(); file = iter.Next()) {
206     if (file.MaybeAsASCII().find(app_id) != std::string::npos)
207       base::DeleteFile(file, false);
208   }
209 }
210
211 }  // namespace
212
213 const base::FilePath::CharType kApplicationsDir[] =
214     FILE_PATH_LITERAL("applications");
215
216 ApplicationService::ApplicationService(RuntimeContext* runtime_context,
217                                        ApplicationStorage* app_storage,
218                                        ApplicationEventManager* event_manager)
219     : runtime_context_(runtime_context),
220       application_storage_(app_storage),
221       event_manager_(event_manager),
222       permission_policy_handler_(new PermissionPolicyManager()) {
223   AddObserver(event_manager);
224 }
225
226 ApplicationService::~ApplicationService() {
227 }
228
229 bool ApplicationService::Install(const base::FilePath& path, std::string* id) {
230   // FIXME(leandro): Installation is not robust enough -- should any step
231   // fail, it can't roll back to a consistent state.
232   if (!base::PathExists(path))
233     return false;
234
235   const base::FilePath data_dir =
236       runtime_context_->GetPath().Append(kApplicationsDir);
237
238   // Make sure the kApplicationsDir exists under data_path, otherwise,
239   // the installation will always fail because of moving application
240   // resources into an invalid directory.
241   if (!base::DirectoryExists(data_dir) &&
242       !base::CreateDirectory(data_dir))
243     return false;
244
245   std::string app_id;
246   base::FilePath unpacked_dir;
247   scoped_ptr<Package> package;
248   if (!base::DirectoryExists(path)) {
249     package = Package::Create(path);
250     package->Extract(&unpacked_dir);
251     app_id = package->Id();
252   } else {
253     unpacked_dir = path;
254   }
255
256   std::string error;
257   scoped_refptr<ApplicationData> application_data = LoadApplication(
258       unpacked_dir, app_id, Manifest::COMMAND_LINE, &error);
259   if (!application_data) {
260     LOG(ERROR) << "Error during application installation: " << error;
261     return false;
262   }
263   if (!permission_policy_handler_->
264       InitApplicationPermission(application_data)) {
265     LOG(ERROR) << "Application permission data is invalid";
266     return false;
267   }
268
269   if (application_storage_->Contains(application_data->ID())) {
270     *id = application_data->ID();
271     LOG(INFO) << "Already installed: " << *id;
272     return false;
273   }
274
275   base::FilePath app_dir = data_dir.AppendASCII(application_data->ID());
276   if (base::DirectoryExists(app_dir)) {
277     if (!base::DeleteFile(app_dir, true))
278       return false;
279   }
280   if (!package) {
281     if (!base::CreateDirectory(app_dir))
282       return false;
283     if (!CopyDirectoryContents(unpacked_dir, app_dir))
284       return false;
285   } else {
286     if (!base::Move(unpacked_dir, app_dir))
287       return false;
288   }
289
290   application_data->SetPath(app_dir);
291
292   if (!application_storage_->AddApplication(application_data)) {
293     LOG(ERROR) << "Application with id " << application_data->ID()
294                << " couldn't be installed.";
295     return false;
296   }
297
298 #if defined(OS_TIZEN)
299   if (!InstallPackageOnTizen(application_data,
300                              runtime_context_->GetPath())) {
301     application_storage_->RemoveApplication(application_data->ID());
302     return false;
303   }
304 #endif
305
306   LOG(INFO) << "Application be installed in: " << app_dir.MaybeAsASCII();
307   LOG(INFO) << "Installed application with id: " << application_data->ID()
308             << " successfully.";
309   *id = application_data->ID();
310
311   SaveSystemEventsInfo(application_data, this, event_manager_);
312
313   FOR_EACH_OBSERVER(Observer, observers_,
314                     OnApplicationInstalled(application_data->ID()));
315
316   return true;
317 }
318
319 bool ApplicationService::Update(const std::string& id,
320                                 const base::FilePath& path) {
321   if (!base::PathExists(path)) {
322     LOG(ERROR) << "The XPK/WGT package file " << path.value() << " is invalid.";
323     return false;
324   }
325
326   if (base::DirectoryExists(path)) {
327     LOG(WARNING) << "Can not update an unpacked XPK/WGT package.";
328     return false;
329   }
330
331   base::FilePath unpacked_dir;
332   base::FilePath origin_dir;
333   std::string app_id;
334   scoped_ptr<Package> package = Package::Create(path);
335   if (!package) {
336     LOG(ERROR) << "XPK/WGT file is invalid.";
337     return false;
338   }
339
340   app_id = package->Id();
341
342   if (app_id.empty()) {
343     LOG(ERROR) << "XPK/WGT file is invalid, and the application id is empty.";
344     return false;
345   }
346
347   if (id.empty() ||
348       id.compare(app_id) != 0) {
349     LOG(ERROR) << "The XPK/WGT file is not the same as expecting.";
350     return false;
351   }
352
353   if (!package->Extract(&unpacked_dir))
354     return false;
355
356   std::string error;
357   scoped_refptr<ApplicationData> new_application =
358       LoadApplication(unpacked_dir,
359                       app_id,
360                       Manifest::COMMAND_LINE,
361                       &error);
362   if (!new_application) {
363     LOG(ERROR) << "An error occurred during application updating: " << error;
364     return false;
365   }
366
367   scoped_refptr<ApplicationData> old_application =
368       application_storage_->GetApplicationData(app_id);
369   if (!old_application) {
370     LOG(INFO) << "Application haven't installed yet: " << app_id;
371     return false;
372   }
373
374   if (old_application->Version()->CompareTo(
375           *(new_application->Version())) >= 0) {
376     LOG(INFO) << "The version number of new XPK/WGT package "
377                  "should be higher than "
378               << old_application->VersionString();
379     return false;
380   }
381
382   const base::FilePath& app_dir = old_application->Path();
383   const base::FilePath tmp_dir(app_dir.value()
384                                + FILE_PATH_LITERAL(".tmp"));
385
386   if (Application* app = GetApplicationByID(app_id)) {
387     LOG(INFO) << "Try to terminate the running application before update.";
388     app->Terminate(Application::Immediate);
389   }
390
391   if (!base::Move(app_dir, tmp_dir) ||
392       !base::Move(unpacked_dir, app_dir))
393     return false;
394
395   new_application = LoadApplication(app_dir,
396                                     app_id,
397                                     Manifest::COMMAND_LINE,
398                                     &error);
399   if (!new_application) {
400     LOG(ERROR) << "Error during loading new package: " << error;
401     base::DeleteFile(app_dir, true);
402     base::Move(tmp_dir, app_dir);
403     return false;
404   }
405
406 #if defined(OS_TIZEN)
407   if (!UninstallPackageOnTizen(old_application,
408                                runtime_context_->GetPath())) {
409     base::DeleteFile(app_dir, true);
410     base::Move(tmp_dir, app_dir);
411     return false;
412   }
413 #endif
414
415   if (!application_storage_->UpdateApplication(new_application)) {
416     LOG(ERROR) << "An Error occurred when updating the application.";
417     base::DeleteFile(app_dir, true);
418     base::Move(tmp_dir, app_dir);
419 #if defined(OS_TIZEN)
420     InstallPackageOnTizen(old_application,
421                           runtime_context_->GetPath());
422 #endif
423     return false;
424   }
425 #if defined(OS_TIZEN)
426   if (!InstallPackageOnTizen(new_application,
427                              runtime_context_->GetPath()))
428     return false;
429 #endif
430   base::DeleteFile(tmp_dir, true);
431
432   SaveSystemEventsInfo(new_application, this, event_manager_);
433
434   FOR_EACH_OBSERVER(Observer, observers_,
435                     OnApplicationUpdated(app_id));
436
437   return true;
438 }
439
440 bool ApplicationService::Uninstall(const std::string& id) {
441   bool result = true;
442
443   scoped_refptr<ApplicationData> application =
444       application_storage_->GetApplicationData(id);
445   if (!application) {
446     LOG(ERROR) << "Cannot uninstall application with id " << id
447                << "; invalid application id";
448     return false;
449   }
450
451   if (Application* app = GetApplicationByID(id)) {
452     LOG(INFO) << "Try to terminate the running application before uninstall.";
453     app->Terminate(Application::Immediate);
454   }
455
456 #if defined(OS_TIZEN)
457   if (!UninstallPackageOnTizen(application,
458                                runtime_context_->GetPath()))
459     result = false;
460 #endif
461
462   if (!application_storage_->RemoveApplication(id)) {
463     LOG(ERROR) << "Cannot uninstall application with id " << id
464                << "; application is not installed.";
465     result = false;
466   }
467
468   const base::FilePath resources =
469       runtime_context_->GetPath().Append(kApplicationsDir).AppendASCII(id);
470   if (base::DirectoryExists(resources) &&
471       !base::DeleteFile(resources, true)) {
472     LOG(ERROR) << "Error occurred while trying to remove application with id "
473                << id << "; Cannot remove all resources.";
474     result = false;
475   }
476
477   content::StoragePartition* partition =
478       content::BrowserContext::GetStoragePartitionForSite(
479           runtime_context_, application->GetBaseURLFromApplicationId(id));
480   partition->ClearDataForOrigin(
481       content::StoragePartition::REMOVE_DATA_MASK_ALL,
482       content::StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL,
483       application->URL(),
484       partition->GetURLRequestContext());
485
486   base::FilePath path;
487   PathService::Get(xwalk::DIR_WGT_STORAGE_PATH, &path);
488   RemoveWidgetStorageFiles(path, id);
489
490   FOR_EACH_OBSERVER(Observer, observers_, OnApplicationUninstalled(id));
491
492   return result;
493 }
494
495 bool ApplicationService::ChangeLocale(const std::string& locale) {
496   const ApplicationData::ApplicationDataMap& apps =
497       application_storage_->GetInstalledApplications();
498   ApplicationData::ApplicationDataMap::const_iterator it;
499   for (it = apps.begin(); it != apps.end(); ++it) {
500     base::string16 error;
501     std::string old_name = it->second->Name();
502     if (!it->second->SetApplicationLocale(locale, &error)) {
503       LOG(ERROR) << "Error when set locale " << locale
504                  << " to application " << it->second->ID()
505                  << "error : " << error;
506     }
507     if (old_name != it->second->Name()) {
508       // After we has changed the application locale, we might get a new name in
509       // the new locale, so call all observer for this event.
510       FOR_EACH_OBSERVER(
511           Observer, observers_,
512           OnApplicationNameChanged(it->second->ID(), it->second->Name()));
513     }
514   }
515 }
516
517 Application* ApplicationService::Launch(
518     scoped_refptr<ApplicationData> application_data,
519     const Application::LaunchParams& launch_params) {
520   if (GetApplicationByID(application_data->ID()) != NULL) {
521     LOG(INFO) << "Application with id: " << application_data->ID()
522               << " is already running.";
523     // FIXME: we need to notify application that it had been attempted
524     // to invoke and let the application to define the further behavior.
525     return NULL;
526   }
527
528   event_manager_->AddEventRouterForApp(application_data);
529   Application* application(new Application(application_data,
530                                            runtime_context_,
531                                            this));
532   ScopedVector<Application>::iterator app_iter =
533       applications_.insert(applications_.end(), application);
534
535   if (!application->Launch(launch_params)) {
536     event_manager_->RemoveEventRouterForApp(application_data);
537     applications_.erase(app_iter);
538     return NULL;
539   }
540
541   FOR_EACH_OBSERVER(Observer, observers_,
542                     DidLaunchApplication(application));
543
544   return application;
545 }
546
547 Application* ApplicationService::Launch(
548     const std::string& id, const Application::LaunchParams& params) {
549   Application* application = NULL;
550   scoped_refptr<ApplicationData> application_data =
551     application_storage_->GetApplicationData(id);
552   if (!application_data) {
553     LOG(ERROR) << "Application with id " << id << " is not installed.";
554     return NULL;
555   }
556
557   if ((application = Launch(application_data, params))) {
558     scoped_refptr<Event> event = Event::CreateEvent(
559         kOnLaunched, scoped_ptr<base::ListValue>(new base::ListValue));
560     event_manager_->SendEvent(application->id(), event);
561   }
562   return application;
563 }
564
565 Application* ApplicationService::Launch(
566     const base::FilePath& path, const Application::LaunchParams& params) {
567   Application* application = NULL;
568   if (!base::DirectoryExists(path))
569     return NULL;
570
571   std::string error;
572   scoped_refptr<ApplicationData> application_data =
573       LoadApplication(path, Manifest::COMMAND_LINE, &error);
574
575   if (!application_data) {
576     LOG(ERROR) << "Error occurred while trying to launch application: "
577                << error;
578     return NULL;
579   }
580
581   if ((application = Launch(application_data, params))) {
582     scoped_refptr<Event> event = Event::CreateEvent(
583         kOnLaunched, scoped_ptr<base::ListValue>(new base::ListValue));
584     event_manager_->SendEvent(application->id(), event);
585   }
586   return application;
587 }
588
589 namespace {
590
591 struct ApplicationRenderHostIDComparator {
592     explicit ApplicationRenderHostIDComparator(int id) : id(id) { }
593     bool operator() (Application* application) {
594       return id == application->GetRenderProcessHostID();
595     }
596     int id;
597 };
598
599 struct ApplicationIDComparator {
600     explicit ApplicationIDComparator(const std::string& app_id)
601       : app_id(app_id) { }
602     bool operator() (Application* application) {
603       return app_id == application->id();
604     }
605     std::string app_id;
606 };
607
608 }  // namespace
609
610 Application* ApplicationService::GetApplicationByRenderHostID(int id) const {
611   ApplicationRenderHostIDComparator comparator(id);
612   ScopedVector<Application>::const_iterator found = std::find_if(
613       applications_.begin(), applications_.end(), comparator);
614   if (found != applications_.end())
615     return *found;
616   return NULL;
617 }
618
619 Application* ApplicationService::GetApplicationByID(
620     const std::string& app_id) const {
621   ApplicationIDComparator comparator(app_id);
622   ScopedVector<Application>::const_iterator found = std::find_if(
623       applications_.begin(), applications_.end(), comparator);
624   if (found != applications_.end())
625     return *found;
626   return NULL;
627 }
628
629 void ApplicationService::AddObserver(Observer* observer) {
630   observers_.AddObserver(observer);
631 }
632
633 void ApplicationService::RemoveObserver(Observer* observer) {
634   observers_.RemoveObserver(observer);
635 }
636
637 void ApplicationService::OnApplicationTerminated(
638                                       Application* application) {
639   ScopedVector<Application>::iterator found = std::find(
640       applications_.begin(), applications_.end(), application);
641   CHECK(found != applications_.end());
642   FOR_EACH_OBSERVER(Observer, observers_,
643                     WillDestroyApplication(application));
644   applications_.erase(found);
645   if (!XWalkRunner::GetInstance()->is_running_as_service() &&
646       applications_.empty()) {
647     base::MessageLoop::current()->PostTask(
648             FROM_HERE, base::MessageLoop::QuitClosure());
649   }
650 }
651
652 void ApplicationService::CheckAPIAccessControl(const std::string& app_id,
653     const std::string& extension_name,
654     const std::string& api_name, const PermissionCallback& callback) {
655   Application* app = GetApplicationByID(app_id);
656   if (!app) {
657     LOG(ERROR) << "No running application found with ID: "
658       << app_id;
659     callback.Run(UNDEFINED_RUNTIME_PERM);
660     return;
661   }
662   if (!app->UseExtension(extension_name)) {
663     LOG(ERROR) << "Can not find extension: "
664       << extension_name << " of Application with ID: "
665       << app_id;
666     callback.Run(UNDEFINED_RUNTIME_PERM);
667     return;
668   }
669   // Permission name should have been registered at extension initialization.
670   std::string permission_name =
671       app->GetRegisteredPermissionName(extension_name, api_name);
672   if (permission_name.empty()) {
673     LOG(ERROR) << "API: " << api_name << " of extension: "
674       << extension_name << " not registered!";
675     callback.Run(UNDEFINED_RUNTIME_PERM);
676     return;
677   }
678   // Okay, since we have the permission name, let's get down to the policies.
679   // First, find out whether the permission is stored for the current session.
680   StoredPermission perm = app->GetPermission(
681       SESSION_PERMISSION, permission_name);
682   if (perm != UNDEFINED_STORED_PERM) {
683     // "PROMPT" should not be in the session storage.
684     DCHECK(perm != PROMPT);
685     if (perm == ALLOW) {
686       callback.Run(ALLOW_SESSION);
687       return;
688     }
689     if (perm == DENY) {
690       callback.Run(DENY_SESSION);
691       return;
692     }
693     NOTREACHED();
694   }
695   // Then, query the persistent policy storage.
696   perm = app->GetPermission(PERSISTENT_PERMISSION, permission_name);
697   // Permission not found in persistent permission table, normally this should
698   // not happen because all the permission needed by the application should be
699   // contained in its manifest, so it also means that the application is asking
700   // for something wasn't allowed.
701   if (perm == UNDEFINED_STORED_PERM) {
702     callback.Run(UNDEFINED_RUNTIME_PERM);
703     return;
704   }
705   if (perm == PROMPT) {
706     // TODO(Bai): We needed to pop-up a dialog asking user to chose one from
707     // either allow/deny for session/one shot/forever. Then, we need to update
708     // the session and persistent policy accordingly.
709     callback.Run(UNDEFINED_RUNTIME_PERM);
710     return;
711   }
712   if (perm == ALLOW) {
713     callback.Run(ALLOW_ALWAYS);
714     return;
715   }
716   if (perm == DENY) {
717     callback.Run(DENY_ALWAYS);
718     return;
719   }
720   NOTREACHED();
721 }
722
723 bool ApplicationService::RegisterPermissions(const std::string& app_id,
724     const std::string& extension_name,
725     const std::string& perm_table) {
726   Application* app = GetApplicationByID(app_id);
727   if (!app) {
728     LOG(ERROR) << "No running application found with ID: " << app_id;
729     return false;
730   }
731   if (!app->UseExtension(extension_name)) {
732     LOG(ERROR) << "Can not find extension: "
733                << extension_name << " of Application with ID: "
734                << app_id;
735     return false;
736   }
737   return app->RegisterPermissions(extension_name, perm_table);
738 }
739
740 }  // namespace application
741 }  // namespace xwalk