Line data Source code
1 : /* SPDX-License-Identifier: Apache-2.0 */
2 : /**
3 : * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved.
4 : *
5 : * @file mlops-plugin-parser.cc
6 : * @date 21 Mar 2024
7 : * @brief This file contains the implementation of a plugin parser for Tizen RPK packages.
8 : * The plugin parser is responsible for parsing JSON files in RPK and updating the database using daemon.
9 : * @see https://github.com/nnstreamer/deviceMLOps.MLAgent
10 : * @author Yongjoo Ahn <yongjoo1.ahn@samsung.com>
11 : * @bug No known bugs except for NYI items
12 : * @todo Add more unit tests using mocks.
13 : * @todo Support UNINSTALL and UPGRADE.
14 : * @todo Support allowed resource other than global resource.
15 : */
16 :
17 : #include <dlog.h>
18 : #include <glib.h>
19 : #include <json-glib/json-glib.h>
20 : #include <mlops-agent-interface.h>
21 : #include <pkgmgr-info.h>
22 :
23 : #define __TAG_ "ml-agent-plugin-parser"
24 : #define LOG_V(prio, tag, fmt, arg...) \
25 : ({ \
26 : do { \
27 : dlog_print (prio, tag, "%s: %s(%d) > " fmt, __MODULE__, __func__, __LINE__, ##arg); \
28 : } while (0); \
29 : })
30 :
31 : #define _D(fmt, arg...) LOG_V (DLOG_DEBUG, __TAG_, fmt, ##arg)
32 : #define _I(fmt, arg...) LOG_V (DLOG_INFO, __TAG_, fmt, ##arg)
33 : #define _W(fmt, arg...) LOG_V (DLOG_WARN, __TAG_, fmt, ##arg)
34 : #define _E(fmt, arg...) LOG_V (DLOG_ERROR, __TAG_, fmt, ##arg)
35 : #define _F(fmt, arg...) LOG_V (DLOG_FATAL, __TAG_, fmt, ##arg)
36 : #define STR_IS_VALID(s) ((s) && (s)[0] != '\0')
37 :
38 : /**
39 : * @brief Struct used to parse metadata tag from xml file.
40 : */
41 : typedef struct _metadata_s {
42 : const char *key;
43 : const char *value;
44 : } _metadata_s;
45 :
46 : /**
47 : * @brief Make pkg-info json string.
48 : */
49 : static gchar *
50 9 : _make_pkg_info (const gchar *pkgid, const gchar *appid, const gchar *res_type,
51 : const gchar *res_version)
52 : {
53 9 : g_autoptr (JsonBuilder) builder = json_builder_new ();
54 9 : json_builder_begin_object (builder);
55 :
56 9 : json_builder_set_member_name (builder, "is_rpk");
57 9 : json_builder_add_string_value (builder, "T");
58 :
59 9 : json_builder_set_member_name (builder, "pkg_id");
60 9 : json_builder_add_string_value (builder, pkgid);
61 :
62 9 : json_builder_set_member_name (builder, "app_id");
63 9 : json_builder_add_string_value (builder, appid ? appid : "");
64 :
65 9 : json_builder_set_member_name (builder, "res_type");
66 9 : json_builder_add_string_value (builder, res_type);
67 :
68 9 : json_builder_set_member_name (builder, "res_version");
69 9 : json_builder_add_string_value (builder, res_version);
70 :
71 9 : json_builder_end_object (builder);
72 :
73 9 : g_autoptr (JsonNode) root = json_builder_get_root (builder);
74 9 : g_autoptr (JsonGenerator) gen = json_generator_new ();
75 9 : json_generator_set_root (gen, root);
76 9 : json_generator_set_pretty (gen, TRUE);
77 :
78 18 : return json_generator_to_data (gen, NULL);
79 9 : }
80 :
81 : /**
82 : * @brief Internal enumeration for data types of json.
83 : */
84 : typedef enum {
85 : MLSVC_JSON_MODEL = 0,
86 : MLSVC_JSON_PIPELINE = 1,
87 : MLSVC_JSON_RESOURCE = 2,
88 : MLSVC_JSON_MAX
89 : } mlsvc_json_type_e;
90 :
91 : /**
92 : * @brief Internal enumeration for package manager event types.
93 : */
94 : typedef enum {
95 : MLSVC_PKGMGR_MDPARSER_PLUGIN_EVENT_TYPE_INSTALL = 0,
96 : MLSVC_PKGMGR_MDPARSER_PLUGIN_EVENT_TYPE_UNINSTALL = 1,
97 : MLSVC_PKGMGR_MDPARSER_PLUGIN_EVENT_TYPE_UPGRADE = 2,
98 : MLSVC_PKGMGR_MDPARSER_PLUGIN_EVENT_TYPE_MAX
99 : } mlsvc_package_manager_event_type_e;
100 :
101 : /**
102 : * @brief Internal function for uninstall models and pipelines.
103 : */
104 : static void
105 2 : _uninstall_rpk (const gchar *name, const gchar *_info, mlsvc_json_type_e json_type)
106 : {
107 2 : g_autoptr (JsonParser) parser = json_parser_new ();
108 2 : g_autoptr (GError) err = NULL;
109 : JsonNode *root;
110 : JsonObject *object;
111 2 : JsonArray *array = NULL;
112 2 : guint _info_len = 1U;
113 :
114 2 : if (!json_parser_load_from_data (parser, _info, -1, &err)) {
115 0 : _E ("Failed to load '%s' info data (%s).", name, err ? err->message : "Unknown error");
116 0 : return;
117 : }
118 :
119 2 : root = json_parser_get_root (parser);
120 2 : if (!root) {
121 0 : _E ("Failed to load '%s' info, cannot get the top node from info.", name);
122 0 : return;
123 : }
124 :
125 2 : if (JSON_NODE_HOLDS_ARRAY (root)) {
126 2 : array = json_node_get_array (root);
127 2 : if (!array) {
128 0 : _E ("Failed to get root array from '%s' info", name);
129 0 : return;
130 : }
131 :
132 2 : _info_len = json_array_get_length (array);
133 : }
134 :
135 : /* Update ML service database. */
136 4 : for (guint i = 0; i < _info_len; ++i) {
137 2 : int ret = 0;
138 :
139 2 : if (array)
140 2 : object = json_array_get_object_element (array, i);
141 : else
142 0 : object = json_node_get_object (root);
143 :
144 2 : const gchar *app_info = json_object_get_string_member (object, "app_info");
145 :
146 : /* If app info is empty string, it is not installed from rpk. */
147 2 : if (!STR_IS_VALID (app_info))
148 0 : continue;
149 :
150 2 : g_autoptr (JsonParser) app_info_parser = json_parser_new ();
151 :
152 2 : if (!json_parser_load_from_data (app_info_parser, app_info, -1, &err)) {
153 0 : _E ("Failed to load '%s' app_info data.", name);
154 0 : return;
155 : }
156 :
157 2 : JsonNode *app_info_root = json_parser_get_root (app_info_parser);
158 2 : if (!app_info_root) {
159 0 : _E ("Failed to load '%s'app_info, cannot get the top node from app_info.", name);
160 0 : return;
161 : }
162 :
163 2 : JsonObject *app_info_object = json_node_get_object (app_info_root);
164 2 : const gchar *is_rpk = json_object_get_string_member (app_info_object, "is_rpk");
165 :
166 2 : if (!is_rpk) {
167 0 : _E ("Failed to get 'is_rpk' from '%s' app_info.", name);
168 0 : return;
169 : }
170 2 : if (g_ascii_strcasecmp (is_rpk, "F") == 0)
171 0 : continue;
172 :
173 2 : switch (json_type) {
174 2 : case MLSVC_JSON_MODEL:
175 : {
176 2 : const gchar *version = json_object_get_string_member (object, "version");
177 :
178 4 : ret = ml_agent_model_delete (
179 2 : name, (const uint32_t) g_ascii_strtoull (version, NULL, 10), TRUE);
180 :
181 2 : if (ret == 0) {
182 2 : _I ("The model is deleted. - name: %s, version %s", name, version);
183 : } else {
184 0 : _E ("Failed to delete model return %d. - name: %s, version: %s",
185 : ret, name, version);
186 : }
187 : }
188 2 : break;
189 0 : case MLSVC_JSON_RESOURCE:
190 : {
191 : /** @todo Support delete resource installed by rpk */
192 : }
193 0 : break;
194 0 : default:
195 0 : _E ("Unknown json type '%d', internal error?", json_type);
196 0 : return;
197 : }
198 : }
199 :
200 2 : _I ("All deleted. - name: %s", name);
201 2 : return;
202 2 : }
203 :
204 : /**
205 : * @brief Parse json and update ml-service database via invoking daemon.
206 : */
207 : static gboolean
208 15 : _parse_json (JsonNode *node, const gchar *app_info, mlsvc_json_type_e json_type,
209 : mlsvc_package_manager_event_type_e event)
210 : {
211 15 : JsonArray *array = NULL;
212 15 : JsonObject *object = NULL;
213 15 : guint json_len = 1U;
214 : gint ret;
215 :
216 15 : if (JSON_NODE_HOLDS_ARRAY (node)) {
217 0 : array = json_node_get_array (node);
218 0 : if (!array) {
219 0 : _E ("Failed to get array from json");
220 0 : return FALSE;
221 : }
222 :
223 0 : json_len = json_array_get_length (array);
224 : }
225 :
226 : /* Update ML service database. */
227 27 : for (guint i = 0; i < json_len; ++i) {
228 15 : if (array)
229 0 : object = json_array_get_object_element (array, i);
230 : else
231 15 : object = json_node_get_object (node);
232 :
233 15 : switch (json_type) {
234 5 : case MLSVC_JSON_MODEL:
235 : {
236 5 : const gchar *name = json_object_get_string_member (object, "name");
237 5 : const gchar *model = json_object_get_string_member (object, "model");
238 5 : const gchar *desc = json_object_get_string_member (object, "description");
239 5 : const gchar *activate = json_object_get_string_member (object, "activate");
240 :
241 5 : if (!name || !model) {
242 1 : _E ("Failed to get name or model from MLSVC_JSON_MODEL.");
243 1 : return FALSE;
244 : }
245 :
246 4 : if (event == MLSVC_PKGMGR_MDPARSER_PLUGIN_EVENT_TYPE_INSTALL) {
247 : guint version;
248 2 : bool active = (activate && g_ascii_strcasecmp (activate, "true") == 0);
249 :
250 2 : ret = ml_agent_model_register (name, model, active,
251 : desc ? desc : "", app_info ? app_info : "", &version);
252 :
253 2 : if (ret == 0) {
254 2 : _I ("The model with name '%s' is registered as version '%u'.", name, version);
255 : } else {
256 0 : _E ("Failed to register the model with name '%s'.", name);
257 0 : return FALSE;
258 : }
259 2 : } else if (event == MLSVC_PKGMGR_MDPARSER_PLUGIN_EVENT_TYPE_UNINSTALL) {
260 2 : g_autofree gchar *model_info = NULL;
261 :
262 2 : ret = ml_agent_model_get_all (name, &model_info);
263 :
264 2 : if (ret == 0) {
265 2 : _uninstall_rpk (name, model_info, json_type);
266 : } else {
267 0 : _I ("The model with name '%s' is already deleted or not installed.", name);
268 : }
269 2 : } else {
270 0 : _E ("Unknown event type '%d', internal error?", event);
271 0 : return FALSE;
272 : }
273 : }
274 4 : break;
275 5 : case MLSVC_JSON_PIPELINE:
276 : {
277 5 : const gchar *name = json_object_get_string_member (object, "name");
278 5 : const gchar *pipe = json_object_get_string_member (object, "pipeline");
279 :
280 5 : if (!name || !pipe) {
281 1 : _E ("Failed to get name or pipeline from MLSVC_JSON_PIPELINE.");
282 1 : return FALSE;
283 : }
284 :
285 4 : if (event == MLSVC_PKGMGR_MDPARSER_PLUGIN_EVENT_TYPE_INSTALL) {
286 2 : ret = ml_agent_pipeline_set_description (name, pipe);
287 :
288 2 : if (ret == 0) {
289 2 : _I ("The pipeline description with name '%s' is registered.", name);
290 : } else {
291 0 : _E ("Failed to register pipeline with name '%s'.", name);
292 0 : return FALSE;
293 : }
294 2 : } else if (event == MLSVC_PKGMGR_MDPARSER_PLUGIN_EVENT_TYPE_UNINSTALL) {
295 2 : ret = ml_agent_pipeline_delete (name);
296 :
297 2 : if (ret == 0) {
298 2 : _I ("The pipeline description with name '%s' is deleted.", name);
299 : } else {
300 0 : _E ("Failed to delete pipeline with name '%s'.", name);
301 0 : return FALSE;
302 : }
303 : } else {
304 0 : _E ("Unknown event type '%d', internal error?", event);
305 0 : return FALSE;
306 : }
307 : }
308 4 : break;
309 5 : case MLSVC_JSON_RESOURCE:
310 : {
311 5 : const gchar *name = json_object_get_string_member (object, "name");
312 5 : const gchar *desc = json_object_get_string_member (object, "description");
313 5 : JsonNode *path_node = json_object_get_member (object, "path");
314 5 : JsonArray *path_array = NULL;
315 : guint path_len;
316 :
317 5 : if (!name) {
318 1 : _E ("Failed to get name from MLSVC_JSON_RESOURCE.");
319 1 : return FALSE;
320 : }
321 :
322 4 : path_len = 1U;
323 4 : if (JSON_NODE_HOLDS_ARRAY (path_node)) {
324 4 : path_array = json_node_get_array (path_node);
325 4 : path_len = (path_array) ? json_array_get_length (path_array) : 0U;
326 : }
327 :
328 4 : if (path_len == 0U) {
329 0 : _E ("Failed to get path from MLSVC_JSON_RESOURCE.");
330 0 : return FALSE;
331 : }
332 :
333 4 : if (event == MLSVC_PKGMGR_MDPARSER_PLUGIN_EVENT_TYPE_INSTALL) {
334 6 : for (guint pidx = 0; pidx < path_len; pidx++) {
335 4 : const gchar *path = NULL;
336 :
337 4 : if (path_array)
338 4 : path = json_array_get_string_element (path_array, pidx);
339 : else
340 0 : path = json_node_get_string (path_node);
341 :
342 4 : if (!path) {
343 0 : _E ("Failed to get path at '%d'th of '%s' from MLSVC_JSON_RESOURCE.",
344 : pidx, name);
345 0 : return FALSE;
346 : }
347 :
348 4 : ret = ml_agent_resource_add (
349 : name, path, desc ? desc : "", app_info ? app_info : "");
350 :
351 4 : if (ret == 0) {
352 4 : _I ("The resource at '%d'th of name '%s' is registered.", pidx, name);
353 : } else {
354 0 : _E ("Failed to register the resource with name '%s'.", name);
355 0 : return FALSE;
356 : }
357 : }
358 2 : } else if (event == MLSVC_PKGMGR_MDPARSER_PLUGIN_EVENT_TYPE_UNINSTALL) {
359 2 : ret = ml_agent_resource_delete (name);
360 :
361 2 : if (ret == 0) {
362 2 : _I ("The resource is deleted. - name: %s", name);
363 : } else {
364 0 : _I ("The model with name '%s' is already deleted or not installed", name);
365 : }
366 : } else {
367 0 : _E ("Unknown event type '%d', internal error?", event);
368 0 : return FALSE;
369 : }
370 : }
371 4 : break;
372 0 : default:
373 0 : _E ("Unknown data type '%d', internal error?", json_type);
374 0 : return FALSE;
375 : }
376 : }
377 12 : return TRUE;
378 : }
379 :
380 : /**
381 : * @brief Internal function to get json configuration file.
382 : */
383 : static gboolean
384 9 : _get_json_config (const gchar *json_path, const gchar *app_info,
385 : mlsvc_package_manager_event_type_e event)
386 : {
387 0 : g_autofree gchar *json_string = NULL;
388 0 : g_autoptr (JsonParser) parser = NULL;
389 0 : g_autoptr (GError) err = NULL;
390 9 : g_autoptr (GList) members = NULL;
391 : GList *iter;
392 : JsonNode *root;
393 : JsonObject *object;
394 :
395 9 : if (!g_file_test (json_path, (GFileTest) (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))) {
396 1 : _E ("The parameter, json_path, is invalid. It should be a valid string.");
397 1 : return FALSE;
398 : }
399 :
400 8 : if (!g_file_get_contents (json_path, &json_string, NULL, NULL)) {
401 0 : _E ("Failed to read configuration file '%s'.", json_path);
402 0 : return FALSE;
403 : }
404 :
405 8 : parser = json_parser_new ();
406 8 : if (!parser) {
407 0 : _E ("Failed to parse configuration file, cannot allocate memory for JsonParser. Out of memory?");
408 0 : return FALSE;
409 : }
410 :
411 8 : if (!json_parser_load_from_data (parser, json_string, -1, &err)) {
412 1 : _E ("Failed to parse configuration file, cannot load json string (%s).",
413 : err ? err->message : "Unknown error");
414 1 : return FALSE;
415 : }
416 :
417 7 : root = json_parser_get_root (parser);
418 7 : if (!root) {
419 0 : _E ("Failed to parse configuration file, cannot get the top node from json string.");
420 0 : return FALSE;
421 : }
422 :
423 7 : object = json_node_get_object (root);
424 7 : members = json_object_get_members (object);
425 :
426 19 : for (iter = members; iter != NULL; iter = iter->next) {
427 15 : const gchar *name = (const gchar *) iter->data;
428 15 : JsonNode *node = json_object_get_member (object, name);
429 : mlsvc_json_type_e json_type;
430 :
431 15 : if (g_ascii_strcasecmp (name, "model") == 0 || g_ascii_strcasecmp (name, "models") == 0) {
432 5 : json_type = MLSVC_JSON_MODEL;
433 10 : } else if (g_ascii_strcasecmp (name, "pipeline") == 0
434 10 : || g_ascii_strcasecmp (name, "pipelines") == 0) {
435 5 : json_type = MLSVC_JSON_PIPELINE;
436 5 : } else if (g_ascii_strcasecmp (name, "resource") == 0
437 5 : || g_ascii_strcasecmp (name, "resources") == 0) {
438 5 : json_type = MLSVC_JSON_RESOURCE;
439 : } else {
440 0 : _E ("Failed to parse '%s' from configuration file, unsupported type.", name);
441 0 : return FALSE;
442 : }
443 :
444 15 : if (!_parse_json (node, app_info, json_type, event)) {
445 3 : _E ("Failed to parse '%s' from configuration file.", name);
446 3 : return FALSE;
447 : }
448 : }
449 :
450 4 : return TRUE;
451 9 : }
452 :
453 : /**
454 : * @brief Internal function to set pkg-mgr parser
455 : */
456 : static int
457 19 : _set_pkgmgr_plugin (const gchar *pkgid, const gchar *appid, GList *metadata,
458 : mlsvc_package_manager_event_type_e event)
459 : {
460 19 : GList *list = NULL;
461 19 : _metadata_s *detail = NULL;
462 : pkgmgrinfo_pkginfo_h handle;
463 19 : int ret = 0;
464 :
465 19 : _I ("pkgid = %s, appid = %s\n", pkgid, appid);
466 :
467 : /* check metadata key/value */
468 19 : list = g_list_first (metadata);
469 19 : while (list) {
470 0 : detail = (_metadata_s *) list->data;
471 0 : _I ("key = %s, value = %s\n", detail->key, detail->value);
472 0 : list = g_list_next (list);
473 : }
474 :
475 19 : ret = pkgmgrinfo_pkginfo_get_pkginfo (pkgid, &handle);
476 19 : if (ret != PMINFO_R_OK) {
477 5 : _E ("Failed to get handle.");
478 5 : return -1;
479 : }
480 :
481 : /* Check whether the package is rpk */
482 14 : char *pkg_type = NULL;
483 14 : ret = pkgmgrinfo_pkginfo_get_type (handle, &pkg_type);
484 14 : if (ret != PMINFO_R_OK) {
485 1 : _E ("Failed to get package type.");
486 1 : pkgmgrinfo_pkginfo_destroy_pkginfo (handle);
487 1 : return -1;
488 : }
489 13 : _I ("pkg_type : %s", pkg_type);
490 :
491 13 : if (g_strcmp0 (pkg_type, "rpk") != 0) {
492 1 : _I ("pkg_type is not rpk. Skip parsing.");
493 1 : pkgmgrinfo_pkginfo_destroy_pkginfo (handle);
494 1 : return 0;
495 : }
496 :
497 12 : char *root_path = NULL;
498 12 : ret = pkgmgrinfo_pkginfo_get_root_path (handle, &root_path);
499 12 : if (ret != PMINFO_R_OK) {
500 1 : _E ("Failed to get root path.");
501 1 : pkgmgrinfo_pkginfo_destroy_pkginfo (handle);
502 1 : return -1;
503 : }
504 11 : _I ("root path: %s", root_path);
505 :
506 11 : char *res_type = NULL;
507 11 : ret = pkgmgrinfo_pkginfo_get_res_type (handle, &res_type);
508 11 : if (ret != PMINFO_R_OK) {
509 1 : _E ("Failed to get res type.");
510 1 : pkgmgrinfo_pkginfo_destroy_pkginfo (handle);
511 1 : return -1;
512 : }
513 10 : _I ("res_type = %s\n", res_type);
514 :
515 10 : char *res_version = NULL;
516 10 : ret = pkgmgrinfo_pkginfo_get_res_version (handle, &res_version);
517 10 : if (ret != PMINFO_R_OK) {
518 1 : _E ("Failed to get res version.");
519 1 : pkgmgrinfo_pkginfo_destroy_pkginfo (handle);
520 1 : return -1;
521 : }
522 9 : _I ("res_version = %s\n", res_version);
523 :
524 9 : g_autofree gchar *app_info = _make_pkg_info (pkgid, appid, res_type, res_version);
525 9 : _I ("app_info = %s\n", app_info);
526 :
527 : /* check rpk_config.json file */
528 9 : g_autofree gchar *json_file = g_build_filename (
529 9 : root_path, "res", "global", res_type, "rpk_config.json", NULL);
530 :
531 9 : if (!_get_json_config (json_file, app_info, event)) {
532 5 : _E ("Failed to parse the config file %s", json_file);
533 5 : pkgmgrinfo_pkginfo_destroy_pkginfo (handle);
534 5 : return -1;
535 : }
536 :
537 4 : _I ("PKGMGR_MDPARSER_PLUGIN finished");
538 4 : pkgmgrinfo_pkginfo_destroy_pkginfo (handle);
539 :
540 4 : return 0;
541 9 : }
542 :
543 : /**
544 : * @brief Handle INSTALL process. Tizen app-installer invoke this function.
545 : */
546 : extern "C" int
547 15 : PKGMGR_MDPARSER_PLUGIN_INSTALL (const char *pkgid, const char *appid, GList *metadata)
548 : {
549 15 : _I ("PKGMGR_MDPARSER_PLUGIN_INSTALL called");
550 15 : return _set_pkgmgr_plugin (
551 15 : pkgid, appid, metadata, MLSVC_PKGMGR_MDPARSER_PLUGIN_EVENT_TYPE_INSTALL);
552 : }
553 :
554 : /**
555 : * @brief Handle UNINSTALL process. Tizen app-installer invoke this function.
556 : */
557 : extern "C" int
558 4 : PKGMGR_MDPARSER_PLUGIN_UNINSTALL (const char *pkgid, const char *appid, GList *metadata)
559 : {
560 4 : _I ("PKGMGR_MDPARSER_PLUGIN_UNINSTALL called");
561 4 : return _set_pkgmgr_plugin (
562 4 : pkgid, appid, metadata, MLSVC_PKGMGR_MDPARSER_PLUGIN_EVENT_TYPE_UNINSTALL);
563 : }
564 :
565 : /**
566 : * @brief Handle UPGRADE process. Tizen app-installer invoke this function.
567 : */
568 : extern "C" int
569 2 : PKGMGR_MDPARSER_PLUGIN_UPGRADE (const char *pkgid, const char *appid, GList *metadata)
570 : {
571 2 : _I ("PKGMGR_MDPARSER_PLUGIN_UPGRADE called");
572 :
573 2 : PKGMGR_MDPARSER_PLUGIN_UNINSTALL (pkgid, appid, metadata);
574 2 : return PKGMGR_MDPARSER_PLUGIN_INSTALL (pkgid, appid, metadata);
575 : }
576 :
577 : /**
578 : * @brief RECOVERINSTALL is invoked after the INSTALL process failed.
579 : */
580 : extern "C" int
581 1 : PKGMGR_MDPARSER_PLUGIN_RECOVERINSTALL (const char *pkgid, const char *appid, GList *metadata)
582 : {
583 1 : _I ("PKGMGR_MDPARSER_PLUGIN_RECOVERINSTALL called");
584 1 : return PKGMGR_MDPARSER_PLUGIN_UNINSTALL (pkgid, appid, metadata);
585 : }
586 :
587 : /**
588 : * @brief RECOVERUPGRADE is invoked after the UPGRADE process failed.
589 : */
590 : extern "C" int
591 1 : PKGMGR_MDPARSER_PLUGIN_RECOVERUPGRADE (const char *pkgid, const char *appid, GList *metadata)
592 : {
593 1 : _I ("PKGMGR_MDPARSER_PLUGIN_RECOVERUPGRADE called");
594 1 : return PKGMGR_MDPARSER_PLUGIN_UPGRADE (pkgid, appid, metadata);
595 : }
596 :
597 : /**
598 : * @brief RECOVERUNINSTALL is invoked after the UNINSTALL process failed.
599 : */
600 : extern "C" int
601 1 : PKGMGR_MDPARSER_PLUGIN_RECOVERUNINSTALL (const char *pkgid, const char *appid, GList *metadata)
602 : {
603 1 : _I ("PKGMGR_MDPARSER_PLUGIN_RECOVERUNINSTALL called");
604 1 : return PKGMGR_MDPARSER_PLUGIN_INSTALL (pkgid, appid, metadata);
605 : }
606 :
607 : /**
608 : * @brief CLEAN is invoked after the installation process completed.
609 : */
610 : extern "C" int
611 1 : PKGMGR_MDPARSER_PLUGIN_CLEAN (const char *pkgid, const char *appid, GList *metadata)
612 : {
613 1 : _I ("PKGMGR_MDPARSER_PLUGIN_CLEAN called");
614 1 : return 0;
615 : }
616 :
617 : /**
618 : * @brief UNDO is invoked after the installation process failed.
619 : */
620 : extern "C" int
621 1 : PKGMGR_MDPARSER_PLUGIN_UNDO (const char *pkgid, const char *appid, GList *metadata)
622 : {
623 1 : _I ("PKGMGR_MDPARSER_PLUGIN_UNDO called");
624 1 : return 0;
625 : }
|