876074cedc6cfb1f1f4bb8524e87aae665af3b76
[platform/framework/web/crosswalk.git] / src / xwalk / application / common / installer / package_installer_tizen.cc
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.
4
5 #include "xwalk/application/common/installer/package_installer_tizen.h"
6
7 #include <sys/types.h>
8 #include <pwd.h>
9 #include <unistd.h>
10 #include <pkgmgr/pkgmgr_parser.h>
11 #include <algorithm>
12 #include <map>
13 #include <string>
14
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"
32
33 namespace info = xwalk::application_packageinfo_constants;
34
35 namespace {
36
37 namespace widget_keys = xwalk::application_widget_keys;
38
39 const base::FilePath kPkgHelper("/usr/bin/xwalk-pkg-helper");
40
41 const base::FilePath kXWalkLauncherBinary("/usr/bin/xwalk-launcher");
42
43 const base::FilePath kDefaultIcon(
44     "/usr/share/icons/default/small/crosswalk.png");
45
46 const std::string kServicePrefix("xwalk-service.");
47 const std::string kAppIdPrefix("xwalk.");
48
49 void WriteMetaDataElement(
50     XmlWriter& writer, // NOLINT
51     xwalk::application::TizenMetaDataInfo* info) {
52   if (!info)
53     return;
54
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);
61     writer.EndElement();
62   }
63 }
64
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))
71     return false;
72
73   std::string package_id =
74       xwalk::application::AppIdToPkgId(application->ID());
75
76   base::FilePath execute_path =
77       app_dir.AppendASCII("bin/").AppendASCII(application->ID());
78   std::string stripped_name = application->Name();
79
80   FILE* file = base::OpenFile(xml_path, "w");
81
82   XmlWriter xml_writer;
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());
91
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());
98
99   xwalk::application::TizenMetaDataInfo* info =
100       static_cast<xwalk::application::TizenMetaDataInfo*>(
101       application->GetManifestData(widget_keys::kTizenMetaDataKey));
102   WriteMetaDataElement(xml_writer, info);
103
104   if (icon_name.empty())
105     xml_writer.WriteElement("icon", info::kDefaultIconName);
106   else
107     xml_writer.WriteElement("icon",
108                             kServicePrefix + application->ID() + ".png");
109   xml_writer.EndElement();  // Ends "ui-application"
110
111   xml_writer.EndElement();  // Ends "manifest" element.
112   xml_writer.StopWriting();
113
114   base::WriteFile(xml_path,
115                   xml_writer.GetWrittenString().c_str(),
116                   xml_writer.GetWrittenString().size());
117
118   base::CloseFile(file);
119   LOG(INFO) << "Converting manifest.json into "
120             << xml_path.BaseName().MaybeAsASCII()
121             << " for installation. [DONE]";
122   return true;
123 }
124
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);
129
130   if (!base::CreateDirectory(execute_path.DirName())) {
131     LOG(ERROR) << "Could not create directory '"
132                << execute_path.DirName().value() << "'.";
133     return false;
134   }
135
136   if (!base::CreateSymbolicLink(kXWalkLauncherBinary, execute_path)) {
137     LOG(ERROR) << "Could not create symbolic link to launcher from '"
138                << execute_path.value() << "'.";
139     return false;
140   }
141   return true;
142 }
143
144 }  // namespace
145
146 namespace xwalk {
147 namespace application {
148
149 PackageInstallerTizen::PackageInstallerTizen(ApplicationStorage* storage)
150     : PackageInstaller(storage) {
151 }
152
153 void PackageInstallerTizen::SetQuiet(bool quiet) {
154   quiet_ = quiet;
155 }
156
157 void PackageInstallerTizen::SetInstallationKey(const std::string& key) {
158   key_ = key;
159 }
160
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);
168     if (!appid.empty())
169       return appid;
170   }
171   return id;
172 }
173
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));
178
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));
183
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";
188
189   // This will clean everything inside '<data dir>/<app id>'.
190   FileDeleter app_dir_cleaner(app_dir, true);
191
192   if (!GeneratePkgInfoXml(app_data, icon_name, app_dir, xml_path)) {
193     LOG(ERROR) << "Failed to create XML metadata file '"
194                << xml_path.value() << "'.";
195     return false;
196   }
197
198   if (!CreateAppSymbolicLink(app_dir, app_id)) {
199     LOG(ERROR) << "Failed to create symbolic link for " << app_id;
200     return false;
201   }
202
203   base::FilePath icon =
204       icon_name.empty() ? kDefaultIcon : app_dir.AppendASCII(icon_name);
205
206   CommandLine cmdline(kPkgHelper);
207   cmdline.AppendSwitchASCII("--install", app_id);
208   cmdline.AppendSwitchPath("--xml", xml_path);
209   cmdline.AppendSwitchPath("--icon", icon);
210   if (quiet_)
211     cmdline.AppendSwitch("-q");
212   if (!key_.empty()) {
213     cmdline.AppendSwitchASCII("--key", key_);
214   }
215
216   int exit_code;
217   std::string output;
218
219   if (!base::GetAppOutputWithExitCode(cmdline, &output, &exit_code)) {
220     LOG(ERROR) << "Could not launch the installation helper process.";
221     return false;
222   }
223
224   if (exit_code != 0) {
225     LOG(ERROR) << "Could not install application: "
226                << output << " (" << exit_code << ")";
227     return false;
228   }
229
230   app_dir_cleaner.Dismiss();
231
232   return true;
233 }
234
235 bool PackageInstallerTizen::PlatformUninstall(ApplicationData* app_data) {
236   bool result = true;
237   std::string app_id(app_data->ID());
238   base::FilePath data_dir;
239   CHECK(PathService::Get(xwalk::DIR_DATA_PATH, &data_dir));
240
241   CommandLine cmdline(kPkgHelper);
242   cmdline.AppendSwitchASCII("--uninstall", app_id);
243   if (quiet_)
244     cmdline.AppendSwitch("-q");
245   if (!key_.empty()) {
246     cmdline.AppendSwitchASCII("--key", key_);
247   }
248
249   int exit_code;
250   std::string output;
251
252   if (!base::GetAppOutputWithExitCode(cmdline, &output, &exit_code)) {
253     LOG(ERROR) << "Could not launch installer helper";
254     result = false;
255   }
256
257   if (exit_code != 0) {
258     LOG(ERROR) << "Could not uninstall application: "
259                << output << " (" << exit_code << ")";
260     result = false;
261   }
262
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() << "'";
267     result = false;
268   }
269
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() << "'";
274     result = false;
275   }
276
277   return result;
278 }
279
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));
284
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));
289
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";
294
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);
298
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() << "'.";
302     return false;
303   }
304
305   if (!CreateAppSymbolicLink(app_dir, app_id))
306     return false;
307
308   base::FilePath icon =
309       icon_name.empty() ? kDefaultIcon : app_dir.AppendASCII(icon_name);
310
311   CommandLine cmdline(kPkgHelper);
312   cmdline.AppendSwitchASCII("--update", app_id);
313   cmdline.AppendSwitchPath("--xml", new_xml_path);
314   cmdline.AppendSwitchPath("--icon", icon);
315   if (quiet_)
316     cmdline.AppendSwitch("-q");
317   if (!key_.empty()) {
318     cmdline.AppendSwitchASCII("--key", key_);
319   }
320
321   int exit_code;
322   std::string output;
323
324   if (!base::GetAppOutputWithExitCode(cmdline, &output, &exit_code)) {
325     LOG(ERROR) << "Could not launch installer helper";
326     return false;
327   }
328
329   if (exit_code != 0) {
330     LOG(ERROR) << "Could not update application: "
331                << output << " (" << exit_code << ")";
332     return false;
333   }
334
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();
339   return true;
340 }
341
342 }  // namespace application
343 }  // namespace xwalk