Upstream version 9.38.204.0
[platform/framework/web/crosswalk.git] / src / xwalk / application / browser / application_service.cc
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.
4
5 #include "xwalk/application/browser/application_service.h"
6
7 #include <hash_set>
8 #include <set>
9 #include <string>
10 #include <vector>
11
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"
23
24 #if defined(OS_TIZEN)
25 #include "xwalk/application/browser/application_service_tizen.h"
26 #endif
27
28 namespace xwalk {
29
30 namespace application {
31
32 ApplicationService::ApplicationService(RuntimeContext* runtime_context)
33   : runtime_context_(runtime_context) {
34 }
35
36 scoped_ptr<ApplicationService> ApplicationService::Create(
37     RuntimeContext* runtime_context) {
38 #if defined(OS_TIZEN)
39   return make_scoped_ptr<ApplicationService>(
40     new ApplicationServiceTizen(runtime_context));
41 #else
42   return make_scoped_ptr(new ApplicationService(runtime_context));
43 #endif
44 }
45
46 ApplicationService::~ApplicationService() {
47 }
48
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.
57     return NULL;
58   }
59
60   Application* application = Application::Create(application_data,
61     runtime_context_).release();
62   ScopedVector<Application>::iterator app_iter =
63       applications_.insert(applications_.end(), application);
64
65   if (!application->Launch(launch_params)) {
66     applications_.erase(app_iter);
67     return NULL;
68   }
69
70   application->set_observer(this);
71
72   FOR_EACH_OBSERVER(Observer, observers_,
73                     DidLaunchApplication(application));
74
75   return application;
76 }
77
78 Application* ApplicationService::LaunchFromUnpackedPath(
79     const base::FilePath& path, const Application::LaunchParams& params) {
80   std::string error;
81   scoped_refptr<ApplicationData> application_data;
82   if (!base::DirectoryExists(path)) {
83     LOG(ERROR) << "Invalid input parameter: " << path.AsUTF8Unsafe();
84     return NULL;
85   }
86
87   application_data =
88       LoadApplication(path, ApplicationData::LOCAL_DIRECTORY, &error);
89
90   if (!application_data) {
91     LOG(ERROR) << "Error occurred while trying to load application: "
92                << error;
93     return NULL;
94   }
95
96   return Launch(application_data, params);
97 }
98
99 Application* ApplicationService::LaunchFromPackagePath(
100     const base::FilePath& path, const Application::LaunchParams& params) {
101   scoped_ptr<Package> package = Package::Create(path);
102   if (!package || !package->IsValid()) {
103     LOG(ERROR) << "Failed to obtain valid package from "
104                << path.AsUTF8Unsafe();
105     return NULL;
106   }
107
108   base::FilePath tmp_dir, target_dir;
109   if (!GetTempDir(&tmp_dir)) {
110     LOG(ERROR) << "Failed to obtain system temp directory.";
111     return NULL;
112   }
113
114   std::string error;
115   scoped_refptr<ApplicationData> application_data;
116
117   base::CreateTemporaryDirInDir(tmp_dir, package->name(), &target_dir);
118   if (package->ExtractTo(target_dir)) {
119     std::string id = tmp_dir.BaseName().AsUTF8Unsafe();
120     application_data =
121         LoadApplication(
122             target_dir, id, ApplicationData::TEMP_DIRECTORY, &error);
123   }
124
125   if (!application_data) {
126     LOG(ERROR) << "Error occurred while trying to load application: "
127                << error;
128     return NULL;
129   }
130
131   return Launch(application_data, params);
132 }
133
134 // Launch an application created from arbitrary url.
135 // FIXME: This application should have the same strict permissions
136 // as common browser apps.
137 Application* ApplicationService::LaunchHostedURL(
138     const GURL& url, const Application::LaunchParams& params) {
139   const std::string& url_spec = url.spec();
140   if (url_spec.empty()) {
141       LOG(ERROR) << "Failed to launch application from the URL: " << url;
142       return NULL;
143   }
144
145   const std::string& app_id = GenerateId(url_spec);
146
147   base::DictionaryValue manifest;
148   // FIXME: define permissions!
149   manifest.SetString(application_manifest_keys::kStartURLKey, url_spec);
150   // FIXME: Why use URL as name?
151   manifest.SetString(application_manifest_keys::kNameKey, url_spec);
152   manifest.SetString(application_manifest_keys::kXWalkVersionKey, "0");
153
154   std::string error;
155   scoped_refptr<ApplicationData> app_data =
156         ApplicationData::Create(base::FilePath(),
157             ApplicationData::EXTERNAL_URL, manifest, app_id, &error);
158   DCHECK(app_data);
159
160   return Launch(app_data, params);
161 }
162
163 namespace {
164
165 struct ApplicationRenderHostIDComparator {
166     explicit ApplicationRenderHostIDComparator(int id) : id(id) { }
167     bool operator() (Application* application) {
168       return id == application->GetRenderProcessHostID();
169     }
170     int id;
171 };
172
173 struct ApplicationIDComparator {
174     explicit ApplicationIDComparator(const std::string& app_id)
175       : app_id(app_id) { }
176     bool operator() (Application* application) {
177       return app_id == application->id();
178     }
179     std::string app_id;
180 };
181
182 }  // namespace
183
184 Application* ApplicationService::GetApplicationByRenderHostID(int id) const {
185   ApplicationRenderHostIDComparator comparator(id);
186   ScopedVector<Application>::const_iterator found = std::find_if(
187       applications_.begin(), applications_.end(), comparator);
188   if (found != applications_.end())
189     return *found;
190   return NULL;
191 }
192
193 Application* ApplicationService::GetApplicationByID(
194     const std::string& app_id) const {
195   ApplicationIDComparator comparator(app_id);
196   ScopedVector<Application>::const_iterator found = std::find_if(
197       applications_.begin(), applications_.end(), comparator);
198   if (found != applications_.end())
199     return *found;
200   return NULL;
201 }
202
203 void ApplicationService::AddObserver(Observer* observer) {
204   observers_.AddObserver(observer);
205 }
206
207 void ApplicationService::RemoveObserver(Observer* observer) {
208   observers_.RemoveObserver(observer);
209 }
210
211 void ApplicationService::OnApplicationTerminated(
212                                       Application* application) {
213   ScopedVector<Application>::iterator found = std::find(
214       applications_.begin(), applications_.end(), application);
215   CHECK(found != applications_.end());
216   FOR_EACH_OBSERVER(Observer, observers_,
217                     WillDestroyApplication(application));
218   scoped_refptr<ApplicationData> app_data = application->data();
219   applications_.erase(found);
220
221   if (app_data->source_type() == ApplicationData::TEMP_DIRECTORY) {
222       LOG(INFO) << "Deleting the app temporary directory "
223                 << app_data->Path().AsUTF8Unsafe();
224       content::BrowserThread::PostTask(content::BrowserThread::FILE,
225           FROM_HERE, base::Bind(base::IgnoreResult(&base::DeleteFile),
226                                 app_data->Path(), true /*recursive*/));
227       // FIXME: So far we simply clean up all the app persistent data,
228       // further we need to add an appropriate logic to handle it.
229       content::BrowserContext::GarbageCollectStoragePartitions(
230           runtime_context_,
231           make_scoped_ptr(new base::hash_set<base::FilePath>()),
232           base::Bind(&base::DoNothing));
233   }
234
235 #if !defined(SHARED_PROCESS_MODE)
236   if (applications_.empty()) {
237     base::MessageLoop::current()->PostTask(
238             FROM_HERE, base::MessageLoop::QuitClosure());
239   }
240 #endif
241 }
242
243 void ApplicationService::CheckAPIAccessControl(const std::string& app_id,
244     const std::string& extension_name,
245     const std::string& api_name, const PermissionCallback& callback) {
246   Application* app = GetApplicationByID(app_id);
247   if (!app) {
248     LOG(ERROR) << "No running application found with ID: "
249       << app_id;
250     callback.Run(UNDEFINED_RUNTIME_PERM);
251     return;
252   }
253   if (!app->UseExtension(extension_name)) {
254     LOG(ERROR) << "Can not find extension: "
255       << extension_name << " of Application with ID: "
256       << app_id;
257     callback.Run(UNDEFINED_RUNTIME_PERM);
258     return;
259   }
260   // Permission name should have been registered at extension initialization.
261   std::string permission_name =
262       app->GetRegisteredPermissionName(extension_name, api_name);
263   if (permission_name.empty()) {
264     LOG(ERROR) << "API: " << api_name << " of extension: "
265       << extension_name << " not registered!";
266     callback.Run(UNDEFINED_RUNTIME_PERM);
267     return;
268   }
269   // Okay, since we have the permission name, let's get down to the policies.
270   // First, find out whether the permission is stored for the current session.
271   StoredPermission perm = app->GetPermission(
272       SESSION_PERMISSION, permission_name);
273   if (perm != UNDEFINED_STORED_PERM) {
274     // "PROMPT" should not be in the session storage.
275     DCHECK(perm != PROMPT);
276     if (perm == ALLOW) {
277       callback.Run(ALLOW_SESSION);
278       return;
279     }
280     if (perm == DENY) {
281       callback.Run(DENY_SESSION);
282       return;
283     }
284     NOTREACHED();
285   }
286   // Then, query the persistent policy storage.
287   perm = app->GetPermission(PERSISTENT_PERMISSION, permission_name);
288   // Permission not found in persistent permission table, normally this should
289   // not happen because all the permission needed by the application should be
290   // contained in its manifest, so it also means that the application is asking
291   // for something wasn't allowed.
292   if (perm == UNDEFINED_STORED_PERM) {
293     callback.Run(UNDEFINED_RUNTIME_PERM);
294     return;
295   }
296   if (perm == PROMPT) {
297     // TODO(Bai): We needed to pop-up a dialog asking user to chose one from
298     // either allow/deny for session/one shot/forever. Then, we need to update
299     // the session and persistent policy accordingly.
300     callback.Run(UNDEFINED_RUNTIME_PERM);
301     return;
302   }
303   if (perm == ALLOW) {
304     callback.Run(ALLOW_ALWAYS);
305     return;
306   }
307   if (perm == DENY) {
308     callback.Run(DENY_ALWAYS);
309     return;
310   }
311   NOTREACHED();
312 }
313
314 bool ApplicationService::RegisterPermissions(const std::string& app_id,
315     const std::string& extension_name,
316     const std::string& perm_table) {
317   Application* app = GetApplicationByID(app_id);
318   if (!app) {
319     LOG(ERROR) << "No running application found with ID: " << app_id;
320     return false;
321   }
322   if (!app->UseExtension(extension_name)) {
323     LOG(ERROR) << "Can not find extension: "
324                << extension_name << " of Application with ID: "
325                << app_id;
326     return false;
327   }
328   return app->RegisterPermissions(extension_name, perm_table);
329 }
330
331 }  // namespace application
332 }  // namespace xwalk