#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/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"
+#include "xwalk/application/browser/installer/tizen/service_package_installer.h"
#endif
using xwalk::RuntimeContext;
new CloseAfterLoadObserver(application, event_manager, contents);
}
+void SaveSystemEventsInfo(
+ xwalk::application::ApplicationService* application_service,
+ scoped_refptr<xwalk::application::ApplicationData> application_data,
+ xwalk::application::ApplicationEventManager* event_manager) {
+ // We need to run main document after installation in order to
+ // register system events.
+ if (application_data->HasMainDocument()) {
+ if (xwalk::application::Application* application =
+ application_service->Launch(application_data->ID())) {
+ WaitForFinishLoad(application->data(), event_manager,
+ application->GetMainDocumentRuntime()->web_contents());
+ }
+ }
+}
+
#if defined(OS_TIZEN_MOBILE)
bool InstallPackageOnTizen(xwalk::application::ApplicationService* service,
xwalk::application::ApplicationStorage* storage,
- const std::string& app_id,
+ xwalk::application::ApplicationData* application,
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;
+ if (xwalk::XWalkRunner::GetInstance()->is_running_as_service()) {
+ return InstallApplicationForTizen(application, data_dir);
+ }
scoped_ptr<xwalk::application::PackageInstaller> installer =
xwalk::application::PackageInstaller::Create(service, storage,
- app_id, data_dir);
+ application->ID(), data_dir);
if (!installer || !installer->Install()) {
LOG(ERROR) << "An error occurred during installation on Tizen.";
return false;
bool UninstallPackageOnTizen(xwalk::application::ApplicationService* service,
xwalk::application::ApplicationStorage* storage,
- const std::string& app_id,
+ xwalk::application::ApplicationData* application,
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;
+ if (xwalk::XWalkRunner::GetInstance()->is_running_as_service()) {
+ return UninstallApplicationForTizen(application, data_dir);
+ }
scoped_ptr<xwalk::application::PackageInstaller> installer =
xwalk::application::PackageInstaller::Create(service, storage,
- app_id, data_dir);
+ application->ID(), data_dir);
if (!installer || !installer->Uninstall()) {
LOG(ERROR) << "An error occurred during uninstallation on Tizen.";
return false;
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);
}
// 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;
}
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;
#if defined(OS_TIZEN_MOBILE)
if (!InstallPackageOnTizen(this, application_storage_,
- application_data->ID(),
- runtime_context_->GetPath()))
+ application_data.get(),
+ runtime_context_->GetPath())) {
+ application_storage_->RemoveApplication(application_data->ID());
return false;
+ }
#endif
LOG(INFO) << "Application be installed in: " << app_dir.MaybeAsASCII();
<< " 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_MOBILE)
+ if (!UninstallPackageOnTizen(this, application_storage_,
+ old_application.get(),
+ 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_MOBILE)
+ InstallPackageOnTizen(this, application_storage_,
+ old_application.get(),
+ runtime_context_->GetPath());
+#endif
+ return false;
+ }
+#if defined(OS_TIZEN_MOBILE)
+ if (!InstallPackageOnTizen(this, application_storage_,
+ new_application.get(),
+ 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) {
+ 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_MOBILE)
- if (!UninstallPackageOnTizen(this, application_storage_, id,
+ if (!UninstallPackageOnTizen(this, application_storage_, application.get(),
runtime_context_->GetPath()))
- return false;
+ 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 =
!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(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) {
return NULL;
}
- return Launch(application_data);
+ return Launch(application_data, params);
}
Application* ApplicationService::Launch(const base::FilePath& path) {
return NULL;
}
- return Launch(application_data);
+ return Launch(application_data, Application::LaunchParams());
}
Application* ApplicationService::Launch(const GURL& url) {
base::DictionaryValue manifest;
// FIXME: define permissions!
- manifest.SetString(keys::kLaunchWebURLKey, url_spec);
- manifest.SetString(keys::kNameKey, "XWalk Browser");
+ manifest.SetString(keys::kURLKey, url_spec);
+ manifest.SetString(keys::kNameKey, "XWalk Dummy App");
manifest.SetString(keys::kVersionKey, "0");
manifest.SetInteger(keys::kManifestVersionKey, 1);
std::string error;
return NULL;
}
- return Launch(application_data, Application::LaunchWebURLKey);
+ Application::LaunchParams launch_params;
+ launch_params.entry_points = Application::URLKey;
+ return Launch(application_data, launch_params);
}
namespace {
Application* ApplicationService::Launch(
scoped_refptr<ApplicationData> application_data,
- Application::LaunchEntryPoints entry_points) {
+ const Application::LaunchParams& launch_params) {
if (GetApplicationByID(application_data->ID()) != NULL) {
LOG(INFO) << "Application with id: " << application_data->ID()
<< " is already running.";
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()) {
+ if (!application->Launch(launch_params)) {
event_manager_->RemoveEventRouterForApp(application_data);
applications_.erase(app_iter);
return NULL;
return application;
}
+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;
+ }
+ 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();
+}
+
+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
} // namespace xwalk