Upstream version 7.35.139.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 <set>
8 #include <string>
9
10 #include "base/files/file_enumerator.h"
11 #include "base/file_util.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/path_service.h"
15 #include "base/version.h"
16 #include "content/public/browser/storage_partition.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_storage.h"
21 #include "xwalk/application/browser/application_system.h"
22 #include "xwalk/application/browser/installer/package.h"
23 #include "xwalk/application/common/application_file_util.h"
24 #include "xwalk/application/common/permission_policy_manager.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 #include "xwalk/application/browser/installer/tizen/package_installer.h"
33 #endif
34
35 namespace xwalk {
36 namespace application {
37
38 namespace {
39
40 bool CopyDirectoryContents(const base::FilePath& from,
41     const base::FilePath& to) {
42   base::FileEnumerator iter(from, false,
43       base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
44   for (base::FilePath path = iter.Next(); !path.empty(); path = iter.Next()) {
45     if (iter.GetInfo().IsDirectory()) {
46       if (!base::CopyDirectory(path, to, true))
47         return false;
48     } else if (!base::CopyFile(path, to.Append(path.BaseName()))) {
49         return false;
50     }
51   }
52
53   return true;
54 }
55
56 void RemoveWidgetStorageFiles(const base::FilePath& storage_path,
57                               const std::string& app_id) {
58   base::FileEnumerator iter(storage_path, true,
59                             base::FileEnumerator::FILES);
60   for (base::FilePath file = iter.Next(); !file.empty(); file = iter.Next()) {
61     if (file.MaybeAsASCII().find(app_id) != std::string::npos)
62       base::DeleteFile(file, false);
63   }
64 }
65
66 }  // namespace
67
68 const base::FilePath::CharType kApplicationsDir[] =
69     FILE_PATH_LITERAL("applications");
70
71 ApplicationService::ApplicationService(RuntimeContext* runtime_context,
72                                        ApplicationStorage* app_storage)
73     : runtime_context_(runtime_context),
74       application_storage_(app_storage),
75       permission_policy_handler_(new PermissionPolicyManager()) {
76 }
77
78 ApplicationService::~ApplicationService() {
79 }
80
81 bool ApplicationService::Install(const base::FilePath& path, std::string* id) {
82   // FIXME(leandro): Installation is not robust enough -- should any step
83   // fail, it can't roll back to a consistent state.
84   if (!base::PathExists(path))
85     return false;
86
87   const base::FilePath data_dir =
88       runtime_context_->GetPath().Append(kApplicationsDir);
89
90   // Make sure the kApplicationsDir exists under data_path, otherwise,
91   // the installation will always fail because of moving application
92   // resources into an invalid directory.
93   if (!base::DirectoryExists(data_dir) &&
94       !base::CreateDirectory(data_dir))
95     return false;
96
97   std::string app_id;
98   base::FilePath unpacked_dir;
99   scoped_ptr<Package> package;
100   if (!base::DirectoryExists(path)) {
101     package = Package::Create(path);
102     package->Extract(&unpacked_dir);
103     app_id = package->Id();
104   } else {
105     unpacked_dir = path;
106   }
107
108   std::string error;
109   scoped_refptr<ApplicationData> application_data = LoadApplication(
110       unpacked_dir, app_id, Manifest::COMMAND_LINE, &error);
111   if (!application_data) {
112     LOG(ERROR) << "Error during application installation: " << error;
113     return false;
114   }
115   if (!permission_policy_handler_->
116       InitApplicationPermission(application_data)) {
117     LOG(ERROR) << "Application permission data is invalid";
118     return false;
119   }
120
121   if (application_storage_->Contains(application_data->ID())) {
122     *id = application_data->ID();
123     LOG(INFO) << "Already installed: " << *id;
124     return false;
125   }
126
127   base::FilePath app_dir = data_dir.AppendASCII(application_data->ID());
128   if (base::DirectoryExists(app_dir)) {
129     if (!base::DeleteFile(app_dir, true))
130       return false;
131   }
132   if (!package) {
133     if (!base::CreateDirectory(app_dir))
134       return false;
135     if (!CopyDirectoryContents(unpacked_dir, app_dir))
136       return false;
137   } else {
138     if (!base::Move(unpacked_dir, app_dir))
139       return false;
140   }
141
142   application_data->SetPath(app_dir);
143
144   if (!application_storage_->AddApplication(application_data)) {
145     LOG(ERROR) << "Application with id " << application_data->ID()
146                << " couldn't be installed.";
147     return false;
148   }
149
150 #if defined(OS_TIZEN)
151   if (!PackageInstaller::InstallApplication(
152         application_data, runtime_context_->GetPath())) {
153     application_storage_->RemoveApplication(application_data->ID());
154     return false;
155   }
156 #endif
157
158   LOG(INFO) << "Application be installed in: " << app_dir.MaybeAsASCII();
159   LOG(INFO) << "Installed application with id: " << application_data->ID()
160             << " successfully.";
161   *id = application_data->ID();
162
163   FOR_EACH_OBSERVER(Observer, observers_,
164                     OnApplicationInstalled(application_data->ID()));
165
166   return true;
167 }
168
169 bool ApplicationService::Update(const std::string& id,
170                                 const base::FilePath& path) {
171   if (!base::PathExists(path)) {
172     LOG(ERROR) << "The XPK/WGT package file " << path.value() << " is invalid.";
173     return false;
174   }
175
176   if (base::DirectoryExists(path)) {
177     LOG(WARNING) << "Can not update an unpacked XPK/WGT package.";
178     return false;
179   }
180
181   base::FilePath unpacked_dir;
182   base::FilePath origin_dir;
183   std::string app_id;
184   scoped_ptr<Package> package = Package::Create(path);
185   if (!package) {
186     LOG(ERROR) << "XPK/WGT file is invalid.";
187     return false;
188   }
189
190   app_id = package->Id();
191
192   if (app_id.empty()) {
193     LOG(ERROR) << "XPK/WGT file is invalid, and the application id is empty.";
194     return false;
195   }
196
197   if (id.empty() ||
198       id.compare(app_id) != 0) {
199     LOG(ERROR) << "The XPK/WGT file is not the same as expecting.";
200     return false;
201   }
202
203   if (!package->Extract(&unpacked_dir))
204     return false;
205
206   std::string error;
207   scoped_refptr<ApplicationData> new_application =
208       LoadApplication(unpacked_dir,
209                       app_id,
210                       Manifest::COMMAND_LINE,
211                       &error);
212   if (!new_application) {
213     LOG(ERROR) << "An error occurred during application updating: " << error;
214     return false;
215   }
216
217   scoped_refptr<ApplicationData> old_application =
218       application_storage_->GetApplicationData(app_id);
219   if (!old_application) {
220     LOG(INFO) << "Application haven't installed yet: " << app_id;
221     return false;
222   }
223
224   if (old_application->Version()->CompareTo(
225           *(new_application->Version())) >= 0) {
226     LOG(INFO) << "The version number of new XPK/WGT package "
227                  "should be higher than "
228               << old_application->VersionString();
229     return false;
230   }
231
232   const base::FilePath& app_dir = old_application->Path();
233   const base::FilePath tmp_dir(app_dir.value()
234                                + FILE_PATH_LITERAL(".tmp"));
235
236   if (Application* app = GetApplicationByID(app_id)) {
237     LOG(INFO) << "Try to terminate the running application before update.";
238     app->Terminate();
239   }
240
241   if (!base::Move(app_dir, tmp_dir) ||
242       !base::Move(unpacked_dir, app_dir))
243     return false;
244
245   new_application = LoadApplication(app_dir,
246                                     app_id,
247                                     Manifest::COMMAND_LINE,
248                                     &error);
249   if (!new_application) {
250     LOG(ERROR) << "Error during loading new package: " << error;
251     base::DeleteFile(app_dir, true);
252     base::Move(tmp_dir, app_dir);
253     return false;
254   }
255
256   if (!application_storage_->UpdateApplication(new_application)) {
257     LOG(ERROR) << "Fail to update application, roll back to the old one.";
258     base::DeleteFile(app_dir, true);
259     base::Move(tmp_dir, app_dir);
260     return false;
261   }
262
263 #if defined(OS_TIZEN)
264   if (!PackageInstaller::UpdateApplication(
265         new_application, runtime_context_->GetPath())) {
266     LOG(ERROR) << "Fail to update package on Tizen, roll back to the old one.";
267     base::DeleteFile(app_dir, true);
268     if (!application_storage_->UpdateApplication(old_application)) {
269       LOG(ERROR) << "Fail to revert old application info, "
270                  << "remove the application as a last resort.";
271       application_storage_->RemoveApplication(old_application->ID());
272       return false;
273     }
274     base::Move(tmp_dir, app_dir);
275     return false;
276   }
277 #endif
278
279   base::DeleteFile(tmp_dir, true);
280
281   FOR_EACH_OBSERVER(Observer, observers_,
282                     OnApplicationUpdated(app_id));
283
284   return true;
285 }
286
287 bool ApplicationService::Uninstall(const std::string& id) {
288   bool result = true;
289
290   scoped_refptr<ApplicationData> application =
291       application_storage_->GetApplicationData(id);
292   if (!application) {
293     LOG(ERROR) << "Cannot uninstall application with id " << id
294                << "; invalid application id";
295     return false;
296   }
297
298   if (Application* app = GetApplicationByID(id)) {
299     LOG(INFO) << "Try to terminate the running application before uninstall.";
300     app->Terminate();
301   }
302
303 #if defined(OS_TIZEN)
304   if (!PackageInstaller::UninstallApplication(
305         application, runtime_context_->GetPath()))
306     result = false;
307 #endif
308
309   if (!application_storage_->RemoveApplication(id)) {
310     LOG(ERROR) << "Cannot uninstall application with id " << id
311                << "; application is not installed.";
312     result = false;
313   }
314
315   const base::FilePath resources =
316       runtime_context_->GetPath().Append(kApplicationsDir).AppendASCII(id);
317   if (base::DirectoryExists(resources) &&
318       !base::DeleteFile(resources, true)) {
319     LOG(ERROR) << "Error occurred while trying to remove application with id "
320                << id << "; Cannot remove all resources.";
321     result = false;
322   }
323
324   content::StoragePartition* partition =
325       content::BrowserContext::GetStoragePartitionForSite(
326           runtime_context_, application->GetBaseURLFromApplicationId(id));
327   partition->ClearDataForOrigin(
328       content::StoragePartition::REMOVE_DATA_MASK_ALL,
329       content::StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL,
330       application->URL(),
331       partition->GetURLRequestContext());
332
333   base::FilePath path;
334   PathService::Get(xwalk::DIR_WGT_STORAGE_PATH, &path);
335   RemoveWidgetStorageFiles(path, id);
336
337   FOR_EACH_OBSERVER(Observer, observers_, OnApplicationUninstalled(id));
338
339   return result;
340 }
341
342 void ApplicationService::ChangeLocale(const std::string& locale) {
343   const ApplicationData::ApplicationDataMap& apps =
344       application_storage_->GetInstalledApplications();
345   ApplicationData::ApplicationDataMap::const_iterator it;
346   for (it = apps.begin(); it != apps.end(); ++it) {
347     base::string16 error;
348     std::string old_name = it->second->Name();
349     if (!it->second->SetApplicationLocale(locale, &error)) {
350       LOG(ERROR) << "Error when set locale " << locale
351                  << " to application " << it->second->ID()
352                  << "error : " << error;
353     }
354     if (old_name != it->second->Name()) {
355       // After we has changed the application locale, we might get a new name in
356       // the new locale, so call all observer for this event.
357       FOR_EACH_OBSERVER(
358           Observer, observers_,
359           OnApplicationNameChanged(it->second->ID(), it->second->Name()));
360     }
361   }
362 }
363
364 Application* ApplicationService::Launch(
365     scoped_refptr<ApplicationData> application_data,
366     const Application::LaunchParams& launch_params) {
367   if (GetApplicationByID(application_data->ID()) != NULL) {
368     LOG(INFO) << "Application with id: " << application_data->ID()
369               << " is already running.";
370     // FIXME: we need to notify application that it had been attempted
371     // to invoke and let the application to define the further behavior.
372     return NULL;
373   }
374
375 #if defined(OS_TIZEN)
376   Application* application(new ApplicationTizen(application_data,
377     runtime_context_, this));
378 #else
379   Application* application(new Application(application_data,
380     runtime_context_, this));
381 #endif
382
383   ScopedVector<Application>::iterator app_iter =
384       applications_.insert(applications_.end(), application);
385
386   if (!application->Launch(launch_params)) {
387     applications_.erase(app_iter);
388     return NULL;
389   }
390
391   FOR_EACH_OBSERVER(Observer, observers_,
392                     DidLaunchApplication(application));
393
394   return application;
395 }
396
397 Application* ApplicationService::Launch(
398     const std::string& id, const Application::LaunchParams& params) {
399   Application* application = NULL;
400   scoped_refptr<ApplicationData> application_data =
401     application_storage_->GetApplicationData(id);
402   if (!application_data) {
403     LOG(ERROR) << "Application with id " << id << " is not installed.";
404     return NULL;
405   }
406
407   return Launch(application_data, params);
408 }
409
410 Application* ApplicationService::Launch(
411     const base::FilePath& path, const Application::LaunchParams& params) {
412   Application* application = NULL;
413   if (!base::DirectoryExists(path))
414     return NULL;
415
416   std::string error;
417   scoped_refptr<ApplicationData> application_data =
418       LoadApplication(path, Manifest::COMMAND_LINE, &error);
419
420   if (!application_data) {
421     LOG(ERROR) << "Error occurred while trying to launch application: "
422                << error;
423     return NULL;
424   }
425
426   return Launch(application_data, params);
427 }
428
429 namespace {
430
431 struct ApplicationRenderHostIDComparator {
432     explicit ApplicationRenderHostIDComparator(int id) : id(id) { }
433     bool operator() (Application* application) {
434       return id == application->GetRenderProcessHostID();
435     }
436     int id;
437 };
438
439 struct ApplicationIDComparator {
440     explicit ApplicationIDComparator(const std::string& app_id)
441       : app_id(app_id) { }
442     bool operator() (Application* application) {
443       return app_id == application->id();
444     }
445     std::string app_id;
446 };
447
448 }  // namespace
449
450 Application* ApplicationService::GetApplicationByRenderHostID(int id) const {
451   ApplicationRenderHostIDComparator comparator(id);
452   ScopedVector<Application>::const_iterator found = std::find_if(
453       applications_.begin(), applications_.end(), comparator);
454   if (found != applications_.end())
455     return *found;
456   return NULL;
457 }
458
459 Application* ApplicationService::GetApplicationByID(
460     const std::string& app_id) const {
461   ApplicationIDComparator comparator(app_id);
462   ScopedVector<Application>::const_iterator found = std::find_if(
463       applications_.begin(), applications_.end(), comparator);
464   if (found != applications_.end())
465     return *found;
466   return NULL;
467 }
468
469 void ApplicationService::AddObserver(Observer* observer) {
470   observers_.AddObserver(observer);
471 }
472
473 void ApplicationService::RemoveObserver(Observer* observer) {
474   observers_.RemoveObserver(observer);
475 }
476
477 void ApplicationService::OnApplicationTerminated(
478                                       Application* application) {
479   ScopedVector<Application>::iterator found = std::find(
480       applications_.begin(), applications_.end(), application);
481   CHECK(found != applications_.end());
482   FOR_EACH_OBSERVER(Observer, observers_,
483                     WillDestroyApplication(application));
484   applications_.erase(found);
485   if (!XWalkRunner::GetInstance()->is_running_as_service() &&
486       applications_.empty()) {
487     base::MessageLoop::current()->PostTask(
488             FROM_HERE, base::MessageLoop::QuitClosure());
489   }
490 }
491
492 void ApplicationService::CheckAPIAccessControl(const std::string& app_id,
493     const std::string& extension_name,
494     const std::string& api_name, const PermissionCallback& callback) {
495   Application* app = GetApplicationByID(app_id);
496   if (!app) {
497     LOG(ERROR) << "No running application found with ID: "
498       << app_id;
499     callback.Run(UNDEFINED_RUNTIME_PERM);
500     return;
501   }
502   if (!app->UseExtension(extension_name)) {
503     LOG(ERROR) << "Can not find extension: "
504       << extension_name << " of Application with ID: "
505       << app_id;
506     callback.Run(UNDEFINED_RUNTIME_PERM);
507     return;
508   }
509   // Permission name should have been registered at extension initialization.
510   std::string permission_name =
511       app->GetRegisteredPermissionName(extension_name, api_name);
512   if (permission_name.empty()) {
513     LOG(ERROR) << "API: " << api_name << " of extension: "
514       << extension_name << " not registered!";
515     callback.Run(UNDEFINED_RUNTIME_PERM);
516     return;
517   }
518   // Okay, since we have the permission name, let's get down to the policies.
519   // First, find out whether the permission is stored for the current session.
520   StoredPermission perm = app->GetPermission(
521       SESSION_PERMISSION, permission_name);
522   if (perm != UNDEFINED_STORED_PERM) {
523     // "PROMPT" should not be in the session storage.
524     DCHECK(perm != PROMPT);
525     if (perm == ALLOW) {
526       callback.Run(ALLOW_SESSION);
527       return;
528     }
529     if (perm == DENY) {
530       callback.Run(DENY_SESSION);
531       return;
532     }
533     NOTREACHED();
534   }
535   // Then, query the persistent policy storage.
536   perm = app->GetPermission(PERSISTENT_PERMISSION, permission_name);
537   // Permission not found in persistent permission table, normally this should
538   // not happen because all the permission needed by the application should be
539   // contained in its manifest, so it also means that the application is asking
540   // for something wasn't allowed.
541   if (perm == UNDEFINED_STORED_PERM) {
542     callback.Run(UNDEFINED_RUNTIME_PERM);
543     return;
544   }
545   if (perm == PROMPT) {
546     // TODO(Bai): We needed to pop-up a dialog asking user to chose one from
547     // either allow/deny for session/one shot/forever. Then, we need to update
548     // the session and persistent policy accordingly.
549     callback.Run(UNDEFINED_RUNTIME_PERM);
550     return;
551   }
552   if (perm == ALLOW) {
553     callback.Run(ALLOW_ALWAYS);
554     return;
555   }
556   if (perm == DENY) {
557     callback.Run(DENY_ALWAYS);
558     return;
559   }
560   NOTREACHED();
561 }
562
563 bool ApplicationService::RegisterPermissions(const std::string& app_id,
564     const std::string& extension_name,
565     const std::string& perm_table) {
566   Application* app = GetApplicationByID(app_id);
567   if (!app) {
568     LOG(ERROR) << "No running application found with ID: " << app_id;
569     return false;
570   }
571   if (!app->UseExtension(extension_name)) {
572     LOG(ERROR) << "Can not find extension: "
573                << extension_name << " of Application with ID: "
574                << app_id;
575     return false;
576   }
577   return app->RegisterPermissions(extension_name, perm_table);
578 }
579
580 }  // namespace application
581 }  // namespace xwalk