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.h"
20 #include "xwalk/application/browser/application_storage.h"
21 #include "xwalk/application/browser/application_system.h"
22 #include "xwalk/application/browser/installer/package.h"
23 #include "xwalk/application/common/application_file_util.h"
24 #include "xwalk/application/common/permission_policy_manager.h"
25 #include "xwalk/runtime/browser/runtime_context.h"
26 #include "xwalk/runtime/browser/runtime.h"
27 #include "xwalk/runtime/browser/xwalk_runner.h"
28 #include "xwalk/runtime/common/xwalk_paths.h"
31 #include "xwalk/application/browser/application_tizen.h"
32 #include "xwalk/application/browser/installer/tizen/package_installer.h"
36 namespace application {
40 bool CopyDirectoryContents(const base::FilePath& from,
41 const base::FilePath& to) {
42 base::FileEnumerator iter(from, false,
43 base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
44 for (base::FilePath path = iter.Next(); !path.empty(); path = iter.Next()) {
45 if (iter.GetInfo().IsDirectory()) {
46 if (!base::CopyDirectory(path, to, true))
48 } else if (!base::CopyFile(path, to.Append(path.BaseName()))) {
56 void RemoveWidgetStorageFiles(const base::FilePath& storage_path,
57 const std::string& app_id) {
58 base::FileEnumerator iter(storage_path, true,
59 base::FileEnumerator::FILES);
60 for (base::FilePath file = iter.Next(); !file.empty(); file = iter.Next()) {
61 if (file.MaybeAsASCII().find(app_id) != std::string::npos)
62 base::DeleteFile(file, false);
68 const base::FilePath::CharType kApplicationsDir[] =
69 FILE_PATH_LITERAL("applications");
71 ApplicationService::ApplicationService(RuntimeContext* runtime_context,
72 ApplicationStorage* app_storage)
73 : runtime_context_(runtime_context),
74 application_storage_(app_storage),
75 permission_policy_handler_(new PermissionPolicyManager()) {
78 ApplicationService::~ApplicationService() {
81 bool ApplicationService::Install(const base::FilePath& path, std::string* id) {
82 // FIXME(leandro): Installation is not robust enough -- should any step
83 // fail, it can't roll back to a consistent state.
84 if (!base::PathExists(path))
87 const base::FilePath data_dir =
88 runtime_context_->GetPath().Append(kApplicationsDir);
90 // Make sure the kApplicationsDir exists under data_path, otherwise,
91 // the installation will always fail because of moving application
92 // resources into an invalid directory.
93 if (!base::DirectoryExists(data_dir) &&
94 !base::CreateDirectory(data_dir))
98 base::FilePath unpacked_dir;
99 scoped_ptr<Package> package;
100 if (!base::DirectoryExists(path)) {
101 package = Package::Create(path);
102 package->Extract(&unpacked_dir);
103 app_id = package->Id();
109 scoped_refptr<ApplicationData> application_data = LoadApplication(
110 unpacked_dir, app_id, Manifest::COMMAND_LINE, &error);
111 if (!application_data) {
112 LOG(ERROR) << "Error during application installation: " << error;
115 if (!permission_policy_handler_->
116 InitApplicationPermission(application_data)) {
117 LOG(ERROR) << "Application permission data is invalid";
121 if (application_storage_->Contains(application_data->ID())) {
122 *id = application_data->ID();
123 LOG(INFO) << "Already installed: " << *id;
127 base::FilePath app_dir = data_dir.AppendASCII(application_data->ID());
128 if (base::DirectoryExists(app_dir)) {
129 if (!base::DeleteFile(app_dir, true))
133 if (!base::CreateDirectory(app_dir))
135 if (!CopyDirectoryContents(unpacked_dir, app_dir))
138 if (!base::Move(unpacked_dir, app_dir))
142 application_data->SetPath(app_dir);
144 if (!application_storage_->AddApplication(application_data)) {
145 LOG(ERROR) << "Application with id " << application_data->ID()
146 << " couldn't be installed.";
150 #if defined(OS_TIZEN)
151 if (!PackageInstaller::InstallApplication(
152 application_data, runtime_context_->GetPath())) {
153 application_storage_->RemoveApplication(application_data->ID());
158 LOG(INFO) << "Application be installed in: " << app_dir.MaybeAsASCII();
159 LOG(INFO) << "Installed application with id: " << application_data->ID()
161 *id = application_data->ID();
163 FOR_EACH_OBSERVER(Observer, observers_,
164 OnApplicationInstalled(application_data->ID()));
169 bool ApplicationService::Update(const std::string& id,
170 const base::FilePath& path) {
171 if (!base::PathExists(path)) {
172 LOG(ERROR) << "The XPK/WGT package file " << path.value() << " is invalid.";
176 if (base::DirectoryExists(path)) {
177 LOG(WARNING) << "Can not update an unpacked XPK/WGT package.";
181 base::FilePath unpacked_dir;
182 base::FilePath origin_dir;
184 scoped_ptr<Package> package = Package::Create(path);
186 LOG(ERROR) << "XPK/WGT file is invalid.";
190 app_id = package->Id();
192 if (app_id.empty()) {
193 LOG(ERROR) << "XPK/WGT file is invalid, and the application id is empty.";
198 id.compare(app_id) != 0) {
199 LOG(ERROR) << "The XPK/WGT file is not the same as expecting.";
203 if (!package->Extract(&unpacked_dir))
207 scoped_refptr<ApplicationData> new_application =
208 LoadApplication(unpacked_dir,
210 Manifest::COMMAND_LINE,
212 if (!new_application) {
213 LOG(ERROR) << "An error occurred during application updating: " << error;
217 scoped_refptr<ApplicationData> old_application =
218 application_storage_->GetApplicationData(app_id);
219 if (!old_application) {
220 LOG(INFO) << "Application haven't installed yet: " << app_id;
224 if (old_application->Version()->CompareTo(
225 *(new_application->Version())) >= 0) {
226 LOG(INFO) << "The version number of new XPK/WGT package "
227 "should be higher than "
228 << old_application->VersionString();
232 const base::FilePath& app_dir = old_application->Path();
233 const base::FilePath tmp_dir(app_dir.value()
234 + FILE_PATH_LITERAL(".tmp"));
236 if (Application* app = GetApplicationByID(app_id)) {
237 LOG(INFO) << "Try to terminate the running application before update.";
241 if (!base::Move(app_dir, tmp_dir) ||
242 !base::Move(unpacked_dir, app_dir))
245 new_application = LoadApplication(app_dir,
247 Manifest::COMMAND_LINE,
249 if (!new_application) {
250 LOG(ERROR) << "Error during loading new package: " << error;
251 base::DeleteFile(app_dir, true);
252 base::Move(tmp_dir, app_dir);
256 if (!application_storage_->UpdateApplication(new_application)) {
257 LOG(ERROR) << "Fail to update application, roll back to the old one.";
258 base::DeleteFile(app_dir, true);
259 base::Move(tmp_dir, app_dir);
263 #if defined(OS_TIZEN)
264 if (!PackageInstaller::UpdateApplication(
265 new_application, runtime_context_->GetPath())) {
266 LOG(ERROR) << "Fail to update package on Tizen, roll back to the old one.";
267 base::DeleteFile(app_dir, true);
268 if (!application_storage_->UpdateApplication(old_application)) {
269 LOG(ERROR) << "Fail to revert old application info, "
270 << "remove the application as a last resort.";
271 application_storage_->RemoveApplication(old_application->ID());
274 base::Move(tmp_dir, app_dir);
279 base::DeleteFile(tmp_dir, true);
281 FOR_EACH_OBSERVER(Observer, observers_,
282 OnApplicationUpdated(app_id));
287 bool ApplicationService::Uninstall(const std::string& id) {
290 scoped_refptr<ApplicationData> application =
291 application_storage_->GetApplicationData(id);
293 LOG(ERROR) << "Cannot uninstall application with id " << id
294 << "; invalid application id";
298 if (Application* app = GetApplicationByID(id)) {
299 LOG(INFO) << "Try to terminate the running application before uninstall.";
303 #if defined(OS_TIZEN)
304 if (!PackageInstaller::UninstallApplication(
305 application, runtime_context_->GetPath()))
309 if (!application_storage_->RemoveApplication(id)) {
310 LOG(ERROR) << "Cannot uninstall application with id " << id
311 << "; application is not installed.";
315 const base::FilePath resources =
316 runtime_context_->GetPath().Append(kApplicationsDir).AppendASCII(id);
317 if (base::DirectoryExists(resources) &&
318 !base::DeleteFile(resources, true)) {
319 LOG(ERROR) << "Error occurred while trying to remove application with id "
320 << id << "; Cannot remove all resources.";
324 content::StoragePartition* partition =
325 content::BrowserContext::GetStoragePartitionForSite(
326 runtime_context_, application->GetBaseURLFromApplicationId(id));
327 partition->ClearDataForOrigin(
328 content::StoragePartition::REMOVE_DATA_MASK_ALL,
329 content::StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL,
331 partition->GetURLRequestContext());
334 PathService::Get(xwalk::DIR_WGT_STORAGE_PATH, &path);
335 RemoveWidgetStorageFiles(path, id);
337 FOR_EACH_OBSERVER(Observer, observers_, OnApplicationUninstalled(id));
342 void ApplicationService::ChangeLocale(const std::string& locale) {
343 const ApplicationData::ApplicationDataMap& apps =
344 application_storage_->GetInstalledApplications();
345 ApplicationData::ApplicationDataMap::const_iterator it;
346 for (it = apps.begin(); it != apps.end(); ++it) {
347 base::string16 error;
348 std::string old_name = it->second->Name();
349 if (!it->second->SetApplicationLocale(locale, &error)) {
350 LOG(ERROR) << "Error when set locale " << locale
351 << " to application " << it->second->ID()
352 << "error : " << error;
354 if (old_name != it->second->Name()) {
355 // After we has changed the application locale, we might get a new name in
356 // the new locale, so call all observer for this event.
358 Observer, observers_,
359 OnApplicationNameChanged(it->second->ID(), it->second->Name()));
364 Application* ApplicationService::Launch(
365 scoped_refptr<ApplicationData> application_data,
366 const Application::LaunchParams& launch_params) {
367 if (GetApplicationByID(application_data->ID()) != NULL) {
368 LOG(INFO) << "Application with id: " << application_data->ID()
369 << " is already running.";
370 // FIXME: we need to notify application that it had been attempted
371 // to invoke and let the application to define the further behavior.
375 #if defined(OS_TIZEN)
376 Application* application(new ApplicationTizen(application_data,
377 runtime_context_, this));
379 Application* application(new Application(application_data,
380 runtime_context_, this));
383 ScopedVector<Application>::iterator app_iter =
384 applications_.insert(applications_.end(), application);
386 if (!application->Launch(launch_params)) {
387 applications_.erase(app_iter);
391 FOR_EACH_OBSERVER(Observer, observers_,
392 DidLaunchApplication(application));
397 Application* ApplicationService::Launch(
398 const std::string& id, const Application::LaunchParams& params) {
399 Application* application = NULL;
400 scoped_refptr<ApplicationData> application_data =
401 application_storage_->GetApplicationData(id);
402 if (!application_data) {
403 LOG(ERROR) << "Application with id " << id << " is not installed.";
407 return Launch(application_data, params);
410 Application* ApplicationService::Launch(
411 const base::FilePath& path, const Application::LaunchParams& params) {
412 Application* application = NULL;
413 if (!base::DirectoryExists(path))
417 scoped_refptr<ApplicationData> application_data =
418 LoadApplication(path, Manifest::COMMAND_LINE, &error);
420 if (!application_data) {
421 LOG(ERROR) << "Error occurred while trying to launch application: "
426 return Launch(application_data, params);
431 struct ApplicationRenderHostIDComparator {
432 explicit ApplicationRenderHostIDComparator(int id) : id(id) { }
433 bool operator() (Application* application) {
434 return id == application->GetRenderProcessHostID();
439 struct ApplicationIDComparator {
440 explicit ApplicationIDComparator(const std::string& app_id)
442 bool operator() (Application* application) {
443 return app_id == application->id();
450 Application* ApplicationService::GetApplicationByRenderHostID(int id) const {
451 ApplicationRenderHostIDComparator comparator(id);
452 ScopedVector<Application>::const_iterator found = std::find_if(
453 applications_.begin(), applications_.end(), comparator);
454 if (found != applications_.end())
459 Application* ApplicationService::GetApplicationByID(
460 const std::string& app_id) const {
461 ApplicationIDComparator comparator(app_id);
462 ScopedVector<Application>::const_iterator found = std::find_if(
463 applications_.begin(), applications_.end(), comparator);
464 if (found != applications_.end())
469 void ApplicationService::AddObserver(Observer* observer) {
470 observers_.AddObserver(observer);
473 void ApplicationService::RemoveObserver(Observer* observer) {
474 observers_.RemoveObserver(observer);
477 void ApplicationService::OnApplicationTerminated(
478 Application* application) {
479 ScopedVector<Application>::iterator found = std::find(
480 applications_.begin(), applications_.end(), application);
481 CHECK(found != applications_.end());
482 FOR_EACH_OBSERVER(Observer, observers_,
483 WillDestroyApplication(application));
484 applications_.erase(found);
485 if (!XWalkRunner::GetInstance()->is_running_as_service() &&
486 applications_.empty()) {
487 base::MessageLoop::current()->PostTask(
488 FROM_HERE, base::MessageLoop::QuitClosure());
492 void ApplicationService::CheckAPIAccessControl(const std::string& app_id,
493 const std::string& extension_name,
494 const std::string& api_name, const PermissionCallback& callback) {
495 Application* app = GetApplicationByID(app_id);
497 LOG(ERROR) << "No running application found with ID: "
499 callback.Run(UNDEFINED_RUNTIME_PERM);
502 if (!app->UseExtension(extension_name)) {
503 LOG(ERROR) << "Can not find extension: "
504 << extension_name << " of Application with ID: "
506 callback.Run(UNDEFINED_RUNTIME_PERM);
509 // Permission name should have been registered at extension initialization.
510 std::string permission_name =
511 app->GetRegisteredPermissionName(extension_name, api_name);
512 if (permission_name.empty()) {
513 LOG(ERROR) << "API: " << api_name << " of extension: "
514 << extension_name << " not registered!";
515 callback.Run(UNDEFINED_RUNTIME_PERM);
518 // Okay, since we have the permission name, let's get down to the policies.
519 // First, find out whether the permission is stored for the current session.
520 StoredPermission perm = app->GetPermission(
521 SESSION_PERMISSION, permission_name);
522 if (perm != UNDEFINED_STORED_PERM) {
523 // "PROMPT" should not be in the session storage.
524 DCHECK(perm != PROMPT);
526 callback.Run(ALLOW_SESSION);
530 callback.Run(DENY_SESSION);
535 // Then, query the persistent policy storage.
536 perm = app->GetPermission(PERSISTENT_PERMISSION, permission_name);
537 // Permission not found in persistent permission table, normally this should
538 // not happen because all the permission needed by the application should be
539 // contained in its manifest, so it also means that the application is asking
540 // for something wasn't allowed.
541 if (perm == UNDEFINED_STORED_PERM) {
542 callback.Run(UNDEFINED_RUNTIME_PERM);
545 if (perm == PROMPT) {
546 // TODO(Bai): We needed to pop-up a dialog asking user to chose one from
547 // either allow/deny for session/one shot/forever. Then, we need to update
548 // the session and persistent policy accordingly.
549 callback.Run(UNDEFINED_RUNTIME_PERM);
553 callback.Run(ALLOW_ALWAYS);
557 callback.Run(DENY_ALWAYS);
563 bool ApplicationService::RegisterPermissions(const std::string& app_id,
564 const std::string& extension_name,
565 const std::string& perm_table) {
566 Application* app = GetApplicationByID(app_id);
568 LOG(ERROR) << "No running application found with ID: " << app_id;
571 if (!app->UseExtension(extension_name)) {
572 LOG(ERROR) << "Can not find extension: "
573 << extension_name << " of Application with ID: "
577 return app->RegisterPermissions(extension_name, perm_table);
580 } // namespace application