Fix to send different signal based on recovery info
[platform/core/appfw/app-installers.git] / src / common / pkgmgr_signal.cc
1 // Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
2 // Use of this source code is governed by a apache 2.0 license that can be
3 // found in the LICENSE file.
4
5 #include "common/pkgmgr_signal.h"
6
7 #include <manifest_parser/utils/logging.h>
8
9 #include <unistd.h>
10 #include <sys/types.h>
11 #include <systemd/sd-login.h>
12 #include <tzplatform_config.h>
13
14 #include <cassert>
15 #include <map>
16 #include <vector>
17
18 #include "common/pkgmgr_query.h"
19
20 namespace {
21
22 namespace ci = common_installer;
23
24 const uid_t kGlobalUserUid = tzplatform_getuid(TZ_SYS_GLOBALAPP_USER);
25 const std::map<ci::RequestType, const char*> kEventStr = {
26   {ci::RequestType::Install, PKGMGR_INSTALLER_INSTALL_EVENT_STR},
27   {ci::RequestType::Recovery, PKGMGR_INSTALLER_INSTALL_EVENT_STR},
28   {ci::RequestType::Reinstall, PKGMGR_INSTALLER_UPGRADE_EVENT_STR},
29   {ci::RequestType::Uninstall, PKGMGR_INSTALLER_UNINSTALL_EVENT_STR},
30   {ci::RequestType::PartialUninstall, PKGMGR_INSTALLER_UNINSTALL_EVENT_STR},
31   {ci::RequestType::Update, PKGMGR_INSTALLER_UPGRADE_EVENT_STR},
32   {ci::RequestType::ReadonlyUpdateInstall, PKGMGR_INSTALLER_UPGRADE_EVENT_STR},
33   {ci::RequestType::ReadonlyUpdateUninstall,
34       PKGMGR_INSTALLER_UPGRADE_EVENT_STR},
35   {ci::RequestType::Delta, PKGMGR_INSTALLER_UPGRADE_EVENT_STR},
36   {ci::RequestType::Move, PKGMGR_INSTALLER_MOVE_EVENT_STR},
37   {ci::RequestType::MountInstall, PKGMGR_INSTALLER_INSTALL_EVENT_STR},
38   {ci::RequestType::MountUpdate, PKGMGR_INSTALLER_UPGRADE_EVENT_STR},
39   {ci::RequestType::ManifestDirectInstall, PKGMGR_INSTALLER_INSTALL_EVENT_STR},
40   {ci::RequestType::ManifestDirectUpdate, PKGMGR_INSTALLER_UPGRADE_EVENT_STR},
41   {ci::RequestType::ManifestPartialInstall, PKGMGR_INSTALLER_INSTALL_EVENT_STR},
42   {ci::RequestType::ManifestPartialUpdate, PKGMGR_INSTALLER_UPGRADE_EVENT_STR},
43   {ci::RequestType::DisablePkg, PKGMGR_INSTALLER_UNINSTALL_EVENT_STR},
44   {ci::RequestType::EnablePkg, PKGMGR_INSTALLER_INSTALL_EVENT_STR},
45   {ci::RequestType::MigrateExtImg, PKGMGR_INSTALLER_UPGRADE_EVENT_STR},
46   {ci::RequestType::Unknown, PKGMGR_INSTALLER_UNKNOWN_EVENT_STR}
47 };
48
49 }  // namespace
50
51 namespace common_installer {
52
53 PkgmgrSignal::State PkgmgrSignal::state_ = PkgmgrSignal::State::NOT_SENT;
54
55 PkgmgrSignal::PkgmgrSignal(pkgmgr_installer* pi, RequestType req_type)
56     : pi_(pi), request_type_(req_type), error_message_sent_(false) {
57   uid_ = pkgmgr_installer_get_uid(pi_);
58   request_mode_ = GetRequestMode(uid_);
59 }
60
61 bool PkgmgrSignal::SendStarted(
62     const std::string& type, const std::string& pkgid,
63     const RecoveryInfo& recovery_info) {
64   if (state_ != State::NOT_SENT) {
65     return false;
66   }
67
68   if (!SetupUserList(pkgid))
69     LOG(WARNING) << "Failed to setup user list";
70
71   auto key = kEventStr.find(request_type_);
72   if (key == kEventStr.end()) {
73     return false;
74   }
75   const char* value;
76   if (request_type_ == ci::RequestType::Recovery) {
77     value = GetRecoverySignalValue(recovery_info.recovery_file->type());
78     if (!value)
79       return false;
80   }
81   else {
82     value = key->second;
83   }
84   if (!SendSignal(PKGMGR_INSTALLER_START_KEY_STR, value, type, pkgid)) {
85     return false;
86   }
87   for (auto l : user_list_) {
88     key = kEventStr.find(l.second);
89     if (key == kEventStr.end())
90       continue;
91     SendSignal(l.first, PKGMGR_INSTALLER_START_KEY_STR, value, type,
92         pkgid);
93   }
94
95   state_ = State::STARTED;
96
97   // workaround for pkgmgr client to know all appids which are uninstalled
98   if (request_type_ == ci::RequestType::Uninstall) {
99     if (!SendAppids(type, pkgid))
100       return false;
101     for (auto l : user_list_)
102       SendAppids(l.first, type, pkgid);
103   }
104
105   return true;
106 }
107
108 const char* PkgmgrSignal::GetRecoverySignalValue(RequestType recovery_type) {
109   switch (recovery_type) {
110   case RequestType::Install:
111   case RequestType::Uninstall:
112   case RequestType::MountInstall:
113     return PKGMGR_INSTALLER_UNINSTALL_EVENT_STR;
114   case RequestType::Update:
115   case RequestType::Reinstall:
116   case RequestType::Delta:
117   case RequestType::MountUpdate:
118   case RequestType::ReadonlyUpdateInstall:
119     return PKGMGR_INSTALLER_UPGRADE_EVENT_STR;
120   default:
121     LOG(ERROR) << "Unsupported request type for recovery";
122     return nullptr;
123   }
124 }
125
126 bool PkgmgrSignal::SendProgress(int progress,
127     const std::string& type, const std::string& pkgid) {
128   if (state_ != State::STARTED) {
129     return false;
130   }
131
132   if (!SendSignal(PKGMGR_INSTALLER_INSTALL_PERCENT_KEY_STR,
133       std::to_string(progress).c_str(), type, pkgid))
134     return false;
135   for (auto l : user_list_)
136     // ignore error case
137     SendSignal(l.first, PKGMGR_INSTALLER_INSTALL_PERCENT_KEY_STR,
138         std::to_string(progress).c_str(), type, pkgid);
139
140   return true;
141 }
142
143 bool PkgmgrSignal::SendFinished(
144     Step::Status result, const std::string& type, const std::string& pkgid) {
145   if (state_ != State::STARTED) {
146     return false;
147   }
148   if (result != Step::Status::OK && !error_message_sent_) {
149     if (!SendSignal(
150         PKGMGR_INSTALLER_ERROR_KEY_STR,
151         std::to_string(static_cast<int>(result)).c_str(), type, pkgid)) {
152       return false;
153     }
154     for (auto l : user_list_)
155       SendSignal(l.first,
156           PKGMGR_INSTALLER_ERROR_KEY_STR,
157           std::to_string(static_cast<int>(result)).c_str(), type, pkgid);
158   }
159   if (!SendSignal(
160       PKGMGR_INSTALLER_END_KEY_STR, GetResultKey(result), type, pkgid)) {
161     return false;
162   }
163   for (auto l : user_list_)
164     SendSignal(l.first,
165         PKGMGR_INSTALLER_END_KEY_STR, GetResultKey(result), type, pkgid);
166   state_ = State::FINISHED;
167   return true;
168 }
169
170 bool PkgmgrSignal::SendError(
171     Step::Status result,
172     const std::string& error_message,
173     const std::string& type,
174     const std::string& pkgid) {
175   if (state_ != State::STARTED) {
176     return false;
177   }
178   std::string error_value = std::to_string(static_cast<int>(result));
179   if (!error_message.empty()) {
180     error_value = error_value + ":" + error_message;
181   }
182   LOG(ERROR) << "PkgmgrSignal error_value: (" << error_value << ")";
183   error_message_sent_ = true;
184   if (!SendSignal(
185       PKGMGR_INSTALLER_ERROR_KEY_STR,
186       error_value.c_str(),
187       type,
188       pkgid))
189     return false;
190   for (auto l : user_list_)
191     SendSignal(l.first,
192         PKGMGR_INSTALLER_ERROR_KEY_STR,
193         error_value.c_str(),
194         type,
195         pkgid);
196   return true;
197 }
198
199 bool PkgmgrSignal::SendSignal(
200     const char* key,
201     const char* value,
202     const std::string& type,
203     const std::string& pkgid) const {
204   // send pkgmgr signal
205   if (pkgmgr_installer_send_signal(
206         pi_,
207         !type.empty() ?  type.c_str(): "",
208         !pkgid.empty() ? pkgid.c_str() : "",
209         key,
210         value)) {
211     LOG(ERROR) << "Fail to send pkgmgr signal";
212     return false;
213   }
214
215   LOG(DEBUG) << "Success to send pkgmgr signal"
216              << " PKGID=" << pkgid
217              << " KEY=" << key
218              << " VALUE=" << value;
219   return true;
220 }
221
222 bool PkgmgrSignal::SendSignal(
223     uid_t uid,
224     const char* key,
225     const char* value,
226     const std::string& type,
227     const std::string& pkgid) const {
228   // send pkgmgr signal
229   if (pkgmgr_installer_send_signal_for_uid(
230         pi_,
231         uid,
232         !type.empty() ?  type.c_str(): "",
233         !pkgid.empty() ? pkgid.c_str() : "",
234         key,
235         value)) {
236     LOG(ERROR) << "Fail to send pkgmgr signal";
237     return false;
238   }
239
240   LOG(DEBUG) << "Success to send pkgmgr signal"
241              << " USER=" << uid
242              << " PKGID=" << pkgid
243              << " KEY=" << key
244              << " VALUE=" << value;
245   return true;
246 }
247
248 const char* PkgmgrSignal::GetResultKey(Step::Status result) const {
249   switch (result) {
250     case Step::Status::OK:
251       return PKGMGR_INSTALLER_OK_EVENT_STR;
252     default:
253       return PKGMGR_INSTALLER_FAIL_EVENT_STR;
254   }
255 }
256
257 bool PkgmgrSignal::SendAppids(const std::string& type,
258                               const std::string& pkgid) const {
259   std::vector<std::string> appids;
260   ci::PkgQueryInterface pkg_query(pkgid, pkgmgr_installer_get_uid(pi_));
261   if (!pkg_query.AppidsForPkgId(&appids))
262     return true;
263   for (auto& appid : appids) {
264     if (pkgmgr_installer_send_app_uninstall_signal(pi_, type.c_str(),
265                                                     pkgid.c_str(),
266                                                     appid.c_str()))
267       return false;
268   }
269   return true;
270 }
271
272 bool PkgmgrSignal::SendAppids(uid_t uid,
273                               const std::string& type,
274                               const std::string& pkgid) const {
275   std::vector<std::string> appids;
276   ci::PkgQueryInterface pkg_query(pkgid, pkgmgr_installer_get_uid(pi_));
277   if (!pkg_query.AppidsForPkgId(&appids))
278     return true;
279   for (auto& appid : appids) {
280     if (pkgmgr_installer_send_app_uninstall_signal_for_uid(
281         pi_, uid, type.c_str(), pkgid.c_str(), appid.c_str()))
282       return false;
283   }
284   return true;
285 }
286
287 bool PkgmgrSignal::SetupUserList(const std::string& pkgid) {
288   int i;
289   uid_t* uids = nullptr;
290   int n = sd_get_uids(&uids);
291
292   if (n < 0)
293     return false;
294   ci::PkgQueryInterface pkg_query_for_global(pkgid, kGlobalUserUid);
295   for (i = 0; i < n; i++) {
296     ci::PkgQueryInterface pkg_query(pkgid, uids[i]);
297     switch (request_mode_) {
298       case RequestMode::GLOBAL:
299         // if user pkg is installed, installer will not send signal to user.
300         if (pkg_query.IsPackageInstalled(ci::RequestMode::USER))
301           continue;
302         else
303           user_list_.emplace_back(uids[i], request_type_);
304         break;
305       case RequestMode::USER:
306         if (uid_ != uids[i])
307           continue;
308         // if global pkg is installed,
309         // user pkg operation will be handled as update.
310         if (pkg_query_for_global.IsPackageInstalled(ci::RequestMode::GLOBAL))
311           user_list_.emplace_back(uids[i], RequestType::Update);
312         else
313           user_list_.emplace_back(uids[i], request_type_);
314         break;
315       default:
316         user_list_.emplace_back(uids[i], request_type_);
317         break;
318     }
319   }
320
321   if (uids)
322     free(uids);
323
324   return true;
325 }
326
327 }  // namespace common_installer