Compare commits
	
		
			37 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					a08513ade0 | ||
| 
						 | 
					1a57e01e07 | ||
| 
						 | 
					6d4faf19b8 | ||
| 
						 | 
					96e6845e16 | ||
| 
						 | 
					b33adeb708 | ||
| 
						 | 
					ea0e294a74 | ||
| 
						 | 
					2d878c2391 | ||
| 
						 | 
					6dec867cd3 | ||
| 
						 | 
					d8bd7b9366 | ||
| 
						 | 
					b52e4c6dee | ||
| 
						 | 
					21046af42f | ||
| 
						 | 
					3cbe1d6ac8 | ||
| 
						 | 
					b4b1a99a27 | ||
| 
						 | 
					f5a2d481e3 | ||
| 
						 | 
					da57a15852 | ||
| 
						 | 
					9d0ac624c5 | ||
| 
						 | 
					b8ccc80b87 | ||
| 
						 | 
					27e2dac22e | ||
| 
						 | 
					a4ec4e382d | ||
| 
						 | 
					30df5faf64 | ||
| 
						 | 
					0aa29d8a91 | ||
| 
						 | 
					3ace986e4a | ||
| 
						 | 
					064ab48eee | ||
| 
						 | 
					12c1725ab1 | ||
| 
						 | 
					ba2ddf4163 | ||
| 
						 | 
					3d16384acd | ||
| 
						 | 
					0f73626025 | ||
| 
						 | 
					84fb44e519 | ||
| 
						 | 
					aafe23396a | ||
| 
						 | 
					51f270df67 | ||
| 
						 | 
					e9c404de92 | ||
| 
						 | 
					141bda151b | ||
| 
						 | 
					e952380ce6 | ||
| 
						 | 
					721f5dc469 | ||
| 
						 | 
					434b17eefe | ||
| 
						 | 
					af6a1c84ef | ||
| 
						 | 
					a0ce447a1f | 
							
								
								
									
										4
									
								
								LICENSE
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								LICENSE
									
									
									
									
									
								
							@@ -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:
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										58
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										58
									
								
								Makefile
									
									
									
									
									
								
							@@ -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 = 28
 | 
			
		||||
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)
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										57
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										57
									
								
								debian/changelog
									
									
									
									
										vendored
									
									
								
							@@ -1,3 +1,60 @@
 | 
			
		||||
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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								debian/control
									
									
									
									
										vendored
									
									
								
							@@ -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
									
									
								
							
							
						
						
									
										10
									
								
								debian/copyright
									
									
									
									
										vendored
									
									
								
							@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,14 +1,14 @@
 | 
			
		||||
Name: libgbinder
 | 
			
		||||
Version: 1.0.28
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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*
 | 
			
		||||
@@ -1202,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;
 | 
			
		||||
@@ -1276,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;
 | 
			
		||||
@@ -1288,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
 | 
			
		||||
@@ -1333,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);
 | 
			
		||||
@@ -1342,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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
@@ -1521,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 {
 | 
			
		||||
@@ -1561,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 */
 | 
			
		||||
@@ -1587,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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1621,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);
 | 
			
		||||
@@ -1642,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
 | 
			
		||||
 
 | 
			
		||||
@@ -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 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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 $*
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
									
								
							
							
						
						
									
										140
									
								
								test/binder-ping/Makefile
									
									
									
									
									
										Normal 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)
 | 
			
		||||
							
								
								
									
										187
									
								
								test/binder-ping/binder-ping.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								test/binder-ping/binder-ping.c
									
									
									
									
									
										Normal 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:
 | 
			
		||||
 */
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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 $@
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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,8 @@ test_basic(
 | 
			
		||||
 | 
			
		||||
    /* Invalid path */
 | 
			
		||||
    g_assert(!gbinder_ipc_new("invalid path", NULL));
 | 
			
		||||
 | 
			
		||||
    gbinder_ipc_exit();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
@@ -166,6 +168,7 @@ test_async_oneway(
 | 
			
		||||
 | 
			
		||||
    gbinder_local_request_unref(req);
 | 
			
		||||
    gbinder_ipc_unref(ipc);
 | 
			
		||||
    g_main_loop_unref(loop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
@@ -187,6 +190,7 @@ test_sync_oneway(
 | 
			
		||||
        GBINDER_STATUS_OK);
 | 
			
		||||
    gbinder_local_request_unref(req);
 | 
			
		||||
    gbinder_ipc_unref(ipc);
 | 
			
		||||
    gbinder_ipc_exit();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
@@ -230,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
 | 
			
		||||
@@ -272,6 +277,7 @@ test_sync_reply_error(
 | 
			
		||||
 | 
			
		||||
    gbinder_local_request_unref(req);
 | 
			
		||||
    gbinder_ipc_unref(ipc);
 | 
			
		||||
    gbinder_ipc_exit();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*==========================================================================*
 | 
			
		||||
@@ -341,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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -387,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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -433,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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -481,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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -510,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);
 | 
			
		||||
}
 | 
			
		||||
@@ -540,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
 | 
			
		||||
 *==========================================================================*/
 | 
			
		||||
@@ -589,6 +634,7 @@ test_transact_cancel(
 | 
			
		||||
    test_run(&test_opt, loop);
 | 
			
		||||
 | 
			
		||||
    gbinder_ipc_unref(ipc);
 | 
			
		||||
    gbinder_ipc_exit();
 | 
			
		||||
    g_main_loop_unref(loop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -633,6 +679,7 @@ test_transact_cancel2(
 | 
			
		||||
    test_run(&test_opt, loop);
 | 
			
		||||
 | 
			
		||||
    gbinder_ipc_unref(ipc);
 | 
			
		||||
    gbinder_ipc_exit();
 | 
			
		||||
    g_main_loop_unref(loop);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -673,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;
 | 
			
		||||
@@ -697,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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -735,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;
 | 
			
		||||
@@ -759,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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -840,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;
 | 
			
		||||
@@ -864,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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -911,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;
 | 
			
		||||
@@ -935,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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -960,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();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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 [] = {
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -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));
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user