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.
5 #include "xwalk/application/browser/installer/tizen/package_installer.h"
10 #include <pkgmgr/pkgmgr_parser.h>
14 #include "base/file_util.h"
15 #include "base/files/file_enumerator.h"
16 #include "base/logging.h"
17 #include "base/path_service.h"
18 #include "third_party/libxml/chromium/libxml_utils.h"
19 #include "xwalk/application/browser/application_storage.h"
20 #include "xwalk/application/browser/installer/tizen/packageinfo_constants.h"
22 namespace info = xwalk::application_packageinfo_constants;
25 namespace application {
27 PackageInstaller::~PackageInstaller() {
31 scoped_ptr<PackageInstaller> PackageInstaller::Create(
32 ApplicationService* service,
33 ApplicationStorage* storage,
34 const std::string& package_id,
35 const base::FilePath& data_dir) {
36 if (!base::PathExists(data_dir))
37 return scoped_ptr<PackageInstaller>();
38 scoped_ptr<PackageInstaller> handler(
39 new PackageInstaller(service, storage, package_id, data_dir));
41 return scoped_ptr<PackageInstaller>();
42 return handler.Pass();
45 PackageInstaller::PackageInstaller(
46 ApplicationService* service,
47 ApplicationStorage* storage,
48 const std::string& package_id,
49 const base::FilePath& data_dir)
52 , package_id_(package_id)
53 , data_dir_(data_dir) {
57 bool PackageInstaller::Init() {
58 app_dir_ = data_dir_.Append(info::kAppDir).AppendASCII(package_id_);
59 xml_path_ = base::FilePath(info::kXmlDir)
60 .AppendASCII(package_id_ + std::string(info::kXmlExtension));
61 execute_path_ = app_dir_.Append(info::kExecDir).AppendASCII(package_id_);
63 application_ = storage_->GetApplicationData(package_id_);
65 LOG(ERROR) << "Application " << package_id_
66 << " haven't been installed in Xwalk database.";
69 stripped_name_ = application_->Name();
71 std::remove_if(stripped_name_.begin(), stripped_name_.end(), ::isspace),
72 stripped_name_.end());
74 if (!application_->GetManifest()->GetString(info::kIconKey, &icon_name_))
75 LOG(WARNING) << "Fail to get application icon name.";
77 icon_path_ = base::FilePath(info::kIconDir).AppendASCII(
78 package_id_ + info::kSeparator + stripped_name_ +
79 base::FilePath::FromUTF8Unsafe(icon_name_).Extension());
83 bool PackageInstaller::GeneratePkgInfoXml() {
84 base::FilePath dir_xml(xml_path_.DirName());
85 if (!base::PathExists(dir_xml) &&
86 !base::CreateDirectory(dir_xml))
89 FILE* file = base::OpenFile(xml_path_, "w");
91 xml_writer.StartWriting();
92 xml_writer.StartElement("manifest");
93 xml_writer.AddAttribute("xmlns", "http://tizen.org/ns/packages");
94 xml_writer.AddAttribute("package", package_id_);
95 xml_writer.AddAttribute("version", application_->VersionString());
96 xml_writer.WriteElement("label", application_->Name());
97 xml_writer.WriteElement("description", application_->Description());
100 xml_writer.StartElement("ui-application");
101 xml_writer.AddAttribute("appid",
102 package_id_ + info::kSeparator + stripped_name_);
103 xml_writer.AddAttribute("exec", execute_path_.MaybeAsASCII());
104 xml_writer.AddAttribute("type", "c++app");
105 xml_writer.AddAttribute("taskmanage", "true");
106 xml_writer.WriteElement("label", application_->Name());
107 if (icon_name_.empty())
108 xml_writer.WriteElement("icon", info::kDefaultIconName);
110 xml_writer.WriteElement("icon", icon_path_.BaseName().MaybeAsASCII());
111 xml_writer.EndElement(); // Ends "ui-application"
114 xml_writer.EndElement(); // Ends "manifest" element.
115 xml_writer.StopWriting();
117 file_util::WriteFile(xml_path_,
118 xml_writer.GetWrittenString().c_str(),
119 xml_writer.GetWrittenString().size());
120 base::CloseFile(file);
121 LOG(INFO) << "Converting manifest.json into "
122 << xml_path_.BaseName().MaybeAsASCII()
123 << " for installation. [DONE]";
127 bool PackageInstaller::CopyOrLinkResources() {
128 base::FilePath icon = app_dir_.AppendASCII(icon_name_);
129 if (!icon_name_.empty() && base::PathExists(icon))
130 base::CopyFile(icon, icon_path_);
132 base::FilePath xwalk_path(info::kXwalkPath);
133 base::FilePath dir_exec(execute_path_.DirName());
134 if (!base::PathExists(dir_exec))
135 base::CreateDirectory(dir_exec);
137 base::CreateSymbolicLink(xwalk_path, execute_path_);
138 LOG(INFO) << "Copying and linking files into correct locations. [DONE]";
142 bool PackageInstaller::WriteToPackageInfoDB() {
146 char pwd_buffer[1024];
149 getpwnam_r(info::kOwner, &pwd, pwd_buffer, sizeof(pwd_buffer), &res);
151 LOG(ERROR) << "Fail to get PW name";
156 if (!ChangeOwnerRecursive(data_dir_.Append(info::kAppDir), uid, gid) ||
157 !ChangeOwnerRecursive(data_dir_.Append(info::kAppDBPath), uid, gid) ||
158 !ChangeOwnerRecursive(
159 data_dir_.Append(info::kAppDBJournalPath), uid, gid))
162 if (access(xml_path_.MaybeAsASCII().c_str(), F_OK) != 0)
164 int result = pkgmgr_parser_parse_manifest_for_installation(
165 xml_path_.MaybeAsASCII().c_str(), NULL);
167 LOG(ERROR) << "Manifest parser error: " << result;
170 LOG(INFO) << "Writing package information in database. [DONE]";
174 bool PackageInstaller::Install() {
175 return GeneratePkgInfoXml() &&
176 CopyOrLinkResources() &&
177 WriteToPackageInfoDB();
180 bool PackageInstaller::Uninstall() {
182 int result = pkgmgr_parser_parse_manifest_for_uninstallation(
183 xml_path_.MaybeAsASCII().c_str(), NULL);
185 LOG(ERROR) << "Manifest parser error: " << result;
189 success &= base::DeleteFile(icon_path_, false);
190 success &= base::DeleteFile(execute_path_, false);
191 success &= base::DeleteFile(xml_path_, false);
195 LOG(INFO) << "Removing and unlinking files from installed locations. [DONE]";
199 bool PackageInstaller::ChangeOwnerRecursive(
200 const base::FilePath& path,
203 if (lchown(path.MaybeAsASCII().c_str(), uid, gid) != 0) {
204 LOG(ERROR) << "Failed to change ownership of " << path.MaybeAsASCII();
208 base::FileEnumerator file_iter(
211 base::FileEnumerator::FILES|base::FileEnumerator::DIRECTORIES);
212 base::FilePath file(file_iter.Next());
213 while (!file.empty()) {
214 if (!ChangeOwnerRecursive(file, uid, gid))
216 file = file_iter.Next();
221 } // namespace application