Upstream version 10.38.210.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 "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"
24
25 #if defined(OS_TIZEN)
26 #include "xwalk/application/browser/application_service_tizen.h"
27 #endif
28
29 namespace xwalk {
30
31 namespace application {
32
33 ApplicationService::ApplicationService(RuntimeContext* runtime_context)
34   : runtime_context_(runtime_context) {
35 }
36
37 scoped_ptr<ApplicationService> ApplicationService::Create(
38     RuntimeContext* runtime_context) {
39 #if defined(OS_TIZEN)
40   return make_scoped_ptr<ApplicationService>(
41     new ApplicationServiceTizen(runtime_context));
42 #else
43   return make_scoped_ptr(new ApplicationService(runtime_context));
44 #endif
45 }
46
47 ApplicationService::~ApplicationService() {
48 }
49
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.
58     return NULL;
59   }
60
61   Application* application = Application::Create(application_data,
62     runtime_context_).release();
63   ScopedVector<Application>::iterator app_iter =
64       applications_.insert(applications_.end(), application);
65
66   if (!application->Launch(launch_params)) {
67     applications_.erase(app_iter);
68     return NULL;
69   }
70
71   application->set_observer(this);
72
73   FOR_EACH_OBSERVER(Observer, observers_,
74                     DidLaunchApplication(application));
75
76   return application;
77 }
78
79 Application* ApplicationService::LaunchFromManifestPath(
80     const base::FilePath& path, Manifest::Type manifest_type,
81         const Application::LaunchParams& params) {
82   std::string error;
83   scoped_ptr<Manifest> manifest = LoadManifest(path, manifest_type, &error);
84   if (!manifest) {
85     LOG(ERROR) << "Failed to load manifest.";
86     return NULL;
87   }
88
89   base::FilePath app_path = path.DirName();
90   LOG(ERROR) << "Loading app from " << app_path.MaybeAsASCII();
91
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: "
97                << error;
98     return NULL;
99   }
100
101   return Launch(application_data, params);
102 }
103
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();
110     return NULL;
111   }
112
113   base::FilePath tmp_dir, target_dir;
114   if (!GetTempDir(&tmp_dir)) {
115     LOG(ERROR) << "Failed to obtain system temp directory.";
116     return NULL;
117   }
118
119 #if defined (OS_WIN)
120   base::CreateTemporaryDirInDir(tmp_dir,
121       base::UTF8ToWide(package->name()), &target_dir);
122 #else
123   base::CreateTemporaryDirInDir(tmp_dir, package->name(), &target_dir);
124 #endif
125   if (!package->ExtractTo(target_dir)) {
126     LOG(ERROR) << "Failed to unpack to a temporary directory: "
127                << target_dir.MaybeAsASCII();
128     return NULL;
129   }
130
131   std::string error;
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: "
137                << error;
138     return NULL;
139   }
140
141   return Launch(application_data, params);
142 }
143
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;
152       return NULL;
153   }
154
155   const std::string& app_id = GenerateId(url_spec);
156
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");
163
164   scoped_ptr<Manifest> manifest(
165       new Manifest(settings.Pass(), Manifest::TYPE_MANIFEST));
166
167   std::string error;
168   scoped_refptr<ApplicationData> app_data =
169         ApplicationData::Create(base::FilePath(), app_id,
170         ApplicationData::EXTERNAL_URL, manifest.Pass(), &error);
171   DCHECK(app_data);
172
173   return Launch(app_data, params);
174 }
175
176 namespace {
177
178 struct ApplicationRenderHostIDComparator {
179     explicit ApplicationRenderHostIDComparator(int id) : id(id) { }
180     bool operator() (Application* application) {
181       return id == application->GetRenderProcessHostID();
182     }
183     int id;
184 };
185
186 struct ApplicationIDComparator {
187     explicit ApplicationIDComparator(const std::string& app_id)
188       : app_id(app_id) { }
189     bool operator() (Application* application) {
190       return app_id == application->id();
191     }
192     std::string app_id;
193 };
194
195 }  // namespace
196
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())
202     return *found;
203   return NULL;
204 }
205
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())
212     return *found;
213   return NULL;
214 }
215
216 void ApplicationService::AddObserver(Observer* observer) {
217   observers_.AddObserver(observer);
218 }
219
220 void ApplicationService::RemoveObserver(Observer* observer) {
221   observers_.RemoveObserver(observer);
222 }
223
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);
233
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(
243           runtime_context_,
244           make_scoped_ptr(new base::hash_set<base::FilePath>()),
245           base::Bind(&base::DoNothing));
246   }
247
248 #if !defined(SHARED_PROCESS_MODE)
249   if (applications_.empty()) {
250     base::MessageLoop::current()->PostTask(
251             FROM_HERE, base::MessageLoop::QuitClosure());
252   }
253 #endif
254 }
255
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);
260   if (!app) {
261     LOG(ERROR) << "No running application found with ID: "
262       << app_id;
263     callback.Run(UNDEFINED_RUNTIME_PERM);
264     return;
265   }
266   if (!app->UseExtension(extension_name)) {
267     LOG(ERROR) << "Can not find extension: "
268       << extension_name << " of Application with ID: "
269       << app_id;
270     callback.Run(UNDEFINED_RUNTIME_PERM);
271     return;
272   }
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);
280     return;
281   }
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);
289     if (perm == ALLOW) {
290       callback.Run(ALLOW_SESSION);
291       return;
292     }
293     if (perm == DENY) {
294       callback.Run(DENY_SESSION);
295       return;
296     }
297     NOTREACHED();
298   }
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);
307     return;
308   }
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);
314     return;
315   }
316   if (perm == ALLOW) {
317     callback.Run(ALLOW_ALWAYS);
318     return;
319   }
320   if (perm == DENY) {
321     callback.Run(DENY_ALWAYS);
322     return;
323   }
324   NOTREACHED();
325 }
326
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);
331   if (!app) {
332     LOG(ERROR) << "No running application found with ID: " << app_id;
333     return false;
334   }
335   if (!app->UseExtension(extension_name)) {
336     LOG(ERROR) << "Can not find extension: "
337                << extension_name << " of Application with ID: "
338                << app_id;
339     return false;
340   }
341   return app->RegisterPermissions(extension_name, perm_table);
342 }
343
344 }  // namespace application
345 }  // namespace xwalk