Upstream version 8.36.161.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/files/file_enumerator.h"
13 #include "base/file_util.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/path_service.h"
17 #include "content/public/browser/web_contents.h"
18 #include "content/public/browser/web_contents_observer.h"
19 #include "xwalk/application/browser/application.h"
20 #include "xwalk/application/browser/application_system.h"
21 #include "xwalk/application/common/application_storage.h"
22 #include "xwalk/application/common/installer/package.h"
23 #include "xwalk/application/common/installer/package_installer.h"
24 #include "xwalk/application/common/application_file_util.h"
25 #include "xwalk/runtime/browser/runtime_context.h"
26 #include "xwalk/runtime/browser/runtime.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_tizen.h"
32 #endif
33
34 namespace xwalk {
35
36 namespace application {
37
38 namespace {
39
40 const base::FilePath::CharType kApplicationDataDirName[] =
41     FILE_PATH_LITERAL("Storage/ext");
42
43 base::FilePath GetStoragePartitionPath(
44     const base::FilePath& base_path, const std::string& app_id) {
45   return base_path.Append(kApplicationDataDirName).Append(app_id);
46 }
47
48 void CollectUnusedStoragePartitions(RuntimeContext* context,
49                                     ApplicationStorage* storage) {
50   std::vector<std::string> app_ids;
51   if (!storage->GetInstalledApplicationIDs(app_ids))
52     return;
53
54   scoped_ptr<base::hash_set<base::FilePath> > active_paths(
55       new base::hash_set<base::FilePath>());
56
57   for (unsigned i = 0; i < app_ids.size(); ++i) {
58     active_paths->insert(
59         GetStoragePartitionPath(context->GetPath(), app_ids.at(i)));
60   }
61
62   content::BrowserContext::GarbageCollectStoragePartitions(
63       context, active_paths.Pass(), base::Bind(&base::DoNothing));
64 }
65
66 }  // namespace
67
68 ApplicationService::ApplicationService(RuntimeContext* runtime_context,
69                                        ApplicationStorage* app_storage)
70     : runtime_context_(runtime_context),
71       application_storage_(app_storage),
72       package_installer_(PackageInstaller::Create(app_storage)) {
73   CollectUnusedStoragePartitions(runtime_context, app_storage);
74 }
75
76 ApplicationService::~ApplicationService() {
77 }
78
79 bool ApplicationService::Install(const base::FilePath& path, std::string* id) {
80   if (!package_installer_->Install(path, id))
81     return false;
82
83   FOR_EACH_OBSERVER(Observer, observers_,
84                     OnApplicationInstalled(*id));
85
86   return true;
87 }
88
89 bool ApplicationService::Update(const std::string& id,
90                                 const base::FilePath& path) {
91   if (Application* app = GetApplicationByID(id)) {
92     LOG(INFO) << "Try to terminate the running application before uninstall.";
93     app->Terminate();
94   }
95
96   if (!package_installer_->Update(id, path))
97     return false;
98
99   FOR_EACH_OBSERVER(Observer, observers_,
100                     OnApplicationUpdated(id));
101
102   return true;
103 }
104
105 bool ApplicationService::Uninstall(const std::string& id) {
106   if (Application* app = GetApplicationByID(id)) {
107     LOG(INFO) << "Try to terminate the running application before uninstall.";
108     app->Terminate();
109   }
110
111   if (!package_installer_->Uninstall(id))
112     return false;
113
114   FOR_EACH_OBSERVER(Observer, observers_, OnApplicationUninstalled(id));
115
116   return true;
117 }
118
119 void ApplicationService::ChangeLocale(const std::string& locale) {
120   ApplicationData::ApplicationDataMap apps;
121   if (!application_storage_->GetInstalledApplications(apps))
122     return;
123
124   ApplicationData::ApplicationDataMap::const_iterator it;
125   for (it = apps.begin(); it != apps.end(); ++it) {
126     base::string16 error;
127     std::string old_name = it->second->Name();
128     if (!it->second->SetApplicationLocale(locale, &error)) {
129       LOG(ERROR) << "Error when set locale " << locale
130                  << " to application " << it->second->ID()
131                  << "error : " << error;
132     }
133     if (old_name != it->second->Name()) {
134       // After we has changed the application locale, we might get a new name in
135       // the new locale, so call all observer for this event.
136       FOR_EACH_OBSERVER(
137           Observer, observers_,
138           OnApplicationNameChanged(it->second->ID(), it->second->Name()));
139     }
140   }
141 }
142
143 Application* ApplicationService::Launch(
144     scoped_refptr<ApplicationData> application_data,
145     const Application::LaunchParams& launch_params) {
146   if (GetApplicationByID(application_data->ID()) != NULL) {
147     LOG(INFO) << "Application with id: " << application_data->ID()
148               << " is already running.";
149     // FIXME: we need to notify application that it had been attempted
150     // to invoke and let the application to define the further behavior.
151     return NULL;
152   }
153
154 #if defined(OS_TIZEN)
155   Application* application(new ApplicationTizen(application_data,
156     runtime_context_, this));
157 #else
158   Application* application(new Application(application_data,
159     runtime_context_, this));
160 #endif
161
162   ScopedVector<Application>::iterator app_iter =
163       applications_.insert(applications_.end(), application);
164
165   if (!application->Launch(launch_params)) {
166     applications_.erase(app_iter);
167     return NULL;
168   }
169
170   FOR_EACH_OBSERVER(Observer, observers_,
171                     DidLaunchApplication(application));
172
173   return application;
174 }
175
176 Application* ApplicationService::Launch(
177     const std::string& id, const Application::LaunchParams& params) {
178   Application* application = NULL;
179   scoped_refptr<ApplicationData> application_data =
180     application_storage_->GetApplicationData(id);
181   if (!application_data) {
182     LOG(ERROR) << "Application with id " << id << " is not installed.";
183     return NULL;
184   }
185
186   return Launch(application_data, params);
187 }
188
189 Application* ApplicationService::Launch(
190     const base::FilePath& path, const Application::LaunchParams& params) {
191   Application* application = NULL;
192   if (!base::DirectoryExists(path))
193     return NULL;
194
195   std::string error;
196   scoped_refptr<ApplicationData> application_data =
197       LoadApplication(path, Manifest::COMMAND_LINE, &error);
198
199   if (!application_data) {
200     LOG(ERROR) << "Error occurred while trying to launch application: "
201                << error;
202     return NULL;
203   }
204
205   return Launch(application_data, params);
206 }
207
208 namespace {
209
210 struct ApplicationRenderHostIDComparator {
211     explicit ApplicationRenderHostIDComparator(int id) : id(id) { }
212     bool operator() (Application* application) {
213       return id == application->GetRenderProcessHostID();
214     }
215     int id;
216 };
217
218 struct ApplicationIDComparator {
219     explicit ApplicationIDComparator(const std::string& app_id)
220       : app_id(app_id) { }
221     bool operator() (Application* application) {
222       return app_id == application->id();
223     }
224     std::string app_id;
225 };
226
227 }  // namespace
228
229 Application* ApplicationService::GetApplicationByRenderHostID(int id) const {
230   ApplicationRenderHostIDComparator comparator(id);
231   ScopedVector<Application>::const_iterator found = std::find_if(
232       applications_.begin(), applications_.end(), comparator);
233   if (found != applications_.end())
234     return *found;
235   return NULL;
236 }
237
238 Application* ApplicationService::GetApplicationByID(
239     const std::string& app_id) const {
240   ApplicationIDComparator comparator(app_id);
241   ScopedVector<Application>::const_iterator found = std::find_if(
242       applications_.begin(), applications_.end(), comparator);
243   if (found != applications_.end())
244     return *found;
245   return NULL;
246 }
247
248 void ApplicationService::AddObserver(Observer* observer) {
249   observers_.AddObserver(observer);
250 }
251
252 void ApplicationService::RemoveObserver(Observer* observer) {
253   observers_.RemoveObserver(observer);
254 }
255
256 void ApplicationService::OnApplicationTerminated(
257                                       Application* application) {
258   ScopedVector<Application>::iterator found = std::find(
259       applications_.begin(), applications_.end(), application);
260   CHECK(found != applications_.end());
261   FOR_EACH_OBSERVER(Observer, observers_,
262                     WillDestroyApplication(application));
263   applications_.erase(found);
264   if (!XWalkRunner::GetInstance()->is_running_as_service() &&
265       applications_.empty()) {
266     base::MessageLoop::current()->PostTask(
267             FROM_HERE, base::MessageLoop::QuitClosure());
268   }
269 }
270
271 void ApplicationService::CheckAPIAccessControl(const std::string& app_id,
272     const std::string& extension_name,
273     const std::string& api_name, const PermissionCallback& callback) {
274   Application* app = GetApplicationByID(app_id);
275   if (!app) {
276     LOG(ERROR) << "No running application found with ID: "
277       << app_id;
278     callback.Run(UNDEFINED_RUNTIME_PERM);
279     return;
280   }
281   if (!app->UseExtension(extension_name)) {
282     LOG(ERROR) << "Can not find extension: "
283       << extension_name << " of Application with ID: "
284       << app_id;
285     callback.Run(UNDEFINED_RUNTIME_PERM);
286     return;
287   }
288   // Permission name should have been registered at extension initialization.
289   std::string permission_name =
290       app->GetRegisteredPermissionName(extension_name, api_name);
291   if (permission_name.empty()) {
292     LOG(ERROR) << "API: " << api_name << " of extension: "
293       << extension_name << " not registered!";
294     callback.Run(UNDEFINED_RUNTIME_PERM);
295     return;
296   }
297   // Okay, since we have the permission name, let's get down to the policies.
298   // First, find out whether the permission is stored for the current session.
299   StoredPermission perm = app->GetPermission(
300       SESSION_PERMISSION, permission_name);
301   if (perm != UNDEFINED_STORED_PERM) {
302     // "PROMPT" should not be in the session storage.
303     DCHECK(perm != PROMPT);
304     if (perm == ALLOW) {
305       callback.Run(ALLOW_SESSION);
306       return;
307     }
308     if (perm == DENY) {
309       callback.Run(DENY_SESSION);
310       return;
311     }
312     NOTREACHED();
313   }
314   // Then, query the persistent policy storage.
315   perm = app->GetPermission(PERSISTENT_PERMISSION, permission_name);
316   // Permission not found in persistent permission table, normally this should
317   // not happen because all the permission needed by the application should be
318   // contained in its manifest, so it also means that the application is asking
319   // for something wasn't allowed.
320   if (perm == UNDEFINED_STORED_PERM) {
321     callback.Run(UNDEFINED_RUNTIME_PERM);
322     return;
323   }
324   if (perm == PROMPT) {
325     // TODO(Bai): We needed to pop-up a dialog asking user to chose one from
326     // either allow/deny for session/one shot/forever. Then, we need to update
327     // the session and persistent policy accordingly.
328     callback.Run(UNDEFINED_RUNTIME_PERM);
329     return;
330   }
331   if (perm == ALLOW) {
332     callback.Run(ALLOW_ALWAYS);
333     return;
334   }
335   if (perm == DENY) {
336     callback.Run(DENY_ALWAYS);
337     return;
338   }
339   NOTREACHED();
340 }
341
342 bool ApplicationService::RegisterPermissions(const std::string& app_id,
343     const std::string& extension_name,
344     const std::string& perm_table) {
345   Application* app = GetApplicationByID(app_id);
346   if (!app) {
347     LOG(ERROR) << "No running application found with ID: " << app_id;
348     return false;
349   }
350   if (!app->UseExtension(extension_name)) {
351     LOG(ERROR) << "Can not find extension: "
352                << extension_name << " of Application with ID: "
353                << app_id;
354     return false;
355   }
356   return app->RegisterPermissions(extension_name, perm_table);
357 }
358
359 }  // namespace application
360 }  // namespace xwalk