Remove boost dependency
[platform/core/appfw/app-installers.git] / src / common / plugins / plugin_manager.cc
1 // Copyright (c) 2016 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/plugins/plugin_manager.h"
6
7 #include <pkgmgr-info.h>
8
9 #include <algorithm>
10 #include <string>
11 #include <utility>
12 #include <vector>
13
14 #include "common/plugins/plugin_factory.h"
15 #include "common/plugins/plugin_list_parser.h"
16 #include "common/plugins/plugin_xml_parser.h"
17 #include "common/plugins/category_plugin.h"
18 #include "common/plugins/metadata_plugin.h"
19 #include "common/plugins/tag_plugin.h"
20 #include "common/utils/glist_range.h"
21
22 namespace {
23
24 bool IsSubKey(const std::string& subkey, const std::string& key) {
25   if (subkey.find(key) != 0)
26     return false;
27   if (subkey.size() != key.size() && subkey.at(key.size()) != '/')
28     return false;
29   return true;
30 }
31
32 bool AddPluginInfo(std::shared_ptr<common_installer::PluginInfo> plugin_info,
33                    manifest_x* manifest) {
34   plugin_x *plugin = static_cast<plugin_x*>(calloc(1, sizeof(plugin_x)));
35   if (!plugin) {
36     LOG(ERROR) << "out of memory";
37     return false;
38   }
39   plugin->pkgid = strdup(manifest->package);
40   plugin->plugin_type = strdup(plugin_info->type().c_str());
41   plugin->plugin_name = strdup(plugin_info->name().c_str());
42   if (!plugin->pkgid || !plugin->plugin_type || !plugin->plugin_name) {
43     LOG(ERROR) << "out of memory";
44     free(plugin->pkgid);
45     free(plugin->plugin_type);
46     free(plugin->plugin_name);
47     free(plugin);
48     return false;
49   }
50
51   manifest->plugin = g_list_append(manifest->plugin, plugin);
52   return true;
53 }
54
55 }  // namespace
56
57 namespace common_installer {
58
59 bool PluginManager::IsDataRemoved(const char* data_type,
60                                   const std::string& data) {
61   PkgQueryInterface pkg_query(pkgid_, uid_);
62   return pkg_query.IsPluginExecuted(data_type, data);
63 }
64
65 bool PluginManager::GenerateUnknownTagList(
66     std::vector<std::string>* xml_tags) {
67   if (!xml_parser_.Parse()) {
68     LOG(ERROR) << "Parse xml function error";
69     return false;
70   }
71
72   *xml_tags = xml_parser_.tags_list();
73   return true;
74 }
75
76 bool PluginManager::GeneratePluginInfoList(
77     PluginManager::PluginInfoList* plugin_info_list) {
78   if (!list_parser_.Parse()) {
79     LOG(ERROR) << "Parse list function error";
80     return false;
81   }
82
83   *plugin_info_list = list_parser_.PluginInfoList();
84   return true;
85 }
86
87 bool PluginManager::LoadPlugins(Plugin::ActionType action_type) {
88   std::vector<std::string> xml_tags;
89   if (!GenerateUnknownTagList(&xml_tags))
90     return false;
91
92   PluginInfoList plugin_info_list;
93   if (!GeneratePluginInfoList(&plugin_info_list))
94     return false;
95
96   PluginFactory factory;
97
98   std::sort(xml_tags.begin(), xml_tags.end());
99
100   // This loop loads plugin which are needed according to manifest file
101   // Different pkgmgr plugin types have different condition upon which they
102   // are being loaded
103   LOG(DEBUG) << "Loading pkgmgr plugins...";
104   for (std::shared_ptr<PluginInfo> plugin_info : plugin_info_list) {
105     std::unique_ptr<Plugin> plugin;
106     if (plugin_info->type() == TagPlugin::kType) {
107       // load tag plugin only if tag exists in manifest file
108       auto iter = std::lower_bound(xml_tags.begin(), xml_tags.end(),
109                                      plugin_info->name());
110       if (iter != xml_tags.end() && *iter == plugin_info->name()) {
111         plugin = factory.CreatePluginByPluginInfo(*plugin_info);
112         if (!plugin) {
113           LOG(WARNING) << "Failed to load plugin: " << plugin_info->path()
114                      << " Plugin has been skipped.";
115         } else {
116           if (!AddPluginInfo(plugin_info, manifest_))
117             return false;
118         }
119       } else if (action_type == Plugin::ActionType::Upgrade) {
120         if (IsDataRemoved(TagPlugin::kType, plugin_info->name())) {
121           plugin = factory.CreatePluginByPluginInfo(*plugin_info,
122               Plugin::ActionType::Removed);
123           if (!plugin)
124             LOG(WARNING) << "Failed to load plugin: " << plugin_info->path()
125                          << " Plugin has been skipped.";
126         }
127       }
128     } else if (plugin_info->type() == MetadataPlugin::kType) {
129       bool done = false;
130       for (application_x* app : GListRange<application_x*>(
131            manifest_->application)) {
132         for (metadata_x* meta : GListRange<metadata_x*>(app->metadata)) {
133           if (IsSubKey(meta->key, plugin_info->name())) {
134             plugin = factory.CreatePluginByPluginInfo(*plugin_info);
135             if (!plugin)
136               LOG(WARNING) << "Failed to load plugin: "
137                            << plugin_info->path()
138                            << " Plugin has been skipped.";
139             done = true;
140             break;
141           }
142         }
143         if (done)
144           break;
145       }
146       /* metadata of package, since Tizen 7.5 */
147       for (metadata_x* meta : GListRange<metadata_x*>(manifest_->metadata)) {
148         if (IsSubKey(meta->key, plugin_info->name())) {
149           plugin = factory.CreatePluginByPluginInfo(*plugin_info);
150           if (!plugin)
151             LOG(WARNING) << "Failed to load plugin: "
152                          << plugin_info->path()
153                          << " Plugin has been skipped.";
154           break;
155         }
156       }
157       if (!done && action_type == Plugin::ActionType::Upgrade &&
158           IsDataRemoved(MetadataPlugin::kType, plugin_info->name())) {
159         plugin = factory.CreatePluginByPluginInfo(*plugin_info,
160             Plugin::ActionType::Removed);
161         if (!plugin)
162           LOG(WARNING) << "Failed to load plugin: "
163                        << plugin_info->path()
164                        << " Plugin has been skipped.";
165       }
166     } else if (plugin_info->type() == CategoryPlugin::kType) {
167       bool done = false;
168       for (application_x* app : GListRange<application_x*>(
169            manifest_->application)) {
170         for (const char* category : GListRange<char*>(app->category)) {
171           if (std::string(category).compare(plugin_info->name()) == 0) {
172             plugin = factory.CreatePluginByPluginInfo(*plugin_info);
173             if (!plugin) {
174               LOG(WARNING) << "Failed to load plugin: "
175                            << plugin_info->path()
176                            << " Plugin has been skipped.";
177             }
178             done = true;
179             break;
180           }
181         }
182         if (done)
183           break;
184       }
185       if (!done && action_type == Plugin::ActionType::Upgrade &&
186           IsDataRemoved(CategoryPlugin::kType, plugin_info->name())) {
187         plugin = factory.CreatePluginByPluginInfo(*plugin_info,
188             Plugin::ActionType::Removed);
189         if (!plugin)
190           LOG(WARNING) << "Failed to load plugin: "
191                        << plugin_info->path()
192                        << " Plugin has been skipped.";
193       }
194     }
195
196     if (plugin) {
197       loaded_plugins_.push_back(std::move(plugin));
198       LOG(DEBUG) << "Loaded plugin: " << plugin_info->path();
199     }
200   }
201   return true;
202 }
203
204 bool PluginManager::RunPlugins(Plugin::ActionType action_type) {
205   LOG(DEBUG) << "Running pkgmgr plugins...";
206   for (auto& plugin : loaded_plugins_) {
207     auto& plugin_info = plugin->plugin_info();
208     LOG(INFO) << "Running plugin: " << plugin_info.path();
209     bool success = plugin->Run(xml_parser_.doc_ptr(), manifest_, action_type);
210     if (!success) {
211       bool vitalness = plugin_info.vitalness();
212       if (vitalness) {
213         LOG(ERROR) << plugin_info.path() << " fails";
214         return false;
215       } else {
216         LOG(ERROR) << plugin_info.path()
217                    << " fails but installation is ongoing";
218       }
219     }
220   }
221   return true;
222 }
223
224 }  // namespace common_installer