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