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.
5 #include "xwalk/application/browser/application_service.h"
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"
33 #include "xwalk/application/browser/installer/tizen/service_package_installer.h"
37 namespace application {
41 void WaitForEventAndClose(
42 const std::string& app_id,
43 const std::string& event_name,
44 ApplicationService* application_service,
45 ApplicationEventManager* event_manager) {
47 class CloseOnEventArrived : public EventObserver {
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) {}
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_)
66 if (Application* app = application_service_->GetApplicationByID(app_id))
67 app->Terminate(Application::Immediate);
73 std::string event_name_;
74 ApplicationService* application_service_;
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);
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 {
91 CloseAfterLoadObserver(
92 const std::string& app_id,
93 ApplicationService* application_service,
94 ApplicationEventManager* event_manager,
95 content::WebContents* contents)
96 : content::WebContentsObserver(contents),
98 application_service_(application_service),
99 event_manager_(event_manager) {
100 DCHECK(application_service_);
101 DCHECK(event_manager_);
104 virtual void DidFinishLoad(
106 const GURL& validate_url,
108 content::RenderViewHost* render_view_host) OVERRIDE {
109 Application* app = application_service_->GetApplicationByID(id_);
115 if (!IsEventHandlerRegistered(app->data(), kOnInstalled)) {
116 app->Terminate(Application::Immediate);
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);
123 WaitForEventAndClose(
124 id_, event->name(), application_service_, event_manager_);
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();
137 ApplicationService* application_service_;
138 ApplicationEventManager* event_manager_;
141 // This object is self-destroyed when an event occurs.
142 new CloseAfterLoadObserver(
143 app_id, application_service, event_manager, contents);
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());
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.";
170 return InstallApplicationForTizen(application_data, data_dir);
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.";
181 return UninstallApplicationForTizen(application_data, data_dir);
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))
193 } else if (!base::CopyFile(path, to.Append(path.BaseName()))) {
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);
213 const base::FilePath::CharType kApplicationsDir[] =
214 FILE_PATH_LITERAL("applications");
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);
226 ApplicationService::~ApplicationService() {
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))
235 const base::FilePath data_dir =
236 runtime_context_->GetPath().Append(kApplicationsDir);
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))
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();
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;
263 if (!permission_policy_handler_->
264 InitApplicationPermission(application_data)) {
265 LOG(ERROR) << "Application permission data is invalid";
269 if (application_storage_->Contains(application_data->ID())) {
270 *id = application_data->ID();
271 LOG(INFO) << "Already installed: " << *id;
275 base::FilePath app_dir = data_dir.AppendASCII(application_data->ID());
276 if (base::DirectoryExists(app_dir)) {
277 if (!base::DeleteFile(app_dir, true))
281 if (!base::CreateDirectory(app_dir))
283 if (!CopyDirectoryContents(unpacked_dir, app_dir))
286 if (!base::Move(unpacked_dir, app_dir))
290 application_data->SetPath(app_dir);
292 if (!application_storage_->AddApplication(application_data)) {
293 LOG(ERROR) << "Application with id " << application_data->ID()
294 << " couldn't be installed.";
298 #if defined(OS_TIZEN)
299 if (!InstallPackageOnTizen(application_data,
300 runtime_context_->GetPath())) {
301 application_storage_->RemoveApplication(application_data->ID());
306 LOG(INFO) << "Application be installed in: " << app_dir.MaybeAsASCII();
307 LOG(INFO) << "Installed application with id: " << application_data->ID()
309 *id = application_data->ID();
311 SaveSystemEventsInfo(application_data, this, event_manager_);
313 FOR_EACH_OBSERVER(Observer, observers_,
314 OnApplicationInstalled(application_data->ID()));
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.";
326 if (base::DirectoryExists(path)) {
327 LOG(WARNING) << "Can not update an unpacked XPK/WGT package.";
331 base::FilePath unpacked_dir;
332 base::FilePath origin_dir;
334 scoped_ptr<Package> package = Package::Create(path);
336 LOG(ERROR) << "XPK/WGT file is invalid.";
340 app_id = package->Id();
342 if (app_id.empty()) {
343 LOG(ERROR) << "XPK/WGT file is invalid, and the application id is empty.";
348 id.compare(app_id) != 0) {
349 LOG(ERROR) << "The XPK/WGT file is not the same as expecting.";
353 if (!package->Extract(&unpacked_dir))
357 scoped_refptr<ApplicationData> new_application =
358 LoadApplication(unpacked_dir,
360 Manifest::COMMAND_LINE,
362 if (!new_application) {
363 LOG(ERROR) << "An error occurred during application updating: " << error;
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;
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();
382 const base::FilePath& app_dir = old_application->Path();
383 const base::FilePath tmp_dir(app_dir.value()
384 + FILE_PATH_LITERAL(".tmp"));
386 if (Application* app = GetApplicationByID(app_id)) {
387 LOG(INFO) << "Try to terminate the running application before update.";
388 app->Terminate(Application::Immediate);
391 if (!base::Move(app_dir, tmp_dir) ||
392 !base::Move(unpacked_dir, app_dir))
395 new_application = LoadApplication(app_dir,
397 Manifest::COMMAND_LINE,
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);
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);
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());
425 #if defined(OS_TIZEN)
426 if (!InstallPackageOnTizen(new_application,
427 runtime_context_->GetPath()))
430 base::DeleteFile(tmp_dir, true);
432 SaveSystemEventsInfo(new_application, this, event_manager_);
434 FOR_EACH_OBSERVER(Observer, observers_,
435 OnApplicationUpdated(app_id));
440 bool ApplicationService::Uninstall(const std::string& id) {
443 scoped_refptr<ApplicationData> application =
444 application_storage_->GetApplicationData(id);
446 LOG(ERROR) << "Cannot uninstall application with id " << id
447 << "; invalid application id";
451 if (Application* app = GetApplicationByID(id)) {
452 LOG(INFO) << "Try to terminate the running application before uninstall.";
453 app->Terminate(Application::Immediate);
456 #if defined(OS_TIZEN)
457 if (!UninstallPackageOnTizen(application,
458 runtime_context_->GetPath()))
462 if (!application_storage_->RemoveApplication(id)) {
463 LOG(ERROR) << "Cannot uninstall application with id " << id
464 << "; application is not installed.";
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.";
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,
484 partition->GetURLRequestContext());
487 PathService::Get(xwalk::DIR_WGT_STORAGE_PATH, &path);
488 RemoveWidgetStorageFiles(path, id);
490 FOR_EACH_OBSERVER(Observer, observers_, OnApplicationUninstalled(id));
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;
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.
511 Observer, observers_,
512 OnApplicationNameChanged(it->second->ID(), it->second->Name()));
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.
528 event_manager_->AddEventRouterForApp(application_data);
529 Application* application(new Application(application_data,
532 ScopedVector<Application>::iterator app_iter =
533 applications_.insert(applications_.end(), application);
535 if (!application->Launch(launch_params)) {
536 event_manager_->RemoveEventRouterForApp(application_data);
537 applications_.erase(app_iter);
541 FOR_EACH_OBSERVER(Observer, observers_,
542 DidLaunchApplication(application));
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.";
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);
565 Application* ApplicationService::Launch(
566 const base::FilePath& path, const Application::LaunchParams& params) {
567 Application* application = NULL;
568 if (!base::DirectoryExists(path))
572 scoped_refptr<ApplicationData> application_data =
573 LoadApplication(path, Manifest::COMMAND_LINE, &error);
575 if (!application_data) {
576 LOG(ERROR) << "Error occurred while trying to launch application: "
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);
591 struct ApplicationRenderHostIDComparator {
592 explicit ApplicationRenderHostIDComparator(int id) : id(id) { }
593 bool operator() (Application* application) {
594 return id == application->GetRenderProcessHostID();
599 struct ApplicationIDComparator {
600 explicit ApplicationIDComparator(const std::string& app_id)
602 bool operator() (Application* application) {
603 return app_id == application->id();
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())
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())
629 void ApplicationService::AddObserver(Observer* observer) {
630 observers_.AddObserver(observer);
633 void ApplicationService::RemoveObserver(Observer* observer) {
634 observers_.RemoveObserver(observer);
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());
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);
657 LOG(ERROR) << "No running application found with ID: "
659 callback.Run(UNDEFINED_RUNTIME_PERM);
662 if (!app->UseExtension(extension_name)) {
663 LOG(ERROR) << "Can not find extension: "
664 << extension_name << " of Application with ID: "
666 callback.Run(UNDEFINED_RUNTIME_PERM);
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);
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);
686 callback.Run(ALLOW_SESSION);
690 callback.Run(DENY_SESSION);
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);
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);
713 callback.Run(ALLOW_ALWAYS);
717 callback.Run(DENY_ALWAYS);
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);
728 LOG(ERROR) << "No running application found with ID: " << app_id;
731 if (!app->UseExtension(extension_name)) {
732 LOG(ERROR) << "Can not find extension: "
733 << extension_name << " of Application with ID: "
737 return app->RegisterPermissions(extension_name, perm_table);
740 } // namespace application