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"
8 #include <ext/hash_set>
16 #include "base/files/file_util.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "content/public/browser/browser_thread.h"
19 #include "content/public/browser/web_contents.h"
20 #include "content/public/browser/web_contents_observer.h"
21 #include "xwalk/application/browser/application.h"
22 #include "xwalk/application/common/application_manifest_constants.h"
23 #include "xwalk/application/common/application_file_util.h"
24 #include "xwalk/application/common/id_util.h"
25 #include "xwalk/runtime/browser/runtime.h"
26 #include "xwalk/runtime/browser/xwalk_browser_context.h"
27 #include "xwalk/runtime/browser/xwalk_runner.h"
28 #include "xwalk/runtime/common/xwalk_paths.h"
31 #include "xwalk/application/browser/application_service_tizen.h"
36 namespace application {
38 ApplicationService::ApplicationService(XWalkBrowserContext* browser_context)
39 : browser_context_(browser_context) {
42 scoped_ptr<ApplicationService> ApplicationService::Create(
43 XWalkBrowserContext* browser_context) {
45 return make_scoped_ptr<ApplicationService>(
46 new ApplicationServiceTizen(browser_context));
48 return make_scoped_ptr(new ApplicationService(browser_context));
52 ApplicationService::~ApplicationService() {
55 Application* ApplicationService::Launch(
56 scoped_refptr<ApplicationData> application_data,
57 const Application::LaunchParams& launch_params) {
58 if (GetApplicationByID(application_data->ID()) != NULL) {
59 LOG(INFO) << "Application with id: " << application_data->ID()
60 << " is already running.";
61 // FIXME: we need to notify application that it had been attempted
62 // to invoke and let the application to define the further behavior.
66 Application* application = Application::Create(application_data,
67 browser_context_).release();
68 ScopedVector<Application>::iterator app_iter =
69 applications_.insert(applications_.end(), application);
71 if (!application->Launch(launch_params)) {
72 applications_.erase(app_iter);
76 application->set_observer(this);
78 FOR_EACH_OBSERVER(Observer, observers_,
79 DidLaunchApplication(application));
84 Application* ApplicationService::LaunchFromManifestPath(
85 const base::FilePath& path, Manifest::Type manifest_type,
86 const Application::LaunchParams& params) {
88 scoped_ptr<Manifest> manifest = LoadManifest(path, manifest_type, &error);
90 LOG(ERROR) << "Failed to load manifest.";
94 base::FilePath app_path = path.DirName();
95 LOG(ERROR) << "Loading app from " << app_path.MaybeAsASCII();
97 scoped_refptr<ApplicationData> application_data = ApplicationData::Create(
98 app_path, std::string(), ApplicationData::LOCAL_DIRECTORY,
99 manifest.Pass(), &error);
100 if (!application_data.get()) {
101 LOG(ERROR) << "Error occurred while trying to load application: "
106 return Launch(application_data, params);
109 Application* ApplicationService::LaunchFromPackagePath(
110 const base::FilePath& path, const Application::LaunchParams& params) {
111 scoped_ptr<Package> package = Package::Create(path);
112 if (!package || !package->IsValid()) {
113 LOG(ERROR) << "Failed to obtain valid package from "
114 << path.AsUTF8Unsafe();
118 base::FilePath tmp_dir, target_dir;
119 if (!GetTempDir(&tmp_dir)) {
120 LOG(ERROR) << "Failed to obtain system temp directory.";
125 base::CreateTemporaryDirInDir(tmp_dir,
126 base::UTF8ToWide(package->name()), &target_dir);
128 base::CreateTemporaryDirInDir(tmp_dir, package->name(), &target_dir);
130 if (!package->ExtractTo(target_dir)) {
131 LOG(ERROR) << "Failed to unpack to a temporary directory: "
132 << target_dir.MaybeAsASCII();
137 scoped_refptr<ApplicationData> application_data = LoadApplication(
138 target_dir, std::string(), ApplicationData::TEMP_DIRECTORY,
139 package->manifest_type(), &error);
140 if (!application_data.get()) {
141 LOG(ERROR) << "Error occurred while trying to load application: "
146 return Launch(application_data, params);
149 // Launch an application created from arbitrary url.
150 // FIXME: This application should have the same strict permissions
151 // as common browser apps.
152 Application* ApplicationService::LaunchHostedURL(
153 const GURL& url, const Application::LaunchParams& params) {
154 const std::string& url_spec = url.spec();
155 if (url_spec.empty()) {
156 LOG(ERROR) << "Failed to launch application from the URL: " << url;
160 const std::string& app_id = GenerateId(url_spec);
162 scoped_ptr<base::DictionaryValue> settings(new base::DictionaryValue());
163 // FIXME: define permissions!
164 settings->SetString(application_manifest_keys::kStartURLKey, url_spec);
165 // FIXME: Why use URL as name?
166 settings->SetString(application_manifest_keys::kNameKey, url_spec);
167 settings->SetString(application_manifest_keys::kXWalkVersionKey, "0");
169 scoped_ptr<Manifest> manifest(
170 new Manifest(settings.Pass(), Manifest::TYPE_MANIFEST));
173 scoped_refptr<ApplicationData> app_data =
174 ApplicationData::Create(base::FilePath(), app_id,
175 ApplicationData::EXTERNAL_URL, manifest.Pass(), &error);
176 DCHECK(app_data.get());
178 return Launch(app_data, params);
183 struct ApplicationRenderHostIDComparator {
184 explicit ApplicationRenderHostIDComparator(int id) : id(id) { }
185 bool operator() (Application* application) {
186 return id == application->GetRenderProcessHostID();
191 struct ApplicationIDComparator {
192 explicit ApplicationIDComparator(const std::string& app_id)
194 bool operator() (Application* application) {
195 return app_id == application->id();
202 Application* ApplicationService::GetApplicationByRenderHostID(int id) const {
203 ApplicationRenderHostIDComparator comparator(id);
204 ScopedVector<Application>::const_iterator found = std::find_if(
205 applications_.begin(), applications_.end(), comparator);
206 if (found != applications_.end())
211 Application* ApplicationService::GetApplicationByID(
212 const std::string& app_id) const {
213 ApplicationIDComparator comparator(app_id);
214 ScopedVector<Application>::const_iterator found = std::find_if(
215 applications_.begin(), applications_.end(), comparator);
216 if (found != applications_.end())
221 void ApplicationService::AddObserver(Observer* observer) {
222 observers_.AddObserver(observer);
225 void ApplicationService::RemoveObserver(Observer* observer) {
226 observers_.RemoveObserver(observer);
229 void ApplicationService::OnApplicationTerminated(
230 Application* application) {
231 ScopedVector<Application>::iterator found = std::find(
232 applications_.begin(), applications_.end(), application);
233 CHECK(found != applications_.end());
234 FOR_EACH_OBSERVER(Observer, observers_,
235 WillDestroyApplication(application));
236 scoped_refptr<ApplicationData> app_data = application->data();
237 applications_.erase(found);
239 if (app_data->source_type() == ApplicationData::TEMP_DIRECTORY) {
240 LOG(INFO) << "Deleting the app temporary directory "
241 << app_data->path().AsUTF8Unsafe();
242 content::BrowserThread::PostTask(content::BrowserThread::FILE,
243 FROM_HERE, base::Bind(base::IgnoreResult(&base::DeleteFile),
244 app_data->path(), true /*recursive*/));
245 // FIXME: So far we simply clean up all the app persistent data,
246 // further we need to add an appropriate logic to handle it.
247 content::BrowserContext::GarbageCollectStoragePartitions(
249 make_scoped_ptr(new base::hash_set<base::FilePath>()),
250 base::Bind(&base::DoNothing));
253 if (!XWalkRunner::GetInstance()->shared_process_mode_enabled()) {
254 if (applications_.empty()) {
255 base::MessageLoop::current()->PostTask(
256 FROM_HERE, base::MessageLoop::QuitClosure());
261 void ApplicationService::CheckAPIAccessControl(const std::string& app_id,
262 const std::string& extension_name,
263 const std::string& api_name, const PermissionCallback& callback) {
264 Application* app = GetApplicationByID(app_id);
266 LOG(ERROR) << "No running application found with ID: "
268 callback.Run(UNDEFINED_RUNTIME_PERM);
271 if (!app->UseExtension(extension_name)) {
272 LOG(ERROR) << "Can not find extension: "
273 << extension_name << " of Application with ID: "
275 callback.Run(UNDEFINED_RUNTIME_PERM);
278 // Permission name should have been registered at extension initialization.
279 std::string permission_name =
280 app->GetRegisteredPermissionName(extension_name, api_name);
281 if (permission_name.empty()) {
282 LOG(ERROR) << "API: " << api_name << " of extension: "
283 << extension_name << " not registered!";
284 callback.Run(UNDEFINED_RUNTIME_PERM);
287 // Okay, since we have the permission name, let's get down to the policies.
288 // First, find out whether the permission is stored for the current session.
289 StoredPermission perm = app->GetPermission(
290 SESSION_PERMISSION, permission_name);
291 if (perm != UNDEFINED_STORED_PERM) {
292 // "PROMPT" should not be in the session storage.
293 DCHECK(perm != PROMPT);
295 callback.Run(ALLOW_SESSION);
299 callback.Run(DENY_SESSION);
304 // Then, query the persistent policy storage.
305 perm = app->GetPermission(PERSISTENT_PERMISSION, permission_name);
306 // Permission not found in persistent permission table, normally this should
307 // not happen because all the permission needed by the application should be
308 // contained in its manifest, so it also means that the application is asking
309 // for something wasn't allowed.
310 if (perm == UNDEFINED_STORED_PERM) {
311 callback.Run(UNDEFINED_RUNTIME_PERM);
314 if (perm == PROMPT) {
315 // TODO(Bai): We needed to pop-up a dialog asking user to chose one from
316 // either allow/deny for session/one shot/forever. Then, we need to update
317 // the session and persistent policy accordingly.
318 callback.Run(UNDEFINED_RUNTIME_PERM);
322 callback.Run(ALLOW_ALWAYS);
326 callback.Run(DENY_ALWAYS);
332 bool ApplicationService::RegisterPermissions(const std::string& app_id,
333 const std::string& extension_name,
334 const std::string& perm_table) {
335 Application* app = GetApplicationByID(app_id);
337 LOG(ERROR) << "No running application found with ID: " << app_id;
340 if (!app->UseExtension(extension_name)) {
341 LOG(ERROR) << "Can not find extension: "
342 << extension_name << " of Application with ID: "
346 return app->RegisterPermissions(extension_name, perm_table);
349 } // namespace application