4de70fec0bc59a611f811e4534598b8df15c3358
[platform/core/appfw/app-installers.git] / src / common / plugins / metadata_plugin.cc
1 // Copyright (c) 2015 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/plugins/metadata_plugin.h"
6
7 #include <pkgmgr-info.h>
8 #include <pkgmgr_parser.h>
9
10 #include <algorithm>
11 #include <map>
12 #include <vector>
13
14 #include "common/utils/glist_range.h"
15
16 namespace {
17
18 std::string GetMetadataTag(const std::string& url) {
19   return url.substr(url.find_last_of('/') + 1);
20 }
21
22 void ClearMetadataDetail(gpointer data) {
23   __metadata_t* meta = reinterpret_cast<__metadata_t*>(data);
24   if (meta->key)
25     free(const_cast<char*>(meta->key));
26   if (meta->value)
27     free(const_cast<char*>(meta->value));
28   free(meta);
29 }
30
31 }  // namespace
32
33 namespace common_installer {
34
35 const char MetadataPlugin::kType[] = "metadata";
36
37 std::unique_ptr<MetadataPlugin> MetadataPlugin::Create(
38     const PluginInfo& plugin_info) {
39   std::unique_ptr<MetadataPlugin> plugin(new MetadataPlugin(plugin_info));
40   if (!plugin->Load())
41     return nullptr;
42   return plugin;
43 }
44
45 bool MetadataPlugin::AddPluginInfo(manifest_x* manifest, const char* appid) {
46   plugin_x* plugin = static_cast<plugin_x*>(calloc(1, sizeof(plugin_x)));
47   if (!plugin) {
48     LOG(ERROR) << "out of memory";
49     return false;
50   }
51   plugin->pkgid = strdup(manifest->package);
52   plugin->appid = strdup(appid);
53   plugin->plugin_type = strdup(plugin_info_.type().c_str());
54   plugin->plugin_name = strdup(plugin_info_.name().c_str());
55   if (!plugin->pkgid || !plugin->appid |
56       !plugin->plugin_type || !plugin->plugin_name) {
57     LOG(ERROR) << "out of memory";
58     free(plugin->pkgid);
59     free(plugin->appid);
60     free(plugin->plugin_type);
61     free(plugin->plugin_name);
62     free(plugin);
63     return false;
64   }
65   manifest->plugin = g_list_append(manifest->plugin, plugin);
66   return true;
67 }
68
69 std::string MetadataPlugin::GetFunctionName(ActionType action) const {
70   static std::map<ActionType, std::string> names {
71     {ActionType::Install,  "PKGMGR_MDPARSER_PLUGIN_INSTALL"},
72     {ActionType::Upgrade,  "PKGMGR_MDPARSER_PLUGIN_UPGRADE"},
73     {ActionType::Uninstall,  "PKGMGR_MDPARSER_PLUGIN_UNINSTALL"},
74     {ActionType::RecoverInstall,  "PKGMGR_MDPARSER_PLUGIN_RECOVERINSTALL"},
75     {ActionType::RecoverUpgrade,  "PKGMGR_MDPARSER_PLUGIN_RECOVERUPGRADE"},
76     {ActionType::RecoverUninstall,  "PKGMGR_MDPARSER_PLUGIN_RECOVERUNINSTALL"},
77     {ActionType::Clean, "PKGMGR_MDPARSER_PLUGIN_CLEAN"},
78     {ActionType::Undo, "PKGMGR_MDPARSER_PLUGIN_UNDO"},
79     {ActionType::Removed, "PKGMGR_MDPARSER_PLUGIN_REMOVED"},
80   };
81
82   auto pos = names.find(action);
83   if (pos == names.end()) {
84     LOG(INFO) << "Function name not defined";
85     return "";
86   }
87   return pos->second;
88 }
89
90 bool MetadataPlugin::Run(xmlDocPtr /*doc_ptr*/, manifest_x* manifest,
91                          ActionType action_type) {
92   std::string name;
93   std::string tag = GetMetadataTag(plugin_info_.name());
94   if (tag.empty())
95     return false;
96
97   if (action_type == ActionType::Upgrade) {
98     if (pkgmgrinfo_plugininfo_foreach_plugininfo(manifest->package,
99         MetadataPlugin::kType,
100         plugin_info_.name().c_str(),
101         [](const char*, const char* appid, const char*,
102             const char*, void* user_data) -> int {
103           auto* appid_list =
104               static_cast<std::vector<std::string>*>(user_data);
105           appid_list->emplace_back(std::string(appid));
106           return PMINFO_R_OK;
107         },
108         &appid_list_) != PMINFO_R_OK) {
109       LOG(ERROR) << "Failed to get previous execution info";
110       return false;
111     }
112     std::sort(appid_list_.begin(), appid_list_.end());
113   }
114
115   for (application_x* app : GListRange<application_x*>(manifest->application)) {
116     // pack all metadata starting with key to list that will
117     // be sent to the plugin.
118     // e.g. all http://developer.samsung.com/tizen/metadata/profile/*
119     //   will be packed for http://developer.samsung.com/tizen/metadata/profile
120     GList* md_list = nullptr;
121     for (metadata_x* meta : GListRange<metadata_x*>(app->metadata)) {
122       const std::string& sub_key_prefix = plugin_info_.name();
123       if (meta->key && meta->value &&
124           std::string(meta->key).find(sub_key_prefix) == 0) {
125         __metadata_t* md = reinterpret_cast<__metadata_t*>(
126             calloc(1, sizeof(__metadata_t)));
127         if (!md) {
128           LOG(ERROR) << "Out of memory";
129           g_list_free_full(md_list, &ClearMetadataDetail);
130           return false;
131         }
132         md->key = strdup(meta->key);
133         if (!md->key) {
134           LOG(ERROR) << "Out of memory";
135           free(md);
136           g_list_free_full(md_list, &ClearMetadataDetail);
137           return false;
138         }
139         md->value = strdup(meta->value);
140         if (!md->value) {
141           LOG(ERROR) << "Out of memory";
142           ClearMetadataDetail(md);
143           g_list_free_full(md_list, &ClearMetadataDetail);
144           return false;
145         }
146         md_list = g_list_append(md_list, md);
147       }
148     }
149
150     // skip application if it has no given metadata
151     if (!md_list) {
152       continue;
153     } else {
154       name = GetFunctionName(action_type);
155       if (!AddPluginInfo(manifest, app->appid)) {
156         g_list_free_full(md_list, &ClearMetadataDetail);
157         return false;
158       }
159       auto iter = std::lower_bound(appid_list_.begin(), appid_list_.end(),
160                                      app->appid);
161       if (iter != appid_list_.end() && *iter == app->appid)
162         appid_list_.erase(iter);
163     }
164     int result = 0;
165     Exec(name, &result, manifest->package, app->appid, md_list);
166     if (result) {
167       LOG(ERROR) << "Function: " << name << " of plugin "
168                  << plugin_info_.path() << " failed";
169       g_list_free_full(md_list, &ClearMetadataDetail);
170       return false;
171     }
172     g_list_free_full(md_list, &ClearMetadataDetail);
173   }
174
175   if (action_type == ActionType::Clean ||
176       action_type == ActionType::Undo)
177     name = GetFunctionName(action_type);
178   else
179     name = GetFunctionName(ActionType::Removed);
180   for (auto appid : appid_list_) {
181     int result = 0;
182     Exec(name, &result, manifest->package, appid.c_str(), nullptr);
183     if (result) {
184       LOG(ERROR) << "Function: " << name << " of plugin "
185                 << plugin_info_.path() << " failed";
186       return false;
187     }
188   }
189   return true;
190 }
191
192 }  // namespace common_installer