Upstream version 9.38.207.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::LaunchFromManifestPath(
79     const base::FilePath& path, Manifest::Type manifest_type,
80         const Application::LaunchParams& params) {
81   std::string error;
82   scoped_ptr<Manifest> manifest = LoadManifest(path, manifest_type, &error);
83   if (!manifest) {
84     LOG(ERROR) << "Failed to load manifest.";
85     return NULL;
86   }
87
88   base::FilePath app_path = path.DirName();
89   LOG(ERROR) << "Loading app from " << app_path.MaybeAsASCII();
90
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: "
96                << error;
97     return NULL;
98   }
99
100   return Launch(application_data, params);
101 }
102
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();
109     return NULL;
110   }
111
112   base::FilePath tmp_dir, target_dir;
113   if (!GetTempDir(&tmp_dir)) {
114     LOG(ERROR) << "Failed to obtain system temp directory.";
115     return NULL;
116   }
117
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();
122     return NULL;
123   }
124
125   std::string error;
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: "
131                << error;
132     return NULL;
133   }
134
135   return Launch(application_data, params);
136 }
137
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;
146       return NULL;
147   }
148
149   const std::string& app_id = GenerateId(url_spec);
150
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");
157
158   scoped_ptr<Manifest> manifest(
159       new Manifest(settings.Pass(), Manifest::TYPE_MANIFEST));
160
161   std::string error;
162   scoped_refptr<ApplicationData> app_data =
163         ApplicationData::Create(base::FilePath(), app_id,
164         ApplicationData::EXTERNAL_URL, manifest.Pass(), &error);
165   DCHECK(app_data);
166
167   return Launch(app_data, params);
168 }
169
170 namespace {
171
172 struct ApplicationRenderHostIDComparator {
173     explicit ApplicationRenderHostIDComparator(int id) : id(id) { }
174     bool operator() (Application* application) {
175       return id == application->GetRenderProcessHostID();
176     }
177     int id;
178 };
179
180 struct ApplicationIDComparator {
181     explicit ApplicationIDComparator(const std::string& app_id)
182       : app_id(app_id) { }
183     bool operator() (Application* application) {
184       return app_id == application->id();
185     }
186     std::string app_id;
187 };
188
189 }  // namespace
190
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())
196     return *found;
197   return NULL;
198 }
199
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())
206     return *found;
207   return NULL;
208 }
209
210 void ApplicationService::AddObserver(Observer* observer) {
211   observers_.AddObserver(observer);
212 }
213
214 void ApplicationService::RemoveObserver(Observer* observer) {
215   observers_.RemoveObserver(observer);
216 }
217
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);
227
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(
237           runtime_context_,
238           make_scoped_ptr(new base::hash_set<base::FilePath>()),
239           base::Bind(&base::DoNothing));
240   }
241
242 #if !defined(SHARED_PROCESS_MODE)
243   if (applications_.empty()) {
244     base::MessageLoop::current()->PostTask(
245             FROM_HERE, base::MessageLoop::QuitClosure());
246   }
247 #endif
248 }
249
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);
254   if (!app) {
255     LOG(ERROR) << "No running application found with ID: "
256       << app_id;
257     callback.Run(UNDEFINED_RUNTIME_PERM);
258     return;
259   }
260   if (!app->UseExtension(extension_name)) {
261     LOG(ERROR) << "Can not find extension: "
262       << extension_name << " of Application with ID: "
263       << app_id;
264     callback.Run(UNDEFINED_RUNTIME_PERM);
265     return;
266   }
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);
274     return;
275   }
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);
283     if (perm == ALLOW) {
284       callback.Run(ALLOW_SESSION);
285       return;
286     }
287     if (perm == DENY) {
288       callback.Run(DENY_SESSION);
289       return;
290     }
291     NOTREACHED();
292   }
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);
301     return;
302   }
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);
308     return;
309   }
310   if (perm == ALLOW) {
311     callback.Run(ALLOW_ALWAYS);
312     return;
313   }
314   if (perm == DENY) {
315     callback.Run(DENY_ALWAYS);
316     return;
317   }
318   NOTREACHED();
319 }
320
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);
325   if (!app) {
326     LOG(ERROR) << "No running application found with ID: " << app_id;
327     return false;
328   }
329   if (!app->UseExtension(extension_name)) {
330     LOG(ERROR) << "Can not find extension: "
331                << extension_name << " of Application with ID: "
332                << app_id;
333     return false;
334   }
335   return app->RegisterPermissions(extension_name, perm_table);
336 }
337
338 }  // namespace application
339 }  // namespace xwalk