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/application_tizen.h"
34 #include "xwalk/application/browser/installer/tizen/package_installer.h"
38 namespace application {
42 void WaitForEventAndClose(
43 const std::string& app_id,
44 const std::string& event_name,
45 ApplicationService* application_service,
46 ApplicationEventManager* event_manager) {
48 class CloseOnEventArrived : public EventObserver {
51 const std::string& event_name,
52 ApplicationService* application_service,
53 ApplicationEventManager* event_manager)
54 : EventObserver(event_manager),
55 event_name_(event_name),
56 application_service_(application_service) {}
59 const std::string& app_id,
60 scoped_refptr<Event> event) OVERRIDE {
61 DCHECK(kOnJavaScriptEventAck == event->name());
62 std::string ack_event_name;
63 event->args()->GetString(0, &ack_event_name);
64 if (ack_event_name != event_name_)
67 if (Application* app = application_service_->GetApplicationByID(app_id))
68 app->Terminate(Application::Immediate);
74 std::string event_name_;
75 ApplicationService* application_service_;
78 DCHECK(event_manager);
79 CloseOnEventArrived* observer =
80 new CloseOnEventArrived(event_name, application_service, event_manager);
81 event_manager->AttachObserver(app_id,
82 kOnJavaScriptEventAck, observer);
85 void WaitForFinishLoad(
86 const std::string& app_id,
87 ApplicationService* application_service,
88 ApplicationEventManager* event_manager,
89 content::WebContents* contents) {
90 class CloseAfterLoadObserver : public content::WebContentsObserver {
92 CloseAfterLoadObserver(
93 const std::string& app_id,
94 ApplicationService* application_service,
95 ApplicationEventManager* event_manager,
96 content::WebContents* contents)
97 : content::WebContentsObserver(contents),
99 application_service_(application_service),
100 event_manager_(event_manager) {
101 DCHECK(application_service_);
102 DCHECK(event_manager_);
105 virtual void DidFinishLoad(
107 const GURL& validate_url,
109 content::RenderViewHost* render_view_host) OVERRIDE {
110 Application* app = application_service_->GetApplicationByID(id_);
116 if (!IsEventHandlerRegistered(app->data(), kOnInstalled)) {
117 app->Terminate(Application::Immediate);
119 scoped_ptr<base::ListValue> event_args(new base::ListValue);
120 scoped_refptr<Event> event =
121 Event::CreateEvent(kOnInstalled, event_args.Pass());
122 event_manager_->SendEvent(id_, event);
124 WaitForEventAndClose(
125 id_, event->name(), application_service_, event_manager_);
131 bool IsEventHandlerRegistered(scoped_refptr<ApplicationData> app_data,
132 const std::string& event_name) const {
133 const std::set<std::string>& events = app_data->GetEvents();
134 return events.find(event_name) != events.end();
138 ApplicationService* application_service_;
139 ApplicationEventManager* event_manager_;
142 // This object is self-destroyed when an event occurs.
143 new CloseAfterLoadObserver(
144 app_id, application_service, event_manager, contents);
147 void SaveSystemEventsInfo(
148 scoped_refptr<ApplicationData> application_data,
149 ApplicationService* application_service,
150 ApplicationEventManager* event_manager) {
151 // We need to run main document after installation in order to
152 // register system events.
153 if (application_data->HasMainDocument()) {
154 if (Application* application =
155 application_service->Launch(application_data->ID())) {
156 WaitForFinishLoad(application->id(), application_service, event_manager,
157 application->GetMainDocumentRuntime()->web_contents());
162 bool CopyDirectoryContents(const base::FilePath& from,
163 const base::FilePath& to) {
164 base::FileEnumerator iter(from, false,
165 base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
166 for (base::FilePath path = iter.Next(); !path.empty(); path = iter.Next()) {
167 if (iter.GetInfo().IsDirectory()) {
168 if (!base::CopyDirectory(path, to, true))
170 } else if (!base::CopyFile(path, to.Append(path.BaseName()))) {
178 void RemoveWidgetStorageFiles(const base::FilePath& storage_path,
179 const std::string& app_id) {
180 base::FileEnumerator iter(storage_path, true,
181 base::FileEnumerator::FILES);
182 for (base::FilePath file = iter.Next(); !file.empty(); file = iter.Next()) {
183 if (file.MaybeAsASCII().find(app_id) != std::string::npos)
184 base::DeleteFile(file, false);
190 const base::FilePath::CharType kApplicationsDir[] =
191 FILE_PATH_LITERAL("applications");
193 ApplicationService::ApplicationService(RuntimeContext* runtime_context,
194 ApplicationStorage* app_storage,
195 ApplicationEventManager* event_manager)
196 : runtime_context_(runtime_context),
197 application_storage_(app_storage),
198 event_manager_(event_manager),
199 permission_policy_handler_(new PermissionPolicyManager()) {
200 AddObserver(event_manager);
203 ApplicationService::~ApplicationService() {
206 bool ApplicationService::Install(const base::FilePath& path, std::string* id) {
207 // FIXME(leandro): Installation is not robust enough -- should any step
208 // fail, it can't roll back to a consistent state.
209 if (!base::PathExists(path))
212 const base::FilePath data_dir =
213 runtime_context_->GetPath().Append(kApplicationsDir);
215 // Make sure the kApplicationsDir exists under data_path, otherwise,
216 // the installation will always fail because of moving application
217 // resources into an invalid directory.
218 if (!base::DirectoryExists(data_dir) &&
219 !base::CreateDirectory(data_dir))
223 base::FilePath unpacked_dir;
224 scoped_ptr<Package> package;
225 if (!base::DirectoryExists(path)) {
226 package = Package::Create(path);
227 package->Extract(&unpacked_dir);
228 app_id = package->Id();
234 scoped_refptr<ApplicationData> application_data = LoadApplication(
235 unpacked_dir, app_id, Manifest::COMMAND_LINE, &error);
236 if (!application_data) {
237 LOG(ERROR) << "Error during application installation: " << error;
240 if (!permission_policy_handler_->
241 InitApplicationPermission(application_data)) {
242 LOG(ERROR) << "Application permission data is invalid";
246 if (application_storage_->Contains(application_data->ID())) {
247 *id = application_data->ID();
248 LOG(INFO) << "Already installed: " << *id;
252 base::FilePath app_dir = data_dir.AppendASCII(application_data->ID());
253 if (base::DirectoryExists(app_dir)) {
254 if (!base::DeleteFile(app_dir, true))
258 if (!base::CreateDirectory(app_dir))
260 if (!CopyDirectoryContents(unpacked_dir, app_dir))
263 if (!base::Move(unpacked_dir, app_dir))
267 application_data->SetPath(app_dir);
269 if (!application_storage_->AddApplication(application_data)) {
270 LOG(ERROR) << "Application with id " << application_data->ID()
271 << " couldn't be installed.";
275 #if defined(OS_TIZEN)
276 if (!PackageInstaller::InstallApplication(
277 application_data, runtime_context_->GetPath())) {
278 application_storage_->RemoveApplication(application_data->ID());
283 LOG(INFO) << "Application be installed in: " << app_dir.MaybeAsASCII();
284 LOG(INFO) << "Installed application with id: " << application_data->ID()
286 *id = application_data->ID();
288 SaveSystemEventsInfo(application_data, this, event_manager_);
290 FOR_EACH_OBSERVER(Observer, observers_,
291 OnApplicationInstalled(application_data->ID()));
296 bool ApplicationService::Update(const std::string& id,
297 const base::FilePath& path) {
298 if (!base::PathExists(path)) {
299 LOG(ERROR) << "The XPK/WGT package file " << path.value() << " is invalid.";
303 if (base::DirectoryExists(path)) {
304 LOG(WARNING) << "Can not update an unpacked XPK/WGT package.";
308 base::FilePath unpacked_dir;
309 base::FilePath origin_dir;
311 scoped_ptr<Package> package = Package::Create(path);
313 LOG(ERROR) << "XPK/WGT file is invalid.";
317 app_id = package->Id();
319 if (app_id.empty()) {
320 LOG(ERROR) << "XPK/WGT file is invalid, and the application id is empty.";
325 id.compare(app_id) != 0) {
326 LOG(ERROR) << "The XPK/WGT file is not the same as expecting.";
330 if (!package->Extract(&unpacked_dir))
334 scoped_refptr<ApplicationData> new_application =
335 LoadApplication(unpacked_dir,
337 Manifest::COMMAND_LINE,
339 if (!new_application) {
340 LOG(ERROR) << "An error occurred during application updating: " << error;
344 scoped_refptr<ApplicationData> old_application =
345 application_storage_->GetApplicationData(app_id);
346 if (!old_application) {
347 LOG(INFO) << "Application haven't installed yet: " << app_id;
351 if (old_application->Version()->CompareTo(
352 *(new_application->Version())) >= 0) {
353 LOG(INFO) << "The version number of new XPK/WGT package "
354 "should be higher than "
355 << old_application->VersionString();
359 const base::FilePath& app_dir = old_application->Path();
360 const base::FilePath tmp_dir(app_dir.value()
361 + FILE_PATH_LITERAL(".tmp"));
363 if (Application* app = GetApplicationByID(app_id)) {
364 LOG(INFO) << "Try to terminate the running application before update.";
365 app->Terminate(Application::Immediate);
368 if (!base::Move(app_dir, tmp_dir) ||
369 !base::Move(unpacked_dir, app_dir))
372 new_application = LoadApplication(app_dir,
374 Manifest::COMMAND_LINE,
376 if (!new_application) {
377 LOG(ERROR) << "Error during loading new package: " << error;
378 base::DeleteFile(app_dir, true);
379 base::Move(tmp_dir, app_dir);
383 if (!application_storage_->UpdateApplication(new_application)) {
384 LOG(ERROR) << "Fail to update application, roll back to the old one.";
385 base::DeleteFile(app_dir, true);
386 base::Move(tmp_dir, app_dir);
390 #if defined(OS_TIZEN)
391 if (!PackageInstaller::UpdateApplication(
392 new_application, runtime_context_->GetPath())) {
393 LOG(ERROR) << "Fail to update package on Tizen, roll back to the old one.";
394 base::DeleteFile(app_dir, true);
395 if (!application_storage_->UpdateApplication(old_application)) {
396 LOG(ERROR) << "Fail to revert old application info, "
397 << "remove the application as a last resort.";
398 application_storage_->RemoveApplication(old_application->ID());
401 base::Move(tmp_dir, app_dir);
406 base::DeleteFile(tmp_dir, true);
408 SaveSystemEventsInfo(new_application, this, event_manager_);
410 FOR_EACH_OBSERVER(Observer, observers_,
411 OnApplicationUpdated(app_id));
416 bool ApplicationService::Uninstall(const std::string& id) {
419 scoped_refptr<ApplicationData> application =
420 application_storage_->GetApplicationData(id);
422 LOG(ERROR) << "Cannot uninstall application with id " << id
423 << "; invalid application id";
427 if (Application* app = GetApplicationByID(id)) {
428 LOG(INFO) << "Try to terminate the running application before uninstall.";
429 app->Terminate(Application::Immediate);
432 #if defined(OS_TIZEN)
433 if (!PackageInstaller::UninstallApplication(
434 application, runtime_context_->GetPath()))
438 if (!application_storage_->RemoveApplication(id)) {
439 LOG(ERROR) << "Cannot uninstall application with id " << id
440 << "; application is not installed.";
444 const base::FilePath resources =
445 runtime_context_->GetPath().Append(kApplicationsDir).AppendASCII(id);
446 if (base::DirectoryExists(resources) &&
447 !base::DeleteFile(resources, true)) {
448 LOG(ERROR) << "Error occurred while trying to remove application with id "
449 << id << "; Cannot remove all resources.";
453 content::StoragePartition* partition =
454 content::BrowserContext::GetStoragePartitionForSite(
455 runtime_context_, application->GetBaseURLFromApplicationId(id));
456 partition->ClearDataForOrigin(
457 content::StoragePartition::REMOVE_DATA_MASK_ALL,
458 content::StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL,
460 partition->GetURLRequestContext());
463 PathService::Get(xwalk::DIR_WGT_STORAGE_PATH, &path);
464 RemoveWidgetStorageFiles(path, id);
466 FOR_EACH_OBSERVER(Observer, observers_, OnApplicationUninstalled(id));
471 void ApplicationService::ChangeLocale(const std::string& locale) {
472 const ApplicationData::ApplicationDataMap& apps =
473 application_storage_->GetInstalledApplications();
474 ApplicationData::ApplicationDataMap::const_iterator it;
475 for (it = apps.begin(); it != apps.end(); ++it) {
476 base::string16 error;
477 std::string old_name = it->second->Name();
478 if (!it->second->SetApplicationLocale(locale, &error)) {
479 LOG(ERROR) << "Error when set locale " << locale
480 << " to application " << it->second->ID()
481 << "error : " << error;
483 if (old_name != it->second->Name()) {
484 // After we has changed the application locale, we might get a new name in
485 // the new locale, so call all observer for this event.
487 Observer, observers_,
488 OnApplicationNameChanged(it->second->ID(), it->second->Name()));
493 Application* ApplicationService::Launch(
494 scoped_refptr<ApplicationData> application_data,
495 const Application::LaunchParams& launch_params) {
496 if (GetApplicationByID(application_data->ID()) != NULL) {
497 LOG(INFO) << "Application with id: " << application_data->ID()
498 << " is already running.";
499 // FIXME: we need to notify application that it had been attempted
500 // to invoke and let the application to define the further behavior.
504 event_manager_->AddEventRouterForApp(application_data);
506 #if defined(OS_TIZEN)
507 Application* application(new ApplicationTizen(application_data,
508 runtime_context_, this));
510 Application* application(new Application(application_data,
511 runtime_context_, this));
514 ScopedVector<Application>::iterator app_iter =
515 applications_.insert(applications_.end(), application);
517 if (!application->Launch(launch_params)) {
518 event_manager_->RemoveEventRouterForApp(application_data);
519 applications_.erase(app_iter);
523 FOR_EACH_OBSERVER(Observer, observers_,
524 DidLaunchApplication(application));
529 Application* ApplicationService::Launch(
530 const std::string& id, const Application::LaunchParams& params) {
531 Application* application = NULL;
532 scoped_refptr<ApplicationData> application_data =
533 application_storage_->GetApplicationData(id);
534 if (!application_data) {
535 LOG(ERROR) << "Application with id " << id << " is not installed.";
539 if ((application = Launch(application_data, params))) {
540 scoped_refptr<Event> event = Event::CreateEvent(
541 kOnLaunched, scoped_ptr<base::ListValue>(new base::ListValue));
542 event_manager_->SendEvent(application->id(), event);
547 Application* ApplicationService::Launch(
548 const base::FilePath& path, const Application::LaunchParams& params) {
549 Application* application = NULL;
550 if (!base::DirectoryExists(path))
554 scoped_refptr<ApplicationData> application_data =
555 LoadApplication(path, Manifest::COMMAND_LINE, &error);
557 if (!application_data) {
558 LOG(ERROR) << "Error occurred while trying to launch application: "
563 if ((application = Launch(application_data, params))) {
564 scoped_refptr<Event> event = Event::CreateEvent(
565 kOnLaunched, scoped_ptr<base::ListValue>(new base::ListValue));
566 event_manager_->SendEvent(application->id(), event);
573 struct ApplicationRenderHostIDComparator {
574 explicit ApplicationRenderHostIDComparator(int id) : id(id) { }
575 bool operator() (Application* application) {
576 return id == application->GetRenderProcessHostID();
581 struct ApplicationIDComparator {
582 explicit ApplicationIDComparator(const std::string& app_id)
584 bool operator() (Application* application) {
585 return app_id == application->id();
592 Application* ApplicationService::GetApplicationByRenderHostID(int id) const {
593 ApplicationRenderHostIDComparator comparator(id);
594 ScopedVector<Application>::const_iterator found = std::find_if(
595 applications_.begin(), applications_.end(), comparator);
596 if (found != applications_.end())
601 Application* ApplicationService::GetApplicationByID(
602 const std::string& app_id) const {
603 ApplicationIDComparator comparator(app_id);
604 ScopedVector<Application>::const_iterator found = std::find_if(
605 applications_.begin(), applications_.end(), comparator);
606 if (found != applications_.end())
611 void ApplicationService::AddObserver(Observer* observer) {
612 observers_.AddObserver(observer);
615 void ApplicationService::RemoveObserver(Observer* observer) {
616 observers_.RemoveObserver(observer);
619 void ApplicationService::OnApplicationTerminated(
620 Application* application) {
621 ScopedVector<Application>::iterator found = std::find(
622 applications_.begin(), applications_.end(), application);
623 CHECK(found != applications_.end());
624 FOR_EACH_OBSERVER(Observer, observers_,
625 WillDestroyApplication(application));
626 applications_.erase(found);
627 if (!XWalkRunner::GetInstance()->is_running_as_service() &&
628 applications_.empty()) {
629 base::MessageLoop::current()->PostTask(
630 FROM_HERE, base::MessageLoop::QuitClosure());
634 void ApplicationService::CheckAPIAccessControl(const std::string& app_id,
635 const std::string& extension_name,
636 const std::string& api_name, const PermissionCallback& callback) {
637 Application* app = GetApplicationByID(app_id);
639 LOG(ERROR) << "No running application found with ID: "
641 callback.Run(UNDEFINED_RUNTIME_PERM);
644 if (!app->UseExtension(extension_name)) {
645 LOG(ERROR) << "Can not find extension: "
646 << extension_name << " of Application with ID: "
648 callback.Run(UNDEFINED_RUNTIME_PERM);
651 // Permission name should have been registered at extension initialization.
652 std::string permission_name =
653 app->GetRegisteredPermissionName(extension_name, api_name);
654 if (permission_name.empty()) {
655 LOG(ERROR) << "API: " << api_name << " of extension: "
656 << extension_name << " not registered!";
657 callback.Run(UNDEFINED_RUNTIME_PERM);
660 // Okay, since we have the permission name, let's get down to the policies.
661 // First, find out whether the permission is stored for the current session.
662 StoredPermission perm = app->GetPermission(
663 SESSION_PERMISSION, permission_name);
664 if (perm != UNDEFINED_STORED_PERM) {
665 // "PROMPT" should not be in the session storage.
666 DCHECK(perm != PROMPT);
668 callback.Run(ALLOW_SESSION);
672 callback.Run(DENY_SESSION);
677 // Then, query the persistent policy storage.
678 perm = app->GetPermission(PERSISTENT_PERMISSION, permission_name);
679 // Permission not found in persistent permission table, normally this should
680 // not happen because all the permission needed by the application should be
681 // contained in its manifest, so it also means that the application is asking
682 // for something wasn't allowed.
683 if (perm == UNDEFINED_STORED_PERM) {
684 callback.Run(UNDEFINED_RUNTIME_PERM);
687 if (perm == PROMPT) {
688 // TODO(Bai): We needed to pop-up a dialog asking user to chose one from
689 // either allow/deny for session/one shot/forever. Then, we need to update
690 // the session and persistent policy accordingly.
691 callback.Run(UNDEFINED_RUNTIME_PERM);
695 callback.Run(ALLOW_ALWAYS);
699 callback.Run(DENY_ALWAYS);
705 bool ApplicationService::RegisterPermissions(const std::string& app_id,
706 const std::string& extension_name,
707 const std::string& perm_table) {
708 Application* app = GetApplicationByID(app_id);
710 LOG(ERROR) << "No running application found with ID: " << app_id;
713 if (!app->UseExtension(extension_name)) {
714 LOG(ERROR) << "Can not find extension: "
715 << extension_name << " of Application with ID: "
719 return app->RegisterPermissions(extension_name, perm_table);
722 } // namespace application