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