1 // Copyright (c) 2014 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.
5 #include "xwalk/application/common/installer/package_installer.h"
12 #include "base/file_util.h"
13 #include "base/files/file_enumerator.h"
14 #include "base/logging.h"
15 #include "base/path_service.h"
16 #include "base/command_line.h"
17 #include "base/process/launch.h"
18 #include "base/version.h"
19 #include "xwalk/application/common/application_data.h"
20 #include "xwalk/application/common/application_file_util.h"
21 #include "xwalk/application/common/application_manifest_constants.h"
22 #include "xwalk/application/common/permission_policy_manager.h"
23 #include "xwalk/application/common/application_storage.h"
24 #include "xwalk/application/common/installer/tizen/packageinfo_constants.h"
25 #include "xwalk/runtime/common/xwalk_paths.h"
28 #include "xwalk/application/common/installer/package_installer_tizen.h"
32 namespace application {
36 bool CopyDirectoryContents(const base::FilePath& from,
37 const base::FilePath& to) {
38 base::FileEnumerator iter(from, false,
39 base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
40 for (base::FilePath path = iter.Next(); !path.empty(); path = iter.Next()) {
41 if (iter.GetInfo().IsDirectory()) {
42 if (!base::CopyDirectory(path, to, true))
44 } else if (!base::CopyFile(path, to.Append(path.BaseName()))) {
52 const base::FilePath::CharType kApplicationsDir[] =
53 FILE_PATH_LITERAL("applications");
57 PackageInstaller::PackageInstaller(ApplicationStorage* storage)
61 PackageInstaller::~PackageInstaller() {
64 scoped_ptr<PackageInstaller> PackageInstaller::Create(
65 ApplicationStorage* storage) {
67 return scoped_ptr<PackageInstaller>(new PackageInstallerTizen(storage));
69 return scoped_ptr<PackageInstaller>(new PackageInstaller(storage));
73 bool PackageInstaller::PlatformInstall(ApplicationData* data) {
77 bool PackageInstaller::PlatformUninstall(ApplicationData* data) {
81 bool PackageInstaller::PlatformUpdate(ApplicationData* updated_data) {
85 bool PackageInstaller::Install(const base::FilePath& path, std::string* id) {
86 // FIXME(leandro): Installation is not robust enough -- should any step
87 // fail, it can't roll back to a consistent state.
88 if (!base::PathExists(path))
91 base::FilePath data_dir;
92 CHECK(PathService::Get(xwalk::DIR_DATA_PATH, &data_dir));
93 data_dir = data_dir.Append(kApplicationsDir);
95 // Make sure the kApplicationsDir exists under data_path, otherwise,
96 // the installation will always fail because of moving application
97 // resources into an invalid directory.
98 if (!base::DirectoryExists(data_dir) &&
99 !base::CreateDirectory(data_dir))
103 base::FilePath unpacked_dir;
104 scoped_ptr<Package> package;
105 if (!base::DirectoryExists(path)) {
106 package = Package::Create(path);
107 package->Extract(&unpacked_dir);
108 app_id = package->Id();
114 scoped_refptr<ApplicationData> app_data = LoadApplication(
115 unpacked_dir, app_id, Manifest::COMMAND_LINE,
116 package->type(), &error);
118 LOG(ERROR) << "Error during application installation: " << error;
122 // FIXME: Probably should be removed, as we should not handle permissions
124 PermissionPolicyManager permission_policy_handler;
125 if (!permission_policy_handler.
126 InitApplicationPermission(app_data)) {
127 LOG(ERROR) << "Application permission data is invalid";
131 if (storage_->Contains(app_data->ID())) {
132 *id = app_data->ID();
133 LOG(INFO) << "Already installed: " << *id;
137 base::FilePath app_dir = data_dir.AppendASCII(app_data->ID());
138 if (base::DirectoryExists(app_dir)) {
139 if (!base::DeleteFile(app_dir, true))
143 if (!base::CreateDirectory(app_dir))
145 if (!CopyDirectoryContents(unpacked_dir, app_dir))
148 if (!base::Move(unpacked_dir, app_dir))
152 app_data->SetPath(app_dir);
154 if (!storage_->AddApplication(app_data)) {
155 LOG(ERROR) << "Application with id " << app_data->ID()
156 << " couldn't be installed due to a Storage error";
157 base::DeleteFile(app_dir, true);
161 if (!PlatformInstall(app_data)) {
162 LOG(ERROR) << "Application with id " << app_data->ID()
163 << " couldn't be installed due to a platform error";
164 storage_->RemoveApplication(app_data->ID());
165 base::DeleteFile(app_dir, true);
169 LOG(INFO) << "Installed application with id: " << app_data->ID()
170 << "to" << app_dir.MaybeAsASCII() << " successfully.";
171 *id = app_data->ID();
176 bool PackageInstaller::Update(const std::string& app_id,
177 const base::FilePath& path) {
178 if (!ApplicationData::IsIDValid(app_id)) {
179 LOG(ERROR) << "The given application id " << app_id << " is invalid.";
183 if (!base::PathExists(path)) {
184 LOG(ERROR) << "The XPK/WGT package file " << path.value() << " is invalid.";
188 if (base::DirectoryExists(path)) {
189 LOG(WARNING) << "Cannot update an unpacked XPK/WGT package.";
193 base::FilePath unpacked_dir;
194 scoped_ptr<Package> package = Package::Create(path);
196 LOG(ERROR) << "XPK/WGT file is invalid.";
200 if (app_id.compare(package->Id()) != 0) {
201 LOG(ERROR) << "The XPK/WGT file is invalid, the application id is not the"
202 << "same as the installed application has.";
206 if (!package->Extract(&unpacked_dir))
210 scoped_refptr<ApplicationData> new_app_data =
211 LoadApplication(unpacked_dir,
213 Manifest::COMMAND_LINE,
217 LOG(ERROR) << "An error occurred during application updating: " << error;
221 scoped_refptr<ApplicationData> old_app_data =
222 storage_->GetApplicationData(app_id);
224 LOG(INFO) << "Application haven't installed yet: " << app_id;
229 #if defined(OS_TIZEN)
230 // For Tizen WGT package, downgrade to a lower version or reinstall
231 // is permitted when using Tizen WRT, Crosswalk runtime need to follow
232 // this behavior on Tizen platform.
233 package->type() != Package::WGT &&
235 old_app_data->Version()->CompareTo(
236 *(new_app_data->Version())) >= 0) {
237 LOG(INFO) << "The version number of new XPK/WGT package "
238 "should be higher than "
239 << old_app_data->VersionString();
243 const base::FilePath& app_dir = old_app_data->Path();
244 const base::FilePath tmp_dir(app_dir.value()
245 + FILE_PATH_LITERAL(".tmp"));
247 if (!base::Move(app_dir, tmp_dir) ||
248 !base::Move(unpacked_dir, app_dir))
251 new_app_data = LoadApplication(app_dir,
253 Manifest::COMMAND_LINE,
257 LOG(ERROR) << "Error during loading new package: " << error;
258 base::DeleteFile(app_dir, true);
259 base::Move(tmp_dir, app_dir);
263 if (!storage_->UpdateApplication(new_app_data)) {
264 LOG(ERROR) << "Fail to update application, roll back to the old one.";
265 base::DeleteFile(app_dir, true);
266 base::Move(tmp_dir, app_dir);
270 if (!PlatformUpdate(new_app_data)) {
271 LOG(ERROR) << "Fail to update application, roll back to the old one.";
272 base::DeleteFile(app_dir, true);
273 if (!storage_->UpdateApplication(old_app_data)) {
274 LOG(ERROR) << "Fail to revert old application info, "
275 << "remove the application as a last resort.";
276 storage_->RemoveApplication(old_app_data->ID());
277 base::DeleteFile(tmp_dir, true);
280 base::Move(tmp_dir, app_dir);
284 base::DeleteFile(tmp_dir, true);
289 bool PackageInstaller::Uninstall(const std::string& id) {
291 scoped_refptr<ApplicationData> app_data = storage_->GetApplicationData(id);
293 LOG(ERROR) << "Failed to find application with id " << id
294 << " among the installed ones.";
298 if (!storage_->RemoveApplication(id)) {
299 LOG(ERROR) << "Cannot uninstall application with id " << id
300 << "; application is not installed.";
304 base::FilePath resources;
305 CHECK(PathService::Get(xwalk::DIR_DATA_PATH, &resources));
306 resources = resources.Append(kApplicationsDir).AppendASCII(id);
307 if (base::DirectoryExists(resources) &&
308 !base::DeleteFile(resources, true)) {
309 LOG(ERROR) << "Error occurred while trying to remove application with id "
310 << id << "; Cannot remove all resources.";
314 if (!PlatformUninstall(app_data))
320 } // namespace application