Compare commits
	
		
			5 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					e196c66264 | ||
| 
						 | 
					8f62f4d65c | ||
| 
						 | 
					8583a72d11 | ||
| 
						 | 
					381446eb4f | ||
| 
						 | 
					eabf5683f4 | 
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							@@ -16,7 +16,7 @@
 | 
			
		||||
 | 
			
		||||
VERSION_MAJOR = 1
 | 
			
		||||
VERSION_MINOR = 1
 | 
			
		||||
VERSION_RELEASE = 17
 | 
			
		||||
VERSION_RELEASE = 18
 | 
			
		||||
 | 
			
		||||
# Version for pkg-config
 | 
			
		||||
PCVERSION = $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_RELEASE)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										6
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							@@ -1,3 +1,9 @@
 | 
			
		||||
libgbinder (1.1.18) unstable; urgency=low
 | 
			
		||||
 | 
			
		||||
  * Disassociate auto-created proxies to stop them from piling up
 | 
			
		||||
 | 
			
		||||
 -- Slava Monich <slava.monich@jolla.com>  Sat, 08 Jan 2022 15:35:56 +0200
 | 
			
		||||
 | 
			
		||||
libgbinder (1.1.17) unstable; urgency=low
 | 
			
		||||
 | 
			
		||||
  * Don't release remote proxy handle too early (sometimes hever)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
Name: libgbinder
 | 
			
		||||
 | 
			
		||||
Version: 1.1.17
 | 
			
		||||
Version: 1.1.18
 | 
			
		||||
Release: 0
 | 
			
		||||
Summary: Binder client library
 | 
			
		||||
License: BSD
 | 
			
		||||
 
 | 
			
		||||
@@ -82,6 +82,7 @@ struct gbinder_driver {
 | 
			
		||||
    void* vm;
 | 
			
		||||
    gsize vmsize;
 | 
			
		||||
    char* dev;
 | 
			
		||||
    const char* name;
 | 
			
		||||
    const GBinderIo* io;
 | 
			
		||||
    const GBinderRpcProtocol* protocol;
 | 
			
		||||
};
 | 
			
		||||
@@ -565,7 +566,8 @@ gbinder_driver_handle_transaction(
 | 
			
		||||
                tx.flags, &txstatus);
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        GWARN("Unhandled transaction %s 0x%08x", iface, tx.code);
 | 
			
		||||
        GWARN("Unhandled transaction %s 0x%08x from %s", iface, tx.code,
 | 
			
		||||
            self->name);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -895,6 +897,9 @@ gbinder_driver_new(
 | 
			
		||||
                    self->vm = vm;
 | 
			
		||||
                    self->vmsize = vmsize;
 | 
			
		||||
                    self->dev = g_strdup(dev);
 | 
			
		||||
                    self->name = self->dev + /* Shorter version for logging */
 | 
			
		||||
                        (g_str_has_prefix(self->dev, "/dev/") ? 5 : 0);
 | 
			
		||||
 | 
			
		||||
                    if (gbinder_system_ioctl(fd, BINDER_SET_MAX_THREADS,
 | 
			
		||||
                        &max_threads) < 0) {
 | 
			
		||||
                        GERR("%s failed to set max threads (%u): %s", dev,
 | 
			
		||||
 
 | 
			
		||||
@@ -207,9 +207,6 @@ typedef struct gbinder_ipc_tx_custom {
 | 
			
		||||
    GDestroyNotify fn_custom_destroy;
 | 
			
		||||
} GBinderIpcTxCustom;
 | 
			
		||||
 | 
			
		||||
GBINDER_INLINE_FUNC const char* gbinder_ipc_name(GBinderIpc* self)
 | 
			
		||||
    { return self->priv->name; }
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
GBinderIpcLooper*
 | 
			
		||||
gbinder_ipc_looper_new(
 | 
			
		||||
@@ -1298,10 +1295,10 @@ gbinder_ipc_priv_get_local_object(
 | 
			
		||||
            if (obj) {
 | 
			
		||||
                gbinder_local_object_ref(obj);
 | 
			
		||||
            } else {
 | 
			
		||||
                GWARN("Unknown local object %p", pointer);
 | 
			
		||||
                GWARN("Unknown local object %p %s", pointer, priv->name);
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            GWARN("Unknown local object %p", pointer);
 | 
			
		||||
            GWARN("Unknown local object %p %s", pointer, priv->name);
 | 
			
		||||
        }
 | 
			
		||||
        g_mutex_unlock(&priv->local_objects_mutex);
 | 
			
		||||
        /* Unlock */
 | 
			
		||||
@@ -1345,6 +1342,8 @@ gbinder_ipc_priv_get_remote_object(
 | 
			
		||||
        }
 | 
			
		||||
        GVERBOSE_("%p handle %u %s", obj, handle, gbinder_ipc_name(self));
 | 
			
		||||
        g_hash_table_replace(priv->remote_objects, key, obj);
 | 
			
		||||
    } else {
 | 
			
		||||
        GWARN("Unknown handle %u %s", handle, priv->name);
 | 
			
		||||
    }
 | 
			
		||||
    g_mutex_unlock(&priv->remote_objects_mutex);
 | 
			
		||||
    /* Unlock */
 | 
			
		||||
@@ -1904,6 +1903,13 @@ gbinder_ipc_unref(
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char*
 | 
			
		||||
gbinder_ipc_name(
 | 
			
		||||
    GBinderIpc* self)
 | 
			
		||||
{
 | 
			
		||||
    return G_LIKELY(self) ? self->priv->name : NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GBinderObjectRegistry*
 | 
			
		||||
gbinder_ipc_object_registry(
 | 
			
		||||
    GBinderIpc* self)
 | 
			
		||||
 
 | 
			
		||||
@@ -113,6 +113,11 @@ gbinder_ipc_unref(
 | 
			
		||||
    GBinderIpc* ipc)
 | 
			
		||||
    GBINDER_INTERNAL;
 | 
			
		||||
 | 
			
		||||
const char*
 | 
			
		||||
gbinder_ipc_name(
 | 
			
		||||
    GBinderIpc* ipc)
 | 
			
		||||
    GBINDER_INTERNAL;
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
gbinder_ipc_looper_check(
 | 
			
		||||
    GBinderIpc* ipc)
 | 
			
		||||
 
 | 
			
		||||
@@ -60,12 +60,9 @@ struct gbinder_proxy_tx {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct gbinder_proxy_object_priv {
 | 
			
		||||
    gulong remote_death_id;
 | 
			
		||||
    gboolean acquired;
 | 
			
		||||
    gboolean dropped;
 | 
			
		||||
    GBinderProxyTx* tx;
 | 
			
		||||
    GMutex mutex; /* Protects the hashtable below */
 | 
			
		||||
    GHashTable* subproxies;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
G_DEFINE_TYPE(GBinderProxyObject, gbinder_proxy_object, \
 | 
			
		||||
@@ -77,79 +74,12 @@ G_DEFINE_TYPE(GBinderProxyObject, gbinder_proxy_object, \
 | 
			
		||||
#define THIS_TYPE GBINDER_TYPE_PROXY_OBJECT
 | 
			
		||||
#define PARENT_CLASS gbinder_proxy_object_parent_class
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
gbinder_proxy_object_subproxy_gone(
 | 
			
		||||
    gpointer proxy,
 | 
			
		||||
    GObject* subproxy)
 | 
			
		||||
{
 | 
			
		||||
    GBinderProxyObject* self = THIS(proxy);
 | 
			
		||||
    GBinderProxyObjectPriv* priv = self->priv;
 | 
			
		||||
 | 
			
		||||
    /* Lock */
 | 
			
		||||
    g_mutex_lock(&priv->mutex);
 | 
			
		||||
    g_hash_table_remove(priv->subproxies, subproxy);
 | 
			
		||||
    if (g_hash_table_size(priv->subproxies) == 0) {
 | 
			
		||||
        g_hash_table_unref(priv->subproxies);
 | 
			
		||||
        priv->subproxies = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    g_mutex_unlock(&priv->mutex);
 | 
			
		||||
    /* Unlock */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
gbinder_proxy_object_drop_subproxies(
 | 
			
		||||
    GBinderProxyObject* self)
 | 
			
		||||
{
 | 
			
		||||
    GBinderProxyObjectPriv* priv = self->priv;
 | 
			
		||||
    GSList* list = NULL;
 | 
			
		||||
 | 
			
		||||
    /* Lock */
 | 
			
		||||
    g_mutex_lock(&priv->mutex);
 | 
			
		||||
    if (priv->subproxies) {
 | 
			
		||||
        GHashTableIter it;
 | 
			
		||||
        gpointer value;
 | 
			
		||||
 | 
			
		||||
        g_hash_table_iter_init(&it, priv->subproxies);
 | 
			
		||||
        while (g_hash_table_iter_next(&it, NULL, &value)) {
 | 
			
		||||
            list = g_slist_append(list, gbinder_local_object_ref(value));
 | 
			
		||||
            g_object_weak_unref(G_OBJECT(value),
 | 
			
		||||
                gbinder_proxy_object_subproxy_gone, self);
 | 
			
		||||
        }
 | 
			
		||||
        g_hash_table_destroy(priv->subproxies);
 | 
			
		||||
        priv->subproxies = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    g_mutex_unlock(&priv->mutex);
 | 
			
		||||
    /* Unlock */
 | 
			
		||||
 | 
			
		||||
    /* Drop (and possibly destroy) the objects outside of the lock */
 | 
			
		||||
    g_slist_free_full(list, (GDestroyNotify) gbinder_local_object_drop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
gbinder_proxy_remote_death_proc(
 | 
			
		||||
    GBinderRemoteObject* obj,
 | 
			
		||||
    void* proxy)
 | 
			
		||||
{
 | 
			
		||||
    GBinderProxyObject* self = THIS(proxy);
 | 
			
		||||
    GBinderProxyObjectPriv* priv = self->priv;
 | 
			
		||||
 | 
			
		||||
    GDEBUG("Remote object %u died on %s", obj->handle, obj->ipc->dev);
 | 
			
		||||
    gbinder_remote_object_remove_handler(obj, priv->remote_death_id);
 | 
			
		||||
    priv->remote_death_id = 0;
 | 
			
		||||
    /* Drop the implicit reference */
 | 
			
		||||
    gbinder_local_object_unref(&self->parent);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
 * Converter
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
 | 
			
		||||
typedef struct gbinder_proxy_object_converter {
 | 
			
		||||
    GBinderObjectConverter pub;
 | 
			
		||||
    GBinderProxyObject* proxy;
 | 
			
		||||
    GBinderIpc* remote;
 | 
			
		||||
    GBinderIpc* local;
 | 
			
		||||
} GBinderProxyObjectConverter;
 | 
			
		||||
@@ -183,8 +113,6 @@ gbinder_proxy_object_converter_handle_to_local(
 | 
			
		||||
    guint32 handle)
 | 
			
		||||
{
 | 
			
		||||
    GBinderProxyObjectConverter* c = gbinder_proxy_object_converter_cast(pub);
 | 
			
		||||
    GBinderProxyObject* proxy = c->proxy;
 | 
			
		||||
    GBinderProxyObjectPriv* priv = proxy->priv;
 | 
			
		||||
    GBinderObjectRegistry* reg = gbinder_ipc_object_registry(c->remote);
 | 
			
		||||
    GBinderRemoteObject* remote = gbinder_object_registry_get_remote(reg,
 | 
			
		||||
        handle, REMOTE_REGISTRY_CAN_CREATE /* but don't acquire */);
 | 
			
		||||
@@ -193,32 +121,7 @@ gbinder_proxy_object_converter_handle_to_local(
 | 
			
		||||
 | 
			
		||||
    if (!local && !remote->dead) {
 | 
			
		||||
        /* GBinderProxyObject will reference GBinderRemoteObject */
 | 
			
		||||
        GBinderProxyObject* subp = gbinder_proxy_object_new(c->local, remote);
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
         * Auto-created proxies may get spontaneously destroyed and
 | 
			
		||||
         * not necessarily on the UI thread.
 | 
			
		||||
         */
 | 
			
		||||
        subp->priv->remote_death_id = gbinder_remote_object_add_death_handler
 | 
			
		||||
            (remote, gbinder_proxy_remote_death_proc, subp);
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
         * Remote keeps an implicit reference to this auto-created
 | 
			
		||||
         * proxy. The reference gets released when the remote object
 | 
			
		||||
         * dies, i.e. by gbinder_proxy_remote_death_proc().
 | 
			
		||||
         */
 | 
			
		||||
        gbinder_local_object_ref(local = GBINDER_LOCAL_OBJECT(subp));
 | 
			
		||||
 | 
			
		||||
        /* Lock */
 | 
			
		||||
        g_mutex_lock(&priv->mutex);
 | 
			
		||||
        if (!priv->subproxies) {
 | 
			
		||||
            priv->subproxies = g_hash_table_new(g_direct_hash, g_direct_equal);
 | 
			
		||||
        }
 | 
			
		||||
        g_hash_table_insert(priv->subproxies, subp, subp);
 | 
			
		||||
        g_object_weak_ref(G_OBJECT(subp),
 | 
			
		||||
            gbinder_proxy_object_subproxy_gone, proxy);
 | 
			
		||||
        g_mutex_unlock(&priv->mutex);
 | 
			
		||||
        /* Unlock */
 | 
			
		||||
        local = &gbinder_proxy_object_new(c->local, remote)->parent;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Release the reference returned by gbinder_object_registry_get_remote */
 | 
			
		||||
@@ -242,7 +145,6 @@ gbinder_proxy_object_converter_init(
 | 
			
		||||
    GBinderIpc* dest = proxy->parent.ipc;
 | 
			
		||||
 | 
			
		||||
    memset(convert, 0, sizeof(*convert));
 | 
			
		||||
    convert->proxy = proxy;
 | 
			
		||||
    convert->remote = remote;
 | 
			
		||||
    convert->local = local;
 | 
			
		||||
    pub->f = &gbinder_converter_fn;
 | 
			
		||||
@@ -347,7 +249,7 @@ gbinder_proxy_object_handle_transaction(
 | 
			
		||||
    GBinderProxyObjectPriv* priv = self->priv;
 | 
			
		||||
    GBinderRemoteObject* remote = self->remote;
 | 
			
		||||
 | 
			
		||||
    if (!priv->dropped && !gbinder_remote_object_is_dead(remote)) {
 | 
			
		||||
    if (!priv->dropped && !remote->dead) {
 | 
			
		||||
        GBinderLocalRequest* fwd;
 | 
			
		||||
        GBinderProxyTx* tx = g_slice_new0(GBinderProxyTx);
 | 
			
		||||
        GBinderProxyObjectConverter convert;
 | 
			
		||||
@@ -375,6 +277,7 @@ gbinder_proxy_object_handle_transaction(
 | 
			
		||||
        gbinder_local_request_unref(fwd);
 | 
			
		||||
        *status = GBINDER_STATUS_OK;
 | 
			
		||||
    } else {
 | 
			
		||||
        GVERBOSE_("dropped: %d dead:%d", priv->dropped, remote->dead);
 | 
			
		||||
        *status = (-EBADMSG);
 | 
			
		||||
    }
 | 
			
		||||
    return NULL;
 | 
			
		||||
@@ -398,10 +301,9 @@ gbinder_proxy_object_acquire(
 | 
			
		||||
{
 | 
			
		||||
    GBinderProxyObject* self = THIS(object);
 | 
			
		||||
    GBinderProxyObjectPriv* priv = self->priv;
 | 
			
		||||
    GBinderRemoteObject* remote = self->remote;
 | 
			
		||||
 | 
			
		||||
    if (priv->remote_death_id && !priv->dropped && !priv->acquired) {
 | 
			
		||||
        GBinderRemoteObject* remote = self->remote;
 | 
			
		||||
 | 
			
		||||
    if (!remote->dead && !priv->dropped && !priv->acquired) {
 | 
			
		||||
        /* Not acquired yet */
 | 
			
		||||
        priv->acquired = TRUE;
 | 
			
		||||
        gbinder_driver_acquire(remote->ipc->driver, remote->handle);
 | 
			
		||||
@@ -418,7 +320,6 @@ gbinder_proxy_object_drop(
 | 
			
		||||
    GBinderProxyObjectPriv* priv = self->priv;
 | 
			
		||||
 | 
			
		||||
    priv->dropped = TRUE;
 | 
			
		||||
    gbinder_proxy_object_drop_subproxies(self);
 | 
			
		||||
    GBINDER_LOCAL_OBJECT_CLASS(PARENT_CLASS)->drop(object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -444,6 +345,8 @@ gbinder_proxy_object_new(
 | 
			
		||||
        if (object) {
 | 
			
		||||
            GBinderProxyObject* self = THIS(object);
 | 
			
		||||
 | 
			
		||||
            GDEBUG("Proxy %p %s => %u %s created", self, gbinder_ipc_name(src),
 | 
			
		||||
                remote->handle, gbinder_ipc_name(remote->ipc));
 | 
			
		||||
            self->remote = gbinder_remote_object_ref(remote);
 | 
			
		||||
            return self;
 | 
			
		||||
        }
 | 
			
		||||
@@ -462,15 +365,25 @@ gbinder_proxy_object_finalize(
 | 
			
		||||
{
 | 
			
		||||
    GBinderProxyObject* self = THIS(object);
 | 
			
		||||
    GBinderProxyObjectPriv* priv = self->priv;
 | 
			
		||||
    GBinderLocalObject* local = &self->parent;
 | 
			
		||||
    GBinderRemoteObject* remote = self->remote;
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * gbinder_local_object_finalize() will also try to do the same thing
 | 
			
		||||
     * i.e. invalidate self but proxy objects need to do it before releasing
 | 
			
		||||
     * the handle, to leave no room for race conditions. That's not very good
 | 
			
		||||
     * because it grabs ipc-wide mutex but shouldn'd have much of an impact
 | 
			
		||||
     * on the performance because finalizing a proxy is not supposed to be a
 | 
			
		||||
     * frequent operation.
 | 
			
		||||
     */
 | 
			
		||||
    gbinder_ipc_invalidate_local_object(local->ipc, local);
 | 
			
		||||
    if (priv->acquired) {
 | 
			
		||||
        gbinder_driver_release(remote->ipc->driver, remote->handle);
 | 
			
		||||
    }
 | 
			
		||||
    gbinder_proxy_object_drop_subproxies(self);
 | 
			
		||||
    gbinder_remote_object_remove_handler(remote, priv->remote_death_id);
 | 
			
		||||
    GDEBUG("Proxy %p %s => %u %s gone", self,
 | 
			
		||||
        gbinder_ipc_name(self->parent.ipc), remote->handle,
 | 
			
		||||
        gbinder_ipc_name(remote->ipc));
 | 
			
		||||
    gbinder_remote_object_unref(remote);
 | 
			
		||||
    g_mutex_clear(&priv->mutex);
 | 
			
		||||
    G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -483,7 +396,6 @@ gbinder_proxy_object_init(
 | 
			
		||||
        THIS_TYPE, GBinderProxyObjectPriv);
 | 
			
		||||
 | 
			
		||||
    self->priv = priv;
 | 
			
		||||
    g_mutex_init(&priv->mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2018-2021 Jolla Ltd.
 | 
			
		||||
 * Copyright (C) 2018-2021 Slava Monich <slava.monich@jolla.com>
 | 
			
		||||
 * Copyright (C) 2018-2022 Jolla Ltd.
 | 
			
		||||
 * Copyright (C) 2018-2022 Slava Monich <slava.monich@jolla.com>
 | 
			
		||||
 *
 | 
			
		||||
 * You may use this file under the terms of BSD license as follows:
 | 
			
		||||
 *
 | 
			
		||||
@@ -55,6 +55,7 @@ static GHashTable* test_fd_map = NULL;
 | 
			
		||||
static GHashTable* test_node_map = NULL;
 | 
			
		||||
static GPrivate test_looper = G_PRIVATE_INIT(NULL);
 | 
			
		||||
static GPrivate test_tx_state = G_PRIVATE_INIT(NULL);
 | 
			
		||||
static guint32 last_auto_handle = 0;
 | 
			
		||||
 | 
			
		||||
G_LOCK_DEFINE_STATIC(test_binder);
 | 
			
		||||
static GMainLoop* test_binder_exit_loop = NULL;
 | 
			
		||||
@@ -125,6 +126,7 @@ typedef struct test_binder_node TestBinderNode;
 | 
			
		||||
struct test_binder_node {
 | 
			
		||||
    int fd;
 | 
			
		||||
    char* path;
 | 
			
		||||
    const char* name;
 | 
			
		||||
    TestBinder* binder;
 | 
			
		||||
    TestBinderNode* other;
 | 
			
		||||
    TEST_LOOPER looper_enabled;
 | 
			
		||||
@@ -146,7 +148,6 @@ typedef struct test_binder {
 | 
			
		||||
    GHashTable* object_map; /* GBinderLocalObject* => handle */
 | 
			
		||||
    GHashTable* handle_map; /* handle => GBinderLocalObject* */
 | 
			
		||||
    TestBinderSubmitThread* submit_thread;
 | 
			
		||||
    guint32 last_auto_handle;
 | 
			
		||||
    GMutex mutex;
 | 
			
		||||
    gboolean passthrough;
 | 
			
		||||
    TestBinderNode node[2];
 | 
			
		||||
@@ -437,13 +438,16 @@ test_binder_register_object_locked(
 | 
			
		||||
    g_assert(!g_hash_table_contains(binder->object_map, obj));
 | 
			
		||||
    g_assert(!g_hash_table_contains(binder->handle_map, GINT_TO_POINTER(h)));
 | 
			
		||||
    if (h == AUTO_HANDLE) {
 | 
			
		||||
        h = ++(binder->last_auto_handle);
 | 
			
		||||
        h = ++last_auto_handle;
 | 
			
		||||
        while (g_hash_table_contains(binder->handle_map, GINT_TO_POINTER(h)) ||
 | 
			
		||||
            g_hash_table_contains(binder->object_map, GINT_TO_POINTER(h))) {
 | 
			
		||||
            h = ++(binder->last_auto_handle);
 | 
			
		||||
            h = ++last_auto_handle;
 | 
			
		||||
        }
 | 
			
		||||
    } else if (last_auto_handle < h) {
 | 
			
		||||
        /* Avoid re-using handles, to make debugging easier */
 | 
			
		||||
        last_auto_handle = h;
 | 
			
		||||
    }
 | 
			
		||||
    GDEBUG("Object %p <=> handle %u", obj, h);
 | 
			
		||||
    GDEBUG("Object %p <=> handle %u %s", obj, h, binder->node[0].name);
 | 
			
		||||
    g_hash_table_insert(binder->handle_map, GINT_TO_POINTER(h), obj);
 | 
			
		||||
    g_hash_table_insert(binder->object_map, obj, GINT_TO_POINTER(h));
 | 
			
		||||
    g_object_weak_ref(G_OBJECT(obj), test_binder_local_object_gone, binder);
 | 
			
		||||
@@ -463,10 +467,10 @@ test_io_passthough_handle_to_object(
 | 
			
		||||
        gpointer obj = g_hash_table_lookup(binder->handle_map, key);
 | 
			
		||||
 | 
			
		||||
        GDEBUG("Handle %u => object %p %s", (guint) handle, obj,
 | 
			
		||||
            binder->node[0].path);
 | 
			
		||||
            binder->node[0].name);
 | 
			
		||||
        return GPOINTER_TO_SIZE(obj);
 | 
			
		||||
    }
 | 
			
		||||
    GDEBUG("Unexpected handle %u %s", (guint) handle, binder->node[0].path);
 | 
			
		||||
    GDEBUG("Unexpected handle %u %s", (guint) handle, binder->node[0].name);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -484,13 +488,13 @@ test_io_passthough_object_to_handle(
 | 
			
		||||
        guint64 handle = GPOINTER_TO_SIZE(value);
 | 
			
		||||
 | 
			
		||||
        GDEBUG("Object %p => handle %u %s", key, (guint) handle,
 | 
			
		||||
            binder->node[0].path);
 | 
			
		||||
            binder->node[0].name);
 | 
			
		||||
        return handle;
 | 
			
		||||
    } else if (key) {
 | 
			
		||||
        GDEBUG("Auto-registering object %p %s", key, binder->node[0].path);
 | 
			
		||||
        GDEBUG("Auto-registering object %p %s", key, binder->node[0].name);
 | 
			
		||||
        return test_binder_register_object_locked(binder, key, AUTO_HANDLE);
 | 
			
		||||
    } else {
 | 
			
		||||
        GDEBUG("Unexpected object %p %s", key, binder->node[0].path);
 | 
			
		||||
        GDEBUG("Unexpected object %p %s", key, binder->node[0].name);
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -565,7 +569,7 @@ test_binder_node_read(
 | 
			
		||||
        const guint32 cmd = node->next_cmd[0];
 | 
			
		||||
        const guint total = 4 + _IOC_SIZE(cmd);
 | 
			
		||||
 | 
			
		||||
        /* Alread have one ready */
 | 
			
		||||
        /* Already have one ready */
 | 
			
		||||
        if (!(test_binder_cmd_read_flags(cmd) & flags)) {
 | 
			
		||||
            GDEBUG("Cmd 0x%08x not for %d", cmd, gettid());
 | 
			
		||||
            *bytes_read = 0;
 | 
			
		||||
@@ -667,7 +671,7 @@ test_tx_state_acquire(
 | 
			
		||||
    while (g_atomic_pointer_get(&node->tx_state) != my_tx_state &&
 | 
			
		||||
        !g_atomic_pointer_compare_and_exchange(&node->tx_state, NULL,
 | 
			
		||||
         my_tx_state)) {
 | 
			
		||||
        GDEBUG("Thread %d is waiting to become a transacton thread",
 | 
			
		||||
        GDEBUG("Thread %d is waiting to become a transaction thread",
 | 
			
		||||
            my_tx_state->tid);
 | 
			
		||||
        test_io_short_wait();
 | 
			
		||||
    }
 | 
			
		||||
@@ -696,7 +700,7 @@ test_tx_state_release(
 | 
			
		||||
        my_tx_state->depth--;
 | 
			
		||||
        my_tx_state->stack = g_renew(TEST_TX_STATE, my_tx_state->stack,
 | 
			
		||||
            my_tx_state->depth);
 | 
			
		||||
        GDEBUG("Thread %d is still a transacton thread", my_tx_state->tid);
 | 
			
		||||
        GDEBUG("Thread %d is still a transaction thread", my_tx_state->tid);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -843,6 +847,8 @@ test_io_passthough_write_64(
 | 
			
		||||
                        buffer->buffer = GPOINTER_TO_SIZE(copy);
 | 
			
		||||
                        g_hash_table_replace(fd->destroy_map, copy, NULL);
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    GDEBUG("Unexpected object type 0x%08x", *obj_ptr);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            g_hash_table_replace(fd->destroy_map, data_offsets, NULL);
 | 
			
		||||
@@ -1594,6 +1600,7 @@ test_binder_fd_new(
 | 
			
		||||
    binder_fd->node = node;
 | 
			
		||||
    binder_fd->fd = dup(node->fd);
 | 
			
		||||
    binder_fd->destroy_map = g_hash_table_new(g_direct_hash, g_direct_equal);
 | 
			
		||||
    GDEBUG("fd %d => %d", binder_fd->fd, node->fd);
 | 
			
		||||
    return binder_fd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1602,11 +1609,12 @@ gbinder_system_open(
 | 
			
		||||
    const char* path,
 | 
			
		||||
    int flags)
 | 
			
		||||
{
 | 
			
		||||
    static const char path_prefix[] = "/dev/";
 | 
			
		||||
    static const char binder_suffix[] = "binder";
 | 
			
		||||
    static const char binder_private_suffix[] = "binder-private";
 | 
			
		||||
    static const char private_suffix[] = "-private";
 | 
			
		||||
 | 
			
		||||
    if (path && g_str_has_prefix(path, "/dev/") &&
 | 
			
		||||
    if (path && g_str_has_prefix(path, path_prefix) &&
 | 
			
		||||
        (g_str_has_suffix(path, binder_suffix) ||
 | 
			
		||||
         g_str_has_suffix(path, binder_private_suffix))) {
 | 
			
		||||
        TestBinderFd* fd;
 | 
			
		||||
@@ -1631,7 +1639,7 @@ gbinder_system_open(
 | 
			
		||||
                node = binder->node + PRIVATE;
 | 
			
		||||
                node->path = g_strdup(path);
 | 
			
		||||
                binder->node[PUBLIC].path = g_strndup(path,
 | 
			
		||||
                    strlen(path) - strlen(private_suffix) - 1);
 | 
			
		||||
                    strlen(path) - strlen(private_suffix));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!test_node_map) {
 | 
			
		||||
@@ -1644,6 +1652,7 @@ gbinder_system_open(
 | 
			
		||||
                this_node->binder = binder;
 | 
			
		||||
                this_node->fd = fds[i];
 | 
			
		||||
                this_node->other = binder->node + ((i + 1) % 2);
 | 
			
		||||
                this_node->name = this_node->path + strlen(path_prefix);
 | 
			
		||||
                g_hash_table_replace(test_node_map, this_node->path, this_node);
 | 
			
		||||
            }
 | 
			
		||||
            binder->object_map = g_hash_table_new
 | 
			
		||||
@@ -1651,8 +1660,8 @@ gbinder_system_open(
 | 
			
		||||
            binder->handle_map = g_hash_table_new
 | 
			
		||||
                (g_direct_hash, g_direct_equal);
 | 
			
		||||
            GDEBUG("Created %s (%d) <=> %s (%d) binder",
 | 
			
		||||
                binder->node[0].path, binder->node[0].fd,
 | 
			
		||||
                binder->node[1].path, binder->node[1].fd);
 | 
			
		||||
                binder->node[0].name, binder->node[0].fd,
 | 
			
		||||
                binder->node[1].name, binder->node[1].fd);
 | 
			
		||||
        }
 | 
			
		||||
        fd = test_binder_fd_new(node);
 | 
			
		||||
        if (!test_fd_map) {
 | 
			
		||||
 
 | 
			
		||||
@@ -438,7 +438,7 @@ test_param(
 | 
			
		||||
 | 
			
		||||
typedef struct test_obj_data {
 | 
			
		||||
    GMainLoop* loop;
 | 
			
		||||
    GBinderLocalObject* tmp_proxy;
 | 
			
		||||
    GBinderLocalObject* obj2;
 | 
			
		||||
    gboolean obj_call_handled;
 | 
			
		||||
    gboolean obj_call_finished;
 | 
			
		||||
    gboolean obj2_call_handled;
 | 
			
		||||
@@ -539,9 +539,9 @@ test_obj_cb(
 | 
			
		||||
    g_assert(gbinder_reader_at_end(&reader));
 | 
			
		||||
 | 
			
		||||
    /* Make sure temporary proxy won't get destroyed too early */
 | 
			
		||||
    test->tmp_proxy = test_binder_object(gbinder_driver_fd(obj->ipc->driver),
 | 
			
		||||
    test->obj2 = test_binder_object(gbinder_driver_fd(obj->ipc->driver),
 | 
			
		||||
        obj2->handle);
 | 
			
		||||
    g_assert(test->tmp_proxy);
 | 
			
		||||
    g_assert(test->obj2);
 | 
			
		||||
 | 
			
		||||
    /* Call remote object */
 | 
			
		||||
    client2 = gbinder_client_new(obj2, TEST_IFACE2);
 | 
			
		||||
@@ -599,39 +599,54 @@ test_obj_run(
 | 
			
		||||
    GBinderRemoteObject* remote_obj;
 | 
			
		||||
    GBinderRemoteObject* remote_proxy;
 | 
			
		||||
    GBinderClient* proxy_client;
 | 
			
		||||
    GBinderIpc* ipc_remote_obj;
 | 
			
		||||
    GBinderIpc* ipc_obj;
 | 
			
		||||
    GBinderIpc* ipc_proxy;
 | 
			
		||||
    GBinderIpc* ipc_remote_proxy;
 | 
			
		||||
    GBinderLocalRequest* req;
 | 
			
		||||
    int fd_obj, fd_proxy;
 | 
			
		||||
    int fd_remote_obj, fd_obj, fd_proxy, fd_remote_proxy;
 | 
			
		||||
 | 
			
		||||
    test_config_init(&config, NULL);
 | 
			
		||||
    memset(&test, 0, sizeof(test));
 | 
			
		||||
    test.loop = g_main_loop_new(NULL, FALSE);
 | 
			
		||||
 | 
			
		||||
    ipc_proxy = gbinder_ipc_new(DEV);
 | 
			
		||||
    ipc_obj = gbinder_ipc_new(DEV_PRIV);
 | 
			
		||||
    fd_proxy = gbinder_driver_fd(ipc_proxy->driver);
 | 
			
		||||
    ipc_remote_obj = gbinder_ipc_new(DEV_PRIV);
 | 
			
		||||
    ipc_obj = gbinder_ipc_new(DEV);
 | 
			
		||||
    ipc_proxy = gbinder_ipc_new(DEV2);
 | 
			
		||||
    ipc_remote_proxy = gbinder_ipc_new(DEV2_PRIV);
 | 
			
		||||
 | 
			
		||||
    fd_remote_obj = gbinder_driver_fd(ipc_remote_obj->driver);
 | 
			
		||||
    fd_obj = gbinder_driver_fd(ipc_obj->driver);
 | 
			
		||||
    obj = gbinder_local_object_new(ipc_obj, TEST_IFACES, test_obj_cb, &test);
 | 
			
		||||
    obj2 = gbinder_local_object_new(ipc_obj, TEST_IFACES2, test_obj2_cb, &test);
 | 
			
		||||
    remote_obj = gbinder_remote_object_new(ipc_proxy,
 | 
			
		||||
    fd_proxy = gbinder_driver_fd(ipc_proxy->driver);
 | 
			
		||||
    fd_remote_proxy = gbinder_driver_fd(ipc_remote_proxy->driver);
 | 
			
		||||
 | 
			
		||||
    obj = gbinder_local_object_new(ipc_remote_obj, TEST_IFACES, test_obj_cb, &test);
 | 
			
		||||
    GDEBUG("obj %p", obj);
 | 
			
		||||
    remote_obj = gbinder_remote_object_new(ipc_obj,
 | 
			
		||||
        test_binder_register_object(fd_obj, obj, AUTO_HANDLE),
 | 
			
		||||
        REMOTE_OBJECT_CREATE_ALIVE);
 | 
			
		||||
 | 
			
		||||
    /* remote_proxy(DEV_PRIV) => proxy (DEV) => obj (DEV) => DEV_PRIV */
 | 
			
		||||
    g_assert(!gbinder_proxy_object_new(NULL, remote_obj));
 | 
			
		||||
    /* remote_proxy(DEV2_PRIV) => proxy (DEV) => obj(DEV2_PRIV) */
 | 
			
		||||
    g_assert((proxy = gbinder_proxy_object_new(ipc_proxy, remote_obj)));
 | 
			
		||||
    remote_proxy = gbinder_remote_object_new(ipc_obj,
 | 
			
		||||
    GDEBUG("proxy %p", proxy);
 | 
			
		||||
    remote_proxy = gbinder_remote_object_new(ipc_remote_proxy,
 | 
			
		||||
        test_binder_register_object(fd_proxy, &proxy->parent, AUTO_HANDLE),
 | 
			
		||||
        REMOTE_OBJECT_CREATE_ALIVE);
 | 
			
		||||
    proxy_client = gbinder_client_new(remote_proxy, TEST_IFACE);
 | 
			
		||||
 | 
			
		||||
    test_binder_set_passthrough(fd_remote_obj, TRUE);
 | 
			
		||||
    test_binder_set_passthrough(fd_obj, TRUE);
 | 
			
		||||
    test_binder_set_passthrough(fd_proxy, TRUE);
 | 
			
		||||
    test_binder_set_passthrough(fd_remote_proxy, TRUE);
 | 
			
		||||
 | 
			
		||||
    test_binder_set_looper_enabled(fd_remote_obj, TEST_LOOPER_ENABLE);
 | 
			
		||||
    test_binder_set_looper_enabled(fd_obj, TEST_LOOPER_ENABLE);
 | 
			
		||||
    test_binder_set_looper_enabled(fd_proxy, TEST_LOOPER_ENABLE);
 | 
			
		||||
    test_binder_set_looper_enabled(fd_remote_proxy, TEST_LOOPER_ENABLE);
 | 
			
		||||
 | 
			
		||||
    /* Pass object reference via proxy */
 | 
			
		||||
    obj2 = gbinder_local_object_new(ipc_remote_proxy, TEST_IFACES2, test_obj2_cb, &test);
 | 
			
		||||
    GDEBUG("obj2 %p", obj2);
 | 
			
		||||
    req = gbinder_client_new_request(proxy_client);
 | 
			
		||||
    gbinder_local_request_append_int32(req, TX_PARAM1);
 | 
			
		||||
    gbinder_local_request_append_local_object(req, obj2);
 | 
			
		||||
@@ -646,19 +661,24 @@ test_obj_run(
 | 
			
		||||
    g_assert(test.obj_call_finished);
 | 
			
		||||
    g_assert(test.obj2_call_handled);
 | 
			
		||||
    g_assert(test.obj2_call_finished);
 | 
			
		||||
    g_assert(test.tmp_proxy);
 | 
			
		||||
    gbinder_local_object_unref(test.tmp_proxy);
 | 
			
		||||
    g_assert(test.obj2);
 | 
			
		||||
    gbinder_local_object_unref(test.obj2);
 | 
			
		||||
 | 
			
		||||
    test_binder_unregister_objects(fd_remote_obj);
 | 
			
		||||
    test_binder_unregister_objects(fd_obj);
 | 
			
		||||
    test_binder_unregister_objects(fd_proxy);
 | 
			
		||||
    test_binder_unregister_objects(fd_remote_proxy);
 | 
			
		||||
 | 
			
		||||
    gbinder_local_object_drop(obj);
 | 
			
		||||
    gbinder_local_object_drop(obj2);
 | 
			
		||||
    gbinder_local_object_drop(&proxy->parent);
 | 
			
		||||
    gbinder_remote_object_unref(remote_obj);
 | 
			
		||||
    gbinder_remote_object_unref(remote_proxy);
 | 
			
		||||
    gbinder_client_unref(proxy_client);
 | 
			
		||||
    gbinder_ipc_unref(ipc_remote_obj);
 | 
			
		||||
    gbinder_ipc_unref(ipc_obj);
 | 
			
		||||
    gbinder_ipc_unref(ipc_proxy);
 | 
			
		||||
    gbinder_ipc_unref(ipc_remote_proxy);
 | 
			
		||||
    gbinder_ipc_exit();
 | 
			
		||||
    test_binder_exit_wait(&test_opt, test.loop);
 | 
			
		||||
    test_config_deinit(&config);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user