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 "base/strings/utf_string_conversions.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "content/public/browser/web_contents.h"
16 #include "content/public/browser/web_contents_observer.h"
17 #include "xwalk/application/browser/application.h"
18 #include "xwalk/application/common/application_manifest_constants.h"
19 #include "xwalk/application/common/application_file_util.h"
20 #include "xwalk/application/common/id_util.h"
21 #include "xwalk/runtime/browser/runtime_context.h"
22 #include "xwalk/runtime/browser/runtime.h"
23 #include "xwalk/runtime/common/xwalk_paths.h"
26 #include "xwalk/application/browser/application_service_tizen.h"
31 namespace application {
33 ApplicationService::ApplicationService(RuntimeContext* runtime_context)
34 : runtime_context_(runtime_context) {
37 scoped_ptr<ApplicationService> ApplicationService::Create(
38 RuntimeContext* runtime_context) {
40 return make_scoped_ptr<ApplicationService>(
41 new ApplicationServiceTizen(runtime_context));
43 return make_scoped_ptr(new ApplicationService(runtime_context));
47 ApplicationService::~ApplicationService() {
50 Application* ApplicationService::Launch(
51 scoped_refptr<ApplicationData> application_data,
52 const Application::LaunchParams& launch_params) {
53 if (GetApplicationByID(application_data->ID()) != NULL) {
54 LOG(INFO) << "Application with id: " << application_data->ID()
55 << " is already running.";
56 // FIXME: we need to notify application that it had been attempted
57 // to invoke and let the application to define the further behavior.
61 Application* application = Application::Create(application_data,
62 runtime_context_).release();
63 ScopedVector<Application>::iterator app_iter =
64 applications_.insert(applications_.end(), application);
66 if (!application->Launch(launch_params)) {
67 applications_.erase(app_iter);
71 application->set_observer(this);
73 FOR_EACH_OBSERVER(Observer, observers_,
74 DidLaunchApplication(application));
79 Application* ApplicationService::LaunchFromManifestPath(
80 const base::FilePath& path, Manifest::Type manifest_type,
81 const Application::LaunchParams& params) {
83 scoped_ptr<Manifest> manifest = LoadManifest(path, manifest_type, &error);
85 LOG(ERROR) << "Failed to load manifest.";
89 base::FilePath app_path = path.DirName();
90 LOG(ERROR) << "Loading app from " << app_path.MaybeAsASCII();
92 scoped_refptr<ApplicationData> application_data = ApplicationData::Create(
93 app_path, std::string(), ApplicationData::LOCAL_DIRECTORY,
94 manifest.Pass(), &error);
95 if (!application_data) {
96 LOG(ERROR) << "Error occurred while trying to load application: "
101 return Launch(application_data, params);
104 Application* ApplicationService::LaunchFromPackagePath(
105 const base::FilePath& path, const Application::LaunchParams& params) {
106 scoped_ptr<Package> package = Package::Create(path);
107 if (!package || !package->IsValid()) {
108 LOG(ERROR) << "Failed to obtain valid package from "
109 << path.AsUTF8Unsafe();
113 base::FilePath tmp_dir, target_dir;
114 if (!GetTempDir(&tmp_dir)) {
115 LOG(ERROR) << "Failed to obtain system temp directory.";
120 base::CreateTemporaryDirInDir(tmp_dir,
121 base::UTF8ToWide(package->name()), &target_dir);
123 base::CreateTemporaryDirInDir(tmp_dir, package->name(), &target_dir);
125 if (!package->ExtractTo(target_dir)) {
126 LOG(ERROR) << "Failed to unpack to a temporary directory: "
127 << target_dir.MaybeAsASCII();
132 scoped_refptr<ApplicationData> application_data = LoadApplication(
133 target_dir, std::string(), ApplicationData::TEMP_DIRECTORY,
134 package->manifest_type(), &error);
135 if (!application_data) {
136 LOG(ERROR) << "Error occurred while trying to load application: "
141 return Launch(application_data, params);
144 // Launch an application created from arbitrary url.
145 // FIXME: This application should have the same strict permissions
146 // as common browser apps.
147 Application* ApplicationService::LaunchHostedURL(
148 const GURL& url, const Application::LaunchParams& params) {
149 const std::string& url_spec = url.spec();
150 if (url_spec.empty()) {
151 LOG(ERROR) << "Failed to launch application from the URL: " << url;
155 const std::string& app_id = GenerateId(url_spec);
157 scoped_ptr<base::DictionaryValue> settings(new base::DictionaryValue());
158 // FIXME: define permissions!
159 settings->SetString(application_manifest_keys::kStartURLKey, url_spec);
160 // FIXME: Why use URL as name?
161 settings->SetString(application_manifest_keys::kNameKey, url_spec);
162 settings->SetString(application_manifest_keys::kXWalkVersionKey, "0");
164 scoped_ptr<Manifest> manifest(
165 new Manifest(settings.Pass(), Manifest::TYPE_MANIFEST));
168 scoped_refptr<ApplicationData> app_data =
169 ApplicationData::Create(base::FilePath(), app_id,
170 ApplicationData::EXTERNAL_URL, manifest.Pass(), &error);
173 return Launch(app_data, params);
178 struct ApplicationRenderHostIDComparator {
179 explicit ApplicationRenderHostIDComparator(int id) : id(id) { }
180 bool operator() (Application* application) {
181 return id == application->GetRenderProcessHostID();
186 struct ApplicationIDComparator {
187 explicit ApplicationIDComparator(const std::string& app_id)
189 bool operator() (Application* application) {
190 return app_id == application->id();
197 Application* ApplicationService::GetApplicationByRenderHostID(int id) const {
198 ApplicationRenderHostIDComparator comparator(id);
199 ScopedVector<Application>::const_iterator found = std::find_if(
200 applications_.begin(), applications_.end(), comparator);
201 if (found != applications_.end())
206 Application* ApplicationService::GetApplicationByID(
207 const std::string& app_id) const {
208 ApplicationIDComparator comparator(app_id);
209 ScopedVector<Application>::const_iterator found = std::find_if(
210 applications_.begin(), applications_.end(), comparator);
211 if (found != applications_.end())
216 void ApplicationService::AddObserver(Observer* observer) {
217 observers_.AddObserver(observer);
220 void ApplicationService::RemoveObserver(Observer* observer) {
221 observers_.RemoveObserver(observer);
224 void ApplicationService::OnApplicationTerminated(
225 Application* application) {
226 ScopedVector<Application>::iterator found = std::find(
227 applications_.begin(), applications_.end(), application);
228 CHECK(found != applications_.end());
229 FOR_EACH_OBSERVER(Observer, observers_,
230 WillDestroyApplication(application));
231 scoped_refptr<ApplicationData> app_data = application->data();
232 applications_.erase(found);
234 if (app_data->source_type() == ApplicationData::TEMP_DIRECTORY) {
235 LOG(INFO) << "Deleting the app temporary directory "
236 << app_data->path().AsUTF8Unsafe();
237 content::BrowserThread::PostTask(content::BrowserThread::FILE,
238 FROM_HERE, base::Bind(base::IgnoreResult(&base::DeleteFile),
239 app_data->path(), true /*recursive*/));
240 // FIXME: So far we simply clean up all the app persistent data,
241 // further we need to add an appropriate logic to handle it.
242 content::BrowserContext::GarbageCollectStoragePartitions(
244 make_scoped_ptr(new base::hash_set<base::FilePath>()),
245 base::Bind(&base::DoNothing));
248 #if !defined(SHARED_PROCESS_MODE)
249 if (applications_.empty()) {
250 base::MessageLoop::current()->PostTask(
251 FROM_HERE, base::MessageLoop::QuitClosure());
256 void ApplicationService::CheckAPIAccessControl(const std::string& app_id,
257 const std::string& extension_name,
258 const std::string& api_name, const PermissionCallback& callback) {
259 Application* app = GetApplicationByID(app_id);
261 LOG(ERROR) << "No running application found with ID: "
263 callback.Run(UNDEFINED_RUNTIME_PERM);
266 if (!app->UseExtension(extension_name)) {
267 LOG(ERROR) << "Can not find extension: "
268 << extension_name << " of Application with ID: "
270 callback.Run(UNDEFINED_RUNTIME_PERM);
273 // Permission name should have been registered at extension initialization.
274 std::string permission_name =
275 app->GetRegisteredPermissionName(extension_name, api_name);
276 if (permission_name.empty()) {
277 LOG(ERROR) << "API: " << api_name << " of extension: "
278 << extension_name << " not registered!";
279 callback.Run(UNDEFINED_RUNTIME_PERM);
282 // Okay, since we have the permission name, let's get down to the policies.
283 // First, find out whether the permission is stored for the current session.
284 StoredPermission perm = app->GetPermission(
285 SESSION_PERMISSION, permission_name);
286 if (perm != UNDEFINED_STORED_PERM) {
287 // "PROMPT" should not be in the session storage.
288 DCHECK(perm != PROMPT);
290 callback.Run(ALLOW_SESSION);
294 callback.Run(DENY_SESSION);
299 // Then, query the persistent policy storage.
300 perm = app->GetPermission(PERSISTENT_PERMISSION, permission_name);
301 // Permission not found in persistent permission table, normally this should
302 // not happen because all the permission needed by the application should be
303 // contained in its manifest, so it also means that the application is asking
304 // for something wasn't allowed.
305 if (perm == UNDEFINED_STORED_PERM) {
306 callback.Run(UNDEFINED_RUNTIME_PERM);
309 if (perm == PROMPT) {
310 // TODO(Bai): We needed to pop-up a dialog asking user to chose one from
311 // either allow/deny for session/one shot/forever. Then, we need to update
312 // the session and persistent policy accordingly.
313 callback.Run(UNDEFINED_RUNTIME_PERM);
317 callback.Run(ALLOW_ALWAYS);
321 callback.Run(DENY_ALWAYS);
327 bool ApplicationService::RegisterPermissions(const std::string& app_id,
328 const std::string& extension_name,
329 const std::string& perm_table) {
330 Application* app = GetApplicationByID(app_id);
332 LOG(ERROR) << "No running application found with ID: " << app_id;
335 if (!app->UseExtension(extension_name)) {
336 LOG(ERROR) << "Can not find extension: "
337 << extension_name << " of Application with ID: "
341 return app->RegisterPermissions(extension_name, perm_table);
344 } // namespace application