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.
5 #include "common/dependency_checker.h"
7 #include <pkgmgr-info.h>
9 #include <manifest_parser/utils/logging.h>
10 #include <manifest_parser/utils/version_number.h>
11 #include <tpk_manifest_handlers/application_manifest_constants.h>
12 #include <tpk_manifest_handlers/dependencies_handler.h>
13 #include <tpk_manifest_handlers/package_handler.h>
14 #include <tpk_manifest_handlers/tpk_config_parser.h>
23 #include "common/archive_info.h"
24 #include "common/utils/pkgmgr_query.h"
26 namespace fs = std::filesystem;
27 using Dependency = std::tuple<std::string, std::string, std::string>;
31 const char kRequiredDependencyType[] = "requires";
35 namespace common_installer {
37 static std::string InvalidDependencyError(const std::string& from,
38 const std::string& to, const std::string& required_version) {
39 return "Dependency [" + from + "] -> [" + to
40 + (required_version.empty() ? "" : "(>=" + required_version + ")")
44 bool DependencyChecker::AddInstaller(InstallerPtr installer) {
45 RequestType req_type = pkgmgr_->GetRequestType(installer->GetIndex());
47 case RequestType::Install:
48 case RequestType::Update:
49 case RequestType::ReadonlyUpdateInstall:
50 case RequestType::MountInstall:
51 case RequestType::MountUpdate:
52 case RequestType::Delta:
53 return GetDepInfoFromArchive(std::move(installer));
54 case RequestType::Uninstall:
55 return GetDepInfoFromDB(std::move(installer));
56 case RequestType::ReadonlyUpdateUninstall:
57 return GetDepInfoFromXML(std::move(installer));
64 std::list<InstallerPtr> DependencyChecker::GetSortedAppInstallers() {
65 std::list<InstallerPtr> result;
66 if (!CheckMeetDependency())
68 if (!TopologicalSort(&result))
74 const std::string& DependencyChecker::GetErrorMessage() const {
78 bool DependencyChecker::CheckMeetDependency() {
79 if (!CheckInstallPkg())
81 if (!CheckUninstallPkg())
87 bool DependencyChecker::CheckRequires(const std::string& pkgid) {
88 for (const auto& dep_info : dep_graph_[pkgid]) {
89 std::string require_pkgid = dep_info.first;
90 std::string require_version = dep_info.second;
91 std::string actual_pkg_version;
92 if (install_pkgs_.count(require_pkgid)) {
93 actual_pkg_version = install_pkgs_[require_pkgid];
95 PkgQueryInterface pkg_query(require_pkgid, pkgmgr_->GetUid());
96 if (!pkg_query.IsValid()) {
97 error_ = InvalidDependencyError(pkgid, require_pkgid, require_version);
100 actual_pkg_version = pkg_query.Version();
103 if (utils::VersionNumber(actual_pkg_version).Compare(
104 utils::VersionNumber(require_version)) < 0) {
105 error_ = InvalidDependencyError(pkgid, require_pkgid, require_version);
112 bool DependencyChecker::CheckRequiredBy(const std::string& pkgid,
113 const std::string& pkg_version) {
114 PkgQueryInterface pkg_query(pkgid, pkgmgr_->GetUid());
115 if (!pkg_query.IsValid())
118 std::vector<DependencyInfo> dep_info;
119 if (!pkg_query.PackagesDependsOn(&dep_info)) {
120 error_ = "Failed to get depends on information of package";
123 for (const auto& info : dep_info) {
124 std::string from = std::get<0>(info);
125 std::string to = std::get<1>(info);
126 std::string type = std::get<2>(info);
127 std::string dependent_version = std::get<3>(info);
129 if (to != pkgid || type != kRequiredDependencyType
130 || dependent_version.empty() || install_pkgs_.count(from))
133 if (utils::VersionNumber(pkg_version).Compare(
134 utils::VersionNumber(dependent_version)) < 0) {
135 error_ = InvalidDependencyError(from, to, dependent_version);
142 bool DependencyChecker::CheckInstallPkg() {
143 for (const auto& install_pkg : install_pkgs_) {
144 std::string pkgid = install_pkg.first;
145 std::string pkg_version = install_pkg.second;
146 if (!CheckRequires(pkgid))
148 if (!CheckRequiredBy(pkgid, pkg_version))
154 bool DependencyChecker::CheckUninstallPkg() {
155 for (const auto& pkgid : uninstall_pkgs_) {
156 PkgQueryInterface pkg_query(pkgid, pkgmgr_->GetUid());
157 std::vector<DependencyInfo> dep_info;
158 if (!pkg_query.PackagesDependsOn(&dep_info)) {
159 error_ = "Failed to get depends on information of package";
162 for (const auto& info : dep_info) {
163 std::string from = std::get<0>(info);
164 std::string to = std::get<1>(info);
165 std::string type = std::get<2>(info);
166 std::string dependent_version = std::get<3>(info);
168 if (to != pkgid || type != kRequiredDependencyType)
170 if (uninstall_pkgs_.count(from) == 0) {
171 error_ = InvalidDependencyError(from, to, dependent_version);
179 bool DependencyChecker::DFS(const std::string& node,
180 std::list<InstallerPtr>* result) {
181 if (visited_.count(node)) {
182 if (finished_.count(node)) {
185 error_ = "Graph has circular dependency";
189 visited_.emplace(node);
191 for (const auto& next_node : dep_graph_[node]) {
192 std::string pkgid = next_node.first;
193 if (!DFS(pkgid, result))
197 if (installers_.count(node))
198 result->emplace_back(std::move(installers_[node]));
200 finished_.emplace(node);
204 bool DependencyChecker::GetDepInfoFromArchive(InstallerPtr installer) {
205 std::unique_ptr<ArchiveInfo> archive_info = installer->GetArchiveInfo();
206 if (archive_info == nullptr) {
207 error_ = "Get archive info fail";
210 if (!archive_info->LoadArchiveInfo()) {
211 error_ = "Load archive info fail";
214 std::string pkgid = archive_info->pkgid();
215 std::string version = archive_info->version();
216 std::vector<Dependency> dependencies = archive_info->dependencies();
218 for (const Dependency& dep : dependencies) {
219 std::string dep_pkg = std::get<0>(dep);
220 std::string type = std::get<1>(dep);
221 std::string required_version = std::get<2>(dep);
223 if (type != kRequiredDependencyType)
226 dep_graph_[pkgid].emplace(dep_pkg, required_version);
229 install_pkgs_[pkgid] = version;
230 installers_.emplace(pkgid, std::move(installer));
231 request_pkgid_.emplace_back(pkgid);
236 bool DependencyChecker::GetDepInfoFromDB(InstallerPtr installer) {
237 std::string pkgid = pkgmgr_->GetRequestInfo(installer->GetIndex());
238 PkgQueryInterface pkg_query(pkgid, pkgmgr_->GetUid());
239 if (!pkg_query.IsValid()) {
240 error_ = "Package is not installed";
243 std::vector<DependencyInfo> dep_info;
244 if (!pkg_query.PackagesDependsOn(&dep_info)) {
245 error_ = "Failed to get depends on information of package";
249 for (const auto& info : dep_info) {
250 std::string from = std::get<0>(info);
251 std::string to = std::get<1>(info);
252 std::string type = std::get<2>(info);
253 std::string version = std::get<3>(info);
255 if (type != kRequiredDependencyType)
258 dep_graph_[from].emplace(to, version);
261 uninstall_pkgs_.emplace(pkgid);
262 installers_.emplace(pkgid, std::move(installer));
263 request_pkgid_.emplace_back(pkgid);
268 bool DependencyChecker::GetDepInfoFromXML(InstallerPtr installer) {
269 std::string pkgid = pkgmgr_->GetRequestInfo(installer->GetIndex());
270 PkgQueryInterface pkg_query(pkgid, pkgmgr_->GetUid());
273 fs::path(getUserManifestPath(pkgmgr_->GetUid(), true)) /
274 fs::path(pkgid + ".xml");
276 if (!fs::exists(xml_path)) {
277 error_ = "xml path is not exist";
281 tpk::parse::TPKConfigParser parser;
282 if (!parser.ParseManifest(xml_path)) {
283 error_ = "parse fail";
286 std::shared_ptr<const tpk::parse::PackageInfo> pkg_info =
287 std::static_pointer_cast<const tpk::parse::PackageInfo>(
288 parser.GetManifestData(tpk::application_keys::kManifestKey));
290 error_ = "Package info manifest data has not been found.";
293 install_pkgs_[pkgid] = pkg_info->version();
294 installers_.emplace(pkgid, std::move(installer));
295 request_pkgid_.emplace_back(pkgid);
297 std::shared_ptr<const tpk::parse::DependenciesInfo> dependencies_info =
298 std::static_pointer_cast<const tpk::parse::DependenciesInfo>(
299 parser.GetManifestData(tpk::application_keys::kDependenciesKey));
300 if (!dependencies_info)
303 for (const auto& dependency : dependencies_info->dependencies()) {
304 if (dependency.type() != kRequiredDependencyType)
307 dep_graph_[pkgid].emplace(dependency.pkgid(),
308 dependency.required_version());
314 bool DependencyChecker::TopologicalSort(std::list<InstallerPtr>* result) {
315 for (auto it = request_pkgid_.rbegin(); it != request_pkgid_.rend(); ++it) {
316 if (!DFS(*it, result))
323 } // namespace common_installer