Update To 11.40.268.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 #if defined(OS_MACOSX)
8 #include <ext/hash_set>
9 #else
10 #include <hash_set>
11 #endif
12 #include <set>
13 #include <string>
14 #include <vector>
15
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"
29
30 #if defined(OS_TIZEN)
31 #include "xwalk/application/browser/application_service_tizen.h"
32 #endif
33
34 namespace xwalk {
35
36 namespace application {
37
38 ApplicationService::ApplicationService(XWalkBrowserContext* browser_context)
39   : browser_context_(browser_context) {
40 }
41
42 scoped_ptr<ApplicationService> ApplicationService::Create(
43     XWalkBrowserContext* browser_context) {
44 #if defined(OS_TIZEN)
45   return make_scoped_ptr<ApplicationService>(
46     new ApplicationServiceTizen(browser_context));
47 #else
48   return make_scoped_ptr(new ApplicationService(browser_context));
49 #endif
50 }
51
52 ApplicationService::~ApplicationService() {
53 }
54
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.
63     return NULL;
64   }
65
66   Application* application = Application::Create(application_data,
67     browser_context_).release();
68   ScopedVector<Application>::iterator app_iter =
69       applications_.insert(applications_.end(), application);
70
71   if (!application->Launch(launch_params)) {
72     applications_.erase(app_iter);
73     return NULL;
74   }
75
76   application->set_observer(this);
77
78   FOR_EACH_OBSERVER(Observer, observers_,
79                     DidLaunchApplication(application));
80
81   return application;
82 }
83
84 Application* ApplicationService::LaunchFromManifestPath(
85     const base::FilePath& path, Manifest::Type manifest_type,
86         const Application::LaunchParams& params) {
87   std::string error;
88   scoped_ptr<Manifest> manifest = LoadManifest(path, manifest_type, &error);
89   if (!manifest) {
90     LOG(ERROR) << "Failed to load manifest.";
91     return NULL;
92   }
93
94   base::FilePath app_path = path.DirName();
95   LOG(ERROR) << "Loading app from " << app_path.MaybeAsASCII();
96
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: "
102                << error;
103     return NULL;
104   }
105
106   return Launch(application_data, params);
107 }
108
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();
115     return NULL;
116   }
117
118   base::FilePath tmp_dir, target_dir;
119   if (!GetTempDir(&tmp_dir)) {
120     LOG(ERROR) << "Failed to obtain system temp directory.";
121     return NULL;
122   }
123
124 #if defined (OS_WIN)
125   base::CreateTemporaryDirInDir(tmp_dir,
126       base::UTF8ToWide(package->name()), &target_dir);
127 #else
128   base::CreateTemporaryDirInDir(tmp_dir, package->name(), &target_dir);
129 #endif
130   if (!package->ExtractTo(target_dir)) {
131     LOG(ERROR) << "Failed to unpack to a temporary directory: "
132                << target_dir.MaybeAsASCII();
133     return NULL;
134   }
135
136   std::string error;
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: "
142                << error;
143     return NULL;
144   }
145
146   return Launch(application_data, params);
147 }
148
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;
157       return NULL;
158   }
159
160   const std::string& app_id = GenerateId(url_spec);
161
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");
168
169   scoped_ptr<Manifest> manifest(
170       new Manifest(settings.Pass(), Manifest::TYPE_MANIFEST));
171
172   std::string error;
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());
177
178   return Launch(app_data, params);
179 }
180
181 namespace {
182
183 struct ApplicationRenderHostIDComparator {
184     explicit ApplicationRenderHostIDComparator(int id) : id(id) { }
185     bool operator() (Application* application) {
186       return id == application->GetRenderProcessHostID();
187     }
188     int id;
189 };
190
191 struct ApplicationIDComparator {
192     explicit ApplicationIDComparator(const std::string& app_id)
193       : app_id(app_id) { }
194     bool operator() (Application* application) {
195       return app_id == application->id();
196     }
197     std::string app_id;
198 };
199
200 }  // namespace
201
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())
207     return *found;
208   return NULL;
209 }
210
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())
217     return *found;
218   return NULL;
219 }
220
221 void ApplicationService::AddObserver(Observer* observer) {
222   observers_.AddObserver(observer);
223 }
224
225 void ApplicationService::RemoveObserver(Observer* observer) {
226   observers_.RemoveObserver(observer);
227 }
228
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);
238
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(
248           browser_context_,
249           make_scoped_ptr(new base::hash_set<base::FilePath>()),
250           base::Bind(&base::DoNothing));
251   }
252
253   if (!XWalkRunner::GetInstance()->shared_process_mode_enabled()) {
254     if (applications_.empty()) {
255       base::MessageLoop::current()->PostTask(
256             FROM_HERE, base::MessageLoop::QuitClosure());
257     }
258   }
259 }
260
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);
265   if (!app) {
266     LOG(ERROR) << "No running application found with ID: "
267       << app_id;
268     callback.Run(UNDEFINED_RUNTIME_PERM);
269     return;
270   }
271   if (!app->UseExtension(extension_name)) {
272     LOG(ERROR) << "Can not find extension: "
273       << extension_name << " of Application with ID: "
274       << app_id;
275     callback.Run(UNDEFINED_RUNTIME_PERM);
276     return;
277   }
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);
285     return;
286   }
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);
294     if (perm == ALLOW) {
295       callback.Run(ALLOW_SESSION);
296       return;
297     }
298     if (perm == DENY) {
299       callback.Run(DENY_SESSION);
300       return;
301     }
302     NOTREACHED();
303   }
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);
312     return;
313   }
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);
319     return;
320   }
321   if (perm == ALLOW) {
322     callback.Run(ALLOW_ALWAYS);
323     return;
324   }
325   if (perm == DENY) {
326     callback.Run(DENY_ALWAYS);
327     return;
328   }
329   NOTREACHED();
330 }
331
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);
336   if (!app) {
337     LOG(ERROR) << "No running application found with ID: " << app_id;
338     return false;
339   }
340   if (!app->UseExtension(extension_name)) {
341     LOG(ERROR) << "Can not find extension: "
342                << extension_name << " of Application with ID: "
343                << app_id;
344     return false;
345   }
346   return app->RegisterPermissions(extension_name, perm_table);
347 }
348
349 }  // namespace application
350 }  // namespace xwalk