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"
12 #include "base/file_util.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "content/public/browser/web_contents.h"
15 #include "content/public/browser/web_contents_observer.h"
16 #include "xwalk/application/browser/application.h"
17 #include "xwalk/application/common/application_manifest_constants.h"
18 #include "xwalk/application/common/application_file_util.h"
19 #include "xwalk/application/common/id_util.h"
20 #include "xwalk/runtime/browser/runtime_context.h"
21 #include "xwalk/runtime/browser/runtime.h"
22 #include "xwalk/runtime/common/xwalk_paths.h"
25 #include "xwalk/application/browser/application_service_tizen.h"
30 namespace application {
32 ApplicationService::ApplicationService(RuntimeContext* runtime_context)
33 : runtime_context_(runtime_context) {
36 scoped_ptr<ApplicationService> ApplicationService::Create(
37 RuntimeContext* runtime_context) {
39 return make_scoped_ptr<ApplicationService>(
40 new ApplicationServiceTizen(runtime_context));
42 return make_scoped_ptr(new ApplicationService(runtime_context));
46 ApplicationService::~ApplicationService() {
49 Application* ApplicationService::Launch(
50 scoped_refptr<ApplicationData> application_data,
51 const Application::LaunchParams& launch_params) {
52 if (GetApplicationByID(application_data->ID()) != NULL) {
53 LOG(INFO) << "Application with id: " << application_data->ID()
54 << " is already running.";
55 // FIXME: we need to notify application that it had been attempted
56 // to invoke and let the application to define the further behavior.
60 Application* application = Application::Create(application_data,
61 runtime_context_).release();
62 ScopedVector<Application>::iterator app_iter =
63 applications_.insert(applications_.end(), application);
65 if (!application->Launch(launch_params)) {
66 applications_.erase(app_iter);
70 application->set_observer(this);
72 FOR_EACH_OBSERVER(Observer, observers_,
73 DidLaunchApplication(application));
78 Application* ApplicationService::LaunchFromManifestPath(
79 const base::FilePath& path, Manifest::Type manifest_type,
80 const Application::LaunchParams& params) {
82 scoped_ptr<Manifest> manifest = LoadManifest(path, manifest_type, &error);
84 LOG(ERROR) << "Failed to load manifest.";
88 base::FilePath app_path = path.DirName();
89 LOG(ERROR) << "Loading app from " << app_path.MaybeAsASCII();
91 scoped_refptr<ApplicationData> application_data = ApplicationData::Create(
92 app_path, std::string(), ApplicationData::LOCAL_DIRECTORY,
93 manifest.Pass(), &error);
94 if (!application_data) {
95 LOG(ERROR) << "Error occurred while trying to load application: "
100 return Launch(application_data, params);
103 Application* ApplicationService::LaunchFromPackagePath(
104 const base::FilePath& path, const Application::LaunchParams& params) {
105 scoped_ptr<Package> package = Package::Create(path);
106 if (!package || !package->IsValid()) {
107 LOG(ERROR) << "Failed to obtain valid package from "
108 << path.AsUTF8Unsafe();
112 base::FilePath tmp_dir, target_dir;
113 if (!GetTempDir(&tmp_dir)) {
114 LOG(ERROR) << "Failed to obtain system temp directory.";
118 base::CreateTemporaryDirInDir(tmp_dir, package->name(), &target_dir);
119 if (!package->ExtractTo(target_dir)) {
120 LOG(ERROR) << "Failed to unpack to a temporary directory: "
121 << target_dir.MaybeAsASCII();
126 scoped_refptr<ApplicationData> application_data = LoadApplication(
127 target_dir, std::string(), ApplicationData::TEMP_DIRECTORY,
128 package->manifest_type(), &error);
129 if (!application_data) {
130 LOG(ERROR) << "Error occurred while trying to load application: "
135 return Launch(application_data, params);
138 // Launch an application created from arbitrary url.
139 // FIXME: This application should have the same strict permissions
140 // as common browser apps.
141 Application* ApplicationService::LaunchHostedURL(
142 const GURL& url, const Application::LaunchParams& params) {
143 const std::string& url_spec = url.spec();
144 if (url_spec.empty()) {
145 LOG(ERROR) << "Failed to launch application from the URL: " << url;
149 const std::string& app_id = GenerateId(url_spec);
151 scoped_ptr<base::DictionaryValue> settings(new base::DictionaryValue());
152 // FIXME: define permissions!
153 settings->SetString(application_manifest_keys::kStartURLKey, url_spec);
154 // FIXME: Why use URL as name?
155 settings->SetString(application_manifest_keys::kNameKey, url_spec);
156 settings->SetString(application_manifest_keys::kXWalkVersionKey, "0");
158 scoped_ptr<Manifest> manifest(
159 new Manifest(settings.Pass(), Manifest::TYPE_MANIFEST));
162 scoped_refptr<ApplicationData> app_data =
163 ApplicationData::Create(base::FilePath(), app_id,
164 ApplicationData::EXTERNAL_URL, manifest.Pass(), &error);
167 return Launch(app_data, params);
172 struct ApplicationRenderHostIDComparator {
173 explicit ApplicationRenderHostIDComparator(int id) : id(id) { }
174 bool operator() (Application* application) {
175 return id == application->GetRenderProcessHostID();
180 struct ApplicationIDComparator {
181 explicit ApplicationIDComparator(const std::string& app_id)
183 bool operator() (Application* application) {
184 return app_id == application->id();
191 Application* ApplicationService::GetApplicationByRenderHostID(int id) const {
192 ApplicationRenderHostIDComparator comparator(id);
193 ScopedVector<Application>::const_iterator found = std::find_if(
194 applications_.begin(), applications_.end(), comparator);
195 if (found != applications_.end())
200 Application* ApplicationService::GetApplicationByID(
201 const std::string& app_id) const {
202 ApplicationIDComparator comparator(app_id);
203 ScopedVector<Application>::const_iterator found = std::find_if(
204 applications_.begin(), applications_.end(), comparator);
205 if (found != applications_.end())
210 void ApplicationService::AddObserver(Observer* observer) {
211 observers_.AddObserver(observer);
214 void ApplicationService::RemoveObserver(Observer* observer) {
215 observers_.RemoveObserver(observer);
218 void ApplicationService::OnApplicationTerminated(
219 Application* application) {
220 ScopedVector<Application>::iterator found = std::find(
221 applications_.begin(), applications_.end(), application);
222 CHECK(found != applications_.end());
223 FOR_EACH_OBSERVER(Observer, observers_,
224 WillDestroyApplication(application));
225 scoped_refptr<ApplicationData> app_data = application->data();
226 applications_.erase(found);
228 if (app_data->source_type() == ApplicationData::TEMP_DIRECTORY) {
229 LOG(INFO) << "Deleting the app temporary directory "
230 << app_data->Path().AsUTF8Unsafe();
231 content::BrowserThread::PostTask(content::BrowserThread::FILE,
232 FROM_HERE, base::Bind(base::IgnoreResult(&base::DeleteFile),
233 app_data->Path(), true /*recursive*/));
234 // FIXME: So far we simply clean up all the app persistent data,
235 // further we need to add an appropriate logic to handle it.
236 content::BrowserContext::GarbageCollectStoragePartitions(
238 make_scoped_ptr(new base::hash_set<base::FilePath>()),
239 base::Bind(&base::DoNothing));
242 #if !defined(SHARED_PROCESS_MODE)
243 if (applications_.empty()) {
244 base::MessageLoop::current()->PostTask(
245 FROM_HERE, base::MessageLoop::QuitClosure());
250 void ApplicationService::CheckAPIAccessControl(const std::string& app_id,
251 const std::string& extension_name,
252 const std::string& api_name, const PermissionCallback& callback) {
253 Application* app = GetApplicationByID(app_id);
255 LOG(ERROR) << "No running application found with ID: "
257 callback.Run(UNDEFINED_RUNTIME_PERM);
260 if (!app->UseExtension(extension_name)) {
261 LOG(ERROR) << "Can not find extension: "
262 << extension_name << " of Application with ID: "
264 callback.Run(UNDEFINED_RUNTIME_PERM);
267 // Permission name should have been registered at extension initialization.
268 std::string permission_name =
269 app->GetRegisteredPermissionName(extension_name, api_name);
270 if (permission_name.empty()) {
271 LOG(ERROR) << "API: " << api_name << " of extension: "
272 << extension_name << " not registered!";
273 callback.Run(UNDEFINED_RUNTIME_PERM);
276 // Okay, since we have the permission name, let's get down to the policies.
277 // First, find out whether the permission is stored for the current session.
278 StoredPermission perm = app->GetPermission(
279 SESSION_PERMISSION, permission_name);
280 if (perm != UNDEFINED_STORED_PERM) {
281 // "PROMPT" should not be in the session storage.
282 DCHECK(perm != PROMPT);
284 callback.Run(ALLOW_SESSION);
288 callback.Run(DENY_SESSION);
293 // Then, query the persistent policy storage.
294 perm = app->GetPermission(PERSISTENT_PERMISSION, permission_name);
295 // Permission not found in persistent permission table, normally this should
296 // not happen because all the permission needed by the application should be
297 // contained in its manifest, so it also means that the application is asking
298 // for something wasn't allowed.
299 if (perm == UNDEFINED_STORED_PERM) {
300 callback.Run(UNDEFINED_RUNTIME_PERM);
303 if (perm == PROMPT) {
304 // TODO(Bai): We needed to pop-up a dialog asking user to chose one from
305 // either allow/deny for session/one shot/forever. Then, we need to update
306 // the session and persistent policy accordingly.
307 callback.Run(UNDEFINED_RUNTIME_PERM);
311 callback.Run(ALLOW_ALWAYS);
315 callback.Run(DENY_ALWAYS);
321 bool ApplicationService::RegisterPermissions(const std::string& app_id,
322 const std::string& extension_name,
323 const std::string& perm_table) {
324 Application* app = GetApplicationByID(app_id);
326 LOG(ERROR) << "No running application found with ID: " << app_id;
329 if (!app->UseExtension(extension_name)) {
330 LOG(ERROR) << "Can not find extension: "
331 << extension_name << " of Application with ID: "
335 return app->RegisterPermissions(extension_name, perm_table);
338 } // namespace application