8f28e78989fb618fcd623395538c536815be9cd5
[platform/core/appfw/app-installers.git] / src / common / dependency_checker.cc
1 // Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
2 // Use of this source code is governed by an apache-2.0 license that can be
3 // found in the LICENSE file.
4
5 #include "common/dependency_checker.h"
6
7 #include <boost/filesystem/path.hpp>
8
9 #include <pkgmgr-info.h>
10
11 #include <manifest_parser/utils/logging.h>
12 #include <manifest_parser/utils/version_number.h>
13 #include <tpk_manifest_handlers/application_manifest_constants.h>
14 #include <tpk_manifest_handlers/dependencies_handler.h>
15 #include <tpk_manifest_handlers/package_handler.h>
16 #include <tpk_manifest_handlers/tpk_config_parser.h>
17
18 #include <map>
19 #include <memory>
20 #include <tuple>
21 #include <utility>
22 #include <vector>
23
24 #include "common/archive_info.h"
25 #include "common/utils/pkgmgr_query.h"
26
27 namespace bf = boost::filesystem;
28
29 using Dependency = std::tuple<std::string, std::string, std::string>;
30
31 namespace {
32
33 const char kRequiredDependencyType[] = "requires";
34
35 }  // namespace
36
37 namespace common_installer {
38
39 static std::string InvalidDependencyError(const std::string& from,
40     const std::string& to, const std::string& required_version) {
41   return "Dependency [" + from + "] -> [" + to
42       + (required_version.empty() ? "" : "(>=" + required_version + ")")
43       + "] is not met";
44 }
45
46 bool DependencyChecker::AddInstaller(InstallerPtr installer) {
47   RequestType req_type = pkgmgr_->GetRequestType(installer->GetIndex());
48   switch (req_type) {
49     case RequestType::Install:
50     case RequestType::Update:
51     case RequestType::ReadonlyUpdateInstall:
52     case RequestType::MountInstall:
53     case RequestType::MountUpdate:
54     case RequestType::Delta:
55       return GetDepInfoFromArchive(std::move(installer));
56     case RequestType::Uninstall:
57       return GetDepInfoFromDB(std::move(installer));
58     case RequestType::ReadonlyUpdateUninstall:
59       return GetDepInfoFromXML(std::move(installer));
60     default:
61       return false;
62   }
63   return true;
64 }
65
66 std::list<InstallerPtr> DependencyChecker::GetSortedAppInstallers() {
67   std::list<InstallerPtr> result;
68   if (!CheckMeetDependency())
69     return {};
70   if (!TopologicalSort(&result))
71     return {};
72
73   return result;
74 }
75
76 const std::string& DependencyChecker::GetErrorMessage() const {
77   return error_;
78 }
79
80 bool DependencyChecker::CheckMeetDependency() {
81   if (!CheckInstallPkg())
82     return false;
83   if (!CheckUninstallPkg())
84     return false;
85
86   return true;
87 }
88
89 bool DependencyChecker::CheckRequires(const std::string& pkgid) {
90   for (const auto& dep_info : dep_graph_[pkgid]) {
91     std::string require_pkgid = dep_info.first;
92     std::string require_version = dep_info.second;
93     std::string actual_pkg_version;
94     if (install_pkgs_.count(require_pkgid)) {
95       actual_pkg_version = install_pkgs_[require_pkgid];
96     } else {
97       PkgQueryInterface pkg_query(require_pkgid, pkgmgr_->GetUid());
98       if (!pkg_query.IsValid()) {
99         error_ = InvalidDependencyError(pkgid, require_pkgid, require_version);
100         return false;
101       }
102       actual_pkg_version = pkg_query.Version();
103     }
104
105     if (utils::VersionNumber(actual_pkg_version).Compare(
106         utils::VersionNumber(require_version)) < 0) {
107       error_ = InvalidDependencyError(pkgid, require_pkgid, require_version);
108       return false;
109     }
110   }
111   return true;
112 }
113
114 bool DependencyChecker::CheckRequiredBy(const std::string& pkgid,
115     const std::string& pkg_version) {
116   PkgQueryInterface pkg_query(pkgid, pkgmgr_->GetUid());
117   if (!pkg_query.IsValid())
118     return true;
119
120   std::vector<DependencyInfo> dep_info;
121   if (!pkg_query.PackagesDependsOn(&dep_info)) {
122     error_ = "Failed to get depends on information of package";
123     return false;
124   }
125   for (const auto& info : dep_info) {
126     std::string from = std::get<0>(info);
127     std::string to = std::get<1>(info);
128     std::string type = std::get<2>(info);
129     std::string dependent_version = std::get<3>(info);
130
131     if (to != pkgid || type != kRequiredDependencyType
132         || dependent_version.empty() || install_pkgs_.count(from))
133       continue;
134
135     if (utils::VersionNumber(pkg_version).Compare(
136         utils::VersionNumber(dependent_version)) < 0) {
137       error_ = InvalidDependencyError(from, to, dependent_version);
138       return false;
139     }
140   }
141   return true;
142 }
143
144 bool DependencyChecker::CheckInstallPkg() {
145   for (const auto& install_pkg : install_pkgs_) {
146     std::string pkgid = install_pkg.first;
147     std::string pkg_version = install_pkg.second;
148     if (!CheckRequires(pkgid))
149       return false;
150     if (!CheckRequiredBy(pkgid, pkg_version))
151       return false;
152   }
153   return true;
154 }
155
156 bool DependencyChecker::CheckUninstallPkg() {
157   for (const auto& pkgid : uninstall_pkgs_) {
158     PkgQueryInterface pkg_query(pkgid, pkgmgr_->GetUid());
159     std::vector<DependencyInfo> dep_info;
160     if (!pkg_query.PackagesDependsOn(&dep_info)) {
161       error_ = "Failed to get depends on information of package";
162       return false;
163     }
164     for (const auto& info : dep_info) {
165       std::string from = std::get<0>(info);
166       std::string to = std::get<1>(info);
167       std::string type = std::get<2>(info);
168       std::string dependent_version = std::get<3>(info);
169
170       if (to != pkgid || type != kRequiredDependencyType)
171         continue;
172       if (uninstall_pkgs_.count(from) == 0) {
173         error_ = InvalidDependencyError(from, to, dependent_version);
174         return false;
175       }
176     }
177   }
178   return true;
179 }
180
181 bool DependencyChecker::DFS(const std::string& node,
182                             std::list<InstallerPtr>* result) {
183   if (visited_.count(node)) {
184     if (finished_.count(node)) {
185       return true;
186     } else {
187       error_ = "Graph has circular dependency";
188       return false;
189     }
190   }
191   visited_.emplace(node);
192
193   for (const auto& next_node : dep_graph_[node]) {
194     std::string pkgid = next_node.first;
195     if (!DFS(pkgid, result))
196       return false;
197   }
198
199   if (installers_.count(node))
200     result->emplace_back(std::move(installers_[node]));
201
202   finished_.emplace(node);
203   return true;
204 }
205
206 bool DependencyChecker::GetDepInfoFromArchive(InstallerPtr installer) {
207   std::unique_ptr<ArchiveInfo> archive_info = installer->GetArchiveInfo();
208   if (archive_info == nullptr) {
209     error_ = "Get archive info fail";
210     return false;
211   }
212   if (!archive_info->LoadArchiveInfo()) {
213     error_ = "Load archive info fail";
214     return false;
215   }
216   std::string pkgid = archive_info->pkgid();
217   std::string version = archive_info->version();
218   std::vector<Dependency> dependencies = archive_info->dependencies();
219
220   for (const Dependency& dep : dependencies) {
221     std::string dep_pkg = std::get<0>(dep);
222     std::string type = std::get<1>(dep);
223     std::string required_version = std::get<2>(dep);
224
225     if (type != kRequiredDependencyType)
226       continue;
227
228     dep_graph_[pkgid].emplace(dep_pkg, required_version);
229   }
230
231   install_pkgs_[pkgid] = version;
232   installers_.emplace(pkgid, std::move(installer));
233   request_pkgid_.emplace_back(pkgid);
234
235   return true;
236 }
237
238 bool DependencyChecker::GetDepInfoFromDB(InstallerPtr installer) {
239   std::string pkgid = pkgmgr_->GetRequestInfo(installer->GetIndex());
240   PkgQueryInterface pkg_query(pkgid, pkgmgr_->GetUid());
241   if (!pkg_query.IsValid()) {
242     error_ = "Package is not installed";
243     return false;
244   }
245   std::vector<DependencyInfo> dep_info;
246   if (!pkg_query.PackagesDependsOn(&dep_info)) {
247     error_ = "Failed to get depends on information of package";
248     return false;
249   }
250
251   for (const auto& info : dep_info) {
252     std::string from = std::get<0>(info);
253     std::string to = std::get<1>(info);
254     std::string type = std::get<2>(info);
255     std::string version = std::get<3>(info);
256
257     if (type != kRequiredDependencyType)
258       continue;
259
260     dep_graph_[from].emplace(to, version);
261   }
262
263   uninstall_pkgs_.emplace(pkgid);
264   installers_.emplace(pkgid, std::move(installer));
265   request_pkgid_.emplace_back(pkgid);
266
267   return true;
268 }
269
270 bool DependencyChecker::GetDepInfoFromXML(InstallerPtr installer) {
271   std::string pkgid = pkgmgr_->GetRequestInfo(installer->GetIndex());
272   PkgQueryInterface pkg_query(pkgid, pkgmgr_->GetUid());
273
274   bf::path xml_path =
275       bf::path(getUserManifestPath(pkgmgr_->GetUid(), true)) /
276       bf::path(pkgid + ".xml");
277
278   if (!bf::exists(xml_path)) {
279     error_ = "xml path is not exist";
280     return false;
281   }
282
283   tpk::parse::TPKConfigParser parser;
284   if (!parser.ParseManifest(xml_path)) {
285     error_ = "parse fail";
286     return false;
287   }
288   std::shared_ptr<const tpk::parse::PackageInfo> pkg_info =
289       std::static_pointer_cast<const tpk::parse::PackageInfo>(
290           parser.GetManifestData(tpk::application_keys::kManifestKey));
291   if (!pkg_info) {
292     error_ = "Package info manifest data has not been found.";
293     return false;
294   }
295   install_pkgs_[pkgid] = pkg_info->version();
296   installers_.emplace(pkgid, std::move(installer));
297   request_pkgid_.emplace_back(pkgid);
298
299   std::shared_ptr<const tpk::parse::DependenciesInfo> dependencies_info =
300       std::static_pointer_cast<const tpk::parse::DependenciesInfo>(
301           parser.GetManifestData(tpk::application_keys::kDependenciesKey));
302   if (!dependencies_info)
303     return true;
304
305   for (const auto& dependency : dependencies_info->dependencies()) {
306     if (dependency.type() != kRequiredDependencyType)
307       continue;
308
309     dep_graph_[pkgid].emplace(dependency.pkgid(),
310         dependency.required_version());
311   }
312
313   return true;
314 }
315
316 bool DependencyChecker::TopologicalSort(std::list<InstallerPtr>* result) {
317   for (auto it = request_pkgid_.rbegin(); it != request_pkgid_.rend(); ++it) {
318     if (!DFS(*it, result))
319       return false;
320   }
321   result->reverse();
322   return true;
323 }
324
325 }  // namespace common_installer