Merge pull request #16 from monich/poll
Implement service polling for old servicemanager
This commit is contained in:
		
							
								
								
									
										1
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								Makefile
									
									
									
									
									
								
							@@ -62,6 +62,7 @@ SRC = \
 | 
			
		||||
  gbinder_remote_reply.c \
 | 
			
		||||
  gbinder_remote_request.c \
 | 
			
		||||
  gbinder_rpc_protocol.c \
 | 
			
		||||
  gbinder_servicepoll.c \
 | 
			
		||||
  gbinder_writer.c
 | 
			
		||||
 | 
			
		||||
SRC += \
 | 
			
		||||
 
 | 
			
		||||
@@ -32,6 +32,7 @@
 | 
			
		||||
 | 
			
		||||
#include "gbinder_servicemanager_p.h"
 | 
			
		||||
#include "gbinder_rpc_protocol.h"
 | 
			
		||||
#include "gbinder_servicepoll.h"
 | 
			
		||||
#include "gbinder_log.h"
 | 
			
		||||
 | 
			
		||||
#include <gbinder_client.h>
 | 
			
		||||
@@ -43,13 +44,31 @@
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
 | 
			
		||||
typedef GBinderServiceManager GBinderDefaultServiceManager;
 | 
			
		||||
typedef struct gbinder_defaultservicemanager_watch {
 | 
			
		||||
    GBinderServicePoll* poll;
 | 
			
		||||
    char* name;
 | 
			
		||||
    gulong handler_id;
 | 
			
		||||
    guint notify_id;
 | 
			
		||||
} GBinderDefaultServiceManagerWatch;
 | 
			
		||||
 | 
			
		||||
typedef GBinderServiceManagerClass GBinderDefaultServiceManagerClass;
 | 
			
		||||
typedef struct gbinder_defaultservicemanager {
 | 
			
		||||
    GBinderServiceManager manager;
 | 
			
		||||
    GBinderServicePoll* poll;
 | 
			
		||||
    GHashTable* watch_table;
 | 
			
		||||
} GBinderDefaultServiceManager;
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE(GBinderDefaultServiceManager,
 | 
			
		||||
    gbinder_defaultservicemanager,
 | 
			
		||||
    GBINDER_TYPE_SERVICEMANAGER)
 | 
			
		||||
 | 
			
		||||
#define PARENT_CLASS gbinder_defaultservicemanager_parent_class
 | 
			
		||||
#define GBINDER_TYPE_DEFAULTSERVICEMANAGER \
 | 
			
		||||
    gbinder_defaultservicemanager_get_type()
 | 
			
		||||
#define GBINDER_DEFAULTSERVICEMANAGER(obj) \
 | 
			
		||||
    G_TYPE_CHECK_INSTANCE_CAST((obj), GBINDER_TYPE_DEFAULTSERVICEMANAGER, \
 | 
			
		||||
    GBinderDefaultServiceManager)
 | 
			
		||||
 | 
			
		||||
enum gbinder_defaultservicemanager_calls {
 | 
			
		||||
    GET_SERVICE_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION,
 | 
			
		||||
    CHECK_SERVICE_TRANSACTION,
 | 
			
		||||
@@ -66,7 +85,76 @@ gbinder_defaultservicemanager_new(
 | 
			
		||||
    const char* dev)
 | 
			
		||||
{
 | 
			
		||||
    return gbinder_servicemanager_new_with_type
 | 
			
		||||
        (gbinder_defaultservicemanager_get_type(), dev);
 | 
			
		||||
        (GBINDER_TYPE_DEFAULTSERVICEMANAGER, dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
gbinder_defaultservicemanager_watch_proc(
 | 
			
		||||
    GBinderServicePoll* poll,
 | 
			
		||||
    const char* name_added,
 | 
			
		||||
    void* user_data)
 | 
			
		||||
{
 | 
			
		||||
    GBinderDefaultServiceManagerWatch* watch = user_data;
 | 
			
		||||
 | 
			
		||||
    if (!g_strcmp0(name_added, watch->name)) {
 | 
			
		||||
        GBinderServiceManager* manager =
 | 
			
		||||
            gbinder_servicepoll_manager(watch->poll);
 | 
			
		||||
 | 
			
		||||
        if (watch->notify_id) {
 | 
			
		||||
            g_source_remove(watch->notify_id);
 | 
			
		||||
            watch->notify_id = 0;
 | 
			
		||||
        }
 | 
			
		||||
        gbinder_servicemanager_service_registered(manager, name_added);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
gboolean
 | 
			
		||||
gbinder_defaultservicemanager_watch_notify(
 | 
			
		||||
    gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    GBinderDefaultServiceManagerWatch* watch = user_data;
 | 
			
		||||
    GBinderServiceManager* manager = gbinder_servicepoll_manager(watch->poll);
 | 
			
		||||
    char* name = g_strdup(watch->name);
 | 
			
		||||
 | 
			
		||||
    GASSERT(watch->notify_id);
 | 
			
		||||
    watch->notify_id = 0;
 | 
			
		||||
    gbinder_servicemanager_service_registered(manager, name);
 | 
			
		||||
    g_free(name);
 | 
			
		||||
    return G_SOURCE_REMOVE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
gbinder_defaultservicemanager_watch_free(
 | 
			
		||||
    gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    GBinderDefaultServiceManagerWatch* watch = user_data;
 | 
			
		||||
 | 
			
		||||
    if (watch->notify_id) {
 | 
			
		||||
        g_source_remove(watch->notify_id);
 | 
			
		||||
    }
 | 
			
		||||
    gbinder_servicepoll_remove_handler(watch->poll, watch->handler_id);
 | 
			
		||||
    gbinder_servicepoll_unref(watch->poll);
 | 
			
		||||
    g_free(watch->name);
 | 
			
		||||
    g_slice_free(GBinderDefaultServiceManagerWatch, watch);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
GBinderDefaultServiceManagerWatch*
 | 
			
		||||
gbinder_defaultservicemanager_watch_new(
 | 
			
		||||
    GBinderDefaultServiceManager* manager,
 | 
			
		||||
    const char* name)
 | 
			
		||||
{
 | 
			
		||||
    GBinderDefaultServiceManagerWatch* watch =
 | 
			
		||||
        g_slice_new0(GBinderDefaultServiceManagerWatch);
 | 
			
		||||
 | 
			
		||||
    watch->name = g_strdup(name);
 | 
			
		||||
    watch->poll = gbinder_servicepoll_new(&manager->manager, &manager->poll);
 | 
			
		||||
    watch->handler_id = gbinder_servicepoll_add_handler(watch->poll,
 | 
			
		||||
        gbinder_defaultservicemanager_watch_proc, watch);
 | 
			
		||||
    return watch;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
@@ -157,9 +245,35 @@ gbinder_defaultservicemanager_check_name(
 | 
			
		||||
    GBinderServiceManager* self,
 | 
			
		||||
    const char* name)
 | 
			
		||||
{
 | 
			
		||||
    /* Old servicemanager doesn't support notifications, those would
 | 
			
		||||
     * have to be emulated with polling. Is it necessary though? */
 | 
			
		||||
    return GBINDER_SERVICEMANAGER_NAME_INVALID;
 | 
			
		||||
    return GBINDER_SERVICEMANAGER_NAME_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
gboolean
 | 
			
		||||
gbinder_defaultservicemanager_watch(
 | 
			
		||||
    GBinderServiceManager* manager,
 | 
			
		||||
    const char* name)
 | 
			
		||||
{
 | 
			
		||||
    GBinderDefaultServiceManager* self = GBINDER_DEFAULTSERVICEMANAGER(manager);
 | 
			
		||||
    GBinderDefaultServiceManagerWatch* watch =
 | 
			
		||||
        gbinder_defaultservicemanager_watch_new(self, name);
 | 
			
		||||
 | 
			
		||||
    g_hash_table_replace(self->watch_table, watch->name, watch);
 | 
			
		||||
    if (gbinder_servicepoll_is_known_name(watch->poll, name)) {
 | 
			
		||||
        watch->notify_id =
 | 
			
		||||
            g_idle_add(gbinder_defaultservicemanager_watch_notify, watch);
 | 
			
		||||
    }
 | 
			
		||||
    return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
gbinder_defaultservicemanager_unwatch(
 | 
			
		||||
    GBinderServiceManager* manager,
 | 
			
		||||
    const char* name)
 | 
			
		||||
{
 | 
			
		||||
    g_hash_table_remove(GBINDER_DEFAULTSERVICEMANAGER(manager)->watch_table,
 | 
			
		||||
        name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
@@ -167,6 +281,19 @@ void
 | 
			
		||||
gbinder_defaultservicemanager_init(
 | 
			
		||||
    GBinderDefaultServiceManager* self)
 | 
			
		||||
{
 | 
			
		||||
    self->watch_table = g_hash_table_new_full(g_str_hash, g_str_equal,
 | 
			
		||||
        NULL, gbinder_defaultservicemanager_watch_free);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
gbinder_defaultservicemanager_finalize(
 | 
			
		||||
    GObject* object)
 | 
			
		||||
{
 | 
			
		||||
    GBinderDefaultServiceManager* self = GBINDER_DEFAULTSERVICEMANAGER(object);
 | 
			
		||||
 | 
			
		||||
    g_hash_table_destroy(self->watch_table);
 | 
			
		||||
    G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
@@ -183,7 +310,10 @@ gbinder_defaultservicemanager_class_init(
 | 
			
		||||
    klass->get_service = gbinder_defaultservicemanager_get_service;
 | 
			
		||||
    klass->add_service = gbinder_defaultservicemanager_add_service;
 | 
			
		||||
    klass->check_name = gbinder_defaultservicemanager_check_name;
 | 
			
		||||
    /* No need for other watch callbacks */
 | 
			
		||||
    /* normalize_name is not needed */
 | 
			
		||||
    klass->watch = gbinder_defaultservicemanager_watch;
 | 
			
		||||
    klass->unwatch = gbinder_defaultservicemanager_unwatch;
 | 
			
		||||
    G_OBJECT_CLASS(klass)->finalize = gbinder_defaultservicemanager_finalize;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										268
									
								
								src/gbinder_servicepoll.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										268
									
								
								src/gbinder_servicepoll.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,268 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2018 Jolla Ltd.
 | 
			
		||||
 * Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
 | 
			
		||||
 *
 | 
			
		||||
 * You may use this file under the terms of BSD license as follows:
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions
 | 
			
		||||
 * are met:
 | 
			
		||||
 *
 | 
			
		||||
 *   1. Redistributions of source code must retain the above copyright
 | 
			
		||||
 *      notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 *   2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
 *      notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *      documentation and/or other materials provided with the distribution.
 | 
			
		||||
 *   3. Neither the names of the copyright holders nor the names of its
 | 
			
		||||
 *      contributors may be used to endorse or promote products derived
 | 
			
		||||
 *      from this software without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | 
			
		||||
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
 | 
			
		||||
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | 
			
		||||
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 | 
			
		||||
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 | 
			
		||||
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 | 
			
		||||
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 | 
			
		||||
 * THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "gbinder_servicepoll.h"
 | 
			
		||||
#include "gbinder_servicemanager.h"
 | 
			
		||||
 | 
			
		||||
#include <gutil_strv.h>
 | 
			
		||||
 | 
			
		||||
#include <glib-object.h>
 | 
			
		||||
 | 
			
		||||
/* This is configurable mostly so that unit testing doesn't take too long */
 | 
			
		||||
guint gbinder_servicepoll_interval_ms = 2000;
 | 
			
		||||
 | 
			
		||||
typedef GObjectClass GBinderServicePollClass;
 | 
			
		||||
struct gbinder_servicepoll {
 | 
			
		||||
    GObject object;
 | 
			
		||||
    GBinderServiceManager* manager;
 | 
			
		||||
    char** list;
 | 
			
		||||
    gulong list_id;
 | 
			
		||||
    guint timer_id;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE(GBinderServicePoll, gbinder_servicepoll, G_TYPE_OBJECT)
 | 
			
		||||
#define GBINDER_TYPE_SERVICEPOLL (gbinder_servicepoll_get_type())
 | 
			
		||||
#define GBINDER_SERVICEPOLL(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
 | 
			
		||||
        GBINDER_TYPE_SERVICEPOLL, GBinderServicePoll))
 | 
			
		||||
 | 
			
		||||
enum gbinder_servicepoll_signal {
 | 
			
		||||
    SIGNAL_NAME_ADDED,
 | 
			
		||||
    SIGNAL_COUNT
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const char SIGNAL_NAME_ADDED_NAME[] = "servicepoll-name-added";
 | 
			
		||||
 | 
			
		||||
static guint gbinder_servicepoll_signals[SIGNAL_COUNT] = { 0 };
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * Implementation
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
 | 
			
		||||
/* GBinderServiceManagerListFunc callback returns TRUE to keep the services
 | 
			
		||||
 * list, otherwise the caller will deallocate it. */
 | 
			
		||||
gboolean
 | 
			
		||||
gbinder_servicepoll_list(
 | 
			
		||||
    GBinderServiceManager* sm,
 | 
			
		||||
    char** services,
 | 
			
		||||
    void* user_data)
 | 
			
		||||
{
 | 
			
		||||
    GBinderServicePoll* self = GBINDER_SERVICEPOLL(user_data);
 | 
			
		||||
 | 
			
		||||
    gbinder_servicepoll_ref(self);
 | 
			
		||||
    self->list_id = 0;
 | 
			
		||||
    if (services) {
 | 
			
		||||
        const GStrV* ptr_new;
 | 
			
		||||
 | 
			
		||||
        ptr_new = services = gutil_strv_sort(services, TRUE);
 | 
			
		||||
        if (self->list) {
 | 
			
		||||
            const GStrV* ptr_old = self->list;
 | 
			
		||||
 | 
			
		||||
            while (*ptr_new && *ptr_old) {
 | 
			
		||||
                const int i = gutil_strv_find(ptr_old, *ptr_new);
 | 
			
		||||
 | 
			
		||||
                if (i < 0) {
 | 
			
		||||
                    /* New name */
 | 
			
		||||
                    g_signal_emit(self, gbinder_servicepoll_signals
 | 
			
		||||
                        [SIGNAL_NAME_ADDED], 0, *ptr_new);
 | 
			
		||||
                } else {
 | 
			
		||||
                    int k;
 | 
			
		||||
 | 
			
		||||
                    /* If some names have disappeared, then i may be > 0 */
 | 
			
		||||
                    for (k = 0; k < i; k ++) ptr_old++;
 | 
			
		||||
                    ptr_old++;
 | 
			
		||||
                }
 | 
			
		||||
                ptr_new++;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        while (*ptr_new) {
 | 
			
		||||
            g_signal_emit(self, gbinder_servicepoll_signals
 | 
			
		||||
                [SIGNAL_NAME_ADDED], 0, *ptr_new);
 | 
			
		||||
            ptr_new++;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    g_strfreev(self->list);
 | 
			
		||||
    self->list = services;
 | 
			
		||||
    gbinder_servicepoll_unref(self);
 | 
			
		||||
    return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
gboolean
 | 
			
		||||
gbinder_servicepoll_timer(
 | 
			
		||||
    gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    GBinderServicePoll* self = GBINDER_SERVICEPOLL(user_data);
 | 
			
		||||
 | 
			
		||||
    if (!self->list_id) {
 | 
			
		||||
        self->list_id = gbinder_servicemanager_list(self->manager,
 | 
			
		||||
            gbinder_servicepoll_list, self);
 | 
			
		||||
    }
 | 
			
		||||
    return G_SOURCE_CONTINUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
GBinderServicePoll*
 | 
			
		||||
gbinder_servicepoll_create(
 | 
			
		||||
    GBinderServiceManager* manager)
 | 
			
		||||
{
 | 
			
		||||
    GBinderServicePoll* self = g_object_new(GBINDER_TYPE_SERVICEPOLL, NULL);
 | 
			
		||||
 | 
			
		||||
    self->manager = gbinder_servicemanager_ref(manager);
 | 
			
		||||
    self->list_id = gbinder_servicemanager_list(manager,
 | 
			
		||||
        gbinder_servicepoll_list, self);
 | 
			
		||||
    return self;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * API
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
 | 
			
		||||
GBinderServicePoll*
 | 
			
		||||
gbinder_servicepoll_new(
 | 
			
		||||
    GBinderServiceManager* manager,
 | 
			
		||||
    GBinderServicePoll** weakptr)
 | 
			
		||||
{
 | 
			
		||||
    if (weakptr) {
 | 
			
		||||
        if (*weakptr) {
 | 
			
		||||
            gbinder_servicepoll_ref(*weakptr);
 | 
			
		||||
        } else {
 | 
			
		||||
            *weakptr = gbinder_servicepoll_create(manager);
 | 
			
		||||
            g_object_add_weak_pointer(G_OBJECT(*weakptr), (gpointer*)weakptr);
 | 
			
		||||
        }
 | 
			
		||||
        return *weakptr;
 | 
			
		||||
    } else {
 | 
			
		||||
        return gbinder_servicepoll_create(manager);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GBinderServicePoll*
 | 
			
		||||
gbinder_servicepoll_ref(
 | 
			
		||||
    GBinderServicePoll* self)
 | 
			
		||||
{
 | 
			
		||||
    if (G_LIKELY(self)) {
 | 
			
		||||
        g_object_ref(GBINDER_SERVICEPOLL(self));
 | 
			
		||||
        return self;
 | 
			
		||||
    } else {
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
gbinder_servicepoll_unref(
 | 
			
		||||
    GBinderServicePoll* self)
 | 
			
		||||
{
 | 
			
		||||
    if (G_LIKELY(self)) {
 | 
			
		||||
        g_object_unref(GBINDER_SERVICEPOLL(self));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GBinderServiceManager*
 | 
			
		||||
gbinder_servicepoll_manager(
 | 
			
		||||
    GBinderServicePoll* self)
 | 
			
		||||
{
 | 
			
		||||
    return G_LIKELY(self) ? self->manager : NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
gbinder_servicepoll_is_known_name(
 | 
			
		||||
    GBinderServicePoll* self,
 | 
			
		||||
    const char* name)
 | 
			
		||||
{
 | 
			
		||||
    return G_LIKELY(self) && gutil_strv_contains(self->list, name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gulong
 | 
			
		||||
gbinder_servicepoll_add_handler(
 | 
			
		||||
    GBinderServicePoll* self,
 | 
			
		||||
    GBinderServicePollFunc fn,
 | 
			
		||||
    void* user_data)
 | 
			
		||||
{
 | 
			
		||||
    return (G_LIKELY(self) && G_LIKELY(fn)) ? g_signal_connect(self,
 | 
			
		||||
        SIGNAL_NAME_ADDED_NAME, G_CALLBACK(fn), user_data) : 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
gbinder_servicepoll_remove_handler(
 | 
			
		||||
    GBinderServicePoll* self,
 | 
			
		||||
    gulong id)
 | 
			
		||||
{
 | 
			
		||||
    if (G_LIKELY(self) && G_LIKELY(id)) {
 | 
			
		||||
        g_signal_handler_disconnect(self, id);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * Internals
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
gbinder_servicepoll_init(
 | 
			
		||||
    GBinderServicePoll* self)
 | 
			
		||||
{
 | 
			
		||||
    self->timer_id = g_timeout_add(gbinder_servicepoll_interval_ms,
 | 
			
		||||
        gbinder_servicepoll_timer, self);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
gbinder_servicepoll_finalize(
 | 
			
		||||
    GObject* object)
 | 
			
		||||
{
 | 
			
		||||
    GBinderServicePoll* self = GBINDER_SERVICEPOLL(object);
 | 
			
		||||
 | 
			
		||||
    g_source_remove(self->timer_id);
 | 
			
		||||
    gbinder_servicemanager_cancel(self->manager, self->list_id);
 | 
			
		||||
    gbinder_servicemanager_unref(self->manager);
 | 
			
		||||
    g_strfreev(self->list);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
gbinder_servicepoll_class_init(
 | 
			
		||||
    GBinderServicePollClass* klass)
 | 
			
		||||
{
 | 
			
		||||
    G_OBJECT_CLASS(klass)->finalize = gbinder_servicepoll_finalize;
 | 
			
		||||
    gbinder_servicepoll_signals[SIGNAL_NAME_ADDED] =
 | 
			
		||||
        g_signal_new(SIGNAL_NAME_ADDED_NAME, G_OBJECT_CLASS_TYPE(klass),
 | 
			
		||||
            G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE,
 | 
			
		||||
            1, G_TYPE_STRING);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Local Variables:
 | 
			
		||||
 * mode: C
 | 
			
		||||
 * c-basic-offset: 4
 | 
			
		||||
 * indent-tabs-mode: nil
 | 
			
		||||
 * End:
 | 
			
		||||
 */
 | 
			
		||||
							
								
								
									
										88
									
								
								src/gbinder_servicepoll.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								src/gbinder_servicepoll.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,88 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2018 Jolla Ltd.
 | 
			
		||||
 * Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
 | 
			
		||||
 *
 | 
			
		||||
 * You may use this file under the terms of BSD license as follows:
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions
 | 
			
		||||
 * are met:
 | 
			
		||||
 *
 | 
			
		||||
 *   1. Redistributions of source code must retain the above copyright
 | 
			
		||||
 *      notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 *   2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
 *      notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *      documentation and/or other materials provided with the distribution.
 | 
			
		||||
 *   3. Neither the names of the copyright holders nor the names of its
 | 
			
		||||
 *      contributors may be used to endorse or promote products derived
 | 
			
		||||
 *      from this software without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | 
			
		||||
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
 | 
			
		||||
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | 
			
		||||
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 | 
			
		||||
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 | 
			
		||||
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 | 
			
		||||
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 | 
			
		||||
 * THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef GBINDER_SERVICEPOLL_H
 | 
			
		||||
#define GBINDER_SERVICEPOLL_H
 | 
			
		||||
 | 
			
		||||
#include "gbinder_types_p.h"
 | 
			
		||||
 | 
			
		||||
extern guint gbinder_servicepoll_interval_ms;
 | 
			
		||||
 | 
			
		||||
typedef
 | 
			
		||||
void
 | 
			
		||||
(*GBinderServicePollFunc)(
 | 
			
		||||
    GBinderServicePoll* poll,
 | 
			
		||||
    const char* name_added,
 | 
			
		||||
    void* user_data);
 | 
			
		||||
 | 
			
		||||
GBinderServicePoll*
 | 
			
		||||
gbinder_servicepoll_new(
 | 
			
		||||
    GBinderServiceManager* manager,
 | 
			
		||||
    GBinderServicePoll** weakptr);
 | 
			
		||||
 | 
			
		||||
GBinderServicePoll*
 | 
			
		||||
gbinder_servicepoll_ref(
 | 
			
		||||
    GBinderServicePoll* poll);
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
gbinder_servicepoll_unref(
 | 
			
		||||
    GBinderServicePoll* poll);
 | 
			
		||||
 | 
			
		||||
GBinderServiceManager*
 | 
			
		||||
gbinder_servicepoll_manager(
 | 
			
		||||
    GBinderServicePoll* poll);
 | 
			
		||||
 | 
			
		||||
gboolean
 | 
			
		||||
gbinder_servicepoll_is_known_name(
 | 
			
		||||
    GBinderServicePoll* poll,
 | 
			
		||||
    const char* name);
 | 
			
		||||
 | 
			
		||||
gulong
 | 
			
		||||
gbinder_servicepoll_add_handler(
 | 
			
		||||
    GBinderServicePoll* poll,
 | 
			
		||||
    GBinderServicePollFunc func,
 | 
			
		||||
    void* user_data);
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
gbinder_servicepoll_remove_handler(
 | 
			
		||||
    GBinderServicePoll* poll,
 | 
			
		||||
    gulong id);
 | 
			
		||||
 | 
			
		||||
#endif /* GBINDER_SERVICEPOLL_H */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Local Variables:
 | 
			
		||||
 * mode: C
 | 
			
		||||
 * c-basic-offset: 4
 | 
			
		||||
 * indent-tabs-mode: nil
 | 
			
		||||
 * End:
 | 
			
		||||
 */
 | 
			
		||||
@@ -44,6 +44,7 @@ typedef struct gbinder_ipc GBinderIpc;
 | 
			
		||||
typedef struct gbinder_object_registry GBinderObjectRegistry;
 | 
			
		||||
typedef struct gbinder_output_data GBinderOutputData;
 | 
			
		||||
typedef struct gbinder_rpc_protocol GBinderRpcProtocol;
 | 
			
		||||
typedef struct gbinder_servicepoll GBinderServicePoll;
 | 
			
		||||
 | 
			
		||||
typedef struct hidl_vec {
 | 
			
		||||
    union {
 | 
			
		||||
 
 | 
			
		||||
@@ -15,6 +15,7 @@ all:
 | 
			
		||||
	@$(MAKE) -C unit_remote_reply $*
 | 
			
		||||
	@$(MAKE) -C unit_remote_request $*
 | 
			
		||||
	@$(MAKE) -C unit_servicemanager $*
 | 
			
		||||
	@$(MAKE) -C unit_servicepoll $*
 | 
			
		||||
	@$(MAKE) -C unit_writer $*
 | 
			
		||||
 | 
			
		||||
clean: unitclean
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,7 @@ unit_remote_object \
 | 
			
		||||
unit_remote_reply \
 | 
			
		||||
unit_remote_request \
 | 
			
		||||
unit_servicemanager \
 | 
			
		||||
unit_servicepoll \
 | 
			
		||||
unit_writer"
 | 
			
		||||
 | 
			
		||||
function err() {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								unit/unit_servicepoll/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								unit/unit_servicepoll/Makefile
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
# -*- Mode: makefile-gmake -*-
 | 
			
		||||
 | 
			
		||||
EXE = unit_servicepoll
 | 
			
		||||
 | 
			
		||||
include ../common/Makefile
 | 
			
		||||
							
								
								
									
										448
									
								
								unit/unit_servicepoll/unit_servicepoll.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										448
									
								
								unit/unit_servicepoll/unit_servicepoll.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,448 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2018 Jolla Ltd.
 | 
			
		||||
 * Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
 | 
			
		||||
 *
 | 
			
		||||
 * You may use this file under the terms of BSD license as follows:
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions
 | 
			
		||||
 * are met:
 | 
			
		||||
 *
 | 
			
		||||
 *   1. Redistributions of source code must retain the above copyright
 | 
			
		||||
 *      notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 *   2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
 *      notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *      documentation and/or other materials provided with the distribution.
 | 
			
		||||
 *   3. Neither the names of the copyright holders nor the names of its
 | 
			
		||||
 *      contributors may be used to endorse or promote products derived
 | 
			
		||||
 *      from this software without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | 
			
		||||
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
 | 
			
		||||
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | 
			
		||||
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 | 
			
		||||
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 | 
			
		||||
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 | 
			
		||||
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 | 
			
		||||
 * THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "test_common.h"
 | 
			
		||||
 | 
			
		||||
#include "gbinder_servicemanager_p.h"
 | 
			
		||||
#include "gbinder_servicepoll.h"
 | 
			
		||||
#include "gbinder_rpc_protocol.h"
 | 
			
		||||
 | 
			
		||||
#include <gutil_strv.h>
 | 
			
		||||
#include <gutil_log.h>
 | 
			
		||||
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
 | 
			
		||||
static TestOpt test_opt;
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * TestServiceManager
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
 | 
			
		||||
typedef GBinderServiceManagerClass TestServiceManagerClass;
 | 
			
		||||
typedef struct test_servicemanager {
 | 
			
		||||
    GBinderServiceManager manager;
 | 
			
		||||
    GMutex mutex;
 | 
			
		||||
    char** services;
 | 
			
		||||
} TestServiceManager;
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE(TestServiceManager, test_servicemanager,
 | 
			
		||||
    GBINDER_TYPE_SERVICEMANAGER)
 | 
			
		||||
 | 
			
		||||
#define TEST_SERVICEMANAGER_HANDLE (0)
 | 
			
		||||
#define TEST_SERVICEMANAGER_IFACE "android.os.IServiceManager"
 | 
			
		||||
#define TEST_TYPE_SERVICEMANAGER (test_servicemanager_get_type())
 | 
			
		||||
#define TEST_SERVICEMANAGER(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), \
 | 
			
		||||
    TEST_TYPE_SERVICEMANAGER, TestServiceManager)
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
char**
 | 
			
		||||
test_servicemanager_list(
 | 
			
		||||
    GBinderServiceManager* manager)
 | 
			
		||||
{
 | 
			
		||||
    char** ret;
 | 
			
		||||
    TestServiceManager* self = TEST_SERVICEMANAGER(manager);
 | 
			
		||||
 | 
			
		||||
    g_mutex_lock(&self->mutex);
 | 
			
		||||
    ret = g_strdupv(self->services);
 | 
			
		||||
    GDEBUG("%u", gutil_strv_length(ret));
 | 
			
		||||
    g_mutex_unlock(&self->mutex);
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
GBinderRemoteObject*
 | 
			
		||||
test_servicemanager_get_service(
 | 
			
		||||
    GBinderServiceManager* manager,
 | 
			
		||||
    const char* name,
 | 
			
		||||
    int* status)
 | 
			
		||||
{
 | 
			
		||||
    *status = (-ENOENT);
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
int
 | 
			
		||||
test_servicemanager_add_service(
 | 
			
		||||
    GBinderServiceManager* manager,
 | 
			
		||||
    const char* name,
 | 
			
		||||
    GBinderLocalObject* obj)
 | 
			
		||||
{
 | 
			
		||||
    TestServiceManager* self = TEST_SERVICEMANAGER(manager);
 | 
			
		||||
 | 
			
		||||
    g_mutex_lock(&self->mutex);
 | 
			
		||||
    if (!gutil_strv_contains(self->services, name)) {
 | 
			
		||||
        self->services = gutil_strv_add(self->services, name);
 | 
			
		||||
    }
 | 
			
		||||
    g_mutex_unlock(&self->mutex);
 | 
			
		||||
    return GBINDER_STATUS_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
GBINDER_SERVICEMANAGER_NAME_CHECK
 | 
			
		||||
test_servicemanager_check_name(
 | 
			
		||||
    GBinderServiceManager* manager,
 | 
			
		||||
    const char* name)
 | 
			
		||||
{
 | 
			
		||||
    return name ?
 | 
			
		||||
        GBINDER_SERVICEMANAGER_NAME_INVALID :
 | 
			
		||||
        GBINDER_SERVICEMANAGER_NAME_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
gboolean
 | 
			
		||||
test_servicemanager_watch(
 | 
			
		||||
    GBinderServiceManager* manager,
 | 
			
		||||
    const char* name)
 | 
			
		||||
{
 | 
			
		||||
    return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
test_servicemanager_unwatch(
 | 
			
		||||
    GBinderServiceManager* manager,
 | 
			
		||||
    const char* name)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
test_servicemanager_init(
 | 
			
		||||
    TestServiceManager* self)
 | 
			
		||||
{
 | 
			
		||||
    g_mutex_init(&self->mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
test_servicemanager_finalize(
 | 
			
		||||
    GObject* object)
 | 
			
		||||
{
 | 
			
		||||
    TestServiceManager* self = TEST_SERVICEMANAGER(object);
 | 
			
		||||
 | 
			
		||||
    g_mutex_clear(&self->mutex);
 | 
			
		||||
    g_strfreev(self->services);
 | 
			
		||||
    G_OBJECT_CLASS(test_servicemanager_parent_class)->finalize(object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
test_servicemanager_class_init(
 | 
			
		||||
    TestServiceManagerClass* klass)
 | 
			
		||||
{
 | 
			
		||||
    klass->handle = TEST_SERVICEMANAGER_HANDLE;
 | 
			
		||||
    klass->iface = TEST_SERVICEMANAGER_IFACE;
 | 
			
		||||
    klass->default_device = GBINDER_DEFAULT_HWBINDER;
 | 
			
		||||
    klass->rpc_protocol = &gbinder_rpc_protocol_binder;
 | 
			
		||||
    klass->list = test_servicemanager_list;
 | 
			
		||||
    klass->get_service = test_servicemanager_get_service;
 | 
			
		||||
    klass->add_service = test_servicemanager_add_service;
 | 
			
		||||
    klass->check_name = test_servicemanager_check_name;
 | 
			
		||||
    klass->watch = test_servicemanager_watch;
 | 
			
		||||
    klass->unwatch = test_servicemanager_unwatch;
 | 
			
		||||
    G_OBJECT_CLASS(klass)->finalize = test_servicemanager_finalize;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GBinderServiceManager*
 | 
			
		||||
gbinder_defaultservicemanager_new(
 | 
			
		||||
    const char* dev)
 | 
			
		||||
{
 | 
			
		||||
    return gbinder_servicemanager_new_with_type(TEST_TYPE_SERVICEMANAGER, dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GBinderServiceManager*
 | 
			
		||||
gbinder_hwservicemanager_new(
 | 
			
		||||
    const char* dev)
 | 
			
		||||
{
 | 
			
		||||
    return gbinder_servicemanager_new(dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * null
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
test_null(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    g_assert(!gbinder_servicepoll_ref(NULL));
 | 
			
		||||
    g_assert(!gbinder_servicepoll_manager(NULL));
 | 
			
		||||
    g_assert(!gbinder_servicepoll_is_known_name(NULL, ""));
 | 
			
		||||
    g_assert(!gbinder_servicepoll_add_handler(NULL, NULL, NULL));
 | 
			
		||||
    gbinder_servicepoll_remove_handler(NULL, 0);
 | 
			
		||||
    gbinder_servicepoll_unref(NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * basic
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
test_basic(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    GBinderServicePoll* weakptr = NULL;
 | 
			
		||||
    GBinderServiceManager* manager = gbinder_servicemanager_new(NULL);
 | 
			
		||||
    GBinderServicePoll* poll = gbinder_servicepoll_new(manager, NULL);
 | 
			
		||||
 | 
			
		||||
    g_assert(poll);
 | 
			
		||||
    g_assert(gbinder_servicepoll_manager(poll) == manager);
 | 
			
		||||
    g_assert(!gbinder_servicepoll_is_known_name(poll, "foo"));
 | 
			
		||||
    g_assert(!gbinder_servicepoll_add_handler(poll, NULL, NULL));
 | 
			
		||||
    gbinder_servicepoll_remove_handler(poll, 0); /* this does nothing */
 | 
			
		||||
    gbinder_servicepoll_unref(poll);
 | 
			
		||||
 | 
			
		||||
    poll = gbinder_servicepoll_new(manager, &weakptr);
 | 
			
		||||
    g_assert(poll == weakptr);
 | 
			
		||||
    g_assert(poll == gbinder_servicepoll_new(manager, &weakptr));
 | 
			
		||||
    gbinder_servicepoll_unref(poll);
 | 
			
		||||
    gbinder_servicepoll_unref(poll);
 | 
			
		||||
 | 
			
		||||
    gbinder_servicemanager_unref(manager);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * notify1
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
test_notify_proc(
 | 
			
		||||
    GBinderServicePoll* poll,
 | 
			
		||||
    const char* name_added,
 | 
			
		||||
    void* user_data)
 | 
			
		||||
{
 | 
			
		||||
    GDEBUG("\"%s\" added", name_added);
 | 
			
		||||
    if (!g_strcmp0(name_added, "foo")) {
 | 
			
		||||
        test_quit_later((GMainLoop*)user_data);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
gboolean
 | 
			
		||||
test_notify1_foo(
 | 
			
		||||
    gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    TestServiceManager* test = user_data;
 | 
			
		||||
 | 
			
		||||
    g_mutex_lock(&test->mutex);
 | 
			
		||||
    GDEBUG("adding \"foo\"");
 | 
			
		||||
    test->services = gutil_strv_add(test->services, "foo");
 | 
			
		||||
    g_mutex_unlock(&test->mutex);
 | 
			
		||||
    return G_SOURCE_REMOVE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
gboolean
 | 
			
		||||
test_notify1_bar(
 | 
			
		||||
    gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    TestServiceManager* test = user_data;
 | 
			
		||||
 | 
			
		||||
    g_mutex_lock(&test->mutex);
 | 
			
		||||
    GDEBUG("adding \"bar\"");
 | 
			
		||||
    test->services = gutil_strv_add(test->services, "bar");
 | 
			
		||||
    g_mutex_unlock(&test->mutex);
 | 
			
		||||
    return G_SOURCE_REMOVE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
test_notify1(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    GBinderServicePoll* weakptr = NULL;
 | 
			
		||||
    GBinderServiceManager* manager = gbinder_servicemanager_new(NULL);
 | 
			
		||||
    TestServiceManager* test = TEST_SERVICEMANAGER(manager);
 | 
			
		||||
    GMainLoop* loop = g_main_loop_new(NULL, FALSE);
 | 
			
		||||
    GBinderServicePoll* poll;
 | 
			
		||||
    gulong id;
 | 
			
		||||
 | 
			
		||||
    gbinder_servicepoll_interval_ms = 100;
 | 
			
		||||
    poll = gbinder_servicepoll_new(manager, &weakptr);
 | 
			
		||||
    g_timeout_add(2 * gbinder_servicepoll_interval_ms,
 | 
			
		||||
        test_notify1_bar, test);
 | 
			
		||||
    g_timeout_add(4 * gbinder_servicepoll_interval_ms,
 | 
			
		||||
        test_notify1_foo, test);
 | 
			
		||||
 | 
			
		||||
    id = gbinder_servicepoll_add_handler(poll, test_notify_proc, loop);
 | 
			
		||||
    g_assert(id);
 | 
			
		||||
 | 
			
		||||
    test_run(&test_opt, loop);
 | 
			
		||||
 | 
			
		||||
    g_assert(gbinder_servicepoll_is_known_name(poll, "foo"));
 | 
			
		||||
    g_assert(gbinder_servicepoll_is_known_name(poll, "bar"));
 | 
			
		||||
    gbinder_servicepoll_remove_handler(poll, id);
 | 
			
		||||
    gbinder_servicepoll_unref(poll);
 | 
			
		||||
    g_assert(!weakptr);
 | 
			
		||||
    gbinder_servicemanager_unref(manager);
 | 
			
		||||
    g_main_loop_unref(loop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * notify2
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
gboolean
 | 
			
		||||
test_notify2_foo(
 | 
			
		||||
    gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    TestServiceManager* test = user_data;
 | 
			
		||||
 | 
			
		||||
    g_mutex_lock(&test->mutex);
 | 
			
		||||
    GDEBUG("services = [\"bar\",\"foo\"]");
 | 
			
		||||
    g_strfreev(test->services);
 | 
			
		||||
    test->services = g_strsplit("bar,bar3,foo", ",", -1);
 | 
			
		||||
    g_mutex_unlock(&test->mutex);
 | 
			
		||||
    return G_SOURCE_REMOVE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
gboolean
 | 
			
		||||
test_notify2_bar(
 | 
			
		||||
    gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    TestServiceManager* test = user_data;
 | 
			
		||||
 | 
			
		||||
    g_mutex_lock(&test->mutex);
 | 
			
		||||
    GDEBUG("services = [\"bar1\",\"bar2\",\"bar3\"]");
 | 
			
		||||
    g_strfreev(test->services);
 | 
			
		||||
    test->services = g_strsplit("bar1,bar2,bar3", ",", -1);
 | 
			
		||||
    g_mutex_unlock(&test->mutex);
 | 
			
		||||
    return G_SOURCE_REMOVE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
test_notify2(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    GBinderServicePoll* weakptr = NULL;
 | 
			
		||||
    GBinderServiceManager* manager = gbinder_servicemanager_new(NULL);
 | 
			
		||||
    TestServiceManager* test = TEST_SERVICEMANAGER(manager);
 | 
			
		||||
    GMainLoop* loop = g_main_loop_new(NULL, FALSE);
 | 
			
		||||
    GBinderServicePoll* poll;
 | 
			
		||||
    gulong id;
 | 
			
		||||
 | 
			
		||||
    gbinder_servicepoll_interval_ms = 100;
 | 
			
		||||
    poll = gbinder_servicepoll_new(manager, &weakptr);
 | 
			
		||||
    g_timeout_add(2 * gbinder_servicepoll_interval_ms,
 | 
			
		||||
        test_notify2_bar, test);
 | 
			
		||||
    g_timeout_add(4 * gbinder_servicepoll_interval_ms,
 | 
			
		||||
        test_notify2_foo, test);
 | 
			
		||||
 | 
			
		||||
    /* Reusing test_notify_proc */
 | 
			
		||||
    id = gbinder_servicepoll_add_handler(poll, test_notify_proc, loop);
 | 
			
		||||
    g_assert(id);
 | 
			
		||||
 | 
			
		||||
    test_run(&test_opt, loop);
 | 
			
		||||
 | 
			
		||||
    g_assert(gbinder_servicepoll_is_known_name(poll, "foo"));
 | 
			
		||||
    g_assert(gbinder_servicepoll_is_known_name(poll, "bar"));
 | 
			
		||||
    g_assert(gbinder_servicepoll_is_known_name(poll, "bar3"));
 | 
			
		||||
    g_assert(!gbinder_servicepoll_is_known_name(poll, "bar1"));
 | 
			
		||||
    g_assert(!gbinder_servicepoll_is_known_name(poll, "bar2"));
 | 
			
		||||
    gbinder_servicepoll_remove_handler(poll, id);
 | 
			
		||||
    gbinder_servicepoll_unref(poll);
 | 
			
		||||
    g_assert(!weakptr);
 | 
			
		||||
    gbinder_servicemanager_unref(manager);
 | 
			
		||||
    g_main_loop_unref(loop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * already_there
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
test_already_there_proc(
 | 
			
		||||
    GBinderServicePoll* poll,
 | 
			
		||||
    const char* name_added,
 | 
			
		||||
    void* user_data)
 | 
			
		||||
{
 | 
			
		||||
    g_assert(!g_strcmp0(name_added, "foo"));
 | 
			
		||||
    test_quit_later((GMainLoop*)user_data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
test_already_there(
 | 
			
		||||
    void)
 | 
			
		||||
{
 | 
			
		||||
    GBinderServicePoll* weakptr = NULL;
 | 
			
		||||
    GBinderServiceManager* manager = gbinder_servicemanager_new(NULL);
 | 
			
		||||
    GBinderServicePoll* poll = gbinder_servicepoll_new(manager, &weakptr);
 | 
			
		||||
    TestServiceManager* test = TEST_SERVICEMANAGER(manager);
 | 
			
		||||
    GMainLoop* loop = g_main_loop_new(NULL, FALSE);
 | 
			
		||||
    gulong id;
 | 
			
		||||
 | 
			
		||||
    test->services = gutil_strv_add(test->services, "foo");
 | 
			
		||||
    id = gbinder_servicepoll_add_handler(poll, test_already_there_proc, loop);
 | 
			
		||||
 | 
			
		||||
    g_assert(id);
 | 
			
		||||
    test_run(&test_opt, loop);
 | 
			
		||||
 | 
			
		||||
    gbinder_servicepoll_remove_handler(poll, id);
 | 
			
		||||
    gbinder_servicepoll_unref(poll);
 | 
			
		||||
    g_assert(!weakptr);
 | 
			
		||||
    gbinder_servicemanager_unref(manager);
 | 
			
		||||
    g_main_loop_unref(loop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * Common
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
 | 
			
		||||
#define TEST_(t) "/servicepoll/" t
 | 
			
		||||
 | 
			
		||||
int main(int argc, char* argv[])
 | 
			
		||||
{
 | 
			
		||||
    g_test_init(&argc, &argv, NULL);
 | 
			
		||||
    g_test_add_func(TEST_("null"), test_null);
 | 
			
		||||
    g_test_add_func(TEST_("basic"), test_basic);
 | 
			
		||||
    g_test_add_func(TEST_("notify1"), test_notify1);
 | 
			
		||||
    g_test_add_func(TEST_("notify2"), test_notify2);
 | 
			
		||||
    g_test_add_func(TEST_("already_there"), test_already_there);
 | 
			
		||||
    test_init(&test_opt, argc, argv);
 | 
			
		||||
    return g_test_run();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Local Variables:
 | 
			
		||||
 * mode: C
 | 
			
		||||
 * c-basic-offset: 4
 | 
			
		||||
 * indent-tabs-mode: nil
 | 
			
		||||
 * End:
 | 
			
		||||
 */
 | 
			
		||||
		Reference in New Issue
	
	Block a user