diff options
author | Farshid Monhaseri <monhaseri.f@gmail.com> | 2020-01-22 19:19:16 +0330 |
---|---|---|
committer | Matt Ranostay <matt.ranostay@konsulko.com> | 2020-02-12 15:29:52 -0800 |
commit | c07b257e09a2cfbaeef8b0aaaf0355621c4186e8 (patch) | |
tree | f30ee50b0a64b5494f4eb9d5246337616b7eb4ec | |
parent | ca519329c0cc04607286cebcdb0b7b304473ff96 (diff) |
mediascanner: fix the service memory leakageshalibut_8.0.6halibut/8.0.68.0.6halibut
Bug-AGL: SPEC-3103
- fix memory leakage in 'media_results_get' callback function which
is called by 'media_result' verb. Set free-full the whole list with
'free_media_item' callback function(major leak).
- fix memory leakage in 'MediaPlayerManagerInit' function, file object
is not released(minor leak).
- fix memory leakage in 'media_lightmediascanner_scan' function and
avoid open sqlite3 connection and allocate whole sqlite
resources again and again on every function execution (major leak).
- fix memory leakage in 'on_interface_proxy_properties_changed' when
iterating over 'changed_properties' and not release key & subValues.
Signed-off-by: Farshid Monhaseri <monhaseri.f@gmail.com>
Change-Id: I943a961b0c13be79c70c80e7a4f558958551f800
-rw-r--r-- | binding/media-api.c | 2 | ||||
-rw-r--r-- | binding/media-manager.c | 68 | ||||
-rw-r--r-- | binding/media-manager.h | 2 |
3 files changed, 55 insertions, 17 deletions
diff --git a/binding/media-api.c b/binding/media-api.c index d02ad93..f81177d 100644 --- a/binding/media-api.c +++ b/binding/media-api.c @@ -142,7 +142,7 @@ static void media_results_get (afb_req_t request) } jresp = new_json_object_from_device(list); - g_list_free(list); + g_list_free_full(list,free_media_item); ListUnlock(); if (jresp == NULL) { diff --git a/binding/media-manager.c b/binding/media-manager.c index 549153b..c58da25 100644 --- a/binding/media-manager.c +++ b/binding/media-manager.c @@ -37,9 +37,14 @@ const char *lms_scan_types[] = { "audio", "video", }; +typedef struct { + sqlite3 *db; + gboolean is_open; +}scannerDB; static Binding_RegisterCallback_t g_RegisterCallback = { 0 }; static stMediaPlayerManage MediaPlayerManage = { 0 }; +static scannerDB scanDB = { 0 }; /* ------ LOCAL FUNCTIONS --------- */ void ListLock() { @@ -98,12 +103,17 @@ GList* media_lightmediascanner_scan(GList *list, gchar *uri, int scan_type) gchar *query; int ret = 0; - db_path = scanner1_get_data_base_path(MediaPlayerManage.lms_proxy); + if(!scanDB.is_open) { + db_path = scanner1_get_data_base_path(MediaPlayerManage.lms_proxy); - ret = sqlite3_open(db_path, &conn); - if (ret) { - LOGE("Cannot open SQLITE database: '%s'\n", db_path); - return NULL; + ret = sqlite3_open(db_path, &scanDB.db); + if (ret != SQLITE_OK) { + LOGE("Cannot open SQLITE database: '%s'\n", db_path); + scanDB.is_open = FALSE; + g_list_free_full(list,free_media_item); + return NULL; + } + scanDB.is_open = TRUE; } switch (scan_type) { @@ -120,7 +130,7 @@ GList* media_lightmediascanner_scan(GList *list, gchar *uri, int scan_type) return NULL; } - ret = sqlite3_prepare_v2(conn, query, (int) strlen(query), &res, &tail); + ret = sqlite3_prepare_v2(scanDB.db, query, (int) strlen(query), &res, &tail); if (ret) { LOGE("Cannot execute query '%s'\n", query); g_free(query); @@ -137,6 +147,7 @@ GList* media_lightmediascanner_scan(GList *list, gchar *uri, int scan_type) if (ret) continue; + //We may check the allocation result ... but It may be a bit expensive in such a loop item = g_malloc0(sizeof(*item)); tmp = g_uri_escape_string(path, "/", TRUE); item->path = g_strdup_printf("file://%s", tmp); @@ -156,7 +167,7 @@ GList* media_lightmediascanner_scan(GList *list, gchar *uri, int scan_type) return list; } -static void free_media_item(void *data) +void free_media_item(void *data) { struct Media_Item *item = data; @@ -174,31 +185,34 @@ on_interface_proxy_properties_changed (GDBusProxy *proxy, const gchar* const *invalidated_properties) { GVariantIter iter; - const gchar *key; - GVariant *subValue; - const gchar *pInterface; + gchar *key = NULL; + GVariant *subValue = NULL; + gchar *pInterface = NULL; GList *list = NULL; - + gboolean br = FALSE; pInterface = g_dbus_proxy_get_interface_name (proxy); if (0 != g_strcmp0(pInterface, LIGHTMEDIASCANNER_INTERFACE)) return; g_variant_iter_init (&iter, changed_properties); - while (g_variant_iter_next (&iter, "{&sv}", &key, &subValue)) + while (g_variant_iter_loop(&iter, "{&sv}", &key, &subValue)) { gboolean val; if (0 == g_strcmp0(key,"IsScanning")) { g_variant_get(subValue, "b", &val); if (val == TRUE) - return; + br = TRUE; } else if (0 == g_strcmp0(key, "WriteLocked")) { g_variant_get(subValue, "b", &val); if (val == TRUE) - return; + br = TRUE; } } + if(br) + return; + ListLock(); list = media_lightmediascanner_scan(list, MediaPlayerManage.uri_filter, LMS_AUDIO_SCAN); @@ -258,12 +272,28 @@ unmount_cb (GFileMonitor *mon, { gchar *path = g_file_get_path(file); gchar *uri = g_strconcat("file://", path, NULL); + gint ret = 0; ListLock(); if (g_RegisterCallback.binding_device_removed && event == G_FILE_MONITOR_EVENT_DELETED) { + g_RegisterCallback.binding_device_removed(uri); + ret = sqlite3_close(scanDB.db); + /* TODO: Release SQLite connection handle resources on the end of each session + * + * we should be able to handle the SQLITE_BUSY return value safely + * and be sure the connection handle will be released finally at the end of session + * There are a few synchronous & asynchronous libsqlite methods + * to handle this situation properly. + */ + if(ret == SQLITE_OK) { + scanDB.db = NULL; + scanDB.is_open = FALSE; + } else { + LOGE("Failed to release SQLite connection handle.\n"); + } g_free(path); } else if (event == G_FILE_MONITOR_EVENT_CREATED) { MediaPlayerManage.uri_filter = path; @@ -283,16 +313,22 @@ unmount_cb (GFileMonitor *mon, */ int MediaPlayerManagerInit() { pthread_t thread_id; - GFile *file; - GFileMonitor *mon; + GFile *file = NULL; + GFileMonitor *mon = MediaPlayerManage.mon; int ret; g_mutex_init(&(MediaPlayerManage.m)); + scanDB.is_open = FALSE; + if(mon != NULL) { + g_object_unref(mon); + mon = NULL; + } file = g_file_new_for_path("/media"); g_assert(file != NULL); mon = g_file_monitor (file, G_FILE_MONITOR_NONE, NULL, NULL); + g_object_unref(file); g_assert(mon != NULL); g_signal_connect (mon, "changed", G_CALLBACK(unmount_cb), NULL); diff --git a/binding/media-manager.h b/binding/media-manager.h index 4b381dc..81a0e20 100644 --- a/binding/media-manager.h +++ b/binding/media-manager.h @@ -102,6 +102,7 @@ typedef struct { gchar *uri_filter; GMutex m; Scanner1 *lms_proxy; + GFileMonitor *mon; } stMediaPlayerManage; typedef struct tagBinding_RegisterCallback @@ -111,6 +112,7 @@ typedef struct tagBinding_RegisterCallback } Binding_RegisterCallback_t; /* ------ PUBLIC PLUGIN FUNCTIONS --------- */ +void free_media_item(void *data); void BindingAPIRegister(const Binding_RegisterCallback_t* pstRegisterCallback); int MediaPlayerManagerInit(void); |