Compare commits

...

44 Commits

Author SHA1 Message Date
Slava Monich
a08513ade0 Version 1.0.37 2020-03-17 20:16:33 +02:00
Slava Monich
1a57e01e07 [gbinder] Fixed compilation warnings. JB#42956 2020-03-17 20:12:45 +02:00
Slava Monich
6d4faf19b8 [build] Allow side-by-side linking with libglibutil. JB#49231 2020-03-17 19:57:22 +02:00
Slava Monich
96e6845e16 Version 1.0.36 2020-03-16 16:16:58 +02:00
Slava Monich
b33adeb708 Merge pull request #41 from krnlyng/jb48037
Allow overwriting CC with a predefined one
2020-03-16 16:13:00 +02:00
Frajo Haider
ea0e294a74 [gbinder] Allow overwriting CC with a predefined one. JB#48037 2020-03-16 16:10:40 +02:00
Slava Monich
2d878c2391 Version 1.0.35 2020-02-25 14:02:35 +02:00
Slava Monich
6dec867cd3 [license] Freshened up copyright 2020-02-25 14:01:52 +02:00
Slava Monich
d8bd7b9366 Merge pull request #40 from monich/master
Add binder-ping
2020-02-25 13:55:50 +02:00
Slava Monich
b52e4c6dee [test] Added binder-ping. JB#42956 2020-02-24 23:57:21 +02:00
Slava Monich
21046af42f Version 1.0.34 2019-12-16 12:28:07 +02:00
Slava Monich
3cbe1d6ac8 Merge pull request #39 from monich/exit
Drop remote refs and shutdown loopers on unload
2019-12-16 12:22:28 +02:00
Slava Monich
b4b1a99a27 [unit] Added unit test for gbinder_ipc_exit. JB#48435 2019-12-16 03:13:57 +02:00
Slava Monich
f5a2d481e3 [gbinder] Fixed rare memory leak in GBinderServiceManager
Result needs to be freed even it completion callback never runs.
2019-12-16 03:12:52 +02:00
Slava Monich
da57a15852 [gbinder] Cancel outstanding transactions on unload. JB#48435 2019-12-16 03:11:46 +02:00
Slava Monich
9d0ac624c5 [unit] Housekeeping. JB#48413
Removed unused variable
2019-12-15 18:52:27 +02:00
Slava Monich
b8ccc80b87 [unit] Housekeeping. JB#48413
Fixed compilation warning: duplicate 'const' declaration specifier
2019-12-15 18:50:15 +02:00
Slava Monich
27e2dac22e [gbinder] Drop remote refs and shutdown loopers on unload. JB#48435
That prevents crashes when libgbinder.so is being unloaded. Which
went unnoticed because it typically happens when process exits anyway.

Remote references were preventing libgbinder's internal objects from
being deallocated on unload, which was leaving looper threads running
and trying to execute code already unmapped from the address space.
2019-12-15 18:32:32 +02:00
Slava Monich
a4ec4e382d Version 1.0.33 2019-09-13 15:59:43 +03:00
Slava Monich
30df5faf64 [unit] Added another gbinder_ipc unit test 2019-09-13 15:56:44 +03:00
Slava Monich
0aa29d8a91 Merge pull request #38 from monich/reuse_loopers
Reuse loopers
2019-09-13 15:46:29 +03:00
Slava Monich
3ace986e4a [unit] Don't set LD_LIBRARY_PATH when running unit tests
Now that unit tests get linked with the static variant of the library,
LD_LIBRARY_PATH is no longer needed.
2019-09-13 12:52:43 +03:00
Slava Monich
064ab48eee [unit] Fixed memory leak in gbinder_client unit test 2019-09-13 12:48:56 +03:00
Slava Monich
12c1725ab1 [gbinder] Reuse loopers. JB#42956
There's no need to start a new thread for each blocked request.
Unblocked threads can be moved back to the pool.
2019-09-13 00:59:22 +03:00
Slava Monich
ba2ddf4163 Version 1.0.32 2019-05-17 15:58:22 +03:00
Slava Monich
3d16384acd Merge pull request #37 from monich/dead
Refuse to perform transactions with dead objects
2019-05-17 15:54:12 +03:00
Slava Monich
0f73626025 [gbinder] Refuse to perform transactions with dead objects. JB#42956
Stale handle may be pointing to a random valid object, resulting
in a mess and unexpected behavior.
2019-05-17 15:04:19 +03:00
Slava Monich
84fb44e519 Version 1.0.31 2019-05-13 18:08:00 +03:00
Slava Monich
aafe23396a Merge pull request #36 from monich/drop_handle
Invalidate handle when remote object dies
2019-05-13 18:03:30 +03:00
Slava Monich
51f270df67 [gbinder] Hardcode servicemanager handle. JB#42956
It's always zero, keeping it configurable would complicate object
death handling for no good reason.
2019-05-13 15:09:45 +03:00
Slava Monich
e9c404de92 [gbinder] Invalidate handle when remote object dies. JB#42956
Otherwise the handle may get reused by the remote side but on
our side it would remain mapped to the old GBinderRemoteObject
(as long as there are any references to it), possibly pointing
to an entirely different object.
2019-05-13 14:40:33 +03:00
Slava Monich
141bda151b Version 1.0.30 2019-02-20 12:00:07 +02:00
Slava Monich
e952380ce6 Merge pull request #35 from monich/localobj
Make gbinder_local_object_new() public
2019-02-20 11:57:10 +02:00
Slava Monich
721f5dc469 [gbinder] Made gbinder_local_object_new() public. JB#44551
Until now, gbinder_servicemanager_new_local_object() was the only
API for creating local objects. That was slightly weird because
creating local object don't have much to do servicemanager, it's
a purely local operation. All we need to know is which binder
device (GBinderIpc) the object is going to be associated with.
That's what gbinder_remote_object_ipc() is for.
2019-02-19 23:56:29 +02:00
Slava Monich
434b17eefe Version 1.0.29 2019-02-14 18:18:50 +03:00
Slava Monich
af6a1c84ef Merge pull request #34 from monich/ifaces
Add gbinder_servicemanager_new_local_object2()
2019-02-14 18:12:24 +03:00
Slava Monich
a0ce447a1f [gbinder] Add gbinder_servicemanager_new_local_object2. Fixes JB#44766
It allows to pass a list of interfaces (top-most interface first) for
HIDL_DESCRIPTOR_CHAIN_TRANSACTION to GBinderLocalObject.
2019-02-14 12:31:54 +03:00
Slava Monich
f24145f407 Version 1.0.28 2019-01-29 02:50:13 +02:00
Slava Monich
11c173b2e4 Merge pull request #33 from mer-hybris/jb44588
Set type for local nulls to BINDER_TYPE_WEAK_BINDER
2019-01-29 02:48:09 +02:00
Andrew Branson
aff816d10c [binder] Set type for local nulls to BINDER_TYPE_WEAK_BINDER. JB#44588
Else they are not equivalent to null in Java.
2019-01-29 01:09:52 +01:00
Slava Monich
e1acaa3bdb Version 1.0.27 2019-01-24 18:56:58 +02:00
Slava Monich
c63743ac51 Merge pull request #32 from monich/oneway
Fix outgoing oneway transactions
2019-01-24 18:53:51 +02:00
Slava Monich
6832d9bf46 [unit] Added unit test for async oneway transactions 2019-01-24 18:51:26 +02:00
Slava Monich
4c3ccbc06f [gbinder] Fixed outgoing oneway transactions. JB#42956
Oneway transactions didn't have the appropriate flag set.
Also, a reply was unnecessarily allocated for those and
then just deallocated, which was a total waste.
2019-01-24 18:36:20 +02:00
41 changed files with 1301 additions and 358 deletions

View File

@@ -1,5 +1,5 @@
Copyright (C) 2018-2019 Jolla Ltd.
Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
Copyright (C) 2018-2020 Jolla Ltd.
Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
You may use this file under the terms of BSD license as follows:

View File

@@ -1,16 +1,25 @@
# -*- Mode: makefile-gmake -*-
#
# LIBGLIBUTIL_PATH can be defined to point to libglibutil root directory
# for side-by-side build.
#
.PHONY: clean all debug release test
.PHONY: print_debug_so print_release_so
.PHONY: print_debug_lib print_release_lib
.PHONY: print_debug_lib print_release_lib print_coverage_lib
.PHONY: print_debug_link print_release_link
.PHONY: print_debug_path print_release_path
#
# Required packages
# Library version
#
PKGS = libglibutil glib-2.0 gobject-2.0
VERSION_MAJOR = 1
VERSION_MINOR = 0
VERSION_RELEASE = 37
# Version for pkg-config
PCVERSION = $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_RELEASE)
#
# Default target
@@ -19,15 +28,34 @@ PKGS = libglibutil glib-2.0 gobject-2.0
all: debug release pkgconfig
#
# Library version
# Required packages
#
VERSION_MAJOR = 1
VERSION_MINOR = 0
VERSION_RELEASE = 26
PKGS = glib-2.0 gobject-2.0
# Version for pkg-config
PCVERSION = $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_RELEASE)
ifeq ($(LIBGLIBUTIL_PATH),)
# Assume that libglibutil devel package is installed
PKGS += libglibutil
else
# Side-by-side build
INCLUDES += -I$(LIBGLIBUTIL_PATH)/include
DEBUG_LIBS = -L$(LIBGLIBUTIL_PATH)/build/debug -lglibutil
RELEASE_LIBS = -L$(LIBGLIBUTIL_PATH)/build/release -lglibutil
DEBUG_DEPS = libglibutil_debug
RELEASE_DEPS = libglibutil_release
.PHONY: libglibutil_debug libglibutil_release
libglibutil_debug:
make -C $(LIBGLIBUTIL_PATH) debug
libglibutil_release:
make -C $(LIBGLIBUTIL_PATH) release
endif
#
# Library name
@@ -89,10 +117,10 @@ COVERAGE_BUILD_DIR = $(BUILD_DIR)/coverage
# Tools and flags
#
CC = $(CROSS_COMPILE)gcc
CC ?= $(CROSS_COMPILE)gcc
LD = $(CC)
WARNINGS = -Wall -Wstrict-aliasing -Wunused-result
INCLUDES = -I$(INCLUDE_DIR)
INCLUDES += -I$(INCLUDE_DIR)
BASE_FLAGS = -fPIC
FULL_CFLAGS = $(BASE_FLAGS) $(CFLAGS) $(DEFINES) $(WARNINGS) $(INCLUDES) \
-MMD -MP $(shell pkg-config --cflags $(PKGS))
@@ -110,8 +138,8 @@ ifneq ($(KEEP_SYMBOLS),0)
RELEASE_FLAGS += -g
endif
DEBUG_LDFLAGS = $(FULL_LDFLAGS) $(DEBUG_FLAGS)
RELEASE_LDFLAGS = $(FULL_LDFLAGS) $(RELEASE_FLAGS)
DEBUG_LDFLAGS = $(FULL_LDFLAGS) $(DEBUG_LIBS) $(DEBUG_FLAGS)
RELEASE_LDFLAGS = $(FULL_LDFLAGS) $(RELEASE_LIBS) $(RELEASE_FLAGS)
DEBUG_CFLAGS = $(FULL_CFLAGS) $(DEBUG_FLAGS) -DDEBUG
RELEASE_CFLAGS = $(FULL_CFLAGS) $(RELEASE_FLAGS) -O2
COVERAGE_CFLAGS = $(FULL_CFLAGS) $(COVERAGE_FLAGS) --coverage
@@ -137,8 +165,8 @@ endif
endif
$(PKGCONFIG): | $(BUILD_DIR)
$(DEBUG_OBJS) $(DEBUG_SO): | $(DEBUG_BUILD_DIR)
$(RELEASE_OBJS) $(RELEASE_SO): | $(RELEASE_BUILD_DIR)
$(DEBUG_OBJS) $(DEBUG_SO): | $(DEBUG_BUILD_DIR) $(DEBUG_DEPS)
$(RELEASE_OBJS) $(RELEASE_SO): | $(RELEASE_BUILD_DIR) $(RELEASE_DEPS)
$(COVERAGE_OBJS) $(COVERAGE_LIB): | $(COVERAGE_BUILD_DIR)
#

69
debian/changelog vendored
View File

@@ -1,3 +1,72 @@
libgbinder (1.0.37) unstable; urgency=low
* Allow side-by-side linking with libglibutil
* Fixed compilation warnings
-- Slava Monich <slava.monich@jolla.com> Tue, 17 Mar 2020 20:15:11 +0200
libgbinder (1.0.36) unstable; urgency=low
* Allow overwriting CC
-- Slava Monich <slava.monich@jolla.com> Mon, 16 Mar 2020 16:15:24 +0200
libgbinder (1.0.35) unstable; urgency=low
* Added binder-ping example
-- Slava Monich <slava.monich@jolla.com> Tue, 25 Feb 2020 13:58:19 +0200
libgbinder (1.0.34) unstable; urgency=low
* Better cleanup on unload to prevent crashes on exit
* Fixed rare memory leak in GBinderServiceManager
-- Slava Monich <slava.monich@jolla.com> Mon, 16 Dec 2019 12:25:56 +0200
libgbinder (1.0.33) unstable; urgency=low
* Reuse loopers
-- Slava Monich <slava.monich@jolla.com> Fri, 13 Sep 2019 15:57:47 +0300
libgbinder (1.0.32) unstable; urgency=low
* Refuse to perform transactions with dead objects
-- Slava Monich <slava.monich@jolla.com> Fri, 17 May 2019 15:57:30 +0300
libgbinder (1.0.31) unstable; urgency=low
* Invalidate handle when remote object dies
-- Slava Monich <slava.monich@jolla.com> Mon, 13 May 2019 18:05:35 +0300
libgbinder (1.0.30) unstable; urgency=low
* Added gbinder_local_object_new()
* Added gbinder_remote_object_ipc()
-- Slava Monich <slava.monich@jolla.com> Wed, 20 Feb 2019 11:59:08 +0200
libgbinder (1.0.29) unstable; urgency=low
* Added gbinder_servicemanager_new_local_object2()
-- Slava Monich <slava.monich@jolla.com> Thu, 14 Feb 2019 18:17:53 +0300
libgbinder (1.0.28) unstable; urgency=low
* Set type for local nulls to BINDER_TYPE_WEAK_BINDER
-- Slava Monich <slava.monich@jolla.com> Tue, 29 Jan 2019 02:49:10 +0200
libgbinder (1.0.27) unstable; urgency=low
* Fixed outgoing oneway transactions
-- Slava Monich <slava.monich@jolla.com> Thu, 24 Jan 2019 18:55:16 +0200
libgbinder (1.0.26) unstable; urgency=low
* Implement PING and INTERFACE transactions

4
debian/control vendored
View File

@@ -2,13 +2,13 @@ Source: libgbinder
Section: libs
Priority: optional
Maintainer: Slava Monich <slava.monich@jolla.com>
Build-Depends: debhelper (>= 7), libglib2.0-dev (>= 2.0), libglibutil (>= 1.0.34)
Build-Depends: debhelper (>= 7), libglib2.0-dev (>= 2.0), libglibutil (>= 1.0.35)
Standards-Version: 3.8.4
Package: libgbinder
Section: libs
Architecture: any
Depends: libglibutil (>= 1.0.34), ${shlibs:Depends}, ${misc:Depends}
Depends: libglibutil (>= 1.0.35), ${shlibs:Depends}, ${misc:Depends}
Description: Binder client library
Package: libgbinder-dev

10
debian/copyright vendored
View File

@@ -1,5 +1,5 @@
Copyright (C) 2018 Jolla Ltd.
Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
Copyright (C) 2018-2020 Jolla Ltd.
Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
You may use this file under the terms of BSD license as follows:
@@ -12,9 +12,9 @@ are met:
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 name of Jolla Ltd nor the names of its contributors may
be used to endorse or promote products derived from this software
without specific prior written permission.
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

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -13,9 +13,9 @@
* 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 name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 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
@@ -37,6 +37,14 @@
G_BEGIN_DECLS
GBinderLocalObject*
gbinder_local_object_new(
GBinderIpc* ipc,
const char* const* ifaces,
GBinderLocalTransactFunc handler,
void* user_data) /* Since 1.0.30 */
G_GNUC_WARN_UNUSED_RESULT;
GBinderLocalObject*
gbinder_local_object_ref(
GBinderLocalObject* obj);

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -13,9 +13,9 @@
* 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 name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 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
@@ -51,6 +51,10 @@ void
gbinder_remote_object_unref(
GBinderRemoteObject* obj);
GBinderIpc*
gbinder_remote_object_ipc(
GBinderRemoteObject* obj); /* Since 1.0.30 */
gboolean
gbinder_remote_object_is_dead(
GBinderRemoteObject* obj);

View File

@@ -93,6 +93,13 @@ gbinder_servicemanager_new_local_object(
GBinderLocalTransactFunc handler,
void* user_data);
GBinderLocalObject*
gbinder_servicemanager_new_local_object2(
GBinderServiceManager* sm,
const char* const* ifaces,
GBinderLocalTransactFunc handler,
void* user_data); /* Since 1.0.29 */
GBinderServiceManager*
gbinder_servicemanager_ref(
GBinderServiceManager* sm);

View File

@@ -61,6 +61,7 @@ G_BEGIN_DECLS
typedef struct gbinder_buffer GBinderBuffer;
typedef struct gbinder_client GBinderClient;
typedef struct gbinder_ipc GBinderIpc;
typedef struct gbinder_local_object GBinderLocalObject;
typedef struct gbinder_local_reply GBinderLocalReply;
typedef struct gbinder_local_request GBinderLocalRequest;

View File

@@ -1,14 +1,14 @@
Name: libgbinder
Version: 1.0.26
Version: 1.0.37
Release: 0
Summary: Binder client library
Group: Development/Libraries
License: BSD
URL: https://github.com/mer-hybris/libgbinder
Source: %{name}-%{version}.tar.bz2
Requires: libglibutil >= 1.0.34
Requires: libglibutil >= 1.0.35
BuildRequires: pkgconfig(glib-2.0)
BuildRequires: pkgconfig(libglibutil) >= 1.0.34
BuildRequires: pkgconfig(libglibutil) >= 1.0.35
Requires(post): /sbin/ldconfig
Requires(postun): /sbin/ldconfig

View File

@@ -205,12 +205,15 @@ gbinder_client_transact_sync_reply(
if (G_LIKELY(self)) {
GBinderRemoteObject* obj = self->remote;
if (!req) {
/* Default empty request (just the header, no parameters) */
req = gbinder_client_cast(self)->basic_req;
if (G_LIKELY(!obj->dead)) {
if (!req) {
/* Default empty request (just the header, no parameters) */
req = gbinder_client_cast(self)->basic_req;
}
return gbinder_ipc_transact_sync_reply(obj->ipc, obj->handle,
code, req, status);
}
return gbinder_ipc_transact_sync_reply(obj->ipc, obj->handle,
code, req, status);
GDEBUG("Refusing to perform transaction with a dead object");
}
return NULL;
}
@@ -224,15 +227,18 @@ gbinder_client_transact_sync_oneway(
if (G_LIKELY(self)) {
GBinderRemoteObject* obj = self->remote;
if (!req) {
/* Default empty request (just the header, no parameters) */
req = gbinder_client_cast(self)->basic_req;
if (G_LIKELY(!obj->dead)) {
if (!req) {
/* Default empty request (just the header, no parameters) */
req = gbinder_client_cast(self)->basic_req;
}
return gbinder_ipc_transact_sync_oneway(obj->ipc, obj->handle,
code, req);
}
return gbinder_ipc_transact_sync_oneway(obj->ipc, obj->handle,
code, req);
} else {
return (-EINVAL);
GDEBUG("Refusing to perform transaction with a dead object");
return (-ESTALE);
}
return (-EINVAL);
}
gulong
@@ -247,23 +253,27 @@ gbinder_client_transact(
{
if (G_LIKELY(self)) {
GBinderRemoteObject* obj = self->remote;
GBinderClientTx* tx = g_slice_new0(GBinderClientTx);
tx->client = gbinder_client_ref(self);
tx->reply = reply;
tx->destroy = destroy;
tx->user_data = user_data;
if (G_LIKELY(!obj->dead)) {
GBinderClientTx* tx = g_slice_new0(GBinderClientTx);
if (!req) {
/* Default empty request (just the header, no parameters) */
req = gbinder_client_cast(self)->basic_req;
tx->client = gbinder_client_ref(self);
tx->reply = reply;
tx->destroy = destroy;
tx->user_data = user_data;
if (!req) {
/* Default empty request (just the header, no parameters) */
req = gbinder_client_cast(self)->basic_req;
}
return gbinder_ipc_transact(obj->ipc, obj->handle, code,
flags, req, gbinder_client_transact_reply,
gbinder_client_transact_destroy, tx);
}
return gbinder_ipc_transact(obj->ipc, obj->handle, code, flags, req,
gbinder_client_transact_reply, gbinder_client_transact_destroy, tx);
} else {
return 0;
GDEBUG("Refusing to perform transaction with a dead object");
}
return 0;
}
void

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -76,8 +76,6 @@ enum gbinder_defaultservicemanager_calls {
LIST_SERVICES_TRANSACTION
};
/* As a special case, ServiceManager's handle is zero */
#define DEFAULTSERVICEMANAGER_HANDLE (0)
#define DEFAULTSERVICEMANAGER_IFACE "android.os.IServiceManager"
GBinderServiceManager*
@@ -301,7 +299,6 @@ void
gbinder_defaultservicemanager_class_init(
GBinderDefaultServiceManagerClass* klass)
{
klass->handle = DEFAULTSERVICEMANAGER_HANDLE;
klass->iface = DEFAULTSERVICEMANAGER_IFACE;
klass->default_device = GBINDER_DEFAULT_BINDER;
klass->rpc_protocol = &gbinder_rpc_protocol_binder;

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -80,8 +80,6 @@ enum gbinder_hwservicemanager_notifications {
ON_REGISTRATION_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION
};
/* As a special case, ServiceManager's handle is zero */
#define HWSERVICEMANAGER_HANDLE (0)
#define HWSERVICEMANAGER_IFACE "android.hidl.manager@1.0::IServiceManager"
#define HWSERVICEMANAGER_NOTIFICATION_IFACE \
"android.hidl.manager@1.0::IServiceNotification"
@@ -378,7 +376,6 @@ void
gbinder_hwservicemanager_class_init(
GBinderHwServiceManagerClass* klass)
{
klass->handle = HWSERVICEMANAGER_HANDLE;
klass->iface = HWSERVICEMANAGER_IFACE;
klass->default_device = GBINDER_DEFAULT_HWBINDER;
klass->rpc_protocol = &gbinder_rpc_protocol_hwbinder;

View File

@@ -128,9 +128,13 @@ GBINDER_IO_FN(encode_local_object)(
struct flat_binder_object* dest = out;
memset(dest, 0, sizeof(*dest));
dest->hdr.type = BINDER_TYPE_BINDER;
dest->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
dest->binder = (uintptr_t)obj;
if (obj) {
dest->hdr.type = BINDER_TYPE_BINDER;
dest->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
dest->binder = (uintptr_t)obj;
} else {
dest->hdr.type = BINDER_TYPE_WEAK_BINDER;
}
return sizeof(*dest);
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -14,8 +14,8 @@
* 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.
* 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
@@ -30,6 +30,8 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include "gbinder_ipc.h"
#include "gbinder_driver.h"
#include "gbinder_handler.h"
@@ -87,7 +89,7 @@ static GHashTable* gbinder_ipc_table = NULL;
static pthread_mutex_t gbinder_ipc_mutex = PTHREAD_MUTEX_INITIALIZER;
#define GBINDER_IPC_MAX_TX_THREADS (15)
#define GBINDER_IPC_MAX_LOOPERS (15)
#define GBINDER_IPC_MAX_PRIMARY_LOOPERS (5)
#define GBINDER_IPC_LOOPER_START_TIMEOUT_SEC (2)
/*
@@ -173,6 +175,7 @@ typedef struct gbinder_ipc_tx_priv {
GBinderIpcTxPrivFunc fn_exec;
GBinderIpcTxPrivFunc fn_done;
GBinderIpcTxPrivFunc fn_free;
GSource* completion;
} GBinderIpcTxPriv;
typedef struct gbinder_ipc_tx_internal {
@@ -340,7 +343,9 @@ gbinder_remote_request_complete(
tx->reply = gbinder_local_reply_ref(reply);
tx->state = GBINDER_IPC_LOOPER_TX_COMPLETE;
/* Wake up the looper */
(void)write(tx->pipefd[1], &done, sizeof(done));
if (write(tx->pipefd[1], &done, sizeof(done)) <= 0) {
GWARN("Failed to wake up the looper");
}
break;
default:
GWARN("Unexpected state %d in request completion", tx->state);
@@ -358,6 +363,48 @@ gbinder_remote_request_complete(
* GBinderIpcLooper
*==========================================================================*/
static
void
gbinder_ipc_looper_free(
GBinderIpcLooper* looper)
{
if (looper->thread) {
g_thread_unref(looper->thread);
}
close(looper->pipefd[0]);
close(looper->pipefd[1]);
if (looper->txfd[0] >= 0) {
close(looper->txfd[0]);
close(looper->txfd[1]);
}
gbinder_driver_unref(looper->driver);
g_free(looper->name);
g_cond_clear(&looper->start_cond);
g_mutex_clear(&looper->mutex);
g_slice_free(GBinderIpcLooper, looper);
}
static
GBinderIpcLooper*
gbinder_ipc_looper_ref(
GBinderIpcLooper* looper)
{
GASSERT(looper->refcount > 0);
g_atomic_int_inc(&looper->refcount);
return looper;
}
static
void
gbinder_ipc_looper_unref(
GBinderIpcLooper* looper)
{
GASSERT(looper->refcount > 0);
if (g_atomic_int_dec_and_test(&looper->refcount)) {
gbinder_ipc_looper_free(looper);
}
}
static
gboolean
gbinder_ipc_looper_tx_handle(
@@ -430,7 +477,9 @@ gbinder_ipc_looper_tx_handle(
}
/* And wake up the looper */
(void)write(tx->pipefd[1], &done, sizeof(done));
if (write(tx->pipefd[1], &done, sizeof(done)) <= 0) {
GWARN("Failed to wake up the looper");
}
return G_SOURCE_REMOVE;
}
@@ -442,6 +491,25 @@ gbinder_ipc_looper_tx_done(
gbinder_ipc_looper_tx_unref(data, FALSE);
}
static
void
gbinder_ipc_looper_start(
GBinderIpcLooper* looper)
{
if (!g_atomic_int_get(&looper->started)) {
/* Lock */
g_mutex_lock(&looper->mutex);
if (!g_atomic_int_get(&looper->started)) {
g_cond_wait_until(&looper->start_cond, &looper->mutex,
g_get_monotonic_time() + GBINDER_IPC_LOOPER_START_TIMEOUT_SEC *
G_TIME_SPAN_SECOND);
GASSERT(g_atomic_int_get(&looper->started));
}
g_mutex_unlock(&looper->mutex);
/* Unlock */
}
}
static
gboolean
gbinder_ipc_looper_remove_from_list(
@@ -488,6 +556,18 @@ gbinder_ipc_looper_remove_blocked(
&looper->ipc->priv->blocked_loopers);
}
static
guint
gbinder_ipc_looper_count_primary(
GBinderIpcLooper* looper)
{
const GBinderIpcLooper* ptr = looper->ipc->priv->primary_loopers;
guint n = 0;
for (n = 0; ptr; ptr = ptr->next) n++;
return n;
}
static
GBinderLocalReply*
gbinder_ipc_looper_transact(
@@ -514,12 +594,12 @@ gbinder_ipc_looper_transact(
struct pollfd fds[2];
guint8 done = 0;
GSource* source = g_idle_source_new();
gboolean was_blocked = FALSE;
/* Let GBinderLocalObject handle the transaction on the main thread */
g_source_set_callback(source, gbinder_ipc_looper_tx_handle,
gbinder_ipc_looper_tx_ref(tx), gbinder_ipc_looper_tx_done);
g_source_attach(source, priv->context);
g_source_unref(source);
/* Wait for either transaction completion or looper shutdown */
memset(fds, 0, sizeof(fds));
@@ -543,29 +623,35 @@ gbinder_ipc_looper_transact(
* moved to the blocked_loopers list.
*/
GBinderIpcPriv* priv = looper->ipc->priv;
GBinderIpcLooper* new_looper = NULL;
/* Lock */
g_mutex_lock(&priv->looper_mutex);
if (gbinder_ipc_looper_remove_primary(looper)) {
GBinderIpcLooper* new_looper;
GDEBUG("Primary looper %s is blocked", looper->name);
looper->next = priv->blocked_loopers;
priv->blocked_loopers = looper;
was_blocked = TRUE;
/* Looper will exit once transaction completes */
g_atomic_int_set(&looper->exit, 1);
/* Create new primary looper to replace this one */
new_looper = gbinder_ipc_looper_new(ipc);
if (new_looper) {
new_looper->next = priv->primary_loopers;
priv->primary_loopers = new_looper;
/* If there's no more primary loopers left, create one */
if (!priv->primary_loopers) {
new_looper = gbinder_ipc_looper_new(ipc);
if (new_looper) {
/* Will unref it after it gets started */
gbinder_ipc_looper_ref(new_looper);
priv->primary_loopers = new_looper;
}
}
}
g_mutex_unlock(&priv->looper_mutex);
/* Unlock */
if (new_looper) {
/* Wait until it gets started */
gbinder_ipc_looper_start(new_looper);
gbinder_ipc_looper_unref(new_looper);
}
/* Block until asynchronous transaction gets completed. */
done = 0;
memset(fds, 0, sizeof(fds));
@@ -576,10 +662,12 @@ gbinder_ipc_looper_transact(
poll(fds, 2, -1);
if ((fds[1].revents & POLLIN) &&
read(fds[1].fd, &done, sizeof(done)) == 1) {
GDEBUG("Looper %s is released", looper->name);
GASSERT(done == TX_DONE);
}
}
}
if (done) {
GASSERT(done == TX_DONE);
reply = gbinder_local_reply_ref(tx->reply);
@@ -596,53 +684,32 @@ gbinder_ipc_looper_transact(
} else {
gbinder_ipc_looper_tx_unref(tx, FALSE);
}
g_source_destroy(source);
g_source_unref(source);
if (was_blocked) {
guint n;
g_mutex_lock(&priv->looper_mutex);
n = gbinder_ipc_looper_count_primary(looper);
if (n >= GBINDER_IPC_MAX_PRIMARY_LOOPERS) {
/* Looper will exit once transaction completes */
GDEBUG("Too many primary loopers (%u)", n);
g_atomic_int_set(&looper->exit, 1);
} else {
/* Move it back to the primary list */
gbinder_ipc_looper_remove_blocked(looper);
looper->next = priv->primary_loopers;
priv->primary_loopers = looper;
}
g_mutex_unlock(&priv->looper_mutex);
}
}
*result = status;
return reply;
}
static
void
gbinder_ipc_looper_free(
GBinderIpcLooper* looper)
{
if (looper->thread) {
g_thread_unref(looper->thread);
}
close(looper->pipefd[0]);
close(looper->pipefd[1]);
if (looper->txfd[0] >= 0) {
close(looper->txfd[0]);
close(looper->txfd[1]);
}
gbinder_driver_unref(looper->driver);
g_free(looper->name);
g_cond_clear(&looper->start_cond);
g_mutex_clear(&looper->mutex);
g_slice_free(GBinderIpcLooper, looper);
}
static
GBinderIpcLooper*
gbinder_ipc_looper_ref(
GBinderIpcLooper* looper)
{
GASSERT(looper->refcount > 0);
g_atomic_int_inc(&looper->refcount);
return looper;
}
static
void
gbinder_ipc_looper_unref(
GBinderIpcLooper* looper)
{
GASSERT(looper->refcount > 0);
if (g_atomic_int_dec_and_test(&looper->refcount)) {
gbinder_ipc_looper_free(looper);
}
}
static
gpointer
gbinder_ipc_looper_thread(
@@ -787,27 +854,21 @@ gbinder_ipc_looper_check(
/* Lock */
g_mutex_lock(&priv->looper_mutex);
if (!priv->primary_loopers) {
priv->primary_loopers = gbinder_ipc_looper_new(self);
}
looper = priv->primary_loopers;
if (!looper) {
looper = priv->primary_loopers = gbinder_ipc_looper_new(self);
if (looper) {
gbinder_ipc_looper_ref(looper);
}
g_mutex_unlock(&priv->looper_mutex);
/* Unlock */
/* We are not ready to accept incoming transactions until
* looper has started. We may need to wait a bit. */
if (looper && !g_atomic_int_get(&looper->started)) {
/* Lock */
g_mutex_lock(&looper->mutex);
if (!g_atomic_int_get(&looper->started)) {
g_cond_wait_until(&looper->start_cond, &looper->mutex,
g_get_monotonic_time() +
GBINDER_IPC_LOOPER_START_TIMEOUT_SEC *
G_TIME_SPAN_SECOND);
GASSERT(g_atomic_int_get(&looper->started));
}
g_mutex_unlock(&looper->mutex);
/* Unlock */
if (looper) {
gbinder_ipc_looper_start(looper);
gbinder_ipc_looper_unref(looper);
}
}
}
@@ -865,8 +926,39 @@ gbinder_ipc_looper_join(
* GBinderObjectRegistry
*==========================================================================*/
static
void
gbinder_ipc_invalidate_remote_handle_locked(
GBinderIpcPriv* priv,
guint32 handle)
{
/* Caller holds priv->remote_objects_mutex */
if (priv->remote_objects) {
GVERBOSE_("handle %u", handle);
g_hash_table_remove(priv->remote_objects, GINT_TO_POINTER(handle));
if (g_hash_table_size(priv->remote_objects) == 0) {
g_hash_table_unref(priv->remote_objects);
priv->remote_objects = NULL;
}
}
}
void
gbinder_ipc_invalidate_remote_handle(
GBinderIpc* self,
guint32 handle)
{
GBinderIpcPriv* priv = self->priv;
/* Lock */
g_mutex_lock(&priv->remote_objects_mutex);
gbinder_ipc_invalidate_remote_handle_locked(priv, handle);
g_mutex_unlock(&priv->remote_objects_mutex);
/* Unlock */
}
/**
* Internal function called by gbinder_object_dispose(). Among other things,
* Internal functions called by gbinder_object_dispose(). Among other things,
* it means that it doesn't have to check GBinderIpc pointer for NULL.
*
* Note the following scenario (where object may be either local or remote):
@@ -914,31 +1006,19 @@ gbinder_ipc_remote_object_disposed(
/* Lock */
g_mutex_lock(&priv->remote_objects_mutex);
if (obj->object.ref_count == 1 && priv->remote_objects) {
void* key = GINT_TO_POINTER(obj->handle);
GVERBOSE_("handle %u", obj->handle);
GASSERT(g_hash_table_contains(priv->remote_objects, key));
g_hash_table_remove(priv->remote_objects, key);
if (g_hash_table_size(priv->remote_objects) == 0) {
g_hash_table_unref(priv->remote_objects);
priv->remote_objects = NULL;
}
if (obj->object.ref_count == 1) {
gbinder_ipc_invalidate_remote_handle_locked(priv, obj->handle);
}
g_mutex_unlock(&priv->remote_objects_mutex);
/* Unlock */
}
GBinderLocalObject*
gbinder_ipc_new_local_object(
void
gbinder_ipc_register_local_object(
GBinderIpc* self,
const char* iface,
GBinderLocalTransactFunc txproc,
void* data)
GBinderLocalObject* obj)
{
GBinderIpcPriv* priv = self->priv;
GBinderLocalObject* obj = gbinder_local_object_new
(self, iface, txproc, data);
/* Lock */
g_mutex_lock(&priv->local_objects_mutex);
@@ -951,7 +1031,6 @@ gbinder_ipc_new_local_object(
GVERBOSE_("%p", obj);
gbinder_ipc_looper_check(self);
return obj;
}
static
@@ -1108,6 +1187,38 @@ gbinder_ipc_tx_get_id(
return id;
}
static
void
gbinder_ipc_tx_free(
gpointer data)
{
GBinderIpcTxPriv* tx = data;
GBinderIpcTx* pub = &tx->pub;
GBinderIpc* self = pub->ipc;
GBinderIpcPriv* priv = self->priv;
g_source_unref(tx->completion);
g_hash_table_remove(priv->tx_table, GINT_TO_POINTER(pub->id));
tx->fn_free(tx);
/* This may actually deallocate GBinderIpc object: */
gbinder_ipc_unref(self);
}
static
gboolean
gbinder_ipc_tx_done(
gpointer data)
{
GBinderIpcTxPriv* tx = data;
GBinderIpcTx* pub = &tx->pub;
if (!pub->cancelled) {
tx->fn_done(tx);
}
return G_SOURCE_REMOVE;
}
static
void
gbinder_ipc_tx_pub_init(
@@ -1121,6 +1232,26 @@ gbinder_ipc_tx_pub_init(
tx->user_data = user_data;
}
static
void
gbinder_ipc_tx_priv_init(
GBinderIpcTxPriv* priv,
GBinderIpc* self,
gulong id,
void* user_data,
GBinderIpcTxPrivFunc fn_exec,
GBinderIpcTxPrivFunc fn_done,
GBinderIpcTxPrivFunc fn_free)
{
gbinder_ipc_tx_pub_init(&priv->pub, self, id, user_data);
priv->fn_exec = fn_exec;
priv->fn_done = fn_done;
priv->fn_free = fn_free;
priv->completion = g_idle_source_new();
g_source_set_callback(priv->completion, gbinder_ipc_tx_done, priv,
gbinder_ipc_tx_free);
}
static
inline
GBinderIpcTxInternal*
@@ -1170,14 +1301,19 @@ gbinder_ipc_tx_internal_exec(
GBinderObjectRegistry* reg = &self->priv->object_registry;
/* Perform synchronous transaction */
tx->reply = gbinder_remote_reply_new(&self->priv->object_registry);
tx->status = gbinder_driver_transact(self->driver, reg,
tx->handle, tx->code, tx->req, tx->reply);
if (tx->status != GBINDER_STATUS_OK &&
gbinder_remote_reply_is_empty(tx->reply)) {
/* Drop useless reply */
gbinder_remote_reply_unref(tx->reply);
tx->reply = NULL;
if (tx->flags & GBINDER_TX_FLAG_ONEWAY) {
tx->status = gbinder_driver_transact(self->driver, reg, tx->handle,
tx->code, tx->req, NULL);
} else {
tx->reply = gbinder_remote_reply_new(&self->priv->object_registry);
tx->status = gbinder_driver_transact(self->driver, reg, tx->handle,
tx->code, tx->req, tx->reply);
if (tx->status != GBINDER_STATUS_OK &&
gbinder_remote_reply_is_empty(tx->reply)) {
/* Drop useless reply */
gbinder_remote_reply_unref(tx->reply);
tx->reply = NULL;
}
}
}
@@ -1197,10 +1333,9 @@ gbinder_ipc_tx_internal_new(
GBinderIpcTxInternal* tx = g_slice_new0(GBinderIpcTxInternal);
GBinderIpcTxPriv* priv = &tx->tx;
gbinder_ipc_tx_pub_init(&priv->pub, self, id, user_data);
priv->fn_exec = gbinder_ipc_tx_internal_exec;
priv->fn_done = gbinder_ipc_tx_internal_done;
priv->fn_free = gbinder_ipc_tx_internal_free;
gbinder_ipc_tx_priv_init(priv, self, id, user_data,
gbinder_ipc_tx_internal_exec, gbinder_ipc_tx_internal_done,
gbinder_ipc_tx_internal_free);
tx->code = code;
tx->flags = flags;
@@ -1271,10 +1406,9 @@ gbinder_ipc_tx_custom_new(
GBinderIpcTxCustom* tx = g_slice_new0(GBinderIpcTxCustom);
GBinderIpcTxPriv* priv = &tx->tx;
gbinder_ipc_tx_pub_init(&priv->pub, self, id, user_data);
priv->fn_exec = gbinder_ipc_tx_custom_exec;
priv->fn_done = gbinder_ipc_tx_custom_done;
priv->fn_free = gbinder_ipc_tx_custom_free;
gbinder_ipc_tx_priv_init(priv, self, id, user_data,
gbinder_ipc_tx_custom_exec, gbinder_ipc_tx_custom_done,
gbinder_ipc_tx_custom_free);
tx->fn_custom_exec = exec;
tx->fn_custom_done = done;
@@ -1283,41 +1417,6 @@ gbinder_ipc_tx_custom_new(
return priv;
}
static
void
gbinder_ipc_tx_free(
gpointer data)
{
GBinderIpcTxPriv* tx = data;
GBinderIpcTx* pub = &tx->pub;
GBinderIpc* self = pub->ipc;
GBinderIpcPriv* priv = self->priv;
g_hash_table_remove(priv->tx_table, GINT_TO_POINTER(pub->id));
tx->fn_free(tx);
/* This may actually deallocate GBinderIpc object: */
gbinder_ipc_unref(self);
}
static
gboolean
gbinder_ipc_tx_done(
gpointer data)
{
GBinderIpcTxPriv* tx = data;
GBinderIpcTx* pub = &tx->pub;
GBinderIpc* self = pub->ipc;
GBinderIpcPriv* priv = self->priv;
if (g_hash_table_remove(priv->tx_table, GINT_TO_POINTER(tx->pub.id))) {
GASSERT(!pub->cancelled);
tx->fn_done(tx);
}
return G_SOURCE_REMOVE;
}
/* Invoked on a thread from tx_pool */
static
void
@@ -1328,7 +1427,6 @@ gbinder_ipc_tx_proc(
GBinderIpcTxPriv* tx = data;
GBinderIpc* self = GBINDER_IPC(object);
GBinderIpcPriv* priv = self->priv;
GSource* source = g_idle_source_new();
if (!tx->pub.cancelled) {
tx->fn_exec(tx);
@@ -1337,9 +1435,7 @@ gbinder_ipc_tx_proc(
}
/* The result is handled by the main thread */
g_source_set_callback(source, gbinder_ipc_tx_done, tx, gbinder_ipc_tx_free);
g_source_attach(source, priv->context);
g_source_unref(source);
g_source_attach(tx->completion, priv->context);
}
/*==========================================================================*
@@ -1516,7 +1612,6 @@ gbinder_ipc_cancel(
GBinderIpcTx* tx = g_hash_table_lookup(priv->tx_table, key);
if (tx) {
GVERIFY(g_hash_table_remove(priv->tx_table, key));
tx->cancelled = TRUE;
GVERBOSE_("%lu", id);
} else {
@@ -1556,14 +1651,44 @@ gbinder_ipc_init(
self->pool = gutil_idle_pool_new();
}
static
void
gbinder_ipc_stop_loopers(
GBinderIpc* self)
{
GBinderIpcPriv* priv = self->priv;
GBinderIpcLooper* loopers = NULL;
do {
GBinderIpcLooper* tmp;
/* Lock */
g_mutex_lock(&priv->looper_mutex);
loopers = gbinder_ipc_looper_stop_all(gbinder_ipc_looper_stop_all(NULL,
priv->primary_loopers), priv->blocked_loopers);
priv->blocked_loopers = NULL;
priv->primary_loopers = NULL;
g_mutex_unlock(&priv->looper_mutex);
/* Unlock */
tmp = loopers;
while (tmp) {
GBinderIpcLooper* looper = tmp;
tmp = looper->next;
looper->next = NULL;
gbinder_ipc_looper_join(looper);
gbinder_ipc_looper_unref(looper);
}
} while (loopers);
}
static
void
gbinder_ipc_dispose(
GObject* object)
{
GBinderIpc* self = GBINDER_IPC(object);
GBinderIpcPriv* priv = self->priv;
GBinderIpcLooper* loopers = NULL;
GVERBOSE_("%s", self->dev);
/* Lock */
@@ -1582,24 +1707,7 @@ gbinder_ipc_dispose(
pthread_mutex_unlock(&gbinder_ipc_mutex);
/* Unlock */
/* Lock */
g_mutex_lock(&priv->looper_mutex);
loopers = gbinder_ipc_looper_stop_all(loopers, priv->primary_loopers);
loopers = gbinder_ipc_looper_stop_all(loopers, priv->blocked_loopers);
priv->blocked_loopers = NULL;
priv->primary_loopers = NULL;
g_mutex_unlock(&priv->looper_mutex);
/* Unlock */
while (loopers) {
GBinderIpcLooper* looper = loopers;
loopers = looper->next;
looper->next = NULL;
gbinder_ipc_looper_join(looper);
gbinder_ipc_looper_unref(looper);
}
gbinder_ipc_stop_loopers(self);
G_OBJECT_CLASS(gbinder_ipc_parent_class)->finalize(object);
}
@@ -1616,7 +1724,9 @@ gbinder_ipc_finalize(
g_mutex_clear(&priv->looper_mutex);
g_mutex_clear(&priv->local_objects_mutex);
g_mutex_clear(&priv->remote_objects_mutex);
g_thread_pool_free(priv->tx_pool, FALSE, TRUE);
if (priv->tx_pool) {
g_thread_pool_free(priv->tx_pool, FALSE, TRUE);
}
GASSERT(!g_hash_table_size(priv->tx_table));
g_hash_table_unref(priv->tx_table);
gutil_idle_pool_unref(self->pool);
@@ -1637,6 +1747,91 @@ gbinder_ipc_class_init(
object_class->finalize = gbinder_ipc_finalize;
}
/* Runs at exit */
void
gbinder_ipc_exit()
{
GHashTableIter it;
gpointer key, value;
GSList* ipcs = NULL;
GSList* i;
/* Lock */
pthread_mutex_lock(&gbinder_ipc_mutex);
if (gbinder_ipc_table) {
g_hash_table_iter_init(&it, gbinder_ipc_table);
while (g_hash_table_iter_next(&it, NULL, &value)) {
ipcs = g_slist_append(ipcs, gbinder_ipc_ref(value));
}
}
pthread_mutex_unlock(&gbinder_ipc_mutex);
/* Unlock */
for (i = ipcs; i; i = i->next) {
GBinderIpc* ipc = GBINDER_IPC(i->data);
GBinderIpcPriv* priv = ipc->priv;
GThreadPool* pool = priv->tx_pool;
GSList* local_objs = NULL;
GSList* tx_keys = NULL;
GSList* k;
GSList* l;
/* Terminate looper threads */
GVERBOSE_("%s", ipc->dev);
gbinder_ipc_stop_loopers(ipc);
/* Make sure pooled transaction complete too */
priv->tx_pool = NULL;
g_thread_pool_free(pool, FALSE, TRUE);
/*
* Since this function is supposed to be invoked on the main thread,
* there's no need to synchronize access to priv->tx_table. In any
* case, this must be the last thread associated with this object.
*/
g_hash_table_iter_init(&it, priv->tx_table);
while (g_hash_table_iter_next(&it, &key, NULL)) {
tx_keys = g_slist_append(tx_keys, key);
}
for (k = tx_keys; k; k = k->next) {
GBinderIpcTxPriv* tx = g_hash_table_lookup(priv->tx_table, k->data);
GSource* source = g_source_ref(tx->completion);
GVERBOSE_("tx %lu", tx->pub.id);
g_source_destroy(source);
g_source_unref(source);
}
/* The above loop must destroy all uncompleted transactions */
GASSERT(!g_hash_table_size(priv->tx_table));
g_slist_free(tx_keys);
/* Lock */
g_mutex_lock(&priv->local_objects_mutex);
if (priv->local_objects) {
g_hash_table_iter_init(&it, priv->local_objects);
while (g_hash_table_iter_next(&it, NULL, &value)) {
local_objs = g_slist_append(local_objs,
gbinder_local_object_ref(value));
}
}
g_mutex_unlock(&priv->local_objects_mutex);
/* Unlock */
/* Drop remote references */
for (l = local_objs; l; l = l->next) {
GBinderLocalObject* obj = GBINDER_LOCAL_OBJECT(l->data);
while (obj->strong_refs > 0) {
obj->strong_refs--;
gbinder_local_object_unref(obj);
}
}
g_slist_free_full(local_objs, g_object_unref);
}
g_slist_free_full(ipcs, g_object_unref);
}
/*
* Local Variables:
* mode: C

View File

@@ -68,40 +68,52 @@ void
int status,
void* user_data);
G_GNUC_INTERNAL
GBinderIpc*
gbinder_ipc_new(
const char* dev,
const GBinderRpcProtocol* protocol);
G_GNUC_INTERNAL
GBinderIpc*
gbinder_ipc_ref(
GBinderIpc* ipc);
G_GNUC_INTERNAL
void
gbinder_ipc_unref(
GBinderIpc* ipc);
G_GNUC_INTERNAL
void
gbinder_ipc_looper_check(
GBinderIpc* ipc);
G_GNUC_INTERNAL
GBinderObjectRegistry*
gbinder_ipc_object_registry(
GBinderIpc* ipc);
GBinderLocalObject*
gbinder_ipc_new_local_object(
G_GNUC_INTERNAL
void
gbinder_ipc_register_local_object(
GBinderIpc* ipc,
const char* iface,
GBinderLocalTransactFunc txproc,
void* data);
GBinderLocalObject* obj);
G_GNUC_INTERNAL
GBinderRemoteObject*
gbinder_ipc_get_remote_object(
GBinderIpc* ipc,
guint32 handle,
gboolean maybe_dead);
G_GNUC_INTERNAL
void
gbinder_ipc_invalidate_remote_handle(
GBinderIpc* ipc,
guint32 handle);
G_GNUC_INTERNAL
GBinderRemoteReply*
gbinder_ipc_transact_sync_reply(
GBinderIpc* ipc,
@@ -110,6 +122,7 @@ gbinder_ipc_transact_sync_reply(
GBinderLocalRequest* req,
int* status);
G_GNUC_INTERNAL
int
gbinder_ipc_transact_sync_oneway(
GBinderIpc* ipc,
@@ -117,6 +130,7 @@ gbinder_ipc_transact_sync_oneway(
guint32 code,
GBinderLocalRequest* req);
G_GNUC_INTERNAL
gulong
gbinder_ipc_transact(
GBinderIpc* ipc,
@@ -128,6 +142,7 @@ gbinder_ipc_transact(
GDestroyNotify destroy,
void* user_data);
G_GNUC_INTERNAL
gulong
gbinder_ipc_transact_custom(
GBinderIpc* ipc,
@@ -136,23 +151,33 @@ gbinder_ipc_transact_custom(
GDestroyNotify destroy,
void* user_data);
G_GNUC_INTERNAL
void
gbinder_ipc_cancel(
GBinderIpc* ipc,
gulong id);
/* Internal for GBinderLocalObject */
G_GNUC_INTERNAL
void
gbinder_ipc_local_object_disposed(
GBinderIpc* self,
GBinderLocalObject* obj);
/* Internal for GBinderRemoteObject */
G_GNUC_INTERNAL
void
gbinder_ipc_remote_object_disposed(
GBinderIpc* self,
GBinderRemoteObject* obj);
/* Declared for unit tests */
G_GNUC_INTERNAL
__attribute__((destructor))
void
gbinder_ipc_exit(
void);
#endif /* GBINDER_IPC_H */
/*

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -30,6 +30,8 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include "gbinder_driver.h"
#include "gbinder_ipc.h"
#include "gbinder_local_object_p.h"
@@ -38,11 +40,13 @@
#include "gbinder_writer.h"
#include "gbinder_log.h"
#include <gutil_strv.h>
#include <errno.h>
struct gbinder_local_object_priv {
GMainContext* context;
char* iface;
char** ifaces;
GBinderLocalTransactFunc txproc;
void* user_data;
};
@@ -144,10 +148,11 @@ gbinder_local_object_interface_transaction(
int* status)
{
const GBinderIo* io = gbinder_local_object_io(self);
GBinderLocalObjectPriv* priv = self->priv;
GBinderLocalReply* reply = gbinder_local_reply_new(io);
GVERBOSE(" INTERFACE_TRANSACTION");
gbinder_local_reply_append_string16(reply, self->iface);
gbinder_local_reply_append_string16(reply, priv->ifaces[0]);
*status = GBINDER_STATUS_OK;
return reply;
}
@@ -179,6 +184,7 @@ gbinder_local_object_hidl_get_descriptor_transaction(
{
/*android.hidl.base@1.0::IBase interfaceDescriptor() */
const GBinderIo* io = gbinder_local_object_io(self);
GBinderLocalObjectPriv* priv = self->priv;
GBinderLocalReply* reply = gbinder_local_reply_new(io);
GBinderWriter writer;
@@ -186,8 +192,7 @@ gbinder_local_object_hidl_get_descriptor_transaction(
gbinder_remote_request_interface(req));
gbinder_local_reply_init_writer(reply, &writer);
gbinder_writer_append_int32(&writer, GBINDER_STATUS_OK);
gbinder_writer_append_hidl_string(&writer, self->iface ? self->iface :
hidl_base_interface);
gbinder_writer_append_hidl_string(&writer, priv->ifaces[0]);
*status = GBINDER_STATUS_OK;
return reply;
}
@@ -203,17 +208,14 @@ gbinder_local_object_hidl_descriptor_chain_transaction(
const GBinderIo* io = gbinder_local_object_io(self);
GBinderLocalReply* reply = gbinder_local_reply_new(io);
GBinderWriter writer;
const char* chain[2];
int n = 0;
GVERBOSE(" HIDL_DESCRIPTOR_CHAIN_TRANSACTION \"%s\"",
gbinder_remote_request_interface(req));
if (self->iface) chain[n++] = self->iface;
chain[n++] = hidl_base_interface;
gbinder_local_reply_init_writer(reply, &writer);
gbinder_writer_append_int32(&writer, GBINDER_STATUS_OK);
gbinder_writer_append_hidl_string_vec(&writer, chain, n);
gbinder_writer_append_hidl_string_vec(&writer, (const char**)
self->ifaces, -1);
*status = GBINDER_STATUS_OK;
return reply;
}
@@ -330,20 +332,40 @@ gbinder_local_object_handle_release_proc(
GBinderLocalObject*
gbinder_local_object_new(
GBinderIpc* ipc,
const char* iface,
const char* const* ifaces,
GBinderLocalTransactFunc txproc,
void* user_data)
void* user_data) /* Since 1.0.30 */
{
/* Should only be called from gbinder_ipc_new_local_object() */
if (G_LIKELY(ipc)) {
GBinderLocalObject* self = g_object_new
(GBINDER_TYPE_LOCAL_OBJECT, NULL);
GBinderLocalObjectPriv* priv = self->priv;
guint i = 0, n = gutil_strv_length((char**)ifaces);
gboolean append_base_interface;
if (g_strcmp0(gutil_strv_last((char**)ifaces), hidl_base_interface)) {
append_base_interface = TRUE;
n++;
} else {
append_base_interface = FALSE;
}
priv->ifaces = g_new(char*, n + 1);
if (ifaces) {
while (*ifaces) {
priv->ifaces[i++] = g_strdup(*ifaces++);
}
}
if (append_base_interface) {
priv->ifaces[i++] = g_strdup(hidl_base_interface);
}
priv->ifaces[i] = NULL;
self->ipc = gbinder_ipc_ref(ipc);
self->iface = priv->iface = g_strdup(iface);
self->ifaces = (const char**)priv->ifaces;
priv->txproc = txproc;
priv->user_data = user_data;
gbinder_ipc_register_local_object(ipc, self);
return self;
}
return NULL;
@@ -539,7 +561,7 @@ gbinder_local_object_finalize(
GASSERT(!self->strong_refs);
gbinder_ipc_unref(self->ipc);
g_free(priv->iface);
g_strfreev(priv->ifaces);
G_OBJECT_CLASS(gbinder_local_object_parent_class)->finalize(local);
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -13,9 +13,9 @@
* 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 name of Jolla Ltd nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
* 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
@@ -55,7 +55,7 @@ struct gbinder_local_object {
GObject object;
GBinderLocalObjectPriv* priv;
GBinderIpc* ipc;
const char* iface;
const char* const* ifaces;
gint weak_refs;
gint strong_refs;
};
@@ -87,14 +87,6 @@ GType gbinder_local_object_get_type(void);
#define gbinder_local_object_dev(obj) (gbinder_driver_dev((obj)->ipc->driver))
#define gbinder_local_object_io(obj) (gbinder_driver_io((obj)->ipc->driver))
/* Should only be called from gbinder_ipc_new_local_object() */
GBinderLocalObject*
gbinder_local_object_new(
GBinderIpc* ipc,
const char* iface,
GBinderLocalTransactFunc handler,
void* user_data);
gulong
gbinder_local_object_add_weak_refs_changed_handler(
GBinderLocalObject* obj,

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -30,9 +30,12 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include "gbinder_driver.h"
#include "gbinder_ipc.h"
#include "gbinder_remote_object_p.h"
#include "gbinder_servicemanager_p.h"
#include "gbinder_log.h"
struct gbinder_remote_object_priv {
@@ -71,6 +74,10 @@ gbinder_remote_object_died_on_main_thread(
GASSERT(!self->dead);
if (!self->dead) {
self->dead = TRUE;
/* ServiceManager always has the same handle, and can be reanimated. */
if (self->handle != GBINDER_SERVICEMANAGER_HANDLE) {
gbinder_ipc_invalidate_remote_handle(self->ipc, self->handle);
}
gbinder_driver_clear_death_notification(driver, self);
gbinder_driver_release(driver, self->handle);
g_signal_emit(self, gbinder_remote_object_signals[SIGNAL_DEATH], 0);
@@ -104,6 +111,7 @@ gbinder_remote_object_reanimate(
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
/* Kick the horse */
GASSERT(self->handle == GBINDER_SERVICEMANAGER_HANDLE);
if (gbinder_driver_ping(ipc->driver, reg, self->handle) == 0) {
/* Wow, it's alive! */
self->dead = FALSE;
@@ -172,6 +180,13 @@ gbinder_remote_object_unref(
}
}
GBinderIpc*
gbinder_remote_object_ipc(
GBinderRemoteObject* self) /* Since 1.0.30 */
{
return G_LIKELY(self) ? self->ipc : NULL;
}
gboolean
gbinder_remote_object_is_dead(
GBinderRemoteObject* self)

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2020 Jolla Ltd.
* Copyright (C) 2018-2020 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -14,8 +14,8 @@
* 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.
* 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
@@ -30,6 +30,8 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#define GLIB_DISABLE_DEPRECATION_WARNINGS
#include "gbinder_servicemanager_p.h"
#include "gbinder_client_p.h"
#include "gbinder_local_object_p.h"
@@ -165,6 +167,7 @@ gbinder_servicemanager_list_tx_done(
if (!data->func(data->sm, data->result, data->user_data)) {
g_strfreev(data->result);
}
data->result = NULL;
}
static
@@ -174,6 +177,7 @@ gbinder_servicemanager_list_tx_free(
{
GBinderServiceManagerListTxData* data = user_data;
g_strfreev(data->result);
gbinder_servicemanager_unref(data->sm);
g_slice_free(GBinderServiceManagerListTxData, data);
}
@@ -407,7 +411,7 @@ gbinder_servicemanager_new_with_type(
if (ipc) {
/* Create a possible dead remote object */
GBinderRemoteObject* object = gbinder_ipc_get_remote_object
(ipc, klass->handle, TRUE);
(ipc, GBINDER_SERVICEMANAGER_HANDLE, TRUE);
if (object) {
gboolean first_ref;
@@ -509,10 +513,25 @@ gbinder_servicemanager_new_local_object(
const char* iface,
GBinderLocalTransactFunc txproc,
void* user_data)
{
const char* ifaces[2];
ifaces[0] = iface;
ifaces[1] = NULL;
return gbinder_servicemanager_new_local_object2
(self, ifaces, txproc, user_data);
}
GBinderLocalObject*
gbinder_servicemanager_new_local_object2(
GBinderServiceManager* self,
const char* const* ifaces,
GBinderLocalTransactFunc txproc,
void* user_data)
{
if (G_LIKELY(self)) {
return gbinder_ipc_new_local_object(gbinder_client_ipc(self->client),
iface, txproc, user_data);
return gbinder_local_object_new(gbinder_client_ipc(self->client),
ifaces, txproc, user_data);
}
return NULL;
}

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -39,6 +39,9 @@
#include <glib-object.h>
/* As a special case, ServiceManager's handle is zero */
#define GBINDER_SERVICEMANAGER_HANDLE (0)
typedef struct gbinder_servicemanager_priv GBinderServiceManagerPriv;
typedef struct gbinder_servicemanager {
@@ -60,7 +63,6 @@ typedef struct gbinder_servicemanager_class {
GMutex mutex;
GHashTable* table;
guint32 handle;
const char* iface;
const char* default_device;
const GBinderRpcProtocol* rpc_protocol;

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -40,7 +40,6 @@ typedef struct gbinder_cleanup GBinderCleanup;
typedef struct gbinder_driver GBinderDriver;
typedef struct gbinder_handler GBinderHandler;
typedef struct gbinder_io GBinderIo;
typedef struct gbinder_ipc GBinderIpc;
typedef struct gbinder_object_registry GBinderObjectRegistry;
typedef struct gbinder_output_data GBinderOutputData;
typedef struct gbinder_rpc_protocol GBinderRpcProtocol;

View File

@@ -5,5 +5,6 @@ all:
@$(MAKE) -C binder-client $*
@$(MAKE) -C binder-dump $*
@$(MAKE) -C binder-list $*
@$(MAKE) -C binder-ping $*
@$(MAKE) -C binder-service $*
@$(MAKE) -C rild-card-status $*

View File

@@ -41,7 +41,7 @@ RELEASE_BUILD_DIR = $(BUILD_DIR)/release
# Tools and flags
#
CC = $(CROSS_COMPILE)gcc
CC ?= $(CROSS_COMPILE)gcc
LD = $(CC)
WARNINGS = -Wall
INCLUDES = -I$(LIB_DIR)/include

View File

@@ -41,7 +41,7 @@ RELEASE_BUILD_DIR = $(BUILD_DIR)/release
# Tools and flags
#
CC = $(CROSS_COMPILE)gcc
CC ?= $(CROSS_COMPILE)gcc
LD = $(CC)
WARNINGS = -Wall
INCLUDES = -I$(LIB_DIR)/include

View File

@@ -41,7 +41,7 @@ RELEASE_BUILD_DIR = $(BUILD_DIR)/release
# Tools and flags
#
CC = $(CROSS_COMPILE)gcc
CC ?= $(CROSS_COMPILE)gcc
LD = $(CC)
WARNINGS = -Wall
INCLUDES = -I$(LIB_DIR)/include

140
test/binder-ping/Makefile Normal file
View File

@@ -0,0 +1,140 @@
# -*- Mode: makefile-gmake -*-
.PHONY: all debug release clean cleaner
.PHONY: libgbinder-release libgbinder-debug
#
# Required packages
#
PKGS = glib-2.0 gio-2.0 gio-unix-2.0 libglibutil
#
# Default target
#
all: debug release
#
# Executable
#
EXE = binder-ping
#
# Sources
#
SRC = $(EXE).c
#
# Directories
#
SRC_DIR = .
BUILD_DIR = build
LIB_DIR = ../..
DEBUG_BUILD_DIR = $(BUILD_DIR)/debug
RELEASE_BUILD_DIR = $(BUILD_DIR)/release
#
# Tools and flags
#
CC ?= $(CROSS_COMPILE)gcc
LD = $(CC)
WARNINGS = -Wall
INCLUDES = -I$(LIB_DIR)/include
BASE_FLAGS = -fPIC
CFLAGS = $(BASE_FLAGS) $(DEFINES) $(WARNINGS) $(INCLUDES) -MMD -MP \
$(shell pkg-config --cflags $(PKGS))
LDFLAGS = $(BASE_FLAGS) $(shell pkg-config --libs $(PKGS))
QUIET_MAKE = make --no-print-directory
DEBUG_FLAGS = -g
RELEASE_FLAGS =
ifndef KEEP_SYMBOLS
KEEP_SYMBOLS = 0
endif
ifneq ($(KEEP_SYMBOLS),0)
RELEASE_FLAGS += -g
SUBMAKE_OPTS += KEEP_SYMBOLS=1
endif
DEBUG_LDFLAGS = $(LDFLAGS) $(DEBUG_FLAGS)
RELEASE_LDFLAGS = $(LDFLAGS) $(RELEASE_FLAGS)
DEBUG_CFLAGS = $(CFLAGS) $(DEBUG_FLAGS) -DDEBUG
RELEASE_CFLAGS = $(CFLAGS) $(RELEASE_FLAGS) -O2
#
# Files
#
DEBUG_OBJS = $(SRC:%.c=$(DEBUG_BUILD_DIR)/%.o)
RELEASE_OBJS = $(SRC:%.c=$(RELEASE_BUILD_DIR)/%.o)
DEBUG_SO_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_debug_so)
RELEASE_SO_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_release_so)
DEBUG_LINK_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_debug_link)
RELEASE_LINK_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_release_link)
DEBUG_SO = $(LIB_DIR)/$(DEBUG_SO_FILE)
RELEASE_SO = $(LIB_DIR)/$(RELEASE_SO_FILE)
#
# Dependencies
#
DEPS = $(DEBUG_OBJS:%.o=%.d) $(RELEASE_OBJS:%.o=%.d)
ifneq ($(MAKECMDGOALS),clean)
ifneq ($(strip $(DEPS)),)
-include $(DEPS)
endif
endif
$(DEBUG_OBJS): | $(DEBUG_BUILD_DIR)
$(RELEASE_OBJS): | $(RELEASE_BUILD_DIR)
#
# Rules
#
DEBUG_EXE = $(DEBUG_BUILD_DIR)/$(EXE)
RELEASE_EXE = $(RELEASE_BUILD_DIR)/$(EXE)
debug: libgbinder-debug $(DEBUG_EXE)
release: libgbinder-release $(RELEASE_EXE)
clean:
rm -f *~
rm -fr $(BUILD_DIR)
cleaner: clean
@make -C $(LIB_DIR) clean
$(DEBUG_BUILD_DIR):
mkdir -p $@
$(RELEASE_BUILD_DIR):
mkdir -p $@
$(DEBUG_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
$(CC) -c $(DEBUG_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
$(RELEASE_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
$(CC) -c $(RELEASE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
$(DEBUG_EXE): $(DEBUG_SO) $(DEBUG_BUILD_DIR) $(DEBUG_OBJS)
$(LD) $(DEBUG_OBJS) $(DEBUG_LDFLAGS) $< -o $@
$(RELEASE_EXE): $(RELEASE_SO) $(RELEASE_BUILD_DIR) $(RELEASE_OBJS)
$(LD) $(RELEASE_OBJS) $(RELEASE_LDFLAGS) $< -o $@
ifeq ($(KEEP_SYMBOLS),0)
strip $@
endif
libgbinder-debug:
@make $(SUBMAKE_OPTS) -C $(LIB_DIR) $(DEBUG_SO_FILE) $(DEBUG_LINK_FILE)
libgbinder-release:
@make $(SUBMAKE_OPTS) -C $(LIB_DIR) $(RELEASE_SO_FILE) $(RELEASE_LINK_FILE)

View File

@@ -0,0 +1,187 @@
/*
* Copyright (C) 2020 Jolla Ltd.
* Copyright (C) 2020 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.h>
#include <gutil_log.h>
#define RET_OK (0)
#define RET_NOTFOUND (1)
#define RET_INVARG (2)
#define RET_ERR (3)
#define DEFAULT_BINDER GBINDER_DEFAULT_HWBINDER
#define AIDL_PING_TRANSACTION GBINDER_FOURCC('_','P','N','G')
#define HIDL_PING_TRANSACTION GBINDER_FOURCC(0x0f,'P','N','G')
typedef struct app_options {
const char* fqname;
char* dev;
guint32 ping_code;
const char* iface;
} AppOptions;
static
int
app_run(
const AppOptions* opt)
{
int ret = RET_NOTFOUND;
GBinderServiceManager* sm = gbinder_servicemanager_new(opt->dev);
if (sm) {
int status = 0;
GBinderRemoteObject* remote = gbinder_servicemanager_get_service_sync
(sm, opt->fqname, &status);
if (remote) {
int status;
GBinderClient* client = gbinder_client_new(remote, opt->iface);
GBinderRemoteReply* reply = gbinder_client_transact_sync_reply
(client, opt->ping_code, NULL, &status);
if (reply) {
GINFO("OK");
ret = RET_OK;
} else {
GERR("Ping failed (%d)", status);
ret = RET_ERR;
}
gbinder_remote_reply_unref(reply);
gbinder_client_unref(client);
} else {
GERR("%s not found", opt->fqname);
}
gbinder_servicemanager_unref(sm);
} else {
GERR("No servicemanager at %s", opt->dev);
}
return ret;
}
static
gboolean
app_log_verbose(
const gchar* name,
const gchar* value,
gpointer data,
GError** error)
{
gutil_log_default.level = GLOG_LEVEL_VERBOSE;
return TRUE;
}
static
gboolean
app_log_quiet(
const gchar* name,
const gchar* value,
gpointer data,
GError** error)
{
gutil_log_default.level = GLOG_LEVEL_NONE;
return TRUE;
}
static
gboolean
app_init(
AppOptions* opt,
int argc,
char* argv[])
{
gboolean ok = FALSE;
GOptionEntry entries[] = {
{ "verbose", 'v', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
app_log_verbose, "Enable verbose output", NULL },
{ "quiet", 'q', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK,
app_log_quiet, "Be quiet", NULL },
{ "device", 'd', 0, G_OPTION_ARG_STRING, &opt->dev,
"Binder device [" DEFAULT_BINDER "]", "DEVICE" },
{ NULL }
};
GError* error = NULL;
GOptionContext* options = g_option_context_new("[FQNAME]");
gutil_log_timestamp = FALSE;
gutil_log_default.level = GLOG_LEVEL_DEFAULT;
g_option_context_add_main_entries(options, entries, NULL);
if (g_option_context_parse(options, &argc, &argv, &error)) {
if (!opt->dev || !opt->dev[0]) {
opt->dev = g_strdup(DEFAULT_BINDER);
}
if (argc == 2) {
opt->fqname = argv[1];
if (g_strcmp0(opt->dev, GBINDER_DEFAULT_BINDER)) {
opt->ping_code = HIDL_PING_TRANSACTION;
opt->iface = "android.hidl.base@1.0::IBase";
} else {
opt->ping_code = AIDL_PING_TRANSACTION;
opt->iface = "android.os.IBinder";
}
ok = TRUE;
} else {
char* help = g_option_context_get_help(options, TRUE, NULL);
fprintf(stderr, "%s", help);
g_free(help);
}
} else {
GERR("%s", error->message);
g_error_free(error);
}
g_option_context_free(options);
return ok;
}
int main(int argc, char* argv[])
{
AppOptions opt;
int ret = RET_INVARG;
memset(&opt, 0, sizeof(opt));
if (app_init(&opt, argc, argv)) {
ret = app_run(&opt);
}
g_free(opt.dev);
return ret;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -41,7 +41,7 @@ RELEASE_BUILD_DIR = $(BUILD_DIR)/release
# Tools and flags
#
CC = $(CROSS_COMPILE)gcc
CC ?= $(CROSS_COMPILE)gcc
LD = $(CC)
WARNINGS = -Wall
INCLUDES = -I$(LIB_DIR)/include

View File

@@ -41,7 +41,7 @@ RELEASE_BUILD_DIR = $(BUILD_DIR)/release
# Tools and flags
#
CC = $(CROSS_COMPILE)gcc
CC ?= $(CROSS_COMPILE)gcc
LD = $(CC)
WARNINGS = -Wall
INCLUDES = -I$(LIB_DIR)/include

View File

@@ -42,7 +42,7 @@ COVERAGE_BUILD_DIR = $(BUILD_DIR)/coverage
# Tools and flags
#
CC = $(CROSS_COMPILE)gcc
CC ?= $(CROSS_COMPILE)gcc
LD = $(CC)
WARNINGS += -Wall
INCLUDES += -I$(COMMON_DIR) -I$(LIB_DIR)/src -I$(LIB_DIR)/include
@@ -138,10 +138,10 @@ test_banner:
@echo "===========" $(EXE) "=========== "
test: test_banner debug
@LD_LIBRARY_PATH="$(LIB_DIR)/$(DEBUG_LIB_PATH)" $(DEBUG_EXE)
@$(DEBUG_EXE)
valgrind: test_banner debug
@LD_LIBRARY_PATH="$(LIB_DIR)/$(DEBUG_LIB_PATH)" G_DEBUG=gc-friendly G_SLICE=always-malloc valgrind --tool=memcheck --leak-check=full --show-possibly-lost=no $(DEBUG_EXE)
@G_DEBUG=gc-friendly G_SLICE=always-malloc valgrind --tool=memcheck --leak-check=full --show-possibly-lost=no $(DEBUG_EXE)
$(DEBUG_BUILD_DIR):
mkdir -p $@

View File

@@ -14,8 +14,8 @@
* 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.
* 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
@@ -130,6 +130,45 @@ test_no_header(
gbinder_client_unref(client);
}
/*==========================================================================*
* dead
*==========================================================================*/
static
void
test_dead_done(
GBinderRemoteObject* obj,
void* user_data)
{
GVERBOSE_("");
test_quit_later((GMainLoop*)user_data);
}
static
void
test_dead(
void)
{
const guint handle = 1;
GBinderClient* client = test_client_new(handle, "foo");
GBinderRemoteObject* obj = client->remote;
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
const int fd = gbinder_driver_fd(gbinder_client_ipc(client)->driver);
gbinder_remote_object_add_death_handler(obj, test_dead_done, loop);
test_binder_br_dead_binder(fd, handle);
test_binder_set_looper_enabled(fd, TRUE);
test_run(&test_opt, loop);
g_assert(gbinder_remote_object_is_dead(obj));
g_assert(!gbinder_client_transact_sync_reply(client, 0, NULL, NULL));
g_assert(gbinder_client_transact_sync_oneway(client, 0, NULL) == -ESTALE);
g_assert(!gbinder_client_transact(client, 0, 0, NULL, NULL, NULL, NULL));
gbinder_client_unref(client);
g_main_loop_unref(loop);
}
/*==========================================================================*
* sync_oneway
*==========================================================================*/
@@ -352,6 +391,7 @@ 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_("dead"), test_dead);
g_test_add_func(TEST_("no_header"), test_no_header);
g_test_add_func(TEST_("sync_oneway"), test_sync_oneway);
g_test_add_func(TEST_("sync_reply"), test_sync_reply);

View File

@@ -14,8 +14,8 @@
* 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.
* 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
@@ -34,7 +34,7 @@
#include "gbinder_ipc.h"
#include "gbinder_driver.h"
#include "gbinder_local_object.h"
#include "gbinder_local_object_p.h"
#include "gbinder_local_reply_p.h"
#include "gbinder_local_request_p.h"
#include "gbinder_object_registry.h"
@@ -127,6 +127,48 @@ test_basic(
/* Invalid path */
g_assert(!gbinder_ipc_new("invalid path", NULL));
gbinder_ipc_exit();
}
/*==========================================================================*
* async_oneway
*==========================================================================*/
static
void
test_async_oneway_done(
GBinderIpc* ipc,
GBinderRemoteReply* reply,
int status,
void* user_data)
{
g_assert(!status);
g_assert(!reply);
test_quit_later((GMainLoop*)user_data);
}
static
void
test_async_oneway(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
const int fd = gbinder_driver_fd(ipc->driver);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
gulong id;
test_binder_br_transaction_complete(fd);
id = gbinder_ipc_transact(ipc, 0, 1, GBINDER_TX_FLAG_ONEWAY,
req, test_async_oneway_done, NULL, loop);
g_assert(id);
test_run(&test_opt, loop);
gbinder_local_request_unref(req);
gbinder_ipc_unref(ipc);
g_main_loop_unref(loop);
}
/*==========================================================================*
@@ -148,6 +190,7 @@ test_sync_oneway(
GBINDER_STATUS_OK);
gbinder_local_request_unref(req);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
}
/*==========================================================================*
@@ -191,6 +234,7 @@ test_sync_reply_ok_status(
gbinder_local_request_unref(req);
gbinder_local_reply_unref(reply);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
}
static
@@ -233,6 +277,7 @@ test_sync_reply_error(
gbinder_local_request_unref(req);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
}
/*==========================================================================*
@@ -302,6 +347,7 @@ test_transact_ok(
gbinder_local_request_unref(req);
gbinder_local_reply_unref(reply);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
g_main_loop_unref(loop);
}
@@ -348,6 +394,7 @@ test_transact_dead(
gbinder_ipc_cancel(ipc, id);
gbinder_local_request_unref(req);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
g_main_loop_unref(loop);
}
@@ -394,6 +441,7 @@ test_transact_failed(
gbinder_ipc_cancel(ipc, id);
gbinder_local_request_unref(req);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
g_main_loop_unref(loop);
}
@@ -442,6 +490,7 @@ test_transact_status(
gbinder_ipc_cancel(ipc, id);
gbinder_local_request_unref(req);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
g_main_loop_unref(loop);
}
@@ -471,6 +520,7 @@ test_transact_custom(
g_assert(id);
test_run(&test_opt, loop);
gbinder_ipc_exit();
gbinder_ipc_unref(ipc);
g_main_loop_unref(loop);
}
@@ -501,10 +551,44 @@ test_transact_custom2(
g_assert(id);
test_run(&test_opt, loop);
gbinder_ipc_exit();
gbinder_ipc_unref(ipc);
g_main_loop_unref(loop);
}
/*==========================================================================*
* transact_custom3
*==========================================================================*/
static
void
test_transact_custom3_exec(
const GBinderIpcTx* tx)
{
GVERBOSE_("");
gbinder_ipc_unref(tx->ipc);
test_quit_later((GMainLoop*)tx->user_data);
}
static
void
test_transact_custom3(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
/* Reusing test_transact_cancel_done and test_transact_cancel_destroy */
gulong id = gbinder_ipc_transact_custom(ipc, test_transact_custom3_exec,
NULL, NULL, loop);
g_assert(id);
test_run(&test_opt, loop);
/* Reference to GBinderIpc is released by test_transact_custom3_exec */
gbinder_ipc_exit();
g_main_loop_unref(loop);
}
/*==========================================================================*
* transact_cancel
*==========================================================================*/
@@ -550,6 +634,7 @@ test_transact_cancel(
test_run(&test_opt, loop);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
g_main_loop_unref(loop);
}
@@ -594,6 +679,7 @@ test_transact_cancel2(
test_run(&test_opt, loop);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
g_main_loop_unref(loop);
}
@@ -634,9 +720,10 @@ test_transact_incoming(
const int fd = gbinder_driver_fd(ipc->driver);
const char* dev = gbinder_driver_dev(ipc->driver);
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
const char* const ifaces[] = { "test", NULL };
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderLocalObject* obj = gbinder_ipc_new_local_object
(ipc, "test", test_transact_incoming_proc, loop);
GBinderLocalObject* obj = gbinder_local_object_new
(ipc, ifaces, test_transact_incoming_proc, loop);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
GBinderOutputData* data;
GBinderWriter writer;
@@ -658,6 +745,7 @@ test_transact_incoming(
g_idle_add(test_unref_ipc, ipc);
test_run(&test_opt, loop);
gbinder_ipc_exit();
g_main_loop_unref(loop);
}
@@ -696,9 +784,10 @@ test_transact_status_reply(
const int fd = gbinder_driver_fd(ipc->driver);
const char* dev = gbinder_driver_dev(ipc->driver);
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
const char* const ifaces[] = { "test", NULL };
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderLocalObject* obj = gbinder_ipc_new_local_object
(ipc, "test", test_transact_status_reply_proc, loop);
GBinderLocalObject* obj = gbinder_local_object_new
(ipc, ifaces, test_transact_status_reply_proc, loop);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
GBinderOutputData* data;
GBinderWriter writer;
@@ -720,6 +809,7 @@ test_transact_status_reply(
g_idle_add(test_unref_ipc, ipc);
test_run(&test_opt, loop);
gbinder_ipc_exit();
g_main_loop_unref(loop);
}
@@ -801,9 +891,10 @@ test_transact_async(
const int fd = gbinder_driver_fd(ipc->driver);
const char* dev = gbinder_driver_dev(ipc->driver);
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
const char* const ifaces[] = { "test", NULL };
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderLocalObject* obj = gbinder_ipc_new_local_object
(ipc, "test", test_transact_async_proc, loop);
GBinderLocalObject* obj = gbinder_local_object_new
(ipc, ifaces, test_transact_async_proc, loop);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
GBinderOutputData* data;
GBinderWriter writer;
@@ -825,6 +916,7 @@ test_transact_async(
g_idle_add(test_unref_ipc, ipc);
test_run(&test_opt, loop);
gbinder_ipc_exit();
g_main_loop_unref(loop);
}
@@ -872,9 +964,10 @@ test_transact_async_sync(
const int fd = gbinder_driver_fd(ipc->driver);
const char* dev = gbinder_driver_dev(ipc->driver);
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
const char* const ifaces[] = { "test", NULL };
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderLocalObject* obj = gbinder_ipc_new_local_object
(ipc, "test", test_transact_async_sync_proc, loop);
GBinderLocalObject* obj = gbinder_local_object_new
(ipc, ifaces, test_transact_async_sync_proc, loop);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
GBinderOutputData* data;
GBinderWriter writer;
@@ -896,6 +989,86 @@ test_transact_async_sync(
g_idle_add(test_unref_ipc, ipc);
test_run(&test_opt, loop);
gbinder_ipc_exit();
g_main_loop_unref(loop);
}
/*==========================================================================*
* drop_remote_refs
*==========================================================================*/
static
void
test_drop_remote_refs_cb(
GBinderLocalObject* obj,
void* user_data)
{
GVERBOSE_("%d", obj->strong_refs);
g_assert(obj->strong_refs == 1);
test_quit_later((GMainLoop*)user_data);
}
static
void
test_drop_remote_refs(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderLocalObject* obj = gbinder_local_object_new
(ipc, NULL, NULL, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
int fd = gbinder_driver_fd(ipc->driver);
gulong id = gbinder_local_object_add_strong_refs_changed_handler(obj,
test_drop_remote_refs_cb, loop);
test_binder_br_acquire(fd, obj);
test_binder_set_looper_enabled(fd, TRUE);
test_run(&test_opt, loop);
g_assert(obj->strong_refs == 1);
gbinder_local_object_remove_handler(obj, id);
gbinder_local_object_unref(obj);
/* gbinder_ipc_exit will drop the remote reference */
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
g_main_loop_unref(loop);
}
/*==========================================================================*
* cancel_on_exit
*==========================================================================*/
static
void
test_cancel_on_exit_not_reached(
GBinderIpc* ipc,
GBinderRemoteReply* reply,
int status,
void* user_data)
{
g_assert_not_reached();
}
static
void
test_cancel_on_exit(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
int fd = gbinder_driver_fd(ipc->driver);
/* This transaction will be cancelled by gbinder_ipc_exit */
test_binder_br_transaction_complete(fd);
gbinder_ipc_transact(ipc, 0, 1, GBINDER_TX_FLAG_ONEWAY,
req, test_cancel_on_exit_not_reached, NULL, NULL);
gbinder_local_request_unref(req);
gbinder_ipc_unref(ipc);
gbinder_ipc_exit();
g_main_loop_unref(loop);
}
@@ -911,6 +1084,7 @@ 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_("async_oneway"), test_async_oneway);
g_test_add_func(TEST_("sync_oneway"), test_sync_oneway);
g_test_add_func(TEST_("sync_reply_ok"), test_sync_reply_ok);
g_test_add_func(TEST_("sync_reply_error"), test_sync_reply_error);
@@ -920,12 +1094,15 @@ int main(int argc, char* argv[])
g_test_add_func(TEST_("transact_status"), test_transact_status);
g_test_add_func(TEST_("transact_custom"), test_transact_custom);
g_test_add_func(TEST_("transact_custom2"), test_transact_custom2);
g_test_add_func(TEST_("transact_custom3"), test_transact_custom3);
g_test_add_func(TEST_("transact_cancel"), test_transact_cancel);
g_test_add_func(TEST_("transact_cancel2"), test_transact_cancel2);
g_test_add_func(TEST_("transact_incoming"), test_transact_incoming);
g_test_add_func(TEST_("transact_status_reply"), test_transact_status_reply);
g_test_add_func(TEST_("transact_async"), test_transact_async);
g_test_add_func(TEST_("transact_async_sync"), test_transact_async_sync);
g_test_add_func(TEST_("drop_remote_refs"), test_drop_remote_refs);
g_test_add_func(TEST_("cancel_on_exit"), test_cancel_on_exit);
test_init(&test_opt, argc, argv);
return g_test_run();
}

View File

@@ -150,6 +150,8 @@ void
test_basic(
void)
{
const char* const ifaces_foo[] = { "foo", NULL };
const char* const ifaces_bar[] = { "bar", NULL };
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderLocalObject* foo;
@@ -159,8 +161,8 @@ test_basic(
g_assert(!gbinder_object_registry_get_local(reg, ipc));
/* Create a new local objects */
foo = gbinder_ipc_new_local_object(ipc, "foo", NULL, NULL);
bar = gbinder_ipc_new_local_object(ipc, "bar", NULL, NULL);
foo = gbinder_local_object_new(ipc, ifaces_foo, NULL, NULL);
bar = gbinder_local_object_new(ipc, ifaces_bar, NULL, NULL);
/* But ipc is still not a local object! */
g_assert(!gbinder_object_registry_get_local(reg, ipc));
@@ -202,8 +204,7 @@ test_ping(
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
GBinderLocalObject* obj =
gbinder_ipc_new_local_object(ipc, NULL, NULL, NULL);
GBinderLocalObject* obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
GBinderLocalReply* reply;
GBinderOutputData* out_data;
static const guint8 result[] = { 0x00, 0x00, 0x00, 0x00 };
@@ -245,11 +246,11 @@ test_interface(
int status = INT_MAX;
const char* dev = GBINDER_DEFAULT_HWBINDER;
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
const char* const ifaces[] = { "x", NULL };
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
GBinderLocalObject* obj =
gbinder_ipc_new_local_object(ipc, "x", NULL, NULL);
GBinderLocalObject* obj = gbinder_local_object_new(ipc, ifaces, NULL, NULL);
GBinderLocalReply* reply;
GBinderOutputData* out_data;
static const guint8 result[] = {
@@ -298,8 +299,7 @@ test_hidl_ping(
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
GBinderLocalObject* obj =
gbinder_ipc_new_local_object(ipc, NULL, NULL, NULL);
GBinderLocalObject* obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
GBinderLocalReply* reply;
GBinderOutputData* out_data;
static const guint8 result[] = { 0x00, 0x00, 0x00, 0x00 };
@@ -349,8 +349,7 @@ test_get_descriptor(
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
GBinderLocalObject* obj =
gbinder_ipc_new_local_object(ipc, NULL, NULL, NULL);
GBinderLocalObject* obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
GBinderLocalReply* reply;
gbinder_remote_request_set_data(req, HIDL_PING_TRANSACTION,
@@ -401,15 +400,16 @@ test_descriptor_chain(
};
int status = INT_MAX;
const char* dev = GBINDER_DEFAULT_HWBINDER;
const char* const ifaces[] = { "android.hidl.base@1.0::IBase", NULL };
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
GBinderLocalObject* obj =
gbinder_ipc_new_local_object(ipc, NULL, NULL, NULL);
GBinderLocalObject* obj = gbinder_local_object_new(ipc, ifaces, NULL, NULL);
GBinderLocalReply* reply;
GBinderOutputData* reply_data;
gbinder_remote_request_set_data(req, HIDL_PING_TRANSACTION,
gbinder_remote_request_set_data(req, HIDL_DESCRIPTOR_CHAIN_TRANSACTION,
gbinder_buffer_new(ipc->driver, g_memdup(req_data, sizeof(req_data)),
sizeof(req_data), NULL));
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), base_interface));
@@ -426,6 +426,11 @@ test_descriptor_chain(
g_assert(reply);
g_assert(status == GBINDER_STATUS_OK);
/* Should get 3 buffers - vector, string and its contents */
reply_data = gbinder_local_reply_data(reply);
g_assert(gbinder_output_data_offsets(reply_data)->count == 3);
g_assert(gbinder_output_data_buffers_size(reply_data) == 64);
gbinder_ipc_unref(ipc);
gbinder_local_object_unref(obj);
gbinder_local_reply_unref(reply);
@@ -467,13 +472,14 @@ test_custom_iface(
void)
{
static const guint8 req_data [] = { CUSTOM_INTERFACE_HEADER_BYTES };
const char* const ifaces[] = { custom_iface, NULL };
int count = 0, status = INT_MAX;
const char* dev = GBINDER_DEFAULT_HWBINDER;
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
GBinderLocalObject* obj = gbinder_ipc_new_local_object(ipc, custom_iface,
GBinderLocalObject* obj = gbinder_local_object_new(ipc, ifaces,
test_custom_iface_handler, &count);
GBinderLocalReply* reply;
GBinderReaderData reader_data;
@@ -573,13 +579,14 @@ test_reply_status(
void)
{
static const guint8 req_data [] = { CUSTOM_INTERFACE_HEADER_BYTES };
const char* const ifaces[] = { custom_iface, NULL };
int count = 0, status = 0;
const char* dev = GBINDER_DEFAULT_HWBINDER;
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot, 0, 0);
GBinderLocalObject* obj = gbinder_ipc_new_local_object(ipc, custom_iface,
GBinderLocalObject* obj = gbinder_local_object_new(ipc, ifaces,
test_reply_status_handler, &count);
gbinder_remote_request_set_data(req, HIDL_PING_TRANSACTION,
@@ -618,7 +625,7 @@ test_increfs(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderLocalObject* obj = gbinder_ipc_new_local_object
GBinderLocalObject* obj = gbinder_local_object_new
(ipc, NULL, NULL, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
int fd = gbinder_driver_fd(ipc->driver);
@@ -660,7 +667,7 @@ test_decrefs(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderLocalObject* obj = gbinder_ipc_new_local_object
GBinderLocalObject* obj = gbinder_local_object_new
(ipc, NULL, NULL, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
int fd = gbinder_driver_fd(ipc->driver);
@@ -702,7 +709,7 @@ test_acquire(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderLocalObject* obj = gbinder_ipc_new_local_object
GBinderLocalObject* obj = gbinder_local_object_new
(ipc, NULL, NULL, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
int fd = gbinder_driver_fd(ipc->driver);
@@ -744,8 +751,7 @@ test_release(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER, NULL);
GBinderLocalObject* obj = gbinder_ipc_new_local_object
(ipc, NULL, NULL, NULL);
GBinderLocalObject* obj = gbinder_local_object_new(ipc, NULL, NULL, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
int fd = gbinder_driver_fd(ipc->driver);
gulong id = gbinder_local_object_add_strong_refs_changed_handler(obj,

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -313,7 +313,7 @@ void
test_string16(
void)
{
static const const char input[] = "x";
static const char input[] = "x";
static const guint8 output[] = {
TEST_INT32_BYTES(1),
TEST_INT16_BYTES('x'), 0x00, 0x00
@@ -400,8 +400,8 @@ test_local_object(
GBinderOutputData* data;
GUtilIntArray* offsets;
GBinderIpc* ipc = gbinder_ipc_new(NULL, NULL);
GBinderLocalObject* obj =
gbinder_ipc_new_local_object(ipc, "foo", NULL, NULL);
const char* const ifaces[] = { "android.hidl.base@1.0::IBase", NULL };
GBinderLocalObject* obj = gbinder_local_object_new(ipc, ifaces, NULL, NULL);
/* Append a real object (64-bit I/O is used by test_binder.c) */
reply = gbinder_local_object_new_reply(obj);

View File

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
* Copyright (C) 2018-2019 Jolla Ltd.
* Copyright (C) 2018-2019 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
@@ -341,7 +341,7 @@ void
test_string16(
void)
{
static const const char input[] = "x";
static const char input[] = "x";
static const guint8 output[] = {
TEST_INT32_BYTES(1),
TEST_INT16_BYTES('x'), 0x00, 0x00

View File

@@ -716,7 +716,6 @@ static const BinderObject64 test_hidl_vec_short_buf [] = {
};
/* NULL buffer with size 1 */
static const guint test_hidl_vec_badnull_offsets [] = {0};
static const GBinderHidlVec test_hidl_vec_badnull = {{0}, 1, TRUE};
static const BinderObject64 test_hidl_vec_badnull_buf [] = {
{

View File

@@ -52,6 +52,7 @@ test_null(
{
g_assert(!gbinder_remote_object_new(NULL, 0, FALSE));
g_assert(!gbinder_remote_object_ref(NULL));
g_assert(!gbinder_remote_object_ipc(NULL));
gbinder_remote_object_unref(NULL);
g_assert(gbinder_remote_object_is_dead(NULL));
g_assert(!gbinder_remote_object_add_death_handler(NULL, NULL, NULL));
@@ -76,7 +77,10 @@ test_basic(
g_assert(obj2);
g_assert(obj1->handle == 1u);
g_assert(obj2->handle == 2u);
g_assert(gbinder_remote_object_ipc(obj1) == ipc);
g_assert(gbinder_remote_object_ipc(obj2) == ipc);
g_assert(!gbinder_remote_object_is_dead(obj1));
g_assert(gbinder_remote_object_reanimate(obj1));
g_assert(gbinder_remote_object_ref(obj1) == obj1);
gbinder_remote_object_unref(obj1); /* Compensate the above reference */
g_assert(!gbinder_remote_object_add_death_handler(obj1, NULL, NULL));

View File

@@ -209,7 +209,6 @@ typedef TestServiceManager TestHwServiceManager;
G_DEFINE_TYPE(TestHwServiceManager, test_hwservicemanager,
GBINDER_TYPE_SERVICEMANAGER)
#define TEST_HWSERVICEMANAGER_HANDLE (0)
#define TEST_HWSERVICEMANAGER_IFACE "android.hidl.manager@1.0::IServiceManager"
#define TEST_TYPE_HWSERVICEMANAGER (test_hwservicemanager_get_type())
#define TEST_IS_HWSERVICEMANAGER(obj) \
@@ -280,7 +279,6 @@ void
test_hwservicemanager_class_init(
TestHwServiceManagerClass* klass)
{
klass->handle = TEST_HWSERVICEMANAGER_HANDLE;
klass->iface = TEST_HWSERVICEMANAGER_IFACE;
klass->default_device = GBINDER_DEFAULT_HWBINDER;
klass->rpc_protocol = &gbinder_rpc_protocol_hwbinder;
@@ -312,7 +310,6 @@ typedef TestServiceManager TestDefServiceManager;
G_DEFINE_TYPE(TestDefServiceManager, test_defservicemanager,
GBINDER_TYPE_SERVICEMANAGER)
#define TEST_DEFSERVICEMANAGER_HANDLE (0)
#define TEST_DEFSERVICEMANAGER_IFACE "android.os.IServiceManager"
#define TEST_TYPE_DEFSERVICEMANAGER (test_defservicemanager_get_type())
#define TEST_IS_DEFSERVICEMANAGER(obj) \
@@ -366,7 +363,6 @@ void
test_defservicemanager_class_init(
TestDefServiceManagerClass* klass)
{
klass->handle = TEST_DEFSERVICEMANAGER_HANDLE;
klass->iface = TEST_DEFSERVICEMANAGER_IFACE;
klass->default_device = GBINDER_DEFAULT_BINDER;
klass->rpc_protocol = &gbinder_rpc_protocol_binder;

View File

@@ -93,7 +93,6 @@ typedef struct test_servicemanager {
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), \
@@ -201,7 +200,6 @@ 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;
@@ -264,6 +262,7 @@ test_basic(
{
const char* obj_name = "test";
const char* dev = GBINDER_DEFAULT_BINDER;
const char* const ifaces[] = { "interface", NULL };
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderLocalObject* obj;
@@ -272,7 +271,7 @@ test_basic(
test_setup_ping(ipc);
sm = gbinder_servicemanager_new(dev);
obj = gbinder_ipc_new_local_object(ipc, "interface", NULL, NULL);
obj = gbinder_local_object_new(ipc, ifaces, NULL, NULL);
g_assert(!gbinder_servicename_new(sm, obj, NULL));
sn = gbinder_servicename_new(sm, obj, obj_name);
@@ -305,6 +304,7 @@ test_present(
int add_result)
{
const char* obj_name = "test";
const char* const ifaces[] = { "interface", NULL };
const char* dev = GBINDER_DEFAULT_BINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
const int fd = gbinder_driver_fd(ipc->driver);
@@ -317,7 +317,7 @@ test_present(
test_setup_ping(ipc);
sm = gbinder_servicemanager_new(dev);
TEST_SERVICEMANAGER(sm)->add_result = add_result;
obj = gbinder_ipc_new_local_object(ipc, "interface", NULL, NULL);
obj = gbinder_local_object_new(ipc, ifaces, NULL, NULL);
sn = gbinder_servicename_new(sm, obj, obj_name);
g_assert(sn);
@@ -369,6 +369,7 @@ test_not_present(
void)
{
const char* obj_name = "test";
const char* const ifaces[] = { "interface", NULL };
const char* dev = GBINDER_DEFAULT_BINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
const int fd = gbinder_driver_fd(ipc->driver);
@@ -383,8 +384,7 @@ test_not_present(
sm = gbinder_servicemanager_new(dev);
g_assert(!gbinder_servicemanager_is_present(sm));
id = gbinder_servicemanager_add_presence_handler(sm, test_quit, loop);
obj = gbinder_ipc_new_local_object(ipc, "interface", NULL, NULL);
obj = gbinder_local_object_new(ipc, ifaces, NULL, NULL);
sn = gbinder_servicename_new(sm, obj, obj_name);
g_assert(sn);
@@ -419,6 +419,7 @@ test_cancel(
void)
{
const char* obj_name = "test";
const char* const ifaces[] = { "interface", NULL };
const char* dev = GBINDER_DEFAULT_BINDER;
GBinderIpc* ipc = gbinder_ipc_new(dev, NULL);
const int fd = gbinder_driver_fd(ipc->driver);
@@ -431,7 +432,7 @@ test_cancel(
test_setup_ping(ipc);
sm = gbinder_servicemanager_new(dev);
obj = gbinder_ipc_new_local_object(ipc, "interface", NULL, NULL);
obj = gbinder_local_object_new(ipc, ifaces, NULL, NULL);
/* Block name add calls */
test = TEST_SERVICEMANAGER(sm);

View File

@@ -71,7 +71,6 @@ typedef struct test_servicemanager {
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), \
@@ -173,7 +172,6 @@ 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;