Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / xwalk / application / tools / tizen / xwalk_platform_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/tools/tizen/xwalk_platform_installer.h"
6
7 #include <assert.h>
8 #include <pkgmgr_installer.h>
9 #include <pkgmgr/pkgmgr_parser.h>
10
11 // logging and dlog uses same macro name
12 // to avoid warnings we need to undefine dlog's one
13 #undef LOG
14
15 #include <tzplatform_config.h>
16
17 #include <string>
18
19 #include "base/files/file_path.h"
20 #include "base/files/file_util.h"
21 #include "base/logging.h"
22 #include "xwalk/application/common/id_util.h"
23
24 namespace {
25
26 typedef int (*PkgParser)(const char*, char* const*);
27
28 const base::FilePath kXWalkLauncherBinary("/usr/bin/xwalk-launcher");
29 const char kIconDir[] = "/default/small/";
30 const std::string kServicePrefix("xwalk-service.");
31 const std::string kXmlFileExt(".xml");
32 const std::string kPngFileExt(".png");
33
34 // Package type sent in every signal.
35 const char PKGMGR_PKG_TYPE[] = "wgt";
36
37 // Notification about operation start.
38 const char PKGMGR_START_KEY[] = "start";
39
40 // Value for new installation.
41 const char PKGMGR_START_INSTALL[] = "install";
42
43 // Value for uninstallation.
44 const char PKGMGR_START_UNINSTALL[] = "uninstall";
45
46 // Value for update.
47 const char PKGMGR_START_UPDATE[] = "update";
48
49 // Value for update.
50 const char PKGMGR_START_REINSTALL[] = "reinstall";
51
52 // Notification about end of installation with status.
53 const char PKGMGR_END_KEY[] = "end";
54
55 // Success value of end of installation.
56 const char PKGMGR_END_SUCCESS[] = "ok";
57
58 // Failure value of end of installation.
59 const char PKGMGR_END_FAILURE[] = "fail";
60
61 // Tags for pkgmgr describing package
62 const char* pkgmgr_tags[] = {"removable=true", NULL, };
63
64 const std::string kAppIdPrefix("xwalk.");
65
66 class FileDeleter {
67  public:
68   FileDeleter(const base::FilePath& path, bool recursive)
69       : path_(path),
70         recursive_(recursive) {}
71
72   ~FileDeleter() {
73     if (path_.empty())
74       return;
75
76     base::DeleteFile(path_, recursive_);
77   }
78
79   void Dismiss() {
80     path_.clear();
81   }
82
83  private:
84   base::FilePath path_;
85   bool recursive_;
86 };
87
88 const char* ToEndStatus(bool result) {
89   return result ? PKGMGR_END_SUCCESS : PKGMGR_END_FAILURE;
90 }
91
92 inline base::FilePath GetDestFilePath(const base::FilePath& DirPath,
93                                       const std::string& appid,
94                                       const std::string& file_ext) {
95   return DirPath.Append(kServicePrefix + std::string(appid) + file_ext);
96 }
97
98 bool CopyFileToDst(const base::FilePath& file_src,
99                    const base::FilePath& file_dst) {
100   base::FilePath dir = file_dst.DirName();
101   if (!base::PathExists(dir))
102     base::CreateDirectory(dir);
103   if (!base::CopyFile(file_src, file_dst)) {
104     LOG(ERROR) << "Couldn't copy application file from "
105                << file_src.value() << " to " << file_dst.value();
106     return false;
107   }
108   return true;
109 }
110
111 }  // namespace
112
113 PlatformInstaller::PlatformInstaller()
114     : handle_(NULL) {
115 }
116
117 PlatformInstaller::PlatformInstaller(const std::string& appid)
118     : handle_(NULL),
119       appid_(appid),
120       pkgid_(xwalk::application::AppIdToPkgId(appid)) {
121   if (appid_.empty())
122     LOG(ERROR) << "Invalid app id is provided for pkg installer";
123 }
124
125 PlatformInstaller::~PlatformInstaller() {
126   if (handle_)
127     pkgmgr_installer_free(handle_);
128 }
129
130 bool PlatformInstaller::InitializePkgmgrSignal(int argc,
131     const char** argv) {
132   handle_ = pkgmgr_installer_new();
133   if (!handle_) {
134     LOG(ERROR) << "Fail to get package manager installer handle";
135     return false;
136   }
137
138   LOG(INFO) << "Initializing pkgmgr request...";
139   return pkgmgr_installer_receive_request(handle_,
140                                           argc,
141                                           const_cast<char**>(argv));
142 }
143
144 bool PlatformInstaller::InstallApplication(const base::FilePath& xmlpath,
145     const base::FilePath& iconpath) {
146   SendSignal(PKGMGR_START_KEY, PKGMGR_START_INSTALL);
147   bool ret = InstallApplicationInternal(xmlpath, iconpath);
148   SendSignal(PKGMGR_END_KEY, ToEndStatus(ret));
149   return ret;
150 }
151
152 bool PlatformInstaller::UninstallApplication() {
153   SendSignal(PKGMGR_START_KEY, PKGMGR_START_UNINSTALL);
154   bool ret = UninstallApplicationInternal();
155   SendSignal(PKGMGR_END_KEY, ToEndStatus(ret));
156   return ret;
157 }
158
159 bool PlatformInstaller::UpdateApplication(const base::FilePath& xmlpath,
160     const base::FilePath& iconpath) {
161   SendSignal(PKGMGR_START_KEY, PKGMGR_START_UPDATE);
162   bool ret = UpdateApplicationInternal(xmlpath, iconpath);
163   SendSignal(PKGMGR_END_KEY, ToEndStatus(ret));
164   return ret;
165 }
166
167 bool PlatformInstaller::ReinstallApplication(const std::string& pkgid) {
168   SendSignal(PKGMGR_START_KEY, PKGMGR_START_REINSTALL);
169   bool ret = ReinstallApplicationInternal(pkgid);
170   SendSignal(PKGMGR_END_KEY, ToEndStatus(ret));
171   return ret;
172 }
173
174 bool PlatformInstaller::InstallApplicationInternal(
175     const base::FilePath& xmlpath,
176     const base::FilePath& iconpath) {
177   if (xmlpath.empty() || iconpath.empty()) {
178     LOG(ERROR) << "Invalid xml path or icon path for installation";
179   }
180   base::FilePath global_xml(tzplatform_mkpath(TZ_SYS_RO_PACKAGES, "/"));
181   base::FilePath global_icon(tzplatform_mkpath(TZ_SYS_RO_ICONS, kIconDir));
182   base::FilePath user_xml(tzplatform_mkpath(TZ_USER_PACKAGES, "/"));
183   base::FilePath user_icon(tzplatform_mkpath(TZ_USER_ICONS, "/"));
184
185   base::FilePath xml(user_xml);
186   base::FilePath icon(user_icon);
187
188   uid_t uid = getuid();
189   if (uid == GLOBAL_USER) {
190     xml = global_xml;
191     icon = global_icon;
192   }
193   // FIXME(vcgomes): Add support for more icon types
194   base::FilePath xml_dst = GetDestFilePath(xml, appid_, kXmlFileExt);
195   base::FilePath icon_dst = GetDestFilePath(icon, appid_, kPngFileExt);
196   FileDeleter xml_cleaner(xml_dst, false);
197   FileDeleter icon_cleaner(icon_dst, false);
198
199   if (!CopyFileToDst(xmlpath, xml_dst)
200      || !CopyFileToDst(iconpath, icon_dst))
201     return false;
202
203   LOG(INFO) << "UID of installation : " << uid;
204   if (uid != GLOBAL_USER) {  // For only the user that request installation
205     if (pkgmgr_parser_parse_usr_manifest_for_installation(
206         xmlpath.value().c_str(), uid, const_cast<char**>(pkgmgr_tags))) {
207       LOG(ERROR) << "Couldn't parse manifest XML '"
208                  << xmlpath.value().c_str() << "', uid : " << uid;
209       return false;
210     }
211   } else {  // For all users
212     if (pkgmgr_parser_parse_manifest_for_installation(
213         xmlpath.value().c_str(), const_cast<char**>(pkgmgr_tags))) {
214       LOG(ERROR) << "Couldn't parse manifest XML '"
215                  << xmlpath.value().c_str() << "' for global installation";
216       return false;
217     }
218   }
219   xml_cleaner.Dismiss();
220   icon_cleaner.Dismiss();
221
222   return true;
223 }
224
225 bool PlatformInstaller::UninstallApplicationInternal() {
226   base::FilePath global_xml(tzplatform_mkpath(TZ_SYS_RO_PACKAGES, "/"));
227   base::FilePath global_icon(tzplatform_mkpath(TZ_SYS_RO_ICONS, kIconDir));
228   base::FilePath user_xml(tzplatform_mkpath(TZ_USER_PACKAGES, "/"));
229   base::FilePath user_icon(tzplatform_mkpath(TZ_USER_ICONS, "/"));
230
231   base::FilePath xml(user_xml);
232   base::FilePath icon(user_icon);
233
234   uid_t uid = getuid();
235   if (uid == GLOBAL_USER) {
236     xml = global_xml;
237     icon = global_icon;
238   }
239   // FIXME(vcgomes): Add support for more icon types
240   base::FilePath iconpath = GetDestFilePath(icon, appid_, kPngFileExt);
241   base::FilePath xmlpath = GetDestFilePath(xml, appid_, kXmlFileExt);
242   FileDeleter icon_cleaner(iconpath, false);
243   FileDeleter xml_cleaner(xmlpath, false);
244
245   std::string xmlpath_str = xmlpath.MaybeAsASCII();
246   assert(!xmlpath_str.empty());
247
248   if (uid != GLOBAL_USER) {  // For only the user that request installation
249     if (pkgmgr_parser_parse_usr_manifest_for_uninstallation(xmlpath_str.c_str(),
250         uid, NULL)) {
251       LOG(ERROR) << "Couldn't parse manifest XML '" << xmlpath_str << "', uid"
252                  << uid;
253       icon_cleaner.Dismiss();
254       xml_cleaner.Dismiss();
255     }
256   } else {  // For all users
257     if (pkgmgr_parser_parse_manifest_for_uninstallation(xmlpath_str.c_str(),
258         NULL)) {
259       LOG(ERROR) << "Couldn't parse manifest XML '" << xmlpath_str
260                  << "' for global uninstallation";
261       icon_cleaner.Dismiss();
262       xml_cleaner.Dismiss();
263     }
264   }
265   return true;
266 }
267
268 bool PlatformInstaller::UpdateApplicationInternal(
269     const base::FilePath& xmlpath, const base::FilePath& iconpath) {
270   if (xmlpath.empty() || iconpath.empty()) {
271     LOG(ERROR) << "Invalid xml path or icon path for update";
272   }
273   base::FilePath global_xml(tzplatform_mkpath(TZ_SYS_RO_PACKAGES, "/"));
274   base::FilePath global_icon(tzplatform_mkpath(TZ_SYS_RO_ICONS, kIconDir));
275   base::FilePath user_xml(tzplatform_mkpath(TZ_USER_PACKAGES, "/"));
276   base::FilePath user_icon(tzplatform_mkpath(TZ_USER_ICONS, "/"));
277
278   base::FilePath xml(user_xml);
279   base::FilePath icon(user_icon);
280
281   uid_t uid = getuid();
282   if (uid == GLOBAL_USER) {
283     xml = global_xml;
284     icon = global_icon;
285   }
286   // FIXME(vcgomes): Add support for more icon types
287   base::FilePath xml_dst = GetDestFilePath(xml, appid_, kXmlFileExt);
288   base::FilePath icon_dst = GetDestFilePath(icon, appid_, kPngFileExt);
289   FileDeleter xml_cleaner(xml_dst, false);
290   FileDeleter icon_cleaner(icon_dst, false);
291
292   if (!CopyFileToDst(xmlpath, xml_dst) || !CopyFileToDst(iconpath, icon_dst))
293     return false;
294
295   if (uid != GLOBAL_USER) {  // For only the user that request installation
296     if (pkgmgr_parser_parse_usr_manifest_for_upgrade(xmlpath.value().c_str(),
297         uid, const_cast<char**>(pkgmgr_tags))) {
298       LOG(ERROR) << "Couldn't parse manifest XML '" << xmlpath.value()
299                  << "', uid: " << uid;
300       return false;
301     }
302   } else {  // For all users
303     if (pkgmgr_parser_parse_manifest_for_upgrade(xmlpath.value().c_str(),
304         const_cast<char**>(pkgmgr_tags))) {
305       LOG(ERROR) << "Couldn't parse manifest XML '"
306                  << xmlpath.value() << "' for global update installation";
307       return false;
308      }
309   }
310   xml_cleaner.Dismiss();
311   icon_cleaner.Dismiss();
312
313   return true;
314 }
315
316 bool PlatformInstaller::ReinstallApplicationInternal(const std::string& pkgid) {
317   if (pkgid.empty()) {
318     LOG(ERROR) << "Invalid package ID for reinstallation!";
319     return false;
320   }
321   return true;
322 }
323
324 bool PlatformInstaller::SendSignal(const std::string& key,
325                                    const std::string& value) {
326   if (!handle_) {
327     // this is installation with xwalkctl not pkgmgr
328     return true;
329   }
330
331   if (key.empty() || value.empty()) {
332     LOG(ERROR) << "Fail to send signal, key/value is empty";
333     return false;
334   }
335
336   if (pkgmgr_installer_send_signal(handle_, PKGMGR_PKG_TYPE, pkgid_.c_str(),
337       key.c_str(), value.c_str())) {
338     LOG(ERROR) << "Fail to send package manager signal";
339   }
340   return true;
341 }