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_tizen.h"
10 #include <pkgmgr/pkgmgr_parser.h>
15 #include "base/file_util.h"
16 #include "base/files/file_enumerator.h"
17 #include "base/logging.h"
18 #include "base/memory/ref_counted.h"
19 #include "base/path_service.h"
20 #include "base/command_line.h"
21 #include "base/process/launch.h"
22 #include "third_party/libxml/chromium/libxml_utils.h"
23 #include "xwalk/application/common/application_data.h"
24 #include "xwalk/application/common/application_file_util.h"
25 #include "xwalk/application/common/application_manifest_constants.h"
26 #include "xwalk/application/common/manifest_handlers/tizen_application_handler.h"
27 #include "xwalk/application/common/manifest_handlers/tizen_metadata_handler.h"
28 #include "xwalk/application/common/application_storage.h"
29 #include "xwalk/application/common/installer/tizen/packageinfo_constants.h"
30 #include "xwalk/application/common/id_util.h"
31 #include "xwalk/runtime/common/xwalk_paths.h"
33 namespace info = xwalk::application_packageinfo_constants;
37 namespace widget_keys = xwalk::application_widget_keys;
39 const base::FilePath kPkgHelper("/usr/bin/xwalk-pkg-helper");
41 const base::FilePath kXWalkLauncherBinary("/usr/bin/xwalk-launcher");
43 const base::FilePath kDefaultIcon(
44 "/usr/share/icons/default/small/crosswalk.png");
46 const std::string kServicePrefix("xwalk-service.");
47 const std::string kAppIdPrefix("xwalk.");
49 void WriteMetaDataElement(
50 XmlWriter& writer, // NOLINT
51 xwalk::application::TizenMetaDataInfo* info) {
55 const std::map<std::string, std::string>& metadata = info->metadata();
56 std::map<std::string, std::string>::const_iterator it;
57 for (it = metadata.begin(); it != metadata.end(); ++it) {
58 writer.StartElement("metadata");
59 writer.AddAttribute("key", it->first);
60 writer.AddAttribute("value", it->second);
65 bool GeneratePkgInfoXml(xwalk::application::ApplicationData* application,
66 const std::string& icon_name,
67 const base::FilePath& app_dir,
68 const base::FilePath& xml_path) {
69 if (!base::PathExists(app_dir) &&
70 !base::CreateDirectory(app_dir))
73 std::string package_id =
74 xwalk::application::AppIdToPkgId(application->ID());
76 base::FilePath execute_path =
77 app_dir.AppendASCII("bin/").AppendASCII(application->ID());
78 std::string stripped_name = application->Name();
80 FILE* file = base::OpenFile(xml_path, "w");
83 xml_writer.StartWriting();
84 xml_writer.StartElement("manifest");
85 xml_writer.AddAttribute("xmlns", "http://tizen.org/ns/packages");
86 xml_writer.AddAttribute("package", package_id);
87 xml_writer.AddAttribute("type", "wgt");
88 xml_writer.AddAttribute("version", application->VersionString());
89 xml_writer.WriteElement("label", application->Name());
90 xml_writer.WriteElement("description", application->Description());
92 xml_writer.StartElement("ui-application");
93 xml_writer.AddAttribute("appid", application->ID());
94 xml_writer.AddAttribute("exec", execute_path.MaybeAsASCII());
95 xml_writer.AddAttribute("type", "webapp");
96 xml_writer.AddAttribute("taskmanage", "true");
97 xml_writer.WriteElement("label", application->Name());
99 xwalk::application::TizenMetaDataInfo* info =
100 static_cast<xwalk::application::TizenMetaDataInfo*>(
101 application->GetManifestData(widget_keys::kTizenMetaDataKey));
102 WriteMetaDataElement(xml_writer, info);
104 if (icon_name.empty())
105 xml_writer.WriteElement("icon", info::kDefaultIconName);
107 xml_writer.WriteElement("icon",
108 kServicePrefix + application->ID() + ".png");
109 xml_writer.EndElement(); // Ends "ui-application"
111 xml_writer.EndElement(); // Ends "manifest" element.
112 xml_writer.StopWriting();
114 base::WriteFile(xml_path,
115 xml_writer.GetWrittenString().c_str(),
116 xml_writer.GetWrittenString().size());
118 base::CloseFile(file);
119 LOG(INFO) << "Converting manifest.json into "
120 << xml_path.BaseName().MaybeAsASCII()
121 << " for installation. [DONE]";
125 bool CreateAppSymbolicLink(const base::FilePath& app_dir,
126 const std::string& app_id) {
127 base::FilePath execute_path =
128 app_dir.AppendASCII("bin/").AppendASCII(app_id);
130 if (!base::CreateDirectory(execute_path.DirName())) {
131 LOG(ERROR) << "Could not create directory '"
132 << execute_path.DirName().value() << "'.";
136 if (!base::CreateSymbolicLink(kXWalkLauncherBinary, execute_path)) {
137 LOG(ERROR) << "Could not create symbolic link to launcher from '"
138 << execute_path.value() << "'.";
147 namespace application {
149 PackageInstallerTizen::PackageInstallerTizen(ApplicationStorage* storage)
150 : PackageInstaller(storage) {
153 void PackageInstallerTizen::SetQuiet(bool quiet) {
157 void PackageInstallerTizen::SetInstallationKey(const std::string& key) {
161 std::string PackageInstallerTizen::PrepareUninstallationID(
162 const std::string& id) {
163 // this function fix pkg_id to app_id
164 // if installer was launched with pkg_id
165 if (IsValidPkgID(id)) {
166 LOG(INFO) << "The package id is given " << id << " Will find app_id...";
167 std::string appid = PkgIdToAppId(id);
174 bool PackageInstallerTizen::PlatformInstall(ApplicationData* app_data) {
175 std::string app_id(app_data->ID());
176 base::FilePath data_dir;
177 CHECK(PathService::Get(xwalk::DIR_DATA_PATH, &data_dir));
179 base::FilePath app_dir =
180 data_dir.AppendASCII(info::kAppDir).AppendASCII(app_id);
181 base::FilePath xml_path = data_dir.AppendASCII(info::kAppDir).AppendASCII(
182 app_id + std::string(info::kXmlExtension));
184 std::string icon_name;
185 if (!app_data->GetManifest()->GetString(
186 GetIcon128Key(app_data->GetPackageType()), &icon_name))
187 LOG(WARNING) << "'icon' not included in manifest";
189 // This will clean everything inside '<data dir>/<app id>'.
190 FileDeleter app_dir_cleaner(app_dir, true);
192 if (!GeneratePkgInfoXml(app_data, icon_name, app_dir, xml_path)) {
193 LOG(ERROR) << "Failed to create XML metadata file '"
194 << xml_path.value() << "'.";
198 if (!CreateAppSymbolicLink(app_dir, app_id)) {
199 LOG(ERROR) << "Failed to create symbolic link for " << app_id;
203 base::FilePath icon =
204 icon_name.empty() ? kDefaultIcon : app_dir.AppendASCII(icon_name);
206 CommandLine cmdline(kPkgHelper);
207 cmdline.AppendSwitchASCII("--install", app_id);
208 cmdline.AppendSwitchPath("--xml", xml_path);
209 cmdline.AppendSwitchPath("--icon", icon);
211 cmdline.AppendSwitch("-q");
213 cmdline.AppendSwitchASCII("--key", key_);
219 if (!base::GetAppOutputWithExitCode(cmdline, &output, &exit_code)) {
220 LOG(ERROR) << "Could not launch the installation helper process.";
224 if (exit_code != 0) {
225 LOG(ERROR) << "Could not install application: "
226 << output << " (" << exit_code << ")";
230 app_dir_cleaner.Dismiss();
235 bool PackageInstallerTizen::PlatformUninstall(ApplicationData* app_data) {
237 std::string app_id(app_data->ID());
238 base::FilePath data_dir;
239 CHECK(PathService::Get(xwalk::DIR_DATA_PATH, &data_dir));
241 CommandLine cmdline(kPkgHelper);
242 cmdline.AppendSwitchASCII("--uninstall", app_id);
244 cmdline.AppendSwitch("-q");
246 cmdline.AppendSwitchASCII("--key", key_);
252 if (!base::GetAppOutputWithExitCode(cmdline, &output, &exit_code)) {
253 LOG(ERROR) << "Could not launch installer helper";
257 if (exit_code != 0) {
258 LOG(ERROR) << "Could not uninstall application: "
259 << output << " (" << exit_code << ")";
263 base::FilePath app_dir =
264 data_dir.AppendASCII(info::kAppDir).AppendASCII(app_id);
265 if (!base::DeleteFile(app_dir, true)) {
266 LOG(ERROR) << "Could not remove directory '" << app_dir.value() << "'";
270 base::FilePath xml_path = data_dir.AppendASCII(
271 app_id + std::string(info::kXmlExtension));
272 if (!base::DeleteFile(xml_path, false)) {
273 LOG(ERROR) << "Could not remove file '" << xml_path.value() << "'";
280 bool PackageInstallerTizen::PlatformUpdate(ApplicationData* app_data) {
281 std::string app_id(app_data->ID());
282 base::FilePath data_dir;
283 CHECK(PathService::Get(xwalk::DIR_DATA_PATH, &data_dir));
285 base::FilePath app_dir =
286 data_dir.AppendASCII(info::kAppDir).AppendASCII(app_id);
287 base::FilePath new_xml_path = data_dir.AppendASCII(info::kAppDir).AppendASCII(
288 app_id + ".new" + std::string(info::kXmlExtension));
290 std::string icon_name;
291 if (!app_data->GetManifest()->GetString(
292 GetIcon128Key(app_data->GetPackageType()), &icon_name))
293 LOG(WARNING) << "'icon' not included in manifest";
295 // This will clean everything inside '<data dir>/<app id>' and the new XML.
296 FileDeleter app_dir_cleaner(app_dir, true);
297 FileDeleter new_xml_cleaner(new_xml_path, true);
299 if (!GeneratePkgInfoXml(app_data, icon_name, app_dir, new_xml_path)) {
300 LOG(ERROR) << "Could not create new XML metadata file '"
301 << new_xml_path.value() << "'.";
305 if (!CreateAppSymbolicLink(app_dir, app_id))
308 base::FilePath icon =
309 icon_name.empty() ? kDefaultIcon : app_dir.AppendASCII(icon_name);
311 CommandLine cmdline(kPkgHelper);
312 cmdline.AppendSwitchASCII("--update", app_id);
313 cmdline.AppendSwitchPath("--xml", new_xml_path);
314 cmdline.AppendSwitchPath("--icon", icon);
316 cmdline.AppendSwitch("-q");
318 cmdline.AppendSwitchASCII("--key", key_);
324 if (!base::GetAppOutputWithExitCode(cmdline, &output, &exit_code)) {
325 LOG(ERROR) << "Could not launch installer helper";
329 if (exit_code != 0) {
330 LOG(ERROR) << "Could not update application: "
331 << output << " (" << exit_code << ")";
335 base::FilePath old_xml_path = data_dir.AppendASCII(info::kAppDir).AppendASCII(
336 app_id + std::string(info::kXmlExtension));
337 base::Move(new_xml_path, old_xml_path);
338 app_dir_cleaner.Dismiss();
342 } // namespace application