735bb67aebf6ee1728d369313d03238ef42ba1f1
[platform/framework/web/crosswalk.git] / src / xwalk / application / browser / installer / tizen / service_package_installer.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/browser/installer/tizen/service_package_installer.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 #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 "base/command_line.h"
19 #include "base/process/launch.h"
20 #include "third_party/libxml/chromium/libxml_utils.h"
21 #include "xwalk/application/common/application_data.h"
22 #include "xwalk/application/common/application_manifest_constants.h"
23 #include "xwalk/application/common/manifest_handlers/tizen_metadata_handler.h"
24 #include "xwalk/application/browser/application_storage.h"
25 #include "xwalk/application/browser/installer/tizen/packageinfo_constants.h"
26
27 namespace info = xwalk::application_packageinfo_constants;
28
29 namespace {
30
31 namespace widget_keys = xwalk::application_widget_keys;
32
33 const base::FilePath kPkgHelper("/usr/bin/xwalk-pkg-helper");
34
35 const base::FilePath kXWalkLauncherBinary("/usr/bin/xwalk-launcher");
36
37 const base::FilePath kDefaultIcon(
38     "/usr/share/icons/default/small/crosswalk.png");
39
40 const std::string kServicePrefix("xwalk-service.");
41 const std::string kAppIdPrefix("xwalk.");
42
43 class FileDeleter {
44  public:
45   FileDeleter(const base::FilePath& path, bool recursive)
46       : path_(path),
47         recursive_(recursive) {}
48
49   ~FileDeleter() {
50     if (path_.empty())
51       return;
52
53     base::DeleteFile(path_, recursive_);
54   }
55
56   void Dismiss() {
57     path_.clear();
58   }
59
60  private:
61   base::FilePath path_;
62   bool recursive_;
63 };
64
65 void WriteMetaDataElement(
66     XmlWriter& writer,
67     xwalk::application::TizenMetaDataInfo* info) {
68   if (!info)
69     return;
70
71   const std::map<std::string, std::string>& metadata = info->metadata();
72   std::map<std::string, std::string>::const_iterator it;
73   for (it = metadata.begin(); it != metadata.end(); ++it) {
74     writer.StartElement("metadata");
75     writer.AddAttribute("key", it->first);
76     writer.AddAttribute("value", it->second);
77     writer.EndElement();
78   }
79 }
80
81 bool GeneratePkgInfoXml(xwalk::application::ApplicationData* application,
82                         const std::string& icon_name,
83                         const base::FilePath& app_dir,
84                         const base::FilePath& xml_path) {
85   if (!base::PathExists(app_dir) &&
86       !base::CreateDirectory(app_dir))
87     return false;
88
89   std::string package_id = application->ID();
90   std::string tizen_app_id = kAppIdPrefix + package_id;
91   base::FilePath execute_path =
92       app_dir.AppendASCII("bin/").AppendASCII(tizen_app_id);
93   std::string stripped_name = application->Name();
94
95   FILE* file = base::OpenFile(xml_path, "w");
96
97   XmlWriter xml_writer;
98   xml_writer.StartWriting();
99   xml_writer.StartElement("manifest");
100   xml_writer.AddAttribute("xmlns", "http://tizen.org/ns/packages");
101   xml_writer.AddAttribute("package", package_id);
102   xml_writer.AddAttribute("version", application->VersionString());
103   xml_writer.WriteElement("label", application->Name());
104   xml_writer.WriteElement("description", application->Description());
105
106   xml_writer.StartElement("ui-application");
107   xml_writer.AddAttribute("appid", tizen_app_id);
108   xml_writer.AddAttribute("exec", execute_path.MaybeAsASCII());
109   xml_writer.AddAttribute("type", "c++app");
110   xml_writer.AddAttribute("taskmanage", "true");
111   xml_writer.WriteElement("label", application->Name());
112
113   xwalk::application::TizenMetaDataInfo* info =
114       static_cast<xwalk::application::TizenMetaDataInfo*>(
115       application->GetManifestData(widget_keys::kTizenMetaDataKey));
116   WriteMetaDataElement(xml_writer, info);
117
118   if (icon_name.empty())
119     xml_writer.WriteElement("icon", info::kDefaultIconName);
120   else
121     xml_writer.WriteElement("icon", kServicePrefix + package_id + ".png");
122   xml_writer.EndElement();  // Ends "ui-application"
123
124   xml_writer.EndElement();  // Ends "manifest" element.
125   xml_writer.StopWriting();
126
127   base::WriteFile(xml_path,
128                   xml_writer.GetWrittenString().c_str(),
129                   xml_writer.GetWrittenString().size());
130
131   base::CloseFile(file);
132   LOG(INFO) << "Converting manifest.json into "
133             << xml_path.BaseName().MaybeAsASCII()
134             << " for installation. [DONE]";
135   return true;
136 }
137
138 }  // namespace
139
140 namespace xwalk {
141 namespace application {
142
143 bool InstallApplicationForTizen(
144     ApplicationData* application, const base::FilePath& data_dir) {
145   std::string package_id = application->ID();
146   std::string tizen_app_id = kAppIdPrefix + package_id;
147   base::FilePath app_dir =
148       data_dir.AppendASCII(info::kAppDir).AppendASCII(package_id);
149   base::FilePath xml_path = data_dir.AppendASCII(info::kAppDir).AppendASCII(
150       package_id + std::string(info::kXmlExtension));
151
152   std::string icon_name;
153   if (!application->GetManifest()->GetString(info::kIconKey, &icon_name)) {
154     LOG(WARNING) << "'icon' not included in manifest";
155   }
156   // This will clean everything inside '<data dir>/<app id>'.
157   FileDeleter app_dir_cleaner(app_dir, true);
158
159   if (!GeneratePkgInfoXml(application, icon_name, app_dir, xml_path)) {
160     LOG(ERROR) << "Could not create XML metadata file '"
161                << xml_path.value() << "'.";
162     return false;
163   }
164
165   base::FilePath execute_path =
166       app_dir.AppendASCII("bin/").AppendASCII(tizen_app_id);
167
168   if (!base::CreateDirectory(execute_path.DirName())) {
169     LOG(ERROR) << "Could not create directory '"
170                << execute_path.DirName().value() << "'.";
171     return false;
172   }
173
174   if (!base::CreateSymbolicLink(kXWalkLauncherBinary, execute_path)) {
175     LOG(ERROR) << "Could not create symbolic link to launcher from '"
176                << execute_path.value() << "'.";
177     return false;
178   }
179
180   base::FilePath icon;
181   if (icon_name.empty())
182     icon = kDefaultIcon;
183   else
184     icon = app_dir.AppendASCII(icon_name);
185
186   CommandLine cmdline(kPkgHelper);
187   cmdline.AppendSwitch("--install");
188   cmdline.AppendArg(package_id);
189   cmdline.AppendArgPath(xml_path);
190   cmdline.AppendArgPath(icon);
191
192   int exit_code;
193   std::string output;
194
195   if (!base::GetAppOutputWithExitCode(cmdline, &output, &exit_code)) {
196     LOG(ERROR) << "Could not launch installer helper.";
197     return false;
198   }
199
200   if (exit_code != 0) {
201     LOG(ERROR) << "Could not install application: "
202                << output << " (" << exit_code << ")";
203     return false;
204   }
205
206   app_dir_cleaner.Dismiss();
207
208   return true;
209 }
210
211 bool UninstallApplicationForTizen(ApplicationData* application,
212                                   const base::FilePath& data_dir) {
213   std::string package_id = application->ID();
214   bool result = true;
215
216   CommandLine cmdline(kPkgHelper);
217   cmdline.AppendSwitch("--uninstall");
218   cmdline.AppendArg(package_id);
219
220   int exit_code;
221   std::string output;
222
223   if (!base::GetAppOutputWithExitCode(cmdline, &output, &exit_code)) {
224     LOG(ERROR) << "Could not launch installer helper";
225     result = false;
226   }
227
228   if (exit_code != 0) {
229     LOG(ERROR) << "Could not uninstall application: "
230                << output << " (" << exit_code << ")";
231     result = false;
232   }
233
234   base::FilePath app_dir =
235       data_dir.AppendASCII(info::kAppDir).AppendASCII(package_id);
236   if (!base::DeleteFile(app_dir, true)) {
237     LOG(ERROR) << "Could not remove directory '" << app_dir.value() << "'";
238     result = false;
239   }
240
241   base::FilePath xml_path = data_dir.AppendASCII(
242       package_id + std::string(info::kXmlExtension));
243   if (!base::DeleteFile(xml_path, false)) {
244     LOG(ERROR) << "Could not remove file '" << xml_path.value() << "'";
245     result = false;
246   }
247
248   return result;
249 }
250
251 }  // namespace application
252 }  // namespace xwalk