[gbinder] C interface for Android binder. JB#41335

This commit is contained in:
Slava Monich
2018-03-03 01:39:18 +02:00
commit fb981c9983
114 changed files with 19336 additions and 0 deletions

15
.gitignore vendored Normal file
View File

@@ -0,0 +1,15 @@
*~
debian/files
debian/libgbinder-dev.debhelper.log
debian/libgbinder-dev.substvars
debian/libgbinder-dev
debian/libgbinder.debhelper.log
debian/libgbinder.postinst.debhelper
debian/libgbinder.postrm.debhelper
debian/libgbinder.substvars
debian/libgbinder
debian/tmp
documentation.list
installroot
build
RPMS

29
LICENSE Normal file
View File

@@ -0,0 +1,29 @@
Copyright (C) 2018 Jolla Ltd.
Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
You may use this file under the terms of BSD license as follows:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the 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.
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.

284
Makefile Normal file
View File

@@ -0,0 +1,284 @@
# -*- Mode: makefile-gmake -*-
.PHONY: clean all debug release test
.PHONY: print_debug_so print_release_so
.PHONY: print_debug_lib print_release_lib
.PHONY: print_debug_link print_release_link
.PHONY: print_debug_path print_release_path
#
# Required packages
#
PKGS = libglibutil glib-2.0 gobject-2.0
#
# Default target
#
all: debug release pkgconfig
#
# Library version
#
VERSION_MAJOR = 1
VERSION_MINOR = 0
VERSION_RELEASE = 0
# Version for pkg-config
PCVERSION = $(VERSION_MAJOR).$(VERSION_MINOR).$(VERSION_RELEASE)
#
# Library name
#
NAME = gbinder
LIB_NAME = lib$(NAME)
LIB_DEV_SYMLINK = $(LIB_NAME).so
LIB_SYMLINK1 = $(LIB_DEV_SYMLINK).$(VERSION_MAJOR)
LIB_SYMLINK2 = $(LIB_SYMLINK1).$(VERSION_MINOR)
LIB_SONAME = $(LIB_SYMLINK1)
LIB_SO = $(LIB_SONAME).$(VERSION_MINOR).$(VERSION_RELEASE)
LIB = $(LIB_NAME).a
#
# Sources
#
SRC = \
gbinder_buffer.c \
gbinder_cleanup.c \
gbinder_client.c \
gbinder_driver.c \
gbinder_io_32.c \
gbinder_io_64.c \
gbinder_ipc.c \
gbinder_local_object.c \
gbinder_local_reply.c \
gbinder_local_request.c \
gbinder_reader.c \
gbinder_remote_object.c \
gbinder_remote_reply.c \
gbinder_remote_request.c \
gbinder_rpc_protocol.c \
gbinder_writer.c
SRC += \
gbinder_defaultservicemanager.c \
gbinder_hwservicemanager.c \
gbinder_servicemanager.c
SRC += \
gbinder_system.c
#
# Directories
#
SRC_DIR = src
INCLUDE_DIR = include
BUILD_DIR = build
DEBUG_BUILD_DIR = $(BUILD_DIR)/debug
RELEASE_BUILD_DIR = $(BUILD_DIR)/release
COVERAGE_BUILD_DIR = $(BUILD_DIR)/coverage
#
# Tools and flags
#
CC = $(CROSS_COMPILE)gcc
LD = $(CC)
WARNINGS = -Wall -Wstrict-aliasing -Wunused-result
INCLUDES = -I$(INCLUDE_DIR)
BASE_FLAGS = -fPIC
FULL_CFLAGS = $(BASE_FLAGS) $(CFLAGS) $(DEFINES) $(WARNINGS) $(INCLUDES) \
-MMD -MP $(shell pkg-config --cflags $(PKGS))
FULL_LDFLAGS = $(BASE_FLAGS) $(LDFLAGS) -shared -Wl,-soname,$(LIB_SONAME) \
$(shell pkg-config --libs $(PKGS)) -lpthread
DEBUG_FLAGS = -g
RELEASE_FLAGS =
COVERAGE_FLAGS = -g
ifndef KEEP_SYMBOLS
KEEP_SYMBOLS = 0
endif
ifneq ($(KEEP_SYMBOLS),0)
RELEASE_FLAGS += -g
endif
DEBUG_LDFLAGS = $(FULL_LDFLAGS) $(DEBUG_FLAGS)
RELEASE_LDFLAGS = $(FULL_LDFLAGS) $(RELEASE_FLAGS)
DEBUG_CFLAGS = $(FULL_CFLAGS) $(DEBUG_FLAGS) -DDEBUG
RELEASE_CFLAGS = $(FULL_CFLAGS) $(RELEASE_FLAGS) -O2
COVERAGE_CFLAGS = $(FULL_CFLAGS) $(COVERAGE_FLAGS) --coverage
#
# Files
#
PKGCONFIG = $(BUILD_DIR)/$(LIB_NAME).pc
DEBUG_OBJS = $(SRC:%.c=$(DEBUG_BUILD_DIR)/%.o)
RELEASE_OBJS = $(SRC:%.c=$(RELEASE_BUILD_DIR)/%.o)
COVERAGE_OBJS = $(SRC:%.c=$(COVERAGE_BUILD_DIR)/%.o)
#
# Dependencies
#
DEPS = $(DEBUG_OBJS:%.o=%.d) $(RELEASE_OBJS:%.o=%.d)
ifneq ($(MAKECMDGOALS),clean)
ifneq ($(strip $(DEPS)),)
-include $(DEPS)
endif
endif
$(PKGCONFIG): | $(BUILD_DIR)
$(DEBUG_OBJS) $(DEBUG_SO): | $(DEBUG_BUILD_DIR)
$(RELEASE_OBJS) $(RELEASE_SO): | $(RELEASE_BUILD_DIR)
$(COVERAGE_OBJS) $(COVERAGE_LIB): | $(COVERAGE_BUILD_DIR)
#
# Rules
#
DEBUG_SO = $(DEBUG_BUILD_DIR)/$(LIB_SO)
RELEASE_SO = $(RELEASE_BUILD_DIR)/$(LIB_SO)
DEBUG_LINK = $(DEBUG_BUILD_DIR)/$(LIB_SYMLINK1)
RELEASE_LINK = $(RELEASE_BUILD_DIR)/$(LIB_SYMLINK1)
DEBUG_LIB = $(DEBUG_BUILD_DIR)/$(LIB)
RELEASE_LIB = $(RELEASE_BUILD_DIR)/$(LIB)
COVERAGE_LIB = $(COVERAGE_BUILD_DIR)/$(LIB)
debug: $(DEBUG_SO)
release: $(RELEASE_SO)
debug_lib: $(DEBUG_LIB)
release_lib: $(RELEASE_LIB)
coverage_lib: $(COVERAGE_LIB)
pkgconfig: $(PKGCONFIG)
print_debug_so:
@echo $(DEBUG_SO)
print_release_so:
@echo $(RELEASE_SO)
print_debug_lib:
@echo $(DEBUG_LIB)
print_release_lib:
@echo $(RELEASE_LIB)
print_coverage_lib:
@echo $(COVERAGE_LIB)
print_debug_link:
@echo $(DEBUG_LINK)
print_release_link:
@echo $(RELEASE_LINK)
print_debug_path:
@echo $(DEBUG_BUILD_DIR)
print_release_path:
@echo $(RELEASE_BUILD_DIR)
clean:
make -C test clean
make -C unit clean
rm -fr test/coverage/results test/coverage/*.gcov
rm -f *~ $(SRC_DIR)/*~ $(INCLUDE_DIR)/*~
rm -fr $(BUILD_DIR) RPMS installroot
rm -fr debian/tmp debian/libgbinder debian/libgbinder-dev
rm -f documentation.list debian/files debian/*.substvars
rm -f debian/*.debhelper.log debian/*.debhelper debian/*~
test:
make -C unit test
$(BUILD_DIR):
mkdir -p $@
$(DEBUG_BUILD_DIR):
mkdir -p $@
$(RELEASE_BUILD_DIR):
mkdir -p $@
$(COVERAGE_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 $@
$(COVERAGE_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
$(CC) -c $(COVERAGE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
$(DEBUG_SO): $(DEBUG_OBJS)
$(LD) $(DEBUG_OBJS) $(DEBUG_LDFLAGS) -o $@
ln -sf $(LIB_SO) $(DEBUG_LINK)
$(RELEASE_SO): $(RELEASE_OBJS)
$(LD) $(RELEASE_OBJS) $(RELEASE_LDFLAGS) -o $@
ln -sf $(LIB_SO) $(RELEASE_LINK)
ifeq ($(KEEP_SYMBOLS),0)
strip $@
endif
$(DEBUG_LIB): $(DEBUG_OBJS)
$(AR) rc $@ $?
ranlib $@
$(RELEASE_LIB): $(RELEASE_OBJS)
$(AR) rc $@ $?
ranlib $@
$(COVERAGE_LIB): $(COVERAGE_OBJS)
$(AR) rc $@ $?
ranlib $@
$(PKGCONFIG): $(LIB_NAME).pc.in
sed -e 's/\[version\]/'$(PCVERSION)/g $< > $@
#
# Install
#
INSTALL_PERM = 644
INSTALL = install
INSTALL_DIRS = $(INSTALL) -d
INSTALL_FILES = $(INSTALL) -m $(INSTALL_PERM)
INSTALL_LIB_DIR = $(DESTDIR)/usr/lib
INSTALL_INCLUDE_DIR = $(DESTDIR)/usr/include/$(NAME)
INSTALL_PKGCONFIG_DIR = $(DESTDIR)/usr/lib/pkgconfig
install: $(INSTALL_LIB_DIR)
$(INSTALL_FILES) $(RELEASE_SO) $(INSTALL_LIB_DIR)
ln -sf $(LIB_SO) $(INSTALL_LIB_DIR)/$(LIB_SYMLINK2)
ln -sf $(LIB_SYMLINK2) $(INSTALL_LIB_DIR)/$(LIB_SYMLINK1)
install-dev: install $(INSTALL_INCLUDE_DIR) $(INSTALL_PKGCONFIG_DIR)
$(INSTALL_FILES) $(INCLUDE_DIR)/*.h $(INSTALL_INCLUDE_DIR)
$(INSTALL_FILES) $(PKGCONFIG) $(INSTALL_PKGCONFIG_DIR)
ln -sf $(LIB_SYMLINK1) $(INSTALL_LIB_DIR)/$(LIB_DEV_SYMLINK)
$(INSTALL_LIB_DIR):
$(INSTALL_DIRS) $@
$(INSTALL_INCLUDE_DIR):
$(INSTALL_DIRS) $@
$(INSTALL_PKGCONFIG_DIR):
$(INSTALL_DIRS) $@

1
README Normal file
View File

@@ -0,0 +1 @@
GLib-style interface to binder (Android IPC mechanism)

5
debian/changelog vendored Normal file
View File

@@ -0,0 +1,5 @@
libgbinder (1.0.0) unstable; urgency=low
* Initial release
-- Slava Monich <slava.monich@jolla.com> Thu, 12 Jul 2018 00:37:21 +0300

1
debian/compat vendored Normal file
View File

@@ -0,0 +1 @@
5

18
debian/control vendored Normal file
View File

@@ -0,0 +1,18 @@
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.29)
Standards-Version: 3.8.4
Package: libgbinder
Section: libs
Architecture: any
Depends: libglibutil (>= 1.0.29), ${shlibs:Depends}, ${misc:Depends}
Description: Binder client library
Package: libgbinder-dev
Section: libdevel
Architecture: any
Depends: libgbinder (= ${binary:Version}), ${misc:Depends}
Description: Development files for libgbinder

29
debian/copyright vendored Normal file
View File

@@ -0,0 +1,29 @@
Copyright (C) 2018 Jolla Ltd.
Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
You may use this file under the terms of BSD license as follows:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the 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.
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.

3
debian/libgbinder-dev.install vendored Normal file
View File

@@ -0,0 +1,3 @@
debian/tmp/usr/lib/libgbinder.so usr/lib
include/*.h usr/include/gbinder
build/libgbinder.pc usr/lib/pkgconfig

1
debian/libgbinder.install vendored Normal file
View File

@@ -0,0 +1 @@
debian/tmp/usr/lib/libgbinder.so.* usr/lib

11
debian/rules vendored Executable file
View File

@@ -0,0 +1,11 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
override_dh_auto_install:
dh_auto_install -- install-dev
%:
dh $@

1
debian/source/format vendored Normal file
View File

@@ -0,0 +1 @@
3.0 (native)

58
include/gbinder.h Normal file
View File

@@ -0,0 +1,58 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_H
#define GBINDER_H
/* Convenience header to pull in everything at once */
#include "gbinder_buffer.h"
#include "gbinder_client.h"
#include "gbinder_local_object.h"
#include "gbinder_local_reply.h"
#include "gbinder_local_request.h"
#include "gbinder_reader.h"
#include "gbinder_remote_object.h"
#include "gbinder_remote_reply.h"
#include "gbinder_remote_request.h"
#include "gbinder_servicemanager.h"
#include "gbinder_writer.h"
#endif /* GBINDER_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

59
include/gbinder_buffer.h Normal file
View File

@@ -0,0 +1,59 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_BUFFER_H
#define GBINDER_BUFFER_H
#include <gbinder_types.h>
G_BEGIN_DECLS
struct gbinder_buffer {
void* data;
gsize size;
};
void
gbinder_buffer_free(
GBinderBuffer* buf);
G_END_DECLS
#endif /* GBINDER_BUFFER_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

103
include/gbinder_client.h Normal file
View File

@@ -0,0 +1,103 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_CLIENT_H
#define GBINDER_CLIENT_H
#include <gbinder_types.h>
G_BEGIN_DECLS
typedef
void
(*GBinderClientReplyFunc)(
GBinderClient* client,
GBinderRemoteReply* reply,
int status,
void* user_data);
GBinderClient*
gbinder_client_new(
GBinderRemoteObject* object,
const char* iface);
GBinderClient*
gbinder_client_ref(
GBinderClient* client);
void
gbinder_client_unref(
GBinderClient* client);
GBinderLocalRequest*
gbinder_client_new_request(
GBinderClient* client);
GBinderRemoteReply*
gbinder_client_transact_sync_reply(
GBinderClient* client,
guint32 code,
GBinderLocalRequest* req,
int* status);
int
gbinder_client_transact_sync_oneway(
GBinderClient* client,
guint32 code,
GBinderLocalRequest* req);
gulong
gbinder_client_transact(
GBinderClient* client,
guint32 code,
guint32 flags,
GBinderLocalRequest* req,
GBinderClientReplyFunc reply,
GDestroyNotify destroy,
void* user_data);
void
gbinder_client_cancel(
GBinderClient* client,
gulong id);
G_END_DECLS
#endif /* GBINDER_CLIENT_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,66 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_LOCAL_OBJECT_H
#define GBINDER_LOCAL_OBJECT_H
#include "gbinder_types.h"
G_BEGIN_DECLS
GBinderLocalObject*
gbinder_local_object_ref(
GBinderLocalObject* obj);
void
gbinder_local_object_unref(
GBinderLocalObject* obj);
void
gbinder_local_object_drop(
GBinderLocalObject* obj);
GBinderLocalReply*
gbinder_local_object_new_reply(
GBinderLocalObject* obj);
G_END_DECLS
#endif /* GBINDER_LOCAL_OBJECT_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,110 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_LOCAL_REPLY_H
#define GBINDER_LOCAL_REPLY_H
#include "gbinder_types.h"
G_BEGIN_DECLS
GBinderLocalReply*
gbinder_local_reply_ref(
GBinderLocalReply* reply);
void
gbinder_local_reply_unref(
GBinderLocalReply* reply);
void
gbinder_local_reply_init_writer(
GBinderLocalReply* reply,
GBinderWriter* writer);
void
gbinder_local_reply_cleanup(
GBinderLocalReply* reply,
GDestroyNotify destroy,
gpointer pointer);
GBinderLocalReply*
gbinder_local_reply_append_int32(
GBinderLocalReply* reply,
guint32 value);
GBinderLocalReply*
gbinder_local_reply_append_int64(
GBinderLocalReply* reply,
guint64 value);
GBinderLocalReply*
gbinder_local_reply_append_string8(
GBinderLocalReply* reply,
const char* str);
GBinderLocalReply*
gbinder_local_reply_append_string16(
GBinderLocalReply* reply,
const char* utf8);
GBinderLocalReply*
gbinder_local_reply_append_hidl_string(
GBinderLocalReply* reply,
const char* str);
GBinderLocalReply*
gbinder_local_reply_append_hidl_string_vec(
GBinderLocalReply* reply,
const char* strv[],
gssize count);
GBinderLocalReply*
gbinder_local_reply_append_local_object(
GBinderLocalReply* reply,
GBinderLocalObject* obj);
GBinderLocalReply*
gbinder_local_reply_append_remote_object(
GBinderLocalReply* reply,
GBinderRemoteObject* obj);
G_END_DECLS
#endif /* GBINDER_LOCAL_OBJECT_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,110 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_LOCAL_REQUEST_H
#define GBINDER_LOCAL_REQUEST_H
#include "gbinder_types.h"
G_BEGIN_DECLS
GBinderLocalRequest*
gbinder_local_request_ref(
GBinderLocalRequest* request);
void
gbinder_local_request_unref(
GBinderLocalRequest* request);
void
gbinder_local_request_init_writer(
GBinderLocalRequest* request,
GBinderWriter* writer);
void
gbinder_local_request_cleanup(
GBinderLocalRequest* request,
GDestroyNotify destroy,
gpointer pointer);
GBinderLocalRequest*
gbinder_local_request_append_int32(
GBinderLocalRequest* request,
guint32 value);
GBinderLocalRequest*
gbinder_local_request_append_int64(
GBinderLocalRequest* request,
guint64 value);
GBinderLocalRequest*
gbinder_local_request_append_string8(
GBinderLocalRequest* request,
const char* str);
GBinderLocalRequest*
gbinder_local_request_append_string16(
GBinderLocalRequest* request,
const char* utf8);
GBinderLocalRequest*
gbinder_local_request_append_hidl_string(
GBinderLocalRequest* request,
const char* str);
GBinderLocalRequest*
gbinder_local_request_append_hidl_string_vec(
GBinderLocalRequest* request,
const char* strv[],
gssize count);
GBinderLocalRequest*
gbinder_local_request_append_local_object(
GBinderLocalRequest* request,
GBinderLocalObject* obj);
GBinderLocalRequest*
gbinder_local_request_append_remote_object(
GBinderLocalRequest* request,
GBinderRemoteObject* obj);
G_END_DECLS
#endif /* GBINDER_LOCAL_OBJECT_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

155
include/gbinder_reader.h Normal file
View File

@@ -0,0 +1,155 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_READER_H
#define GBINDER_READER_H
#include "gbinder_types.h"
G_BEGIN_DECLS
/*
* Normally, the reader is initialized by gbinder_remote_reply_init_reader or
* gbinder_remote_request_init_reader function. Note that the reader doesn't
* copy the data nor does it reference the object which initialized it. The
* caller must make sure that the data outlive the reader.
*
* Also, these functions are not NULL tolerant. The reader is normally
* allocated on stack.
*/
struct gbinder_reader {
gconstpointer d[6];
};
gboolean
gbinder_reader_at_end(
GBinderReader* reader);
gboolean
gbinder_reader_read_byte(
GBinderReader* reader,
guchar* value);
gboolean
gbinder_reader_read_bool(
GBinderReader* reader,
gboolean* value);
gboolean
gbinder_reader_read_int32(
GBinderReader* reader,
gint32* value);
gboolean
gbinder_reader_read_uint32(
GBinderReader* reader,
guint32* value);
gboolean
gbinder_reader_read_int64(
GBinderReader* reader,
gint64* value);
gboolean
gbinder_reader_read_uint64(
GBinderReader* reader,
guint64* value);
gboolean
gbinder_reader_read_nullable_object(
GBinderReader* reader,
GBinderRemoteObject** obj);
GBinderRemoteObject*
gbinder_reader_read_object(
GBinderReader* reader)
G_GNUC_WARN_UNUSED_RESULT;
#define gbinder_reader_skip_object(reader) \
gbinder_reader_read_nullable_object(reader, NULL)
GBinderBuffer*
gbinder_reader_read_buffer(
GBinderReader* reader)
G_GNUC_WARN_UNUSED_RESULT;
char*
gbinder_reader_read_hidl_string(
GBinderReader* reader)
G_GNUC_WARN_UNUSED_RESULT;
char**
gbinder_reader_read_hidl_string_vec(
GBinderReader* reader);
gboolean
gbinder_reader_skip_buffer(
GBinderReader* reader);
const char*
gbinder_reader_read_string8(
GBinderReader* reader);
char*
gbinder_reader_read_string16(
GBinderReader* reader)
G_GNUC_WARN_UNUSED_RESULT;
gboolean
gbinder_reader_read_nullable_string16(
GBinderReader* reader,
char** out);
gboolean
gbinder_reader_skip_string16(
GBinderReader* reader);
gsize
gbinder_reader_bytes_read(
GBinderReader* reader);
gsize
gbinder_reader_bytes_remaining(
GBinderReader* reader);
G_END_DECLS
#endif /* GBINDER_READER_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,79 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_REMOTE_OBJECT_H
#define GBINDER_REMOTE_OBJECT_H
#include "gbinder_types.h"
G_BEGIN_DECLS
typedef
void
(*GBinderRemoteObjectNotifyFunc)(
GBinderRemoteObject* obj,
void* user_data);
GBinderRemoteObject*
gbinder_remote_object_ref(
GBinderRemoteObject* obj);
void
gbinder_remote_object_unref(
GBinderRemoteObject* obj);
gboolean
gbinder_remote_object_is_dead(
GBinderRemoteObject* obj);
gulong
gbinder_remote_object_add_death_handler(
GBinderRemoteObject* obj,
GBinderRemoteObjectNotifyFunc func,
void* user_data);
void
gbinder_remote_object_remove_handler(
GBinderRemoteObject* obj,
gulong id);
G_END_DECLS
#endif /* GBINDER_REMOTE_OBJECT_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,99 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_REMOTE_REPLY_H
#define GBINDER_REMOTE_REPLY_H
#include <gbinder_reader.h>
G_BEGIN_DECLS
GBinderRemoteReply*
gbinder_remote_reply_ref(
GBinderRemoteReply* reply);
void
gbinder_remote_reply_unref(
GBinderRemoteReply* reply);
void
gbinder_remote_reply_init_reader(
GBinderRemoteReply* reply,
GBinderReader* reader);
/* Convenience function to decode replies with just one data item */
gboolean
gbinder_remote_reply_read_int32(
GBinderRemoteReply* reply,
gint32* value);
gboolean
gbinder_remote_reply_read_uint32(
GBinderRemoteReply* reply,
guint32* value);
gboolean
gbinder_remote_reply_read_int64(
GBinderRemoteReply* reply,
gint64* value);
gboolean
gbinder_remote_reply_read_uint64(
GBinderRemoteReply* reply,
guint64* value);
const char*
gbinder_remote_reply_read_string8(
GBinderRemoteReply* reply);
char*
gbinder_remote_reply_read_string16(
GBinderRemoteReply* reply)
G_GNUC_WARN_UNUSED_RESULT;
GBinderRemoteObject*
gbinder_remote_reply_read_object(
GBinderRemoteReply* reply)
G_GNUC_WARN_UNUSED_RESULT;
G_END_DECLS
#endif /* GBINDER_REMOTE_REPLY_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,103 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_REMOTE_REQUEST_H
#define GBINDER_REMOTE_REQUEST_H
#include <gbinder_reader.h>
G_BEGIN_DECLS
const char*
gbinder_remote_request_interface(
GBinderRemoteRequest* req);
GBinderRemoteRequest*
gbinder_remote_request_ref(
GBinderRemoteRequest* req);
void
gbinder_remote_request_unref(
GBinderRemoteRequest* req);
void
gbinder_remote_request_init_reader(
GBinderRemoteRequest* req,
GBinderReader* reader);
/* Convenience function to decode requests with just one data item */
gboolean
gbinder_remote_request_read_int32(
GBinderRemoteRequest* req,
gint32* value);
gboolean
gbinder_remote_request_read_uint32(
GBinderRemoteRequest* req,
guint32* value);
gboolean
gbinder_remote_request_read_int64(
GBinderRemoteRequest* req,
gint64* value);
gboolean
gbinder_remote_request_read_uint64(
GBinderRemoteRequest* req,
guint64* value);
const char*
gbinder_remote_request_read_string8(
GBinderRemoteRequest* req);
char*
gbinder_remote_request_read_string16(
GBinderRemoteRequest* req)
G_GNUC_WARN_UNUSED_RESULT;
GBinderRemoteObject*
gbinder_remote_request_read_object(
GBinderRemoteRequest* self)
G_GNUC_WARN_UNUSED_RESULT;
G_END_DECLS
#endif /* GBINDER_REMOTE_REQUEST_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,143 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_SERVICEMANAGER_H
#define GBINDER_SERVICEMANAGER_H
#include <gbinder_types.h>
G_BEGIN_DECLS
/* GBinderServiceManagerListFunc callback returns TRUE to keep the services
* list, otherwise the caller will deallocate it. */
typedef
gboolean
(*GBinderServiceManagerListFunc)(
GBinderServiceManager* sm,
char** services,
void* user_data);
typedef
void
(*GBinderServiceManagerGetServiceFunc)(
GBinderServiceManager* sm,
GBinderRemoteObject* obj,
int status,
void* user_data);
typedef
void
(*GBinderServiceManagerAddServiceFunc)(
GBinderServiceManager* sm,
int status,
void* user_data);
GBinderServiceManager*
gbinder_servicemanager_new(
const char* dev);
GBinderServiceManager*
gbinder_defaultservicemanager_new(
const char* dev);
GBinderServiceManager*
gbinder_hwservicemanager_new(
const char* dev);
GBinderLocalObject*
gbinder_servicemanager_new_local_object(
GBinderServiceManager* sm,
const char* iface,
GBinderLocalTransactFunc handler,
void* user_data);
GBinderServiceManager*
gbinder_servicemanager_ref(
GBinderServiceManager* sm);
void
gbinder_servicemanager_unref(
GBinderServiceManager* sm);
gulong
gbinder_servicemanager_list(
GBinderServiceManager* sm,
GBinderServiceManagerListFunc func,
void* user_data);
char**
gbinder_servicemanager_list_sync(
GBinderServiceManager* sm);
gulong
gbinder_servicemanager_get_service(
GBinderServiceManager* sm,
const char* name,
GBinderServiceManagerGetServiceFunc func,
void* user_data);
GBinderRemoteObject* /* autoreleased */
gbinder_servicemanager_get_service_sync(
GBinderServiceManager* sm,
const char* name,
int* status);
gulong
gbinder_servicemanager_add_service(
GBinderServiceManager* sm,
const char* name,
GBinderLocalObject* obj,
GBinderServiceManagerAddServiceFunc func,
void* user_data);
int
gbinder_servicemanager_add_service_sync(
GBinderServiceManager* sm,
const char* name,
GBinderLocalObject* obj);
void
gbinder_servicemanager_cancel(
GBinderServiceManager* sm,
gulong id);
G_END_DECLS
#endif /* GBINDER_SERVICEMANAGER_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

124
include/gbinder_types.h Normal file
View File

@@ -0,0 +1,124 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_TYPES_H
#define GBINDER_TYPES_H
#include <gutil_types.h>
G_BEGIN_DECLS
#define GBINDER_LOG_MODULE gbinder_log
/*
* Terminology:
*
* 1. RemoteObject is the one we sent requests to.
* 2. LocalObjects may receive incoming transactions (and reply to them)
* 3. We must have a RemoteObject to initiate a transaction.
* We send LocalRequest and receive RemoteReply:
*
* LocalObject --- (LocalRequest) --> Client(RemoteObject)
* LocalObject <-- (RemoteReply) -- RemoteObject
*
* 4. LocalObject knows caller's pid (and therefore credentials)
*
* LocalObject <-- (RemoteRequest) --- (pid)
* LocalObject --- (LocalReply) --> (pid)
*
* 5. Writer prepares the data for LocalRequest and LocalReply
* 6. Reader parses the data coming with RemoteRequest and RemoteReply
*/
typedef struct gbinder_buffer GBinderBuffer;
typedef struct gbinder_client GBinderClient;
typedef struct gbinder_local_object GBinderLocalObject;
typedef struct gbinder_local_reply GBinderLocalReply;
typedef struct gbinder_local_request GBinderLocalRequest;
typedef struct gbinder_reader GBinderReader;
typedef struct gbinder_remote_object GBinderRemoteObject;
typedef struct gbinder_remote_reply GBinderRemoteReply;
typedef struct gbinder_remote_request GBinderRemoteRequest;
typedef struct gbinder_servicemanager GBinderServiceManager;
typedef struct gbinder_writer GBinderWriter;
typedef struct gbinder_parent GBinderParent;
/*
* Each RPC call is identified by the interface name returned
* by gbinder_remote_request_interface() the the transaction code.
* Transaction code itself is not unique.
*
* The value return from GBinderLocalTransactFunc callbacl will be
* ignored for one-way transactions. If GBINDER_TX_FLAG_ONEWAY is
* passed in, the callback should return NULL and that won't be
* interpreted as an error.
*/
typedef
GBinderLocalReply*
(*GBinderLocalTransactFunc)(
GBinderLocalObject* obj,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status,
void* user_data);
#define GBINDER_TX_FLAG_ONEWAY (0x01)
typedef enum gbinder_status {
GBINDER_STATUS_OK = 0,
GBINDER_STATUS_FAILED,
GBINDER_STATUS_DEAD_OBJECT
} GBINDER_STATUS;
#define GBINDER_FOURCC(c1,c2,c3,c4) \
(((c1) << 24) | ((c2) << 16) | ((c3) << 8) | (c4))
#define GBINDER_FIRST_CALL_TRANSACTION (0x00000001)
/* Default binder devices */
#define GBINDER_DEFAULT_BINDER "/dev/binder"
#define GBINDER_DEFAULT_HWBINDER "/dev/hwbinder"
extern GLogModule GBINDER_LOG_MODULE;
G_END_DECLS
#endif /* GBINDER_TYPES_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

145
include/gbinder_writer.h Normal file
View File

@@ -0,0 +1,145 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_WRITER_H
#define GBINDER_WRITER_H
#include <gbinder_types.h>
G_BEGIN_DECLS
/*
* Writers are initialized by LocalRequest and LocalReply objects.
* Note that writers directly update the objects which initialized
* them but don't reference those object. The caller must make sure
* that objects outlive their writers.
*
* Writers are normally allocated on stack.
*/
struct gbinder_writer {
gconstpointer d[4];
};
struct gbinder_parent {
guint32 index;
guint32 offset;
};
void
gbinder_writer_append_int32(
GBinderWriter* writer,
guint32 value);
void
gbinder_writer_append_int64(
GBinderWriter* writer,
guint64 value);
void
gbinder_writer_append_string16(
GBinderWriter* writer,
const char* utf8);
void
gbinder_writer_append_string16_len(
GBinderWriter* writer,
const char* utf8,
gssize num_bytes);
void
gbinder_writer_append_string8(
GBinderWriter* writer,
const char* str);
void
gbinder_writer_append_string8_len(
GBinderWriter* writer,
const char* str,
gsize len);
void
gbinder_writer_append_bool(
GBinderWriter* writer,
gboolean value);
void
gbinder_writer_append_bytes(
GBinderWriter* writer,
const void* data,
gsize size);
guint
gbinder_writer_append_buffer_object_with_parent(
GBinderWriter* writer,
const void* buf,
gsize len,
const GBinderParent* parent);
guint
gbinder_writer_append_buffer_object(
GBinderWriter* writer,
const void* buf,
gsize len);
void
gbinder_writer_append_hidl_string(
GBinderWriter* writer,
const char* str);
void
gbinder_writer_append_hidl_string_vec(
GBinderWriter* writer,
const char* data[],
gssize count);
void
gbinder_writer_append_local_object(
GBinderWriter* writer,
GBinderLocalObject* obj);
void
gbinder_writer_append_remote_object(
GBinderWriter* writer,
GBinderRemoteObject* obj);
G_END_DECLS
#endif /* GBINDER_WRITER_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

10
libgbinder.pc.in Normal file
View File

@@ -0,0 +1,10 @@
name=gbinder
libdir=/usr/lib
includedir=/usr/include
Name: libgbinder
Description: Binder client library
Version: [version]
Requires: glib-2.0 libglibutil
Libs: -L${libdir} -l${name}
Cflags: -I${includedir} -I${includedir}/${name}

51
rpm/libgbinder.spec Normal file
View File

@@ -0,0 +1,51 @@
Name: libgbinder
Version: 1.0.0
Release: 0
Summary: Binder client library
Group: Development/Libraries
License: BSD
URL: https://git.merproject.org/mer-core/libgbinder
Source: %{name}-%{version}.tar.bz2
Requires: libglibutil >= 1.0.29
BuildRequires: pkgconfig(glib-2.0)
BuildRequires: pkgconfig(libglibutil) >= 1.0.29
Requires(post): /sbin/ldconfig
Requires(postun): /sbin/ldconfig
%description
C interfaces for Android binder
%package devel
Summary: Development library for %{name}
Requires: %{name} = %{version}
Requires: pkgconfig
%description devel
This package contains the development library for %{name}.
%prep
%setup -q
%build
make KEEP_SYMBOLS=1 release pkgconfig
%install
rm -rf %{buildroot}
make install-dev DESTDIR=%{buildroot}
%check
make -C unit test
%post -p /sbin/ldconfig
%postun -p /sbin/ldconfig
%files
%defattr(-,root,root,-)
%{_libdir}/%{name}.so.*
%files devel
%defattr(-,root,root,-)
%{_libdir}/pkgconfig/*.pc
%{_libdir}/%{name}.so
%{_includedir}/gbinder/*.h

202
src/binder.h Normal file
View File

@@ -0,0 +1,202 @@
/****************************************************************************
****************************************************************************
***
*** This header was automatically generated from a Linux kernel header
*** of the same name, to make information necessary for userspace to
*** call into the kernel available to libc. It contains only constants,
*** structures, and macros generated from the original header, and thus,
*** contains no copyrightable information.
***
*** To edit the content of this header, modify the corresponding
*** source file (e.g. under external/kernel-headers/original/) then
*** run bionic/libc/kernel/tools/update_all.py
***
*** Any manual change here will be lost the next time this script will
*** be run. You've been warned!
***
****************************************************************************
****************************************************************************/
#ifndef _UAPI_LINUX_BINDER_H
#define _UAPI_LINUX_BINDER_H
#include <linux/types.h>
#include <linux/ioctl.h>
#define B_PACK_CHARS(c1,c2,c3,c4) ((((c1) << 24)) | (((c2) << 16)) | (((c3) << 8)) | (c4))
#define B_TYPE_LARGE 0x85
enum {
BINDER_TYPE_BINDER = B_PACK_CHARS('s', 'b', '*', B_TYPE_LARGE),
BINDER_TYPE_WEAK_BINDER = B_PACK_CHARS('w', 'b', '*', B_TYPE_LARGE),
BINDER_TYPE_HANDLE = B_PACK_CHARS('s', 'h', '*', B_TYPE_LARGE),
BINDER_TYPE_WEAK_HANDLE = B_PACK_CHARS('w', 'h', '*', B_TYPE_LARGE),
BINDER_TYPE_FD = B_PACK_CHARS('f', 'd', '*', B_TYPE_LARGE),
BINDER_TYPE_FDA = B_PACK_CHARS('f', 'd', 'a', B_TYPE_LARGE),
BINDER_TYPE_PTR = B_PACK_CHARS('p', 't', '*', B_TYPE_LARGE),
};
enum {
FLAT_BINDER_FLAG_PRIORITY_MASK = 0xff,
FLAT_BINDER_FLAG_ACCEPTS_FDS = 0x100,
};
#ifdef BINDER_IPC_32BIT
typedef __u32 binder_size_t;
typedef __u32 binder_uintptr_t;
#else
typedef __u64 binder_size_t;
typedef __u64 binder_uintptr_t;
#endif
struct binder_object_header {
__u32 type;
};
struct flat_binder_object {
struct binder_object_header hdr;
__u32 flags;
union {
binder_uintptr_t binder;
__u32 handle;
};
binder_uintptr_t cookie;
};
struct binder_fd_object {
struct binder_object_header hdr;
__u32 pad_flags;
union {
binder_uintptr_t pad_binder;
__u32 fd;
};
binder_uintptr_t cookie;
};
struct binder_buffer_object {
struct binder_object_header hdr;
__u32 flags;
binder_uintptr_t buffer;
binder_size_t length;
binder_size_t parent;
binder_size_t parent_offset;
};
enum {
BINDER_BUFFER_FLAG_HAS_PARENT = 0x01,
};
struct binder_fd_array_object {
struct binder_object_header hdr;
__u32 pad;
binder_size_t num_fds;
binder_size_t parent;
binder_size_t parent_offset;
};
struct binder_write_read {
binder_size_t write_size;
binder_size_t write_consumed;
binder_uintptr_t write_buffer;
binder_size_t read_size;
binder_size_t read_consumed;
binder_uintptr_t read_buffer;
};
struct binder_version {
__s32 protocol_version;
};
#ifdef BINDER_IPC_32BIT
#define BINDER_CURRENT_PROTOCOL_VERSION 7
#else
#define BINDER_CURRENT_PROTOCOL_VERSION 8
#endif
struct binder_node_debug_info {
binder_uintptr_t ptr;
binder_uintptr_t cookie;
__u32 has_strong_ref;
__u32 has_weak_ref;
};
#define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read)
#define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64)
#define BINDER_SET_MAX_THREADS _IOW('b', 5, __u32)
#define BINDER_SET_IDLE_PRIORITY _IOW('b', 6, __s32)
#define BINDER_SET_CONTEXT_MGR _IOW('b', 7, __s32)
#define BINDER_THREAD_EXIT _IOW('b', 8, __s32)
#define BINDER_VERSION _IOWR('b', 9, struct binder_version)
#define BINDER_GET_NODE_DEBUG_INFO _IOWR('b', 11, struct binder_node_debug_info)
enum transaction_flags {
TF_ONE_WAY = 0x01,
TF_ROOT_OBJECT = 0x04,
TF_STATUS_CODE = 0x08,
TF_ACCEPT_FDS = 0x10,
};
struct binder_transaction_data {
union {
__u32 handle;
binder_uintptr_t ptr;
} target;
binder_uintptr_t cookie;
__u32 code;
__u32 flags;
pid_t sender_pid;
uid_t sender_euid;
binder_size_t data_size;
binder_size_t offsets_size;
union {
struct {
binder_uintptr_t buffer;
binder_uintptr_t offsets;
} ptr;
__u8 buf[8];
} data;
};
struct binder_transaction_data_sg {
struct binder_transaction_data transaction_data;
binder_size_t buffers_size;
};
struct binder_ptr_cookie {
binder_uintptr_t ptr;
binder_uintptr_t cookie;
};
struct binder_handle_cookie {
__u32 handle;
binder_uintptr_t cookie;
} __attribute__((packed));
struct binder_pri_desc {
__s32 priority;
__u32 desc;
};
struct binder_pri_ptr_cookie {
__s32 priority;
binder_uintptr_t ptr;
binder_uintptr_t cookie;
};
enum binder_driver_return_protocol {
BR_ERROR = _IOR('r', 0, __s32),
BR_OK = _IO('r', 1),
BR_TRANSACTION = _IOR('r', 2, struct binder_transaction_data),
BR_REPLY = _IOR('r', 3, struct binder_transaction_data),
BR_ACQUIRE_RESULT = _IOR('r', 4, __s32),
BR_DEAD_REPLY = _IO('r', 5),
BR_TRANSACTION_COMPLETE = _IO('r', 6),
BR_INCREFS = _IOR('r', 7, struct binder_ptr_cookie),
BR_ACQUIRE = _IOR('r', 8, struct binder_ptr_cookie),
BR_RELEASE = _IOR('r', 9, struct binder_ptr_cookie),
BR_DECREFS = _IOR('r', 10, struct binder_ptr_cookie),
BR_ATTEMPT_ACQUIRE = _IOR('r', 11, struct binder_pri_ptr_cookie),
BR_NOOP = _IO('r', 12),
BR_SPAWN_LOOPER = _IO('r', 13),
BR_FINISHED = _IO('r', 14),
BR_DEAD_BINDER = _IOR('r', 15, binder_uintptr_t),
BR_CLEAR_DEATH_NOTIFICATION_DONE = _IOR('r', 16, binder_uintptr_t),
BR_FAILED_REPLY = _IO('r', 17),
};
enum binder_driver_command_protocol {
BC_TRANSACTION = _IOW('c', 0, struct binder_transaction_data),
BC_REPLY = _IOW('c', 1, struct binder_transaction_data),
BC_ACQUIRE_RESULT = _IOW('c', 2, __s32),
BC_FREE_BUFFER = _IOW('c', 3, binder_uintptr_t),
BC_INCREFS = _IOW('c', 4, __u32),
BC_ACQUIRE = _IOW('c', 5, __u32),
BC_RELEASE = _IOW('c', 6, __u32),
BC_DECREFS = _IOW('c', 7, __u32),
BC_INCREFS_DONE = _IOW('c', 8, struct binder_ptr_cookie),
BC_ACQUIRE_DONE = _IOW('c', 9, struct binder_ptr_cookie),
BC_ATTEMPT_ACQUIRE = _IOW('c', 10, struct binder_pri_desc),
BC_REGISTER_LOOPER = _IO('c', 11),
BC_ENTER_LOOPER = _IO('c', 12),
BC_EXIT_LOOPER = _IO('c', 13),
BC_REQUEST_DEATH_NOTIFICATION = _IOW('c', 14, struct binder_handle_cookie),
BC_CLEAR_DEATH_NOTIFICATION = _IOW('c', 15, struct binder_handle_cookie),
BC_DEAD_BINDER_DONE = _IOW('c', 16, binder_uintptr_t),
BC_TRANSACTION_SG = _IOW('c', 17, struct binder_transaction_data_sg),
BC_REPLY_SG = _IOW('c', 18, struct binder_transaction_data_sg),
};
#endif

182
src/gbinder_buffer.c Normal file
View File

@@ -0,0 +1,182 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* 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_buffer_p.h"
#include "gbinder_driver.h"
#include "gbinder_log.h"
#include <gutil_macros.h>
typedef struct gbinder_buffer_memory {
gint refcount;
void* buffer;
gsize size;
GBinderDriver* driver;
} GBinderBufferMemory;
typedef struct gbinder_buffer_priv {
GBinderBuffer pub;
GBinderBufferMemory* memory;
} GBinderBufferPriv;
static inline GBinderBufferPriv* gbinder_buffer_cast(GBinderBuffer* buf)
{ return G_CAST(buf, GBinderBufferPriv, pub); }
/*==========================================================================*
* GBinderBufferMemory
*==========================================================================*/
static
GBinderBufferMemory*
gbinder_buffer_memory_new(
GBinderDriver* driver,
void* buffer,
gsize size)
{
GBinderBufferMemory* self = g_slice_new0(GBinderBufferMemory);
g_atomic_int_set(&self->refcount, 1);
self->buffer = buffer;
self->size = size;
self->driver = gbinder_driver_ref(driver);
return self;
}
static
void
gbinder_buffer_memory_free(
GBinderBufferMemory* self)
{
gbinder_driver_free_buffer(self->driver, self->buffer);
gbinder_driver_unref(self->driver);
g_slice_free(GBinderBufferMemory, self);
}
static
GBinderBufferMemory*
gbinder_buffer_memory_ref(
GBinderBufferMemory* self)
{
if (G_LIKELY(self)) {
GASSERT(self->refcount > 0);
g_atomic_int_inc(&self->refcount);
}
return self;
}
static
void
gbinder_buffer_memory_unref(
GBinderBufferMemory* self)
{
if (G_LIKELY(self)) {
GASSERT(self->refcount > 0);
if (g_atomic_int_dec_and_test(&self->refcount)) {
gbinder_buffer_memory_free(self);
}
}
}
/*==========================================================================*
* GBinderBuffer
*==========================================================================*/
static
GBinderBuffer*
gbinder_buffer_alloc(
GBinderBufferMemory* memory,
void* data,
gsize size)
{
GBinderBufferPriv* priv = g_slice_new0(GBinderBufferPriv);
GBinderBuffer* self = &priv->pub;
priv->memory = memory;
self->data = data;
self->size = size;
return self;
}
void
gbinder_buffer_free(
GBinderBuffer* self)
{
if (G_LIKELY(self)) {
GBinderBufferPriv* priv = gbinder_buffer_cast(self);
gbinder_buffer_memory_unref(priv->memory);
g_slice_free(GBinderBufferPriv, priv);
}
}
GBinderBuffer*
gbinder_buffer_new(
GBinderDriver* driver,
void* data,
gsize size)
{
return gbinder_buffer_alloc((driver && data) ?
gbinder_buffer_memory_new(driver, data, size) : NULL, data, size);
}
GBinderBuffer*
gbinder_buffer_new_with_parent(
GBinderBuffer* parent,
void* data,
gsize size)
{
return gbinder_buffer_alloc(parent ?
gbinder_buffer_memory_ref(gbinder_buffer_cast(parent)->memory) : NULL,
data, size);
}
GBinderDriver*
gbinder_buffer_driver(
GBinderBuffer* self)
{
if (G_LIKELY(self)) {
GBinderBufferPriv* priv = gbinder_buffer_cast(self);
if (priv->memory) {
return priv->memory->driver;
}
}
return NULL;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

67
src/gbinder_buffer_p.h Normal file
View File

@@ -0,0 +1,67 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_BUFFER_PRIVATE_H
#define GBINDER_BUFFER_PRIVATE_H
#include <gbinder_buffer.h>
#include "gbinder_types_p.h"
GBinderBuffer*
gbinder_buffer_new(
GBinderDriver* driver,
void* data,
gsize size);
GBinderBuffer*
gbinder_buffer_new_with_parent(
GBinderBuffer* parent,
void* data,
gsize size);
GBinderDriver*
gbinder_buffer_driver(
GBinderBuffer* buf);
#define gbinder_buffer_io(buf) \
gbinder_driver_io(gbinder_buffer_driver(buf))
#endif /* GBINDER_BUFFER_PRIVATE_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

97
src/gbinder_cleanup.c Normal file
View File

@@ -0,0 +1,97 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* 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_cleanup.h"
typedef struct gbinder_cleanup_item {
GDestroyNotify destroy;
gpointer pointer;
} GBinderCleanupItem;
/*
* This is basically a GArray providing better type safety at compile time.
*/
struct gbinder_cleanup {
GBinderCleanupItem* items;
guint count;
};
G_STATIC_ASSERT(sizeof(GBinderCleanup) == sizeof(GArray));
#define ELEMENT_SIZE (sizeof(GBinderCleanupItem))
static
GBinderCleanup*
gbinder_cleanup_new()
{
return (GBinderCleanup*)g_array_sized_new(FALSE, FALSE, ELEMENT_SIZE, 0);
}
void
gbinder_cleanup_free(
GBinderCleanup* self)
{
if (G_LIKELY(self)) {
guint i;
for (i = 0; i < self->count; i++) {
self->items[i].destroy(self->items[i].pointer);
}
g_array_free((GArray*)self, TRUE);
}
}
GBinderCleanup*
gbinder_cleanup_add(
GBinderCleanup* self,
GDestroyNotify destroy,
gpointer pointer)
{
if (G_LIKELY(destroy)) {
GBinderCleanupItem item;
item.destroy = destroy;
item.pointer = pointer;
if (!self) {
self = gbinder_cleanup_new();
}
g_array_append_vals((GArray*)self, (void*)&item, 1);
}
return self;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

56
src/gbinder_cleanup.h Normal file
View File

@@ -0,0 +1,56 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_CLEANUP_H
#define GBINDER_CLEANUP_H
#include "gbinder_types_p.h"
void
gbinder_cleanup_free(
GBinderCleanup* cleanup);
GBinderCleanup*
gbinder_cleanup_add(
GBinderCleanup* cleanup,
GDestroyNotify destroy,
gpointer pointer);
#endif /* GBINDER_CLEANUP_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

271
src/gbinder_client.c Normal file
View File

@@ -0,0 +1,271 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* 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_client_p.h"
#include "gbinder_driver.h"
#include "gbinder_ipc.h"
#include "gbinder_output_data.h"
#include "gbinder_remote_object_p.h"
#include "gbinder_local_reply_p.h"
#include "gbinder_local_request_p.h"
#include "gbinder_log.h"
#include <gutil_macros.h>
#include <errno.h>
typedef struct gbinder_client_priv {
GBinderClient pub;
guint32 refcount;
char* iface;
GBytes* rpc_header;
GBinderLocalRequest* basic_req;
} GBinderClientPriv;
typedef struct gbinder_client_tx {
GBinderClient* client;
GBinderClientReplyFunc reply;
GDestroyNotify destroy;
void* user_data;
} GBinderClientTx;
static inline GBinderClientPriv* gbinder_client_cast(GBinderClient* client)
{ return G_CAST(client, GBinderClientPriv, pub); }
/*==========================================================================*
* Implementation
*==========================================================================*/
static
void
gbinder_client_free(
GBinderClientPriv* priv)
{
GBinderClient* self = &priv->pub;
gbinder_remote_object_unref(self->remote);
gbinder_local_request_unref(priv->basic_req);
g_free(priv->iface);
g_bytes_unref(priv->rpc_header);
g_slice_free(GBinderClientPriv, priv);
}
static
void
gbinder_client_transact_reply(
GBinderIpc* ipc,
GBinderRemoteReply* reply,
int status,
void* data)
{
GBinderClientTx* tx = data;
if (tx->reply) {
tx->reply(tx->client, reply, status, tx->user_data);
}
}
static
void
gbinder_client_transact_destroy(
gpointer data)
{
GBinderClientTx* tx = data;
if (tx->destroy) {
tx->destroy(tx->user_data);
}
gbinder_client_unref(tx->client);
g_slice_free(GBinderClientTx, tx);
}
/*==========================================================================*
* Interface
*==========================================================================*/
GBinderClient*
gbinder_client_new(
GBinderRemoteObject* remote,
const char* iface)
{
if (G_LIKELY(remote) && G_LIKELY(iface)) {
GBinderClientPriv* priv = g_slice_new0(GBinderClientPriv);
GBinderClient* self = &priv->pub;
GBinderIpc* ipc = remote->ipc;
GBinderOutputData* hdr;
g_atomic_int_set(&priv->refcount, 1);
/*
* Generate basic request (without additional parameters) and pull
* header data out of it. The basic request can be reused for those
* transactions which has no additional parameters. The header data
* are needed for building non-trivial requests.
*/
priv->basic_req = gbinder_driver_local_request_new(ipc->driver, iface);
hdr = gbinder_local_request_data(priv->basic_req);
priv->rpc_header = g_bytes_new(hdr->bytes->data, hdr->bytes->len);
self->remote = gbinder_remote_object_ref(remote);
self->iface = priv->iface = g_strdup(iface);
return self;
}
return NULL;
}
GBinderClient*
gbinder_client_ref(
GBinderClient* self)
{
if (G_LIKELY(self)) {
GBinderClientPriv* priv = gbinder_client_cast(self);
GASSERT(priv->refcount > 0);
g_atomic_int_inc(&priv->refcount);
}
return self;
}
void
gbinder_client_unref(
GBinderClient* self)
{
if (G_LIKELY(self)) {
GBinderClientPriv* priv = gbinder_client_cast(self);
GASSERT(priv->refcount > 0);
if (g_atomic_int_dec_and_test(&priv->refcount)) {
gbinder_client_free(priv);
}
}
}
GBinderLocalRequest*
gbinder_client_new_request(
GBinderClient* self)
{
if (G_LIKELY(self)) {
GBinderClientPriv* priv = gbinder_client_cast(self);
const GBinderIo* io = gbinder_driver_io(self->remote->ipc->driver);
return gbinder_local_request_new(io, priv->rpc_header);
}
return NULL;
}
GBinderRemoteReply*
gbinder_client_transact_sync_reply(
GBinderClient* self,
guint32 code,
GBinderLocalRequest* req,
int* status)
{
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;
}
return gbinder_ipc_transact_sync_reply(obj->ipc, obj->handle,
code, req, status);
}
return NULL;
}
int
gbinder_client_transact_sync_oneway(
GBinderClient* self,
guint32 code,
GBinderLocalRequest* req)
{
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;
}
return gbinder_ipc_transact_sync_oneway(obj->ipc, obj->handle,
code, req);
} else {
return (-EINVAL);
}
}
gulong
gbinder_client_transact(
GBinderClient* self,
guint32 code,
guint32 flags,
GBinderLocalRequest* req,
GBinderClientReplyFunc reply,
GDestroyNotify destroy,
void* user_data)
{
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 (!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);
} else {
return 0;
}
}
void
gbinder_client_cancel(
GBinderClient* self,
gulong id)
{
if (G_LIKELY(self)) {
gbinder_ipc_cancel(gbinder_client_ipc(self), id);
}
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

55
src/gbinder_client_p.h Normal file
View File

@@ -0,0 +1,55 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_CLIENT_PRIVATE_H
#define GBINDER_CLIENT_PRIVATE_H
#include <gbinder_client.h>
#include "gbinder_types_p.h"
struct gbinder_client {
const char* iface;
GBinderRemoteObject* remote;
};
#define gbinder_client_ipc(client) ((client)->remote->ipc)
#endif /* GBINDER_CLIENT_PRIVATE_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,180 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* 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_servicemanager_p.h"
#include "gbinder_log.h"
#include <gbinder_client.h>
#include <gbinder_local_request.h>
#include <gbinder_remote_reply.h>
#include <gutil_macros.h>
#include <errno.h>
#include <pthread.h>
typedef GBinderServiceManager GBinderDefaultServiceManager;
typedef GBinderServiceManagerClass GBinderDefaultServiceManagerClass;
G_DEFINE_TYPE(GBinderDefaultServiceManager,
gbinder_defaultservicemanager,
GBINDER_TYPE_SERVICEMANAGER)
enum gbinder_defaultservicemanager_calls {
GET_SERVICE_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION,
CHECK_SERVICE_TRANSACTION,
ADD_SERVICE_TRANSACTION,
LIST_SERVICES_TRANSACTION
};
/* As a special case, ServiceManager's handle is zero */
#define DEFAULTSERVICEMANAGER_HANDLE (0)
#define DEFAULTSERVICEMANAGER_IFACE "android.os.IServiceManager"
GBinderServiceManager*
gbinder_defaultservicemanager_new(
const char* dev)
{
return gbinder_servicemanager_new_with_type
(gbinder_defaultservicemanager_get_type(), dev);
}
static
GBinderLocalRequest*
gbinder_servicemanager_list_services_req(
GBinderServiceManager* self,
gint32 index)
{
return gbinder_local_request_append_int32
(gbinder_client_new_request(self->client), index);
}
static
char**
gbinder_defaultservicemanager_list(
GBinderServiceManager* self)
{
GPtrArray* list = g_ptr_array_new();
GBinderLocalRequest* req = gbinder_servicemanager_list_services_req(self,0);
GBinderRemoteReply* reply;
while ((reply = gbinder_client_transact_sync_reply(self->client,
LIST_SERVICES_TRANSACTION, req, NULL)) != NULL) {
char* service = gbinder_remote_reply_read_string16(reply);
gbinder_remote_reply_unref(reply);
if (service) {
g_ptr_array_add(list, service);
gbinder_local_request_unref(req);
req = gbinder_servicemanager_list_services_req(self, list->len);
} else {
break;
}
}
gbinder_local_request_unref(req);
g_ptr_array_add(list, NULL);
return (char**)g_ptr_array_free(list, FALSE);
}
static
GBinderRemoteObject*
gbinder_defaultservicemanager_get_service(
GBinderServiceManager* self,
const char* name,
int* status)
{
GBinderRemoteObject* obj;
GBinderRemoteReply* reply;
GBinderLocalRequest* req = gbinder_client_new_request(self->client);
gbinder_local_request_append_string16(req, name);
reply = gbinder_client_transact_sync_reply(self->client,
CHECK_SERVICE_TRANSACTION, req, status);
obj = gbinder_remote_reply_read_object(reply);
gbinder_remote_reply_unref(reply);
gbinder_local_request_unref(req);
return obj;
}
static
int
gbinder_defaultservicemanager_add_service(
GBinderServiceManager* self,
const char* name,
GBinderLocalObject* obj)
{
int status;
GBinderRemoteReply* reply;
GBinderLocalRequest* req = gbinder_client_new_request(self->client);
gbinder_local_request_append_string16(req, name);
gbinder_local_request_append_local_object(req, obj);
gbinder_local_request_append_int32(req, 0);
reply = gbinder_client_transact_sync_reply(self->client,
ADD_SERVICE_TRANSACTION, req, &status);
gbinder_remote_reply_unref(reply);
gbinder_local_request_unref(req);
return status;
}
static
void
gbinder_defaultservicemanager_init(
GBinderDefaultServiceManager* self)
{
}
static
void
gbinder_defaultservicemanager_class_init(
GBinderDefaultServiceManagerClass* klass)
{
klass->handle = DEFAULTSERVICEMANAGER_HANDLE;
klass->iface = DEFAULTSERVICEMANAGER_IFACE;
klass->default_device = GBINDER_DEFAULT_BINDER;
klass->list = gbinder_defaultservicemanager_list;
klass->get_service = gbinder_defaultservicemanager_get_service;
klass->add_service = gbinder_defaultservicemanager_add_service;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

1029
src/gbinder_driver.c Normal file

File diff suppressed because it is too large Load Diff

140
src/gbinder_driver.h Normal file
View File

@@ -0,0 +1,140 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_DRIVER_H
#define GBINDER_DRIVER_H
#include "gbinder_types_p.h"
struct pollfd;
GBinderDriver*
gbinder_driver_new(
const char* dev);
GBinderDriver*
gbinder_driver_ref(
GBinderDriver* driver);
void
gbinder_driver_unref(
GBinderDriver* driver);
int
gbinder_driver_fd(
GBinderDriver* driver);
int
gbinder_driver_poll(
GBinderDriver* driver,
struct pollfd* pollfd);
const char*
gbinder_driver_dev(
GBinderDriver* driver);
const GBinderIo*
gbinder_driver_io(
GBinderDriver* driver);
gboolean
gbinder_driver_request_death_notification(
GBinderDriver* driver,
GBinderRemoteObject* obj);
gboolean
gbinder_driver_clear_death_notification(
GBinderDriver* driver,
GBinderRemoteObject* obj);
gboolean
gbinder_driver_increfs(
GBinderDriver* driver,
guint32 handle);
gboolean
gbinder_driver_decrefs(
GBinderDriver* driver,
guint32 handle);
gboolean
gbinder_driver_acquire(
GBinderDriver* driver,
guint32 handle);
gboolean
gbinder_driver_release(
GBinderDriver* driver,
guint32 handle);
void
gbinder_driver_free_buffer(
GBinderDriver* driver,
void* buffer);
gboolean
gbinder_driver_enter_looper(
GBinderDriver* driver);
gboolean
gbinder_driver_exit_looper(
GBinderDriver* driver);
int
gbinder_driver_read(
GBinderDriver* driver,
GBinderObjectRegistry* reg,
GBinderHandler* handler);
int
gbinder_driver_transact(
GBinderDriver* driver,
GBinderObjectRegistry* reg,
guint32 handle,
guint32 code,
GBinderLocalRequest* request,
GBinderRemoteReply* reply);
GBinderLocalRequest*
gbinder_driver_local_request_new(
GBinderDriver* self,
const char* iface);
#endif /* GBINDER_DRIVER_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

72
src/gbinder_handler.h Normal file
View File

@@ -0,0 +1,72 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_HANDLER_H
#define GBINDER_HANDLER_H
#include "gbinder_types_p.h"
typedef struct gbinder_handler_functions {
GBinderLocalReply* (*transact)(GBinderHandler* handler,
GBinderLocalObject* obj, GBinderRemoteRequest* req, guint code,
guint flags, int* status);
} GBinderHandlerFunctions;
struct gbinder_handler {
const GBinderHandlerFunctions* f;
};
/* Inline wrappers */
GBINDER_INLINE_FUNC
GBinderLocalReply*
gbinder_handler_transact(
GBinderHandler* self,
GBinderLocalObject* obj,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status)
{
return self ? self->f->transact(self, obj, req, code, flags, status) :
NULL;
}
#endif /* GBINDER_HANDLER_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,199 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* 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_servicemanager_p.h"
#include "gbinder_log.h"
#include <gbinder_client.h>
#include <gbinder_local_request.h>
#include <gbinder_remote_reply.h>
#include <gbinder_reader.h>
#include <errno.h>
#include <pthread.h>
typedef GBinderServiceManager GBinderHwServiceManager;
typedef GBinderServiceManagerClass GBinderHwServiceManagerClass;
G_DEFINE_TYPE(GBinderHwServiceManager,
gbinder_hwservicemanager,
GBINDER_TYPE_SERVICEMANAGER)
enum gbinder_hwservicemanager_calls {
GET_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION,
ADD_TRANSACTION,
GET_TRANSPORT_TRANSACTION,
LIST_TRANSACTION,
LIST_BY_INTERFACE_TRANSACTION,
REGISTER_FOR_NOTIFICATIONS_TRANSACTION,
DEBUG_DUMP_TRANSACTION,
REGISTER_PASSTHROUGH_CLIENT_TRANSACTION
};
/* As a special case, ServiceManager's handle is zero */
#define HWSERVICEMANAGER_HANDLE (0)
#define HWSERVICEMANAGER_IFACE "android.hidl.manager@1.0::IServiceManager"
GBinderServiceManager*
gbinder_hwservicemanager_new(
const char* dev)
{
return gbinder_servicemanager_new_with_type
(gbinder_hwservicemanager_get_type(), dev);
}
static
char**
gbinder_hwservicemanager_list(
GBinderHwServiceManager* self)
{
GBinderLocalRequest* req = gbinder_client_new_request(self->client);
GBinderRemoteReply* reply = gbinder_client_transact_sync_reply
(self->client, LIST_TRANSACTION, req, NULL);
gbinder_local_request_unref(req);
if (reply) {
GBinderReader reader;
char** result = NULL;
int status = -1;
gbinder_remote_reply_init_reader(reply, &reader);
/* Read status */
GVERIFY(gbinder_reader_read_int32(&reader, &status));
GASSERT(status == GBINDER_STATUS_OK);
/* Followed by hidl_vec<string> */
result = gbinder_reader_read_hidl_string_vec(&reader);
gbinder_remote_reply_unref(reply);
return result;
}
return NULL;
}
static
GBinderRemoteObject*
gbinder_hwservicemanager_get_service(
GBinderServiceManager* self,
const char* fqinstance,
int* status)
{
/* e.g. "android.hardware.radio@1.1::IRadio/slot1" */
const char* sep = strchr(fqinstance, '/');
GBinderRemoteObject* obj = NULL;
if (sep) {
GBinderRemoteReply* reply;
GBinderLocalRequest* req = gbinder_client_new_request(self->client);
char* fqname = g_strndup(fqinstance, sep - fqinstance);
const char* name = sep + 1;
gbinder_local_request_append_hidl_string(req, fqname);
gbinder_local_request_append_hidl_string(req, name);
reply = gbinder_client_transact_sync_reply(self->client,
GET_TRANSACTION, req, status);
if (reply) {
GBinderReader reader;
int status = -1;
gbinder_remote_reply_init_reader(reply, &reader);
/* Read status */
GVERIFY(gbinder_reader_read_int32(&reader, &status));
GASSERT(status == GBINDER_STATUS_OK);
/* Read the object */
obj = gbinder_reader_read_object(&reader);
gbinder_remote_reply_unref(reply);
}
gbinder_local_request_unref(req);
g_free(fqname);
} else {
GERR("Invalid instance \"%s\"", fqinstance);
if (status) *status = (-EINVAL);
}
return obj;
}
static
int
gbinder_hwservicemanager_add_service(
GBinderServiceManager* self,
const char* name,
GBinderLocalObject* obj)
{
int status;
GBinderRemoteReply* reply;
GBinderLocalRequest* req = gbinder_client_new_request(self->client);
/* add(string name, interface service) generates (bool success); */
gbinder_local_request_append_hidl_string(req, name);
gbinder_local_request_append_local_object(req, obj);
reply = gbinder_client_transact_sync_reply(self->client,
ADD_TRANSACTION, req, &status);
gbinder_remote_reply_unref(reply);
gbinder_local_request_unref(req);
return status;
}
static
void
gbinder_hwservicemanager_init(
GBinderHwServiceManager* self)
{
}
static
void
gbinder_hwservicemanager_class_init(
GBinderHwServiceManagerClass* klass)
{
klass->handle = HWSERVICEMANAGER_HANDLE;
klass->iface = HWSERVICEMANAGER_IFACE;
klass->default_device = GBINDER_DEFAULT_HWBINDER;
klass->list = gbinder_hwservicemanager_list;
klass->get_service = gbinder_hwservicemanager_get_service;
klass->add_service = gbinder_hwservicemanager_add_service;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

486
src/gbinder_io.c Normal file
View File

@@ -0,0 +1,486 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* 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_io.h"
#include "gbinder_buffer_p.h"
#include "gbinder_local_object_p.h"
#include "gbinder_remote_object_p.h"
#include "gbinder_object_registry.h"
#include "gbinder_writer.h"
#include "gbinder_system.h"
#include "gbinder_log.h"
#include "binder.h"
#include <gutil_intarray.h>
#include <gutil_macros.h>
#include <errno.h>
/*
* This file is included from gbinder_io_32.c and gbinder_io_64.c to
* generate the code for different ioctl codes and structure sizes.
*/
#define GBINDER_POINTER_SIZE sizeof(binder_uintptr_t)
#define GBINDER_IO_FN__(prefix,suffix) prefix##_##suffix
#define GBINDER_IO_FN_(prefix,suffix) GBINDER_IO_FN__(prefix,suffix)
#define GBINDER_IO_FN(fn) GBINDER_IO_FN_(GBINDER_IO_PREFIX,fn)
static
int
GBINDER_IO_FN(write_read)(
int fd,
GBinderIoBuf* write,
GBinderIoBuf* read)
{
int ret;
struct binder_write_read bwr;
memset(&bwr, 0, sizeof(bwr));
if (write) {
bwr.write_buffer = write->ptr + write->consumed;
bwr.write_size = write->size - write->consumed;
}
if (read) {
bwr.read_buffer = read->ptr + read->consumed;
bwr.read_size = read->size - read->consumed;
}
ret = gbinder_system_ioctl(fd, BINDER_WRITE_READ, &bwr);
if (ret >= 0) {
if (write) {
write->consumed += bwr.write_consumed;
}
if (read) {
read->consumed += bwr.read_consumed;
}
} else {
GERR("binder_write_read: %s", strerror(errno));
}
return ret;
}
/* Writes pointer to the buffer */
static
guint
GBINDER_IO_FN(encode_pointer)(
void* out,
const void* pointer)
{
binder_uintptr_t* dest = out;
*dest = (uintptr_t)pointer;
return sizeof(*dest);
}
/* Encodes flat_buffer_object */
static
guint
GBINDER_IO_FN(encode_local_object)(
void* out,
GBinderLocalObject* obj)
{
struct flat_binder_object* dest = out;
memset(dest, 0, sizeof(*dest));
dest->hdr.type = BINDER_TYPE_BINDER;
dest->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
dest->binder = (uintptr_t)obj;
return sizeof(*dest);
}
static
guint
GBINDER_IO_FN(encode_remote_object)(
void* out,
GBinderRemoteObject* obj)
{
struct flat_binder_object* dest = out;
memset(dest, 0, sizeof(*dest));
if (obj) {
dest->hdr.type = BINDER_TYPE_HANDLE;
dest->flags = FLAT_BINDER_FLAG_ACCEPTS_FDS;
dest->handle = obj->handle;
} else {
dest->hdr.type = BINDER_TYPE_BINDER;
}
return sizeof(*dest);
}
/* Encodes binder_buffer_object */
static
guint
GBINDER_IO_FN(encode_buffer_object)(
void* out,
const void* data,
gsize size,
const GBinderParent* parent)
{
struct binder_buffer_object* dest = out;
memset(dest, 0, sizeof(*dest));
dest->hdr.type = BINDER_TYPE_PTR;
dest->buffer = (uintptr_t)data;
dest->length = size;
if (parent) {
dest->flags |= BINDER_BUFFER_FLAG_HAS_PARENT;
dest->parent = parent->index;
dest->parent_offset = parent->offset;
}
return sizeof(*dest);
}
static
guint
GBINDER_IO_FN(encode_death_notification)(
void* out,
GBinderRemoteObject* obj)
{
struct binder_handle_cookie* dest = out;
/* We find the object by handle, so we use handle as a cookie */
dest->handle = obj->handle;
dest->cookie = obj->handle;
return sizeof(*dest);
}
/* Encodes BC_TRANSACTION data */
static
void
GBINDER_IO_FN(fill_transaction_data)(
struct binder_transaction_data* tr,
guint32 handle,
guint32 code,
const GByteArray* payload,
guint flags,
GUtilIntArray* offsets,
void** offsets_buf)
{
memset(tr, 0, sizeof(*tr));
tr->target.handle = handle;
tr->code = code;
tr->data_size = payload->len;
tr->data.ptr.buffer = (uintptr_t)payload->data;
if (flags & GBINDER_TX_FLAG_ONEWAY) {
tr->flags |= TF_ONE_WAY;
}
if (offsets && offsets->count) {
guint i;
binder_size_t* tx_offsets = g_new(binder_size_t, offsets->count);
tr->offsets_size = offsets->count * sizeof(binder_size_t);
tr->data.ptr.offsets = (uintptr_t)tx_offsets;
for (i = 0; i < offsets->count; i++) {
tx_offsets[i] = offsets->data[i];
}
*offsets_buf = tx_offsets;
} else {
*offsets_buf = NULL;
}
}
static
guint
GBINDER_IO_FN(encode_transaction)(
void* out,
guint32 handle,
guint32 code,
const GByteArray* payload,
guint flags,
GUtilIntArray* offsets,
void** offsets_buf)
{
struct binder_transaction_data* tr = out;
GBINDER_IO_FN(fill_transaction_data)(tr, handle, code, payload, flags,
offsets, offsets_buf);
return sizeof(*tr);
}
/* Encodes BC_TRANSACTION_SG data */
static
guint
GBINDER_IO_FN(encode_transaction_sg)(
void* out,
guint32 handle,
guint32 code,
const GByteArray* payload,
guint flags,
GUtilIntArray* offsets,
void** offsets_buf,
gsize buffers_size)
{
struct binder_transaction_data_sg* sg = out;
GBINDER_IO_FN(fill_transaction_data)(&sg->transaction_data, handle, code,
payload, flags, offsets, offsets_buf);
/* The driver seems to require buffers to be 8-byte aligned */
sg->buffers_size = G_ALIGN8(buffers_size);
return sizeof(*sg);
}
/* Encode BC_REPLY */
static
guint
GBINDER_IO_FN(encode_status_reply)(
void* out,
gint32* status)
{
struct binder_transaction_data* tr = out;
memset(tr, 0, sizeof(*tr));
tr->flags = TF_STATUS_CODE;
tr->data_size = sizeof(*status);
tr->data.ptr.buffer = (uintptr_t)status;
return sizeof(*tr);
}
/* Decode BR_REPLY and BR_TRANSACTION */
static
void
GBINDER_IO_FN(decode_transaction_data)(
const void* data,
GBinderIoTxData* tx)
{
const struct binder_transaction_data* tr = data;
tx->objects = NULL;
tx->code = tr->code;
tx->flags = 0;
tx->target = (void*)(uintptr_t)tr->target.ptr;
tx->data = (void*)(uintptr_t)tr->data.ptr.buffer;
if (tr->flags & TF_STATUS_CODE) {
GASSERT(tr->data_size == 4);
tx->status = *((gint32*)tx->data);
tx->size = 0;
} else {
guint objcount = tr->offsets_size/sizeof(binder_size_t);
const binder_size_t* offsets = (void*)(uintptr_t)tr->data.ptr.offsets;
tx->status = GBINDER_STATUS_OK;
tx->size = tr->data_size;
if (tr->flags & TF_ONE_WAY) {
tx->flags |= GBINDER_TX_FLAG_ONEWAY;
}
if (objcount > 0) {
binder_size_t min_offset = 0;
guint i;
/* Validate the offsets */
for (i = 0; i < objcount; i++) {
if (offsets[i] < min_offset || (offsets[i] +
sizeof(struct flat_binder_object)) > tx->size) {
GWARN("Invalid offset");
objcount = 0;
break;
}
min_offset = offsets[i] + sizeof(struct flat_binder_object);
}
if (objcount > 0) {
tx->objects = g_new(void*, objcount + 1);
for (i = 0; i < objcount; i++) {
tx->objects[i] = (guint8*)tx->data + offsets[i];
}
tx->objects[objcount] = NULL;
}
}
}
}
/* Decode binder_uintptr_t */
static
guint
GBINDER_IO_FN(decode_cookie)(
const void* data,
guint64* cookie)
{
const binder_uintptr_t* ptr = data;
if (cookie) *cookie = *ptr;
return sizeof(*ptr);
}
/* Decode struct binder_ptr_cookie */
static
void*
GBINDER_IO_FN(decode_binder_ptr_cookie)(
const void* data)
{
const struct binder_ptr_cookie* ptr = data;
/* We never send cookie and don't expect it back */
GASSERT(!ptr->cookie);
return (void*)(uintptr_t)ptr->ptr;
}
static
guint
GBINDER_IO_FN(decode_binder_object)(
const void* data,
gsize size,
GBinderObjectRegistry* reg,
GBinderRemoteObject** out)
{
const struct flat_binder_object* obj = data;
if (size >= sizeof(*obj)) {
switch (obj->hdr.type) {
case BINDER_TYPE_HANDLE:
if (out) {
*out = gbinder_object_registry_get_remote(reg, obj->handle);
}
return sizeof(*obj);
default:
GERR("Unsupported binder object type 0x%08x", obj->hdr.type);
break;
}
}
if (out) *out = NULL;
return 0;
}
static
guint
GBINDER_IO_FN(decode_buffer_object)(
GBinderBuffer* buf,
gsize offset,
GBinderBuffer** out)
{
const void* data = (guint8*)buf->data + offset;
const gsize size = (offset < buf->size) ? (buf->size - offset) : 0;
const struct binder_buffer_object* flat = data;
if (size >= sizeof(*flat) && flat->hdr.type == BINDER_TYPE_PTR) {
if (out) {
*out = gbinder_buffer_new_with_parent(buf,
(void*)(uintptr_t)flat->buffer, flat->length);
}
return sizeof(*flat);
}
if (out) *out = NULL;
return 0;
}
const GBinderIo GBINDER_IO_PREFIX = {
.version = BINDER_CURRENT_PROTOCOL_VERSION,
.pointer_size = GBINDER_POINTER_SIZE,
/* Driver command protocol */
.bc = {
.transaction = BC_TRANSACTION,
.reply = BC_REPLY,
.acquire_result = BC_ACQUIRE_RESULT,
.free_buffer = BC_FREE_BUFFER,
.increfs = BC_INCREFS,
.acquire = BC_ACQUIRE,
.release = BC_RELEASE,
.decrefs = BC_DECREFS,
.increfs_done = BC_INCREFS_DONE,
.acquire_done = BC_ACQUIRE_DONE,
.attempt_acquire = BC_ATTEMPT_ACQUIRE,
.register_looper = BC_REGISTER_LOOPER,
.enter_looper = BC_ENTER_LOOPER,
.exit_looper = BC_EXIT_LOOPER,
.request_death_notification = BC_REQUEST_DEATH_NOTIFICATION,
.clear_death_notification = BC_CLEAR_DEATH_NOTIFICATION,
.dead_binder_done = BC_DEAD_BINDER_DONE,
.transaction_sg = BC_TRANSACTION_SG,
.reply_sg = BC_REPLY_SG
},
/* Driver return protocol */
.br = {
.error = BR_ERROR,
.ok = BR_OK,
.transaction = BR_TRANSACTION,
.reply = BR_REPLY,
.acquire_result = BR_ACQUIRE_RESULT,
.dead_reply = BR_DEAD_REPLY,
.transaction_complete = BR_TRANSACTION_COMPLETE,
.increfs = BR_INCREFS,
.acquire = BR_ACQUIRE,
.release = BR_RELEASE,
.decrefs = BR_DECREFS,
.attempt_acquire = BR_ATTEMPT_ACQUIRE,
.noop = BR_NOOP,
.spawn_looper = BR_SPAWN_LOOPER,
.finished = BR_FINISHED,
.dead_binder = BR_DEAD_BINDER,
.clear_death_notification_done = BR_CLEAR_DEATH_NOTIFICATION_DONE,
.failed_reply = BR_FAILED_REPLY
},
/* Encoders */
.encode_pointer = GBINDER_IO_FN(encode_pointer),
.encode_local_object = GBINDER_IO_FN(encode_local_object),
.encode_remote_object = GBINDER_IO_FN(encode_remote_object),
.encode_buffer_object = GBINDER_IO_FN(encode_buffer_object),
.encode_death_notification = GBINDER_IO_FN(encode_death_notification),
.encode_transaction = GBINDER_IO_FN(encode_transaction),
.encode_transaction_sg = GBINDER_IO_FN(encode_transaction_sg),
.encode_status_reply = GBINDER_IO_FN(encode_status_reply),
/* Decoders */
.decode_transaction_data = GBINDER_IO_FN(decode_transaction_data),
.decode_cookie = GBINDER_IO_FN(decode_cookie),
.decode_binder_ptr_cookie = GBINDER_IO_FN(decode_binder_ptr_cookie),
.decode_binder_object = GBINDER_IO_FN(decode_binder_object),
.decode_buffer_object = GBINDER_IO_FN(decode_buffer_object),
/* ioctl wrappers */
.write_read = GBINDER_IO_FN(write_read)
};
/* Compile time constraints */
G_STATIC_ASSERT(GBINDER_POINTER_SIZE <= GBINDER_MAX_POINTER_SIZE);
G_STATIC_ASSERT(sizeof(struct flat_binder_object) <=
GBINDER_MAX_BINDER_OBJECT_SIZE);
G_STATIC_ASSERT(sizeof(struct binder_buffer_object) <=
GBINDER_MAX_BUFFER_OBJECT_SIZE);
G_STATIC_ASSERT(sizeof(struct binder_handle_cookie) <=
GBINDER_MAX_DEATH_NOTIFICATION_SIZE);
G_STATIC_ASSERT(sizeof(struct binder_transaction_data) <=
GBINDER_MAX_BC_TRANSACTION_SIZE);
G_STATIC_ASSERT(sizeof(struct binder_transaction_data_sg) <=
GBINDER_MAX_BC_TRANSACTION_SG_SIZE);
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

181
src/gbinder_io.h Normal file
View File

@@ -0,0 +1,181 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_IO_H
#define GBINDER_IO_H
#include "gbinder_types_p.h"
#include <stdint.h>
typedef struct gbinder_io_buf {
uintptr_t ptr;
gsize size;
gsize consumed;
} GBinderIoBuf;
typedef struct gbinder_io_tx_data {
int status;
guint32 code;
guint32 flags; /* GBINDER_TX_FLAG_xxx */
void* target;
void* data;
gsize size;
void** objects;
} GBinderIoTxData;
/* Read buffer size (allocated on stack, shouldn't be too large) */
#define GBINDER_IO_READ_BUFFER_SIZE (128)
/*
* There are (at least) 2 versions of the binder ioctl API, implemented
* 32-bit and 64-bit kernels. The ioctl codes, transaction commands - many
* of those are derived from the sizes of the structures being passed
* between the driver and the user space client. All these differences
* are abstracted away by the GBinderIo interfaces.
*
* The API version is returned by BINDER_VERSION ioctl which itself doesn't
* depend on the API version (it would be very strange if it did).
*/
struct gbinder_io {
int version;
guint pointer_size;
/* Driver command protocol */
struct gbinder_io_command_codes {
guint transaction;
guint reply;
guint acquire_result;
guint free_buffer;
guint increfs;
guint acquire;
guint release;
guint decrefs;
guint increfs_done;
guint acquire_done;
guint attempt_acquire;
guint register_looper;
guint enter_looper;
guint exit_looper;
guint request_death_notification;
guint clear_death_notification;
guint dead_binder_done;
guint transaction_sg;
guint reply_sg;
} bc;
/* Driver return protocol */
struct gbinder_io_return_codes {
guint error;
guint ok;
guint transaction;
guint reply;
guint acquire_result;
guint dead_reply;
guint transaction_complete;
guint increfs;
guint acquire;
guint release;
guint decrefs;
guint attempt_acquire;
guint noop;
guint spawn_looper;
guint finished;
guint dead_binder;
guint clear_death_notification_done;
guint failed_reply;
} br;
/* Writes pointer to the buffer. The destination buffer must have
* at least GBINDER_IO_MAX_POINTER_SIZE bytes available. The
* actual size is returned. */
#define GBINDER_MAX_POINTER_SIZE (8)
guint (*encode_pointer)(void* out, const void* pointer);
/* Encode flat_buffer_object */
#define GBINDER_MAX_BINDER_OBJECT_SIZE (24)
guint (*encode_local_object)(void* out, GBinderLocalObject* obj);
guint (*encode_remote_object)(void* out, GBinderRemoteObject* obj);
/* Encode binder_buffer_object */
#define GBINDER_MAX_BUFFER_OBJECT_SIZE (40)
guint (*encode_buffer_object)(void* out, const void* data, gsize size,
const GBinderParent* parent);
/* Encode death notification */
#define GBINDER_MAX_DEATH_NOTIFICATION_SIZE (12)
guint (*encode_death_notification)(void* out, GBinderRemoteObject* obj);
/* Encode BC_TRANSACTION/REPLY data */
#define GBINDER_MAX_BC_TRANSACTION_SIZE (64)
guint (*encode_transaction)(void* out, guint32 handle, guint32 code,
const GByteArray* data, guint flags /* See below */,
GUtilIntArray* offsets, void** offsets_buf);
/* Encode BC_TRANSACTION_SG/REPLY_SG data */
#define GBINDER_MAX_BC_TRANSACTION_SG_SIZE (72)
guint (*encode_transaction_sg)(void* out, guint32 handle, guint32 code,
const GByteArray* data, guint flags /* GBINDER_TX_FLAG_xxx */,
GUtilIntArray* offsets, void** offsets_buf,
gsize buffers_size);
/* Encode BC_REPLY */
guint (*encode_status_reply)(void* out, gint32* status);
/* Decoders */
void (*decode_transaction_data)(const void* data, GBinderIoTxData* tx);
#define GBINDER_MAX_PTR_COOKIE_SIZE (16)
void* (*decode_binder_ptr_cookie)(const void* data);
guint (*decode_cookie)(const void* data, guint64* cookie);
guint (*decode_binder_object)(const void* data, gsize size,
GBinderObjectRegistry* reg, GBinderRemoteObject** obj);
guint (*decode_buffer_object)(GBinderBuffer* buf, gsize offset,
GBinderBuffer** out);
/* ioctl wrappers */
int (*write_read)(int fd, GBinderIoBuf* write, GBinderIoBuf* read);
};
extern const GBinderIo gbinder_io_32;
extern const GBinderIo gbinder_io_64;
#endif /* GBINDER_IO_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

44
src/gbinder_io_32.c Normal file
View File

@@ -0,0 +1,44 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* 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.
*/
#define BINDER_IPC_32BIT
#define GBINDER_IO_PREFIX gbinder_io_32
#include "gbinder_io.c"
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

44
src/gbinder_io_64.c Normal file
View File

@@ -0,0 +1,44 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* 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.
*/
#undef BINDER_IPC_32BIT
#define GBINDER_IO_PREFIX gbinder_io_64
#include "gbinder_io.c"
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

1279
src/gbinder_ipc.c Normal file

File diff suppressed because it is too large Load Diff

162
src/gbinder_ipc.h Normal file
View File

@@ -0,0 +1,162 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_IPC_H
#define GBINDER_IPC_H
#include "gbinder_types_p.h"
#include <glib-object.h>
typedef struct gbinder_ipc_priv GBinderIpcPriv;
struct gbinder_ipc {
GObject object;
GBinderIpcPriv* priv;
GBinderDriver* driver;
GUtilIdlePool* pool;
const char* dev;
};
typedef struct gbinder_ipc_tx GBinderIpcTx;
typedef
void
(*GBinderIpcTxFunc)(
const GBinderIpcTx* tx);
struct gbinder_ipc_tx {
gulong id;
gboolean cancelled;
GBinderIpc* ipc;
void* user_data;
};
typedef
void
(*GBinderIpcReplyFunc)(
GBinderIpc* ipc,
GBinderRemoteReply* reply,
int status,
void* user_data);
GBinderIpc*
gbinder_ipc_new(
const char* dev);
GBinderIpc*
gbinder_ipc_ref(
GBinderIpc* ipc);
void
gbinder_ipc_unref(
GBinderIpc* ipc);
void
gbinder_ipc_looper_check(
GBinderIpc* ipc);
GBinderObjectRegistry*
gbinder_ipc_object_registry(
GBinderIpc* ipc);
GBinderLocalObject*
gbinder_ipc_new_local_object(
GBinderIpc* ipc,
const char* iface,
GBinderLocalTransactFunc txproc,
void* data);
GBinderRemoteObject*
gbinder_ipc_get_remote_object(
GBinderIpc* ipc,
guint32 handle);
GBinderRemoteReply*
gbinder_ipc_transact_sync_reply(
GBinderIpc* ipc,
guint32 handle,
guint32 code,
GBinderLocalRequest* req,
int* status);
int
gbinder_ipc_transact_sync_oneway(
GBinderIpc* ipc,
guint32 handle,
guint32 code,
GBinderLocalRequest* req);
gulong
gbinder_ipc_transact(
GBinderIpc* ipc,
guint32 handle,
guint32 code,
guint32 flags, /* GBINDER_TX_FLAG_xxx */
GBinderLocalRequest* req,
GBinderIpcReplyFunc func,
GDestroyNotify destroy,
void* user_data);
gulong
gbinder_ipc_transact_custom(
GBinderIpc* ipc,
GBinderIpcTxFunc exec,
GBinderIpcTxFunc done,
GDestroyNotify destroy,
void* user_data);
void
gbinder_ipc_cancel(
GBinderIpc* ipc,
gulong id);
/* Internal for GBinderLocalObject */
void
gbinder_ipc_local_object_disposed(
GBinderIpc* self,
GBinderLocalObject* obj);
/* Internal for GBinderRemoteObject */
void
gbinder_ipc_remote_object_disposed(
GBinderIpc* self,
GBinderRemoteObject* obj);
#endif /* GBINDER_IPC_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

529
src/gbinder_local_object.c Normal file
View File

@@ -0,0 +1,529 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* 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_driver.h"
#include "gbinder_ipc.h"
#include "gbinder_local_object_p.h"
#include "gbinder_local_reply_p.h"
#include "gbinder_remote_request.h"
#include "gbinder_writer.h"
#include "gbinder_log.h"
#include <errno.h>
struct gbinder_local_object_priv {
GMainContext* context;
char* iface;
GBinderLocalTransactFunc txproc;
void* user_data;
};
G_DEFINE_TYPE(GBinderLocalObject, gbinder_local_object, G_TYPE_OBJECT)
#define GBINDER_LOCAL_OBJECT_GET_CLASS(obj) \
G_TYPE_INSTANCE_GET_CLASS((obj), GBINDER_TYPE_LOCAL_OBJECT, \
GBinderLocalObjectClass)
enum gbinder_local_object_signal {
SIGNAL_WEAK_REFS_CHANGED,
SIGNAL_STRONG_REFS_CHANGED,
SIGNAL_COUNT
};
#define SIGNAL_WEAK_REFS_CHANGED_NAME "weak_refs_changed"
#define SIGNAL_STRONG_REFS_CHANGED_NAME "strong_refs_changed"
static guint gbinder_local_object_signals[SIGNAL_COUNT] = { 0 };
static const char hidl_base_interface[] = "android.hidl.base@1.0::IBase";
/*==========================================================================*
* Implementation
*==========================================================================*/
static
GBINDER_LOCAL_TRANSACTION_SUPPORT
gbinder_local_object_default_can_handle_transaction(
GBinderLocalObject* self,
const char* iface,
guint code)
{
switch (code) {
case HIDL_PING_TRANSACTION:
case HIDL_GET_DESCRIPTOR_TRANSACTION:
case HIDL_DESCRIPTOR_CHAIN_TRANSACTION:
if (!g_strcmp0(iface, hidl_base_interface)) {
return GBINDER_LOCAL_TRANSACTION_LOOPER;
}
/* no break */
default:
return self->priv->txproc ? GBINDER_LOCAL_TRANSACTION_SUPPORTED :
GBINDER_LOCAL_TRANSACTION_NOT_SUPPORTED;
}
}
static
GBinderLocalReply*
gbinder_local_object_default_handle_transaction(
GBinderLocalObject* self,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status)
{
GBinderLocalObjectPriv* priv = self->priv;
if (priv->txproc) {
return priv->txproc(self, req, code, flags, status, priv->user_data);
} else {
if (status) *status = (-EBADMSG);
return NULL;
}
}
static
GBinderLocalReply*
gbinder_local_object_hidl_ping_transaction(
GBinderLocalObject* self,
GBinderRemoteRequest* req,
int* status)
{
/*android.hidl.base@1.0::IBase interfaceDescriptor() */
const GBinderIo* io = gbinder_local_object_io(self);
GBinderLocalReply* reply = gbinder_local_reply_new(io);
GBinderWriter writer;
GVERBOSE(" HIDL_PING_TRANSACTION \"%s\"",
gbinder_remote_request_interface(req));
gbinder_local_reply_init_writer(reply, &writer);
gbinder_writer_append_int32(&writer, GBINDER_STATUS_OK);
*status = GBINDER_STATUS_OK;
return reply;
}
static
GBinderLocalReply*
gbinder_local_object_hidl_get_descriptor_transaction(
GBinderLocalObject* self,
GBinderRemoteRequest* req,
int* status)
{
/*android.hidl.base@1.0::IBase interfaceDescriptor() */
const GBinderIo* io = gbinder_local_object_io(self);
GBinderLocalReply* reply = gbinder_local_reply_new(io);
GBinderWriter writer;
GVERBOSE(" HIDL_GET_DESCRIPTOR_TRANSACTION \"%s\"",
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);
*status = GBINDER_STATUS_OK;
return reply;
}
static
GBinderLocalReply*
gbinder_local_object_hidl_descriptor_chain_transaction(
GBinderLocalObject* self,
GBinderRemoteRequest* req,
int* status)
{
/*android.hidl.base@1.0::IBase interfaceChain() */
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);
*status = GBINDER_STATUS_OK;
return reply;
}
static
GBinderLocalReply*
gbinder_local_object_default_handle_looper_transaction(
GBinderLocalObject* self,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status)
{
switch (code) {
case HIDL_PING_TRANSACTION:
GASSERT(!(flags & GBINDER_TX_FLAG_ONEWAY));
return gbinder_local_object_hidl_ping_transaction
(self, req, status);
case HIDL_GET_DESCRIPTOR_TRANSACTION:
GASSERT(!(flags & GBINDER_TX_FLAG_ONEWAY));
return gbinder_local_object_hidl_get_descriptor_transaction
(self, req, status);
case HIDL_DESCRIPTOR_CHAIN_TRANSACTION:
GASSERT(!(flags & GBINDER_TX_FLAG_ONEWAY));
return gbinder_local_object_hidl_descriptor_chain_transaction
(self, req, status);
default:
if (status) *status = (-EBADMSG);
return NULL;
}
}
static
void
gbinder_local_object_handle_later(
GBinderLocalObject* self,
GSourceFunc function)
{
if (G_LIKELY(self)) {
GBinderLocalObjectPriv* priv = self->priv;
g_main_context_invoke_full(priv->context, G_PRIORITY_DEFAULT, function,
gbinder_local_object_ref(self), g_object_unref);
}
}
static
gboolean
gbinder_local_object_handle_increfs_proc(
gpointer local)
{
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(local);
self->weak_refs++;
g_signal_emit(self, gbinder_local_object_signals
[SIGNAL_WEAK_REFS_CHANGED], 0);
return G_SOURCE_REMOVE;
}
static
gboolean
gbinder_local_object_handle_decrefs_proc(
gpointer local)
{
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(local);
GASSERT(self->weak_refs > 0);
self->weak_refs--;
g_signal_emit(self, gbinder_local_object_signals
[SIGNAL_WEAK_REFS_CHANGED], 0);
return G_SOURCE_REMOVE;
}
static
gboolean
gbinder_local_object_handle_acquire_proc(
gpointer local)
{
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(local);
self->strong_refs++;
g_signal_emit(self, gbinder_local_object_signals
[SIGNAL_STRONG_REFS_CHANGED], 0);
return G_SOURCE_REMOVE;
}
static
gboolean
gbinder_local_object_handle_release_proc(
gpointer local)
{
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(local);
GASSERT(self->strong_refs > 0);
self->strong_refs--;
g_signal_emit(self, gbinder_local_object_signals
[SIGNAL_STRONG_REFS_CHANGED], 0);
return G_SOURCE_REMOVE;
}
/*==========================================================================*
* Interface
*==========================================================================*/
GBinderLocalObject*
gbinder_local_object_new(
GBinderIpc* ipc,
const char* iface,
GBinderLocalTransactFunc txproc,
void* user_data)
{
/* Should only be called from gbinder_ipc_new_local_local_object() */
if (G_LIKELY(ipc)) {
GBinderLocalObject* self = g_object_new
(GBINDER_TYPE_LOCAL_OBJECT, NULL);
GBinderLocalObjectPriv* priv = self->priv;
self->ipc = gbinder_ipc_ref(ipc);
self->iface = priv->iface = g_strdup(iface);
priv->txproc = txproc;
priv->user_data = user_data;
return self;
}
return NULL;
}
GBinderLocalObject*
gbinder_local_object_ref(
GBinderLocalObject* self)
{
if (G_LIKELY(self)) {
g_object_ref(GBINDER_LOCAL_OBJECT(self));
return self;
} else {
return NULL;
}
}
void
gbinder_local_object_unref(
GBinderLocalObject* self)
{
if (G_LIKELY(self)) {
g_object_unref(GBINDER_LOCAL_OBJECT(self));
}
}
void
gbinder_local_object_drop(
GBinderLocalObject* self)
{
if (G_LIKELY(self)) {
GBinderLocalObjectPriv* priv = self->priv;
/* Clear the transaction callback */
priv->txproc = NULL;
priv->user_data = NULL;
g_object_unref(GBINDER_LOCAL_OBJECT(self));
}
}
GBinderLocalReply*
gbinder_local_object_new_reply(
GBinderLocalObject* self)
{
if (G_LIKELY(self)) {
return gbinder_local_reply_new(gbinder_local_object_io(self));
}
return NULL;
}
gulong
gbinder_local_object_add_weak_refs_changed_handler(
GBinderLocalObject* self,
GBinderLocalObjectFunc func,
void* user_data)
{
return (G_LIKELY(self) && G_LIKELY(func)) ? g_signal_connect(self,
SIGNAL_WEAK_REFS_CHANGED_NAME, G_CALLBACK(func), user_data) : 0;
}
gulong
gbinder_local_object_add_strong_refs_changed_handler(
GBinderLocalObject* self,
GBinderLocalObjectFunc func,
void* user_data)
{
return (G_LIKELY(self) && G_LIKELY(func)) ? g_signal_connect(self,
SIGNAL_STRONG_REFS_CHANGED_NAME, G_CALLBACK(func), user_data) : 0;
}
void
gbinder_local_object_remove_handler(
GBinderLocalObject* self,
gulong id)
{
if (G_LIKELY(self) && G_LIKELY(id)) {
g_signal_handler_disconnect(self, id);
}
}
GBINDER_LOCAL_TRANSACTION_SUPPORT
gbinder_local_object_can_handle_transaction(
GBinderLocalObject* self,
const char* iface,
guint code)
{
return G_LIKELY(self) ?
GBINDER_LOCAL_OBJECT_GET_CLASS(self)->can_handle_transaction
(self, iface, code) : GBINDER_LOCAL_TRANSACTION_NOT_SUPPORTED;
}
GBinderLocalReply*
gbinder_local_object_handle_transaction(
GBinderLocalObject* self,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status)
{
if (G_LIKELY(self)) {
return GBINDER_LOCAL_OBJECT_GET_CLASS(self)->handle_transaction
(self, req, code, flags, status);
} else {
if (status) *status = (-EBADMSG);
return NULL;
}
}
GBinderLocalReply*
gbinder_local_object_handle_looper_transaction(
GBinderLocalObject* self,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status)
{
if (G_LIKELY(self)) {
return GBINDER_LOCAL_OBJECT_GET_CLASS(self)->handle_looper_transaction
(self, req, code, flags, status);
} else {
if (status) *status = -EBADMSG;
return NULL;
}
}
void
gbinder_local_object_handle_increfs(
GBinderLocalObject* self)
{
gbinder_local_object_handle_later(self,
gbinder_local_object_handle_increfs_proc);
}
void
gbinder_local_object_handle_decrefs(
GBinderLocalObject* self)
{
gbinder_local_object_handle_later(self,
gbinder_local_object_handle_decrefs_proc);
}
void
gbinder_local_object_handle_acquire(
GBinderLocalObject* self)
{
gbinder_local_object_handle_later(self,
gbinder_local_object_handle_acquire_proc);
}
void
gbinder_local_object_handle_release(
GBinderLocalObject* self)
{
gbinder_local_object_handle_later(self,
gbinder_local_object_handle_release_proc);
}
/*==========================================================================*
* Internals
*==========================================================================*/
static
void
gbinder_local_object_init(
GBinderLocalObject* self)
{
GBinderLocalObjectPriv* priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
GBINDER_TYPE_LOCAL_OBJECT, GBinderLocalObjectPriv);
priv->context = g_main_context_default();
self->priv = priv;
}
static
void
gbinder_local_object_dispose(
GObject* local)
{
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(local);
gbinder_ipc_local_object_disposed(self->ipc, self);
G_OBJECT_CLASS(gbinder_local_object_parent_class)->dispose(local);
}
static
void
gbinder_local_object_finalize(
GObject* local)
{
GBinderLocalObject* self = GBINDER_LOCAL_OBJECT(local);
GBinderLocalObjectPriv* priv = self->priv;
gbinder_ipc_unref(self->ipc);
g_free(priv->iface);
G_OBJECT_CLASS(gbinder_local_object_parent_class)->finalize(local);
}
static
void
gbinder_local_object_class_init(
GBinderLocalObjectClass* klass)
{
GObjectClass* object_class = G_OBJECT_CLASS(klass);
object_class->dispose = gbinder_local_object_dispose;
object_class->finalize = gbinder_local_object_finalize;
g_type_class_add_private(klass, sizeof(GBinderLocalObjectPriv));
klass->handle_transaction =
gbinder_local_object_default_handle_transaction;
klass->handle_looper_transaction =
gbinder_local_object_default_handle_looper_transaction;
klass->can_handle_transaction =
gbinder_local_object_default_can_handle_transaction;
gbinder_local_object_signals[SIGNAL_WEAK_REFS_CHANGED] =
g_signal_new(SIGNAL_WEAK_REFS_CHANGED_NAME,
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, 0,
NULL, NULL, NULL, G_TYPE_NONE, 0);
gbinder_local_object_signals[SIGNAL_STRONG_REFS_CHANGED] =
g_signal_new(SIGNAL_STRONG_REFS_CHANGED_NAME,
G_OBJECT_CLASS_TYPE(klass), G_SIGNAL_RUN_FIRST, 0,
NULL, NULL, NULL, G_TYPE_NONE, 0);
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,161 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_LOCAL_OBJECT_PRIVATE_H
#define GBINDER_LOCAL_OBJECT_PRIVATE_H
#include <gbinder_local_object.h>
#include "gbinder_types_p.h"
#include <glib-object.h>
/*
* Some if this stuff may become public if we decide to allow the clients
* to derive their classes from GBinderLocalObject
*/
typedef
void
(*GBinderLocalObjectFunc)(
GBinderLocalObject* obj,
void* user_data);
typedef struct gbinder_local_object_priv GBinderLocalObjectPriv;
struct gbinder_local_object {
GObject object;
GBinderLocalObjectPriv* priv;
GBinderIpc* ipc;
const char* iface;
gint weak_refs;
gint strong_refs;
};
typedef enum gbinder_local_transaction_support {
GBINDER_LOCAL_TRANSACTION_NOT_SUPPORTED,
GBINDER_LOCAL_TRANSACTION_SUPPORTED, /* On the main thread */
GBINDER_LOCAL_TRANSACTION_LOOPER /* On the looper thread */
} GBINDER_LOCAL_TRANSACTION_SUPPORT;
typedef struct gbinder_local_object_class {
GObjectClass parent;
GBINDER_LOCAL_TRANSACTION_SUPPORT (*can_handle_transaction)
(GBinderLocalObject* self, const char* iface, guint code);
GBinderLocalReply* (*handle_transaction)
(GBinderLocalObject* self, GBinderRemoteRequest* req, guint code,
guint flags, int* status);
GBinderLocalReply* (*handle_looper_transaction)
(GBinderLocalObject* self, GBinderRemoteRequest* req, guint code,
guint flags, int* status);
/* Need to add some placeholders if this class becomes public */
} GBinderLocalObjectClass;
GType gbinder_local_object_get_type(void);
#define GBINDER_TYPE_LOCAL_OBJECT (gbinder_local_object_get_type())
#define GBINDER_LOCAL_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
GBINDER_TYPE_LOCAL_OBJECT, GBinderLocalObject))
#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,
GBinderLocalObjectFunc func,
void* user_data);
gulong
gbinder_local_object_add_strong_refs_changed_handler(
GBinderLocalObject* obj,
GBinderLocalObjectFunc func,
void* user_data);
void
gbinder_local_object_remove_handler(
GBinderLocalObject* obj,
gulong id);
GBINDER_LOCAL_TRANSACTION_SUPPORT
gbinder_local_object_can_handle_transaction(
GBinderLocalObject* self,
const char* iface,
guint code);
GBinderLocalReply*
gbinder_local_object_handle_transaction(
GBinderLocalObject* obj,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status);
GBinderLocalReply*
gbinder_local_object_handle_looper_transaction(
GBinderLocalObject* obj,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status);
void
gbinder_local_object_handle_increfs(
GBinderLocalObject* obj);
void
gbinder_local_object_handle_decrefs(
GBinderLocalObject* obj);
void
gbinder_local_object_handle_acquire(
GBinderLocalObject* obj);
void
gbinder_local_object_handle_release(
GBinderLocalObject* obj);
#endif /* GBINDER_LOCAL_OBJECT_PRIVATE_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

258
src/gbinder_local_reply.c Normal file
View File

@@ -0,0 +1,258 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Contact: 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 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.
*
* 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_local_reply_p.h"
#include "gbinder_output_data.h"
#include "gbinder_writer_p.h"
#include "gbinder_log.h"
#include <gutil_intarray.h>
#include <gutil_macros.h>
struct gbinder_local_reply {
gint refcount;
GBinderWriterData data;
GBinderOutputData out;
};
GBINDER_INLINE_FUNC
GBinderLocalReply*
gbinder_local_reply_output_cast(
GBinderOutputData* out)
{
return G_CAST(out, GBinderLocalReply, out);
}
static
GUtilIntArray*
gbinder_local_reply_output_offsets(
GBinderOutputData* out)
{
return gbinder_local_reply_output_cast(out)->data.offsets;
}
static
gsize
gbinder_local_reply_output_buffers_size(
GBinderOutputData* out)
{
return gbinder_local_reply_output_cast(out)->data.buffers_size;
}
GBinderLocalReply*
gbinder_local_reply_new(
const GBinderIo* io)
{
GASSERT(io);
if (io) {
GBinderLocalReply* self = g_slice_new0(GBinderLocalReply);
GBinderWriterData* data = &self->data;
GBinderOutputData* out = &self->out;
static const GBinderOutputDataFunctions local_reply_output_fn = {
.offsets = gbinder_local_reply_output_offsets,
.buffers_size = gbinder_local_reply_output_buffers_size
};
g_atomic_int_set(&self->refcount, 1);
data->io = io;
out->bytes = data->bytes = g_byte_array_new();
out->f = &local_reply_output_fn;
return self;
}
return NULL;
}
static
void
gbinder_local_reply_free(
GBinderLocalReply* self)
{
GBinderWriterData* data = &self->data;
gutil_int_array_free(data->offsets, TRUE);
g_byte_array_free(data->bytes, TRUE);
gbinder_cleanup_free(data->cleanup);
g_slice_free(GBinderLocalReply, self);
}
GBinderLocalReply*
gbinder_local_reply_ref(
GBinderLocalReply* self)
{
if (G_LIKELY(self)) {
GASSERT(self->refcount > 0);
g_atomic_int_inc(&self->refcount);
}
return self;
}
void
gbinder_local_reply_unref(
GBinderLocalReply* self)
{
if (G_LIKELY(self)) {
GASSERT(self->refcount > 0);
if (g_atomic_int_dec_and_test(&self->refcount)) {
gbinder_local_reply_free(self);
}
}
}
GBinderOutputData*
gbinder_local_reply_data(
GBinderLocalReply* self)
{
return G_LIKELY(self) ? &self->out : NULL;
}
void
gbinder_local_reply_cleanup(
GBinderLocalReply* self,
GDestroyNotify destroy,
gpointer pointer)
{
if (G_LIKELY(self)) {
GBinderWriterData* data = &self->data;
data->cleanup = gbinder_cleanup_add(data->cleanup, destroy, pointer);
} else if (destroy) {
destroy(pointer);
}
}
void
gbinder_local_reply_init_writer(
GBinderLocalReply* self,
GBinderWriter* writer)
{
if (G_LIKELY(writer)) {
gbinder_writer_init(writer, G_LIKELY(self) ? &self->data : NULL);
}
}
GBinderLocalReply*
gbinder_local_reply_append_int32(
GBinderLocalReply* self,
guint32 value)
{
if (G_LIKELY(self)) {
gbinder_writer_data_append_int32(&self->data, value);
}
return self;
}
GBinderLocalReply*
gbinder_local_reply_append_int64(
GBinderLocalReply* self,
guint64 value)
{
if (G_LIKELY(self)) {
gbinder_writer_data_append_int64(&self->data, value);
}
return self;
}
GBinderLocalReply*
gbinder_local_reply_append_string8(
GBinderLocalReply* self,
const char* str)
{
if (G_LIKELY(self)) {
gbinder_writer_data_append_string8(&self->data, str);
}
return self;
}
GBinderLocalReply*
gbinder_local_reply_append_string16(
GBinderLocalReply* self,
const char* utf8)
{
if (G_LIKELY(self)) {
gbinder_writer_data_append_string16(&self->data, utf8);
}
return self;
}
GBinderLocalReply*
gbinder_local_reply_append_hidl_string(
GBinderLocalReply* self,
const char* str)
{
if (G_LIKELY(self)) {
gbinder_writer_data_append_hidl_string(&self->data, str);
}
return self;
}
GBinderLocalReply*
gbinder_local_reply_append_hidl_string_vec(
GBinderLocalReply* self,
const char* strv[],
gssize count)
{
if (G_LIKELY(self)) {
gbinder_writer_data_append_hidl_string_vec(&self->data, strv, count);
}
return self;
}
GBinderLocalReply*
gbinder_local_reply_append_local_object(
GBinderLocalReply* self,
GBinderLocalObject* obj)
{
if (G_LIKELY(self)) {
gbinder_writer_data_append_local_object(&self->data, obj);
}
return self;
}
GBinderLocalReply*
gbinder_local_reply_append_remote_object(
GBinderLocalReply* self,
GBinderRemoteObject* obj)
{
if (G_LIKELY(self)) {
gbinder_writer_data_append_remote_object(&self->data, obj);
}
return self;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,56 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Contact: 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 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_LOCAL_REPLY_PRIVATE_H
#define GBINDER_LOCAL_REPLY_PRIVATE_H
#include <gbinder_local_reply.h>
#include "gbinder_types_p.h"
GBinderLocalReply*
gbinder_local_reply_new(
const GBinderIo* io);
GBinderOutputData*
gbinder_local_reply_data(
GBinderLocalReply* reply);
#endif /* GBINDER_LOCAL_REPLY_PRIVATE_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

267
src/gbinder_local_request.c Normal file
View File

@@ -0,0 +1,267 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Contact: 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 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.
*
* 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_local_request_p.h"
#include "gbinder_output_data.h"
#include "gbinder_writer_p.h"
#include "gbinder_log.h"
#include <gutil_intarray.h>
#include <gutil_macros.h>
struct gbinder_local_request {
gint refcount;
GBinderWriterData data;
GBinderOutputData out;
};
GBINDER_INLINE_FUNC
GBinderLocalRequest*
gbinder_local_request_output_cast(
GBinderOutputData* out)
{
return G_CAST(out, GBinderLocalRequest, out);
}
static
GUtilIntArray*
gbinder_local_request_output_offsets(
GBinderOutputData* out)
{
return gbinder_local_request_output_cast(out)->data.offsets;
}
static
gsize
gbinder_local_request_output_buffers_size(
GBinderOutputData* out)
{
return gbinder_local_request_output_cast(out)->data.buffers_size;
}
GBinderLocalRequest*
gbinder_local_request_new(
const GBinderIo* io,
GBytes* init)
{
GASSERT(io);
if (io) {
GBinderLocalRequest* self = g_slice_new0(GBinderLocalRequest);
GBinderWriterData* writer = &self->data;
GBinderOutputData* out = &self->out;
static const GBinderOutputDataFunctions local_request_output_fn = {
.offsets = gbinder_local_request_output_offsets,
.buffers_size = gbinder_local_request_output_buffers_size
};
g_atomic_int_set(&self->refcount, 1);
writer->io = io;
if (init) {
gsize size;
gconstpointer data = g_bytes_get_data(init, &size);
writer->bytes = g_byte_array_sized_new(size);
g_byte_array_append(writer->bytes, data, size);
} else {
writer->bytes = g_byte_array_new();
}
out->f = &local_request_output_fn;
out->bytes = writer->bytes;
return self;
}
return NULL;
}
static
void
gbinder_local_request_free(
GBinderLocalRequest* self)
{
GBinderWriterData* data = &self->data;
g_byte_array_free(data->bytes, TRUE);
gutil_int_array_free(data->offsets, TRUE);
gbinder_cleanup_free(data->cleanup);
g_slice_free(GBinderLocalRequest, self);
}
GBinderLocalRequest*
gbinder_local_request_ref(
GBinderLocalRequest* self)
{
if (G_LIKELY(self)) {
GASSERT(self->refcount > 0);
g_atomic_int_inc(&self->refcount);
}
return self;
}
void
gbinder_local_request_unref(
GBinderLocalRequest* self)
{
if (G_LIKELY(self)) {
GASSERT(self->refcount > 0);
if (g_atomic_int_dec_and_test(&self->refcount)) {
gbinder_local_request_free(self);
}
}
}
GBinderOutputData*
gbinder_local_request_data(
GBinderLocalRequest* self)
{
return G_LIKELY(self) ? &self->out : NULL;
}
void
gbinder_local_request_cleanup(
GBinderLocalRequest* self,
GDestroyNotify destroy,
gpointer pointer)
{
if (G_LIKELY(self)) {
GBinderWriterData* data = &self->data;
data->cleanup = gbinder_cleanup_add(data->cleanup, destroy, pointer);
} else if (destroy) {
destroy(pointer);
}
}
void
gbinder_local_request_init_writer(
GBinderLocalRequest* self,
GBinderWriter* writer)
{
if (G_LIKELY(writer)) {
gbinder_writer_init(writer, G_LIKELY(self) ? &self->data : NULL);
}
}
GBinderLocalRequest*
gbinder_local_request_append_int32(
GBinderLocalRequest* self,
guint32 value)
{
if (G_LIKELY(self)) {
gbinder_writer_data_append_int32(&self->data, value);
}
return self;
}
GBinderLocalRequest*
gbinder_local_request_append_int64(
GBinderLocalRequest* self,
guint64 value)
{
if (G_LIKELY(self)) {
gbinder_writer_data_append_int64(&self->data, value);
}
return self;
}
GBinderLocalRequest*
gbinder_local_request_append_string8(
GBinderLocalRequest* self,
const char* str)
{
if (G_LIKELY(self)) {
gbinder_writer_data_append_string8(&self->data, str);
}
return self;
}
GBinderLocalRequest*
gbinder_local_request_append_string16(
GBinderLocalRequest* self,
const char* utf8)
{
if (G_LIKELY(self)) {
gbinder_writer_data_append_string16(&self->data, utf8);
}
return self;
}
GBinderLocalRequest*
gbinder_local_request_append_hidl_string(
GBinderLocalRequest* self,
const char* str)
{
if (G_LIKELY(self)) {
gbinder_writer_data_append_hidl_string(&self->data, str);
}
return self;
}
GBinderLocalRequest*
gbinder_local_request_append_hidl_string_vec(
GBinderLocalRequest* self,
const char* strv[],
gssize count)
{
if (G_LIKELY(self)) {
gbinder_writer_data_append_hidl_string_vec(&self->data, strv, count);
}
return self;
}
GBinderLocalRequest*
gbinder_local_request_append_local_object(
GBinderLocalRequest* self,
GBinderLocalObject* obj)
{
if (G_LIKELY(self)) {
gbinder_writer_data_append_local_object(&self->data, obj);
}
return self;
}
GBinderLocalRequest*
gbinder_local_request_append_remote_object(
GBinderLocalRequest* self,
GBinderRemoteObject* obj)
{
if (G_LIKELY(self)) {
gbinder_writer_data_append_remote_object(&self->data, obj);
}
return self;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,57 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Contact: 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 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_LOCAL_REQUEST_PRIVATE_H
#define GBINDER_LOCAL_REQUEST_PRIVATE_H
#include <gbinder_local_request.h>
#include "gbinder_types_p.h"
GBinderLocalRequest*
gbinder_local_request_new(
const GBinderIo* io,
GBytes* init);
GBinderOutputData*
gbinder_local_request_data(
GBinderLocalRequest* req);
#endif /* GBINDER_LOCAL_REQUEST_PRIVATE_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

49
src/gbinder_log.h Normal file
View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_LOG_H
#define GBINDER_LOG_H
#include "gbinder_types.h"
#define GLOG_MODULE_NAME GBINDER_LOG_MODULE
#include <gutil_log.h>
#endif /* GBINDER_LOG_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,97 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_OBJECT_REGISTRY_H
#define GBINDER_OBJECT_REGISTRY_H
#include "gbinder_types_p.h"
typedef struct gbinder_object_registry_functions {
void (*ref)(GBinderObjectRegistry* reg);
void (*unref)(GBinderObjectRegistry* reg);
GBinderLocalObject* (*get_local)(GBinderObjectRegistry* reg,
void* pointer);
GBinderRemoteObject* (*get_remote)(GBinderObjectRegistry* reg,
guint32 handle);
} GBinderObjectRegistryFunctions;
struct gbinder_object_registry {
const GBinderObjectRegistryFunctions* f;
const GBinderIo* io;
};
/* Inline wrappers */
GBINDER_INLINE_FUNC
GBinderObjectRegistry*
gbinder_object_registry_ref(
GBinderObjectRegistry* reg)
{
if (reg) reg->f->ref(reg);
return reg;
}
GBINDER_INLINE_FUNC
void
gbinder_object_registry_unref(
GBinderObjectRegistry* reg)
{
if (reg) reg->f->unref(reg);
}
GBINDER_INLINE_FUNC
GBinderLocalObject*
gbinder_object_registry_get_local(
GBinderObjectRegistry* reg,
void* pointer)
{
return reg ? reg->f->get_local(reg, pointer) : NULL;
}
GBINDER_INLINE_FUNC
GBinderRemoteObject*
gbinder_object_registry_get_remote(
GBinderObjectRegistry* reg,
guint32 handle)
{
return reg ? reg->f->get_remote(reg, handle) : NULL;
}
#endif /* GBINDER_OBJECT_REGISTRY_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

76
src/gbinder_output_data.h Normal file
View File

@@ -0,0 +1,76 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_OUTPUT_DATA_H
#define GBINDER_OUTPUT_DATA_H
#include "gbinder_types_p.h"
typedef struct gbinder_output_data_functions GBinderOutputDataFunctions;
struct gbinder_output_data {
const GBinderOutputDataFunctions* f;
const GByteArray* bytes;
};
struct gbinder_output_data_functions {
GUtilIntArray* (*offsets)(GBinderOutputData* data);
gsize (*buffers_size)(GBinderOutputData* data);
};
/* Inline wrappers */
GBINDER_INLINE_FUNC
GUtilIntArray*
gbinder_output_data_offsets(
GBinderOutputData* data)
{
return data ? data->f->offsets(data) : NULL;
}
GBINDER_INLINE_FUNC
gsize
gbinder_output_data_buffers_size(
GBinderOutputData* data)
{
return data ? data->f->buffers_size(data) : 0;
}
#endif /* GBINDER_OUTPUT_DATA_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

471
src/gbinder_reader.c Normal file
View File

@@ -0,0 +1,471 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* 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_reader_p.h"
#include "gbinder_buffer_p.h"
#include "gbinder_io.h"
#include "gbinder_object_registry.h"
#include "gbinder_log.h"
#include <gutil_macros.h>
typedef struct gbinder_reader_priv {
const guint8* start;
const guint8* end;
const guint8* ptr;
const GBinderReaderData* data;
void** objects;
} GBinderReaderPriv;
G_STATIC_ASSERT(sizeof(GBinderReader) >= sizeof(GBinderReaderPriv));
static inline GBinderReaderPriv* gbinder_reader_cast(GBinderReader* reader)
{ return (GBinderReaderPriv*)reader; }
void
gbinder_reader_init(
GBinderReader* reader,
GBinderReaderData* data,
gsize offset,
gsize len)
{
GBinderReaderPriv* p = gbinder_reader_cast(reader);
p->data = data;
if (G_LIKELY(data)) {
GBinderBuffer* buffer = data->buffer;
if (buffer) {
/* We are assuming that the caller has checked offset and size */
GASSERT(!buffer || (offset + len <= buffer->size));
p->ptr = p->start = (guint8*)buffer->data + offset;
p->end = p->ptr + len;
} else {
p->ptr = p->start = p->end = NULL;
}
p->objects = data->objects;
} else {
p->ptr = p->start = p->end = NULL;
p->objects = NULL;
}
}
gboolean
gbinder_reader_at_end(
GBinderReader* reader)
{
GBinderReaderPriv* p = gbinder_reader_cast(reader);
return p->ptr >= p->end;
}
static
inline
gboolean
gbinder_reader_can_read(
GBinderReaderPriv* p,
gsize len)
{
return (p->end - p->ptr) >= len;
}
gboolean
gbinder_reader_read_byte(
GBinderReader* reader,
guchar* value)
{
GBinderReaderPriv* p = gbinder_reader_cast(reader);
if (p->ptr < p->end) {
if (value) *value = *p->ptr;
p->ptr++;
return TRUE;
} else {
return FALSE;
}
}
gboolean
gbinder_reader_read_bool(
GBinderReader* reader,
gboolean* value)
{
GBinderReaderPriv* p = gbinder_reader_cast(reader);
/* Boolean values are supposed to be padded to 4-byte boundary */
if (gbinder_reader_can_read(p, 4)) {
if (value) {
*value = (p->ptr[0] != 0);
}
p->ptr += 4;
return TRUE;
} else {
return FALSE;
}
}
gboolean
gbinder_reader_read_int32(
GBinderReader* reader,
gint32* value)
{
return gbinder_reader_read_uint32(reader, (guint32*)value);
}
gboolean
gbinder_reader_read_uint32(
GBinderReader* reader,
guint32* value)
{
GBinderReaderPriv* p = gbinder_reader_cast(reader);
if (gbinder_reader_can_read(p, sizeof(*value))) {
if (value) {
const gint32* ptr = (void*)p->ptr;
*value = *ptr;
}
p->ptr += sizeof(*value);
return TRUE;
} else {
return FALSE;
}
}
gboolean
gbinder_reader_read_int64(
GBinderReader* reader,
gint64* value)
{
return gbinder_reader_read_uint64(reader, (guint64*)value);
}
gboolean
gbinder_reader_read_uint64(
GBinderReader* reader,
guint64* value)
{
GBinderReaderPriv* p = gbinder_reader_cast(reader);
if (gbinder_reader_can_read(p, sizeof(*value))) {
if (value) {
const gint64* ptr = (void*)p->ptr;
*value = *ptr;
}
p->ptr += sizeof(*value);
return TRUE;
} else {
return FALSE;
}
}
gboolean
gbinder_reader_read_nullable_object(
GBinderReader* reader,
GBinderRemoteObject** out)
{
GBinderReaderPriv* p = gbinder_reader_cast(reader);
const GBinderReaderData* data = p->data;
if (data && data->reg && p->objects && p->objects[0] &&
p->ptr == p->objects[0]) {
const guint eaten = data->reg->io->decode_binder_object(p->ptr,
gbinder_reader_bytes_remaining(reader), data->reg, out);
if (eaten) {
p->ptr += eaten;
p->objects++;
return TRUE;
}
}
if (out) *out = NULL;
return FALSE;
}
GBinderRemoteObject*
gbinder_reader_read_object(
GBinderReader* reader)
{
GBinderRemoteObject* obj = NULL;
gbinder_reader_read_nullable_object(reader, &obj);
return obj;
}
static
gboolean
gbinder_reader_read_buffer_impl(
GBinderReader* reader,
GBinderBuffer** out)
{
GBinderReaderPriv* p = gbinder_reader_cast(reader);
const GBinderReaderData* data = p->data;
if (data && data->reg && p->objects && p->objects[0] &&
p->ptr == p->objects[0]) {
GBinderBuffer* buf = data->buffer;
const GBinderIo* io = data->reg->io;
const gsize offset = p->ptr - (guint8*)buf->data;
const guint eaten = io->decode_buffer_object(buf, offset, out);
if (eaten) {
p->ptr += eaten;
p->objects++;
return TRUE;
}
}
if (out) *out = NULL;
return FALSE;
}
GBinderBuffer*
gbinder_reader_read_buffer(
GBinderReader* reader)
{
GBinderBuffer* buf = NULL;
gbinder_reader_read_buffer_impl(reader, &buf);
return buf;
}
gboolean
gbinder_reader_skip_buffer(
GBinderReader* reader)
{
return gbinder_reader_read_buffer_impl(reader, NULL);
}
char*
gbinder_reader_read_hidl_string(
GBinderReader* reader)
{
GBinderBuffer* buf = gbinder_reader_read_buffer(reader);
char* str = NULL;
if (buf && buf->size == sizeof(HidlString)) {
const HidlString* s = buf->data;
GBinderBuffer* sbuf = gbinder_reader_read_buffer(reader);
if (sbuf && sbuf->size == s->len + 1 &&
sbuf->data == s->data.str &&
s->data.str[s->len] == 0) {
str = g_strdup(s->data.str);
}
gbinder_buffer_free(sbuf);
}
gbinder_buffer_free(buf);
return str;
}
char**
gbinder_reader_read_hidl_string_vec(
GBinderReader* reader)
{
GBinderBuffer* buf = gbinder_reader_read_buffer(reader);
/* First buffer contains hidl_vector */
if (buf && buf->size == sizeof(HidlVec)) {
HidlVec* vec = buf->data;
const guint n = vec->count;
const void* next = vec->data.ptr;
gbinder_buffer_free(buf);
if (!next && !n) {
char** out = g_new(char*, 1);
out[0] = NULL;
return out;
} else {
/* The second buffer (if any) contains n hidl_string's */
buf = gbinder_reader_read_buffer(reader);
if (buf && buf->data == next && buf->size == sizeof(HidlString)*n) {
const HidlString* strings = buf->data;
GBinderBuffer* sbuf;
GPtrArray* list = g_ptr_array_new();
guint i;
/* Now we expect n buffers containing the actual data */
for (i=0; i<n &&
(sbuf = gbinder_reader_read_buffer(reader)); i++) {
const HidlString* s = strings + i;
if (sbuf->size == s->len + 1 &&
sbuf->data == s->data.str &&
s->data.str[s->len] == 0) {
char* name = g_strdup(s->data.str);
g_ptr_array_add(list, name);
GVERBOSE_("%u. %s", i + 1, name);
gbinder_buffer_free(sbuf);
} else {
GWARN("Unexpected hidl_string buffer %p/%u vs %p/%u",
sbuf->data, (guint)sbuf->size, s->data.str, s->len);
gbinder_buffer_free(sbuf);
break;
}
}
if (i == n) {
gbinder_buffer_free(buf);
g_ptr_array_add(list, NULL);
return (char**)g_ptr_array_free(list, FALSE);
}
g_ptr_array_set_free_func(list, g_free);
g_ptr_array_free(list, TRUE);
}
}
}
GWARN("Invalid hidl_vec<string>");
gbinder_buffer_free(buf);
return NULL;
}
const char*
gbinder_reader_read_string8(
GBinderReader* reader)
{
GBinderReaderPriv* p = gbinder_reader_cast(reader);
const guint8* ptr = p->ptr;
/* Calculate the length */
while (ptr < p->end && *ptr) ptr++;
if (ptr < p->end) {
/* Zero terminator has been found within the bounds */
const gsize len = ptr - p->ptr;
const gsize size = G_ALIGN4(len+1);
if (p->ptr + size <= p->end) {
const char* str = (char*)p->ptr;
p->ptr += size;
return str;
}
}
return NULL;
}
gboolean
gbinder_reader_read_nullable_string16(
GBinderReader* reader,
char** out)
{
GBinderReaderPriv* p = gbinder_reader_cast(reader);
if ((p->ptr + 4) <= p->end) {
const gint32* len_ptr = (gint32*)p->ptr;
const gint32 len = *len_ptr;
if (len == -1) {
/* NULL string */
p->ptr += 4;
if (out) {
*out = NULL;
}
return TRUE;
} else if (len >= 0) {
const guint32 padded_len = G_ALIGN4((len+1)*2);
const gunichar2* utf16 = (const gunichar2*)(p->ptr + 4);
if ((p->ptr + padded_len + 4) <= p->end) {
p->ptr += padded_len + 4;
if (out) {
*out = g_utf16_to_utf8(utf16, len, NULL, NULL, NULL);
}
return TRUE;
}
}
}
return FALSE;
}
char*
gbinder_reader_read_string16(
GBinderReader* reader)
{
char* str = NULL;
gbinder_reader_read_nullable_string16(reader, &str);
return str;
}
gboolean
gbinder_reader_skip_string16(
GBinderReader* reader)
{
GBinderReaderPriv* p = gbinder_reader_cast(reader);
if ((p->ptr + 4) <= p->end) {
const gint32* len_ptr = (gint32*)p->ptr;
const gint32 len = *len_ptr;
if (len == -1) {
/* NULL string */
p->ptr += 4;
return TRUE;
} else if (len >= 0) {
const guint32 padded_len = G_ALIGN4((len+1)*2);
if ((p->ptr + padded_len + 4) <= p->end) {
p->ptr += padded_len + 4;
return TRUE;
}
}
}
return FALSE;
}
gsize
gbinder_reader_bytes_read(
GBinderReader* reader)
{
GBinderReaderPriv* p = gbinder_reader_cast(reader);
return p->ptr - p->start;
}
gsize
gbinder_reader_bytes_remaining(
GBinderReader* reader)
{
GBinderReaderPriv* p = gbinder_reader_cast(reader);
return p->end - p->ptr;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

61
src/gbinder_reader_p.h Normal file
View File

@@ -0,0 +1,61 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_READER_PRIVATE_H
#define GBINDER_READER_PRIVATE_H
#include <gbinder_reader.h>
#include "gbinder_types_p.h"
typedef struct gbinder_reader_data {
GBinderBuffer* buffer;
GBinderObjectRegistry* reg;
void** objects;
} GBinderReaderData;
void
gbinder_reader_init(
GBinderReader* reader,
GBinderReaderData* data,
gsize offset,
gsize len);
#endif /* GBINDER_READER_PRIVATE_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

231
src/gbinder_remote_object.c Normal file
View File

@@ -0,0 +1,231 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* 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_driver.h"
#include "gbinder_ipc.h"
#include "gbinder_remote_object_p.h"
#include "gbinder_log.h"
struct gbinder_remote_object_priv {
GMainContext* context;
};
typedef GObjectClass GBinderRemoteObjectClass;
G_DEFINE_TYPE(GBinderRemoteObject, gbinder_remote_object, G_TYPE_OBJECT)
GType gbinder_remote_object_get_type(void);
#define GBINDER_TYPE_REMOTE_OBJECT (gbinder_remote_object_get_type())
#define GBINDER_REMOTE_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \
GBINDER_TYPE_REMOTE_OBJECT, GBinderRemoteObject))
enum gbinder_remote_object_signal {
SIGNAL_DEATH,
SIGNAL_COUNT
};
#define SIGNAL_DEATH_NAME "death"
static guint gbinder_remote_object_signals[SIGNAL_COUNT] = { 0 };
/*==========================================================================*
* Implementation
*==========================================================================*/
static
void
gbinder_remote_object_died_on_main_thread(
GBinderRemoteObject* self)
{
GASSERT(!self->dead);
self->dead = TRUE;
g_signal_emit(self, gbinder_remote_object_signals[SIGNAL_DEATH], 0);
}
static
gboolean
gbinder_remote_object_died_handle(
gpointer self)
{
gbinder_remote_object_died_on_main_thread(GBINDER_REMOTE_OBJECT(self));
return G_SOURCE_REMOVE;
}
/*==========================================================================*
* Interface
*==========================================================================*/
GBinderRemoteObject*
gbinder_remote_object_new(
GBinderIpc* ipc,
guint32 handle)
{
if (G_LIKELY(ipc) && gbinder_driver_acquire(ipc->driver, handle)) {
GBinderRemoteObject* self = g_object_new
(GBINDER_TYPE_REMOTE_OBJECT, NULL);
self->ipc = gbinder_ipc_ref(ipc);
self->handle = handle;
gbinder_driver_request_death_notification(ipc->driver, self);
return self;
}
return NULL;
}
GBinderRemoteObject*
gbinder_remote_object_ref(
GBinderRemoteObject* self)
{
if (G_LIKELY(self)) {
g_object_ref(GBINDER_REMOTE_OBJECT(self));
return self;
} else {
return NULL;
}
}
void
gbinder_remote_object_unref(
GBinderRemoteObject* self)
{
if (G_LIKELY(self)) {
g_object_unref(GBINDER_REMOTE_OBJECT(self));
}
}
gboolean
gbinder_remote_object_is_dead(
GBinderRemoteObject* self)
{
return G_UNLIKELY(!self) || self->dead;
}
gulong
gbinder_remote_object_add_death_handler(
GBinderRemoteObject* self,
GBinderRemoteObjectNotifyFunc fn,
void* data)
{
if (G_LIKELY(self) && G_LIKELY(fn)) {
/* To receive the notifications, we need to have looper running */
gbinder_ipc_looper_check(self->ipc);
return g_signal_connect(self, SIGNAL_DEATH_NAME, G_CALLBACK(fn), data);
}
return 0;
}
void
gbinder_remote_object_remove_handler(
GBinderRemoteObject* self,
gulong id)
{
if (G_LIKELY(self) && G_LIKELY(id)) {
g_signal_handler_disconnect(self, id);
}
}
void
gbinder_remote_object_handle_death_notification(
GBinderRemoteObject* self)
{
/* This function is invoked from the looper thread, the caller has
* checked the object pointer */
GVERBOSE_("%p %u", self, self->handle);
g_main_context_invoke_full(self->priv->context, G_PRIORITY_DEFAULT,
gbinder_remote_object_died_handle, gbinder_remote_object_ref(self),
g_object_unref);
}
/*==========================================================================*
* Internals
*==========================================================================*/
static
void
gbinder_remote_object_init(
GBinderRemoteObject* self)
{
GBinderRemoteObjectPriv* priv = G_TYPE_INSTANCE_GET_PRIVATE(self,
GBINDER_TYPE_REMOTE_OBJECT, GBinderRemoteObjectPriv);
priv->context = g_main_context_default();
self->priv = priv;
}
static
void
gbinder_remote_object_dispose(
GObject* remote)
{
GBinderRemoteObject* self = GBINDER_REMOTE_OBJECT(remote);
gbinder_ipc_remote_object_disposed(self->ipc, self);
G_OBJECT_CLASS(gbinder_remote_object_parent_class)->dispose(remote);
}
static
void
gbinder_remote_object_finalize(
GObject* remote)
{
GBinderRemoteObject* self = GBINDER_REMOTE_OBJECT(remote);
GBinderIpc* ipc = self->ipc;
GBinderDriver* driver = ipc->driver;
gbinder_driver_clear_death_notification(driver, self);
gbinder_driver_release(driver, self->handle);
gbinder_ipc_unref(ipc);
G_OBJECT_CLASS(gbinder_remote_object_parent_class)->finalize(remote);
}
static
void
gbinder_remote_object_class_init(
GBinderRemoteObjectClass* klass)
{
GObjectClass* remote_class = G_OBJECT_CLASS(klass);
g_type_class_add_private(klass, sizeof(GBinderRemoteObjectPriv));
remote_class->dispose = gbinder_remote_object_dispose;
remote_class->finalize = gbinder_remote_object_finalize;
gbinder_remote_object_signals[SIGNAL_DEATH] =
g_signal_new(SIGNAL_DEATH_NAME, G_OBJECT_CLASS_TYPE(klass),
G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,71 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_REMOTE_OBJECT_PRIVATE_H
#define GBINDER_REMOTE_OBJECT_PRIVATE_H
#include <gbinder_remote_object.h>
#include "gbinder_types_p.h"
#include <glib-object.h>
typedef struct gbinder_remote_object_priv GBinderRemoteObjectPriv;
struct gbinder_remote_object {
GObject object;
GBinderRemoteObjectPriv* priv;
GBinderIpc* ipc;
guint32 handle;
gboolean dead;
};
#define gbinder_remote_object_dev(obj) (gbinder_driver_dev((obj)->ipc->driver))
#define gbinder_remote_object_io(obj) (gbinder_driver_io((obj)->ipc->driver))
GBinderRemoteObject*
gbinder_remote_object_new(
GBinderIpc* ipc,
guint32 handle);
void
gbinder_remote_object_handle_death_notification(
GBinderRemoteObject* obj);
#endif /* GBINDER_REMOTE_OBJECT_PRIVATE_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

239
src/gbinder_remote_reply.c Normal file
View File

@@ -0,0 +1,239 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* 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_remote_reply_p.h"
#include "gbinder_reader_p.h"
#include "gbinder_object_registry.h"
#include "gbinder_buffer.h"
#include "gbinder_log.h"
#include <gutil_macros.h>
struct gbinder_remote_reply {
gint refcount;
GBinderReaderData data;
};
GBinderRemoteReply*
gbinder_remote_reply_new(
GBinderObjectRegistry* reg)
{
GBinderRemoteReply* self = g_slice_new0(GBinderRemoteReply);
GBinderReaderData* data = &self->data;
g_atomic_int_set(&self->refcount, 1);
data->reg = gbinder_object_registry_ref(reg);
return self;
}
static
void
gbinder_remote_reply_free(
GBinderRemoteReply* self)
{
GBinderReaderData* data = &self->data;
gbinder_object_registry_unref(data->reg);
gbinder_buffer_free(data->buffer);
g_free(data->objects);
g_slice_free(GBinderRemoteReply, self);
}
void
gbinder_remote_reply_set_data(
GBinderRemoteReply* self,
GBinderBuffer* buffer,
void** objects)
{
if (G_LIKELY(self)) {
GBinderReaderData* data = &self->data;
g_free(data->objects);
gbinder_buffer_free(data->buffer);
data->buffer = buffer;
data->objects = objects;
} else {
gbinder_buffer_free(buffer);
g_free(objects);
}
}
GBinderRemoteReply*
gbinder_remote_reply_ref(
GBinderRemoteReply* self)
{
if (G_LIKELY(self)) {
GASSERT(self->refcount > 0);
g_atomic_int_inc(&self->refcount);
}
return self;
}
void
gbinder_remote_reply_unref(
GBinderRemoteReply* self)
{
if (G_LIKELY(self)) {
GASSERT(self->refcount > 0);
if (g_atomic_int_dec_and_test(&self->refcount)) {
gbinder_remote_reply_free(self);
}
}
}
gboolean
gbinder_remote_reply_is_empty(
GBinderRemoteReply* self)
{
return !self || !self->data.buffer || !self->data.buffer->size;
}
static
inline
void
gbinder_remote_reply_init_reader2(
GBinderRemoteReply* self,
GBinderReader* p)
{
/* The caller has already checked the reply for NULL */
GBinderReaderData* data = &self->data;
GBinderBuffer* buffer = data->buffer;
if (buffer) {
gbinder_reader_init(p, data, 0, buffer->size);
} else {
gbinder_reader_init(p, data, 0, 0);
}
}
void
gbinder_remote_reply_init_reader(
GBinderRemoteReply* self,
GBinderReader* reader)
{
if (G_LIKELY(self)) {
gbinder_remote_reply_init_reader2(self, reader);
} else {
gbinder_reader_init(reader, NULL, 0, 0);
}
}
gboolean
gbinder_remote_reply_read_int32(
GBinderRemoteReply* self,
gint32* value)
{
return gbinder_remote_reply_read_uint32(self, (guint32*)value);
}
gboolean
gbinder_remote_reply_read_uint32(
GBinderRemoteReply* self,
guint32* value)
{
if (G_LIKELY(self)) {
GBinderReader reader;
gbinder_remote_reply_init_reader2(self, &reader);
return gbinder_reader_read_uint32(&reader, value);
}
return FALSE;
}
gboolean
gbinder_remote_reply_read_int64(
GBinderRemoteReply* self,
gint64* value)
{
return gbinder_remote_reply_read_uint64(self, (guint64*)value);
}
gboolean
gbinder_remote_reply_read_uint64(
GBinderRemoteReply* self,
guint64* value)
{
if (G_LIKELY(self)) {
GBinderReader reader;
gbinder_remote_reply_init_reader2(self, &reader);
return gbinder_reader_read_uint64(&reader, value);
}
return FALSE;
}
const char*
gbinder_remote_reply_read_string8(
GBinderRemoteReply* self)
{
if (G_LIKELY(self)) {
GBinderReader reader;
gbinder_remote_reply_init_reader2(self, &reader);
return gbinder_reader_read_string8(&reader);
}
return NULL;
}
char*
gbinder_remote_reply_read_string16(
GBinderRemoteReply* self)
{
if (G_LIKELY(self)) {
GBinderReader reader;
gbinder_remote_reply_init_reader2(self, &reader);
return gbinder_reader_read_string16(&reader);
}
return NULL;
}
GBinderRemoteObject*
gbinder_remote_reply_read_object(
GBinderRemoteReply* self)
{
if (G_LIKELY(self)) {
GBinderReader reader;
gbinder_remote_reply_init_reader2(self, &reader);
return gbinder_reader_read_object(&reader);
}
return NULL;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,62 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_REMOTE_REPLY_PRIVATE_H
#define GBINDER_REMOTE_REPLY_PRIVATE_H
#include <gbinder_remote_reply.h>
#include "gbinder_types_p.h"
GBinderRemoteReply*
gbinder_remote_reply_new(
GBinderObjectRegistry* reg);
void
gbinder_remote_reply_set_data(
GBinderRemoteReply* reply,
GBinderBuffer* buffer,
void** objects);
gboolean
gbinder_remote_reply_is_empty(
GBinderRemoteReply* reply);
#endif /* GBINDER_REMOTE_REPLY_PRIVATE_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,256 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* 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_remote_request_p.h"
#include "gbinder_reader_p.h"
#include "gbinder_rpc_protocol.h"
#include "gbinder_object_registry.h"
#include "gbinder_buffer.h"
#include "gbinder_log.h"
#include <gutil_macros.h>
struct gbinder_remote_request {
gint refcount;
const GBinderRpcProtocol* protocol;
const char* iface;
char* iface2;
gsize header_size;
GBinderReaderData data;
};
GBinderRemoteRequest*
gbinder_remote_request_new(
GBinderObjectRegistry* reg,
const GBinderRpcProtocol* protocol)
{
GBinderRemoteRequest* self = g_slice_new0(GBinderRemoteRequest);
GBinderReaderData* data = &self->data;
g_atomic_int_set(&self->refcount, 1);
self->protocol = protocol;
data->reg = gbinder_object_registry_ref(reg);
return self;
}
static
void
gbinder_remote_request_free(
GBinderRemoteRequest* self)
{
GBinderReaderData* data = &self->data;
gbinder_object_registry_unref(data->reg);
gbinder_buffer_free(data->buffer);
g_free(data->objects);
g_free(self->iface2);
g_slice_free(GBinderRemoteRequest, self);
}
static
inline
void
gbinder_remote_request_init_reader2(
GBinderRemoteRequest* self,
GBinderReader* p)
{
/* The caller has already checked the request for NULL */
GBinderReaderData* data = &self->data;
GBinderBuffer* buffer = data->buffer;
if (buffer) {
gbinder_reader_init(p, data, self->header_size,
buffer->size - self->header_size);
} else {
gbinder_reader_init(p, data, 0, 0);
}
}
void
gbinder_remote_request_set_data(
GBinderRemoteRequest* self,
GBinderBuffer* buffer,
void** objects)
{
if (G_LIKELY(self)) {
GBinderReaderData* data = &self->data;
GBinderReader reader;
g_free(self->iface2);
g_free(data->objects);
gbinder_buffer_free(data->buffer);
data->buffer = buffer;
data->objects = objects;
/* Parse RPC header */
self->header_size = 0;
gbinder_remote_request_init_reader2(self, &reader);
self->iface = self->protocol->read_rpc_header(&reader, &self->iface2);
self->header_size = gbinder_reader_bytes_read(&reader);
} else {
gbinder_buffer_free(buffer);
g_free(objects);
}
}
const char*
gbinder_remote_request_interface(
GBinderRemoteRequest* self)
{
return G_LIKELY(self) ? self->iface : NULL;
}
GBinderRemoteRequest*
gbinder_remote_request_ref(
GBinderRemoteRequest* self)
{
if (G_LIKELY(self)) {
GASSERT(self->refcount > 0);
g_atomic_int_inc(&self->refcount);
}
return self;
}
void
gbinder_remote_request_unref(
GBinderRemoteRequest* self)
{
if (G_LIKELY(self)) {
GASSERT(self->refcount > 0);
if (g_atomic_int_dec_and_test(&self->refcount)) {
gbinder_remote_request_free(self);
}
}
}
void
gbinder_remote_request_init_reader(
GBinderRemoteRequest* self,
GBinderReader* reader)
{
if (G_LIKELY(self)) {
gbinder_remote_request_init_reader2(self, reader);
} else {
gbinder_reader_init(reader, NULL, 0, 0);
}
}
gboolean
gbinder_remote_request_read_int32(
GBinderRemoteRequest* self,
gint32* value)
{
return gbinder_remote_request_read_uint32(self, (guint32*)value);
}
gboolean
gbinder_remote_request_read_uint32(
GBinderRemoteRequest* self,
guint32* value)
{
if (G_LIKELY(self)) {
GBinderReader reader;
gbinder_remote_request_init_reader2(self, &reader);
return gbinder_reader_read_uint32(&reader, value);
}
return FALSE;
}
gboolean
gbinder_remote_request_read_int64(
GBinderRemoteRequest* self,
gint64* value)
{
return gbinder_remote_request_read_uint64(self, (guint64*)value);
}
gboolean
gbinder_remote_request_read_uint64(
GBinderRemoteRequest* self,
guint64* value)
{
if (G_LIKELY(self)) {
GBinderReader reader;
gbinder_remote_request_init_reader2(self, &reader);
return gbinder_reader_read_uint64(&reader, value);
}
return FALSE;
}
const char*
gbinder_remote_request_read_string8(
GBinderRemoteRequest* self)
{
if (G_LIKELY(self)) {
GBinderReader reader;
gbinder_remote_request_init_reader2(self, &reader);
return gbinder_reader_read_string8(&reader);
}
return NULL;
}
char*
gbinder_remote_request_read_string16(
GBinderRemoteRequest* self)
{
if (G_LIKELY(self)) {
GBinderReader reader;
gbinder_remote_request_init_reader2(self, &reader);
return gbinder_reader_read_string16(&reader);
}
return NULL;
}
GBinderRemoteObject*
gbinder_remote_request_read_object(
GBinderRemoteRequest* self)
{
if (G_LIKELY(self)) {
GBinderReader reader;
gbinder_remote_request_init_reader2(self, &reader);
return gbinder_reader_read_object(&reader);
}
return NULL;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,59 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_REMOTE_REQUEST_PRIVATE_H
#define GBINDER_REMOTE_REQUEST_PRIVATE_H
#include <gbinder_remote_request.h>
#include "gbinder_types_p.h"
GBinderRemoteRequest*
gbinder_remote_request_new(
GBinderObjectRegistry* reg,
const GBinderRpcProtocol* protocol);
void
gbinder_remote_request_set_data(
GBinderRemoteRequest* request,
GBinderBuffer* buffer,
void** objects);
#endif /* GBINDER_REMOTE_REQUEST_PRIVATE_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

136
src/gbinder_rpc_protocol.c Normal file
View File

@@ -0,0 +1,136 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* 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_rpc_protocol.h"
#include "gbinder_reader.h"
#include "gbinder_writer.h"
/*==========================================================================*
* GBinderIpcProtocol callbacks (see Parcel::writeInterfaceToken in Android)
* Note that there are two slightly different kinds of Parcels:
*
* platform/system/libhwbinder/Parcel.cpp
* platform/frameworks/native/libs/binder/Parcel.cpp
*==========================================================================*/
/*==========================================================================*
* /dev/binder
*==========================================================================*/
/* No idea what that is... */
#define STRICT_MODE_PENALTY_GATHER (0x40 << 16)
#define BINDER_RPC_FLAGS (STRICT_MODE_PENALTY_GATHER)
static
void
gbinder_rpc_protocol_binder_write_rpc_header(
GBinderWriter* writer,
const char* iface)
{
/*
* writeInt32(IPCThreadState::self()->getStrictModePolicy() |
* STRICT_MODE_PENALTY_GATHER);
* writeString16(interface);
*/
gbinder_writer_append_int32(writer, BINDER_RPC_FLAGS);
gbinder_writer_append_string16(writer, iface);
}
static
const char*
gbinder_rpc_protocol_binder_read_rpc_header(
GBinderReader* reader,
char** iface)
{
if (gbinder_reader_read_int32(reader, NULL)) {
*iface = gbinder_reader_read_string16(reader);
} else {
*iface = NULL;
}
return *iface;
}
/*==========================================================================*
* /dev/hwbinder
*==========================================================================*/
static
void
gbinder_rpc_protocol_hwbinder_write_rpc_header(
GBinderWriter* writer,
const char* iface)
{
/*
* writeCString(interface);
*/
gbinder_writer_append_string8(writer, iface);
}
static
const char*
gbinder_rpc_protocol_hwbinder_read_rpc_header(
GBinderReader* reader,
char** iface)
{
*iface = NULL;
return gbinder_reader_read_string8(reader);
}
/*==========================================================================*
* Interface
*==========================================================================*/
const GBinderRpcProtocol*
gbinder_rpc_protocol_for_device(
const char* dev)
{
static const GBinderRpcProtocol protocol_binder = {
.read_rpc_header = gbinder_rpc_protocol_binder_read_rpc_header,
.write_rpc_header = gbinder_rpc_protocol_binder_write_rpc_header
};
static const GBinderRpcProtocol protocol_hwbinder = {
.read_rpc_header = gbinder_rpc_protocol_hwbinder_read_rpc_header,
.write_rpc_header = gbinder_rpc_protocol_hwbinder_write_rpc_header
};
return (dev && !strcmp(dev, GBINDER_DEFAULT_HWBINDER)) ?
&protocol_hwbinder : &protocol_binder;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,60 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Contact: 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 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_RPC_PROTOCOL_H
#define GBINDER_RPC_PROTOCOL_H
#include "gbinder_types_p.h"
/*
* For whatever reason services communicating via /dev/binder
* and /dev/hwbinder use slightly different RPC headers.
*/
struct gbinder_rpc_protocol {
const char* (*read_rpc_header)(GBinderReader* reader, char** iface);
void (*write_rpc_header)(GBinderWriter* writer, const char* iface);
};
const GBinderRpcProtocol*
gbinder_rpc_protocol_for_device(
const char* dev);
#endif /* GBINDER_RPC_PROTOCOL_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,521 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* 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_servicemanager_p.h"
#include "gbinder_client_p.h"
#include "gbinder_local_object_p.h"
#include "gbinder_remote_object_p.h"
#include "gbinder_driver.h"
#include "gbinder_ipc.h"
#include "gbinder_log.h"
#include <gbinder_client.h>
#include <gutil_idlepool.h>
#include <errno.h>
G_DEFINE_ABSTRACT_TYPE(GBinderServiceManager, gbinder_servicemanager,
G_TYPE_OBJECT)
#define PARENT_CLASS gbinder_servicemanager_parent_class
#define GBINDER_SERVICEMANAGER(obj) \
G_TYPE_CHECK_INSTANCE_CAST((obj), GBINDER_TYPE_SERVICEMANAGER, \
GBinderServiceManager)
#define GBINDER_SERVICEMANAGER_CLASS(klass) \
G_TYPE_CHECK_CLASS_CAST((klass), GBINDER_TYPE_SERVICEMANAGER, \
GBinderServiceManagerClass)
#define GBINDER_SERVICEMANAGER_GET_CLASS(obj) \
G_TYPE_INSTANCE_GET_CLASS((obj), GBINDER_TYPE_SERVICEMANAGER, \
GBinderServiceManagerClass)
#define GBINDER_IS_SERVICEMANAGER_TYPE(klass) \
G_TYPE_CHECK_CLASS_TYPE(klass, GBINDER_TYPE_SERVICEMANAGER)
/*==========================================================================*
* Implementation
*==========================================================================*/
static
GBinderServiceManagerClass*
gbinder_servicemanager_class_ref(
GType type)
{
if (G_LIKELY(type)) {
GTypeClass* klass = g_type_class_ref(type);
if (klass) {
if (GBINDER_IS_SERVICEMANAGER_TYPE(klass)) {
return GBINDER_SERVICEMANAGER_CLASS(klass);
}
g_type_class_unref(klass);
}
}
return NULL;
}
GBinderServiceManager*
gbinder_servicemanager_new_with_type(
GType type,
const char* dev)
{
GBinderServiceManager* self = NULL;
GBinderServiceManagerClass* klass = gbinder_servicemanager_class_ref(type);
if (klass) {
GBinderIpc* ipc;
if (!dev) dev = klass->default_device;
ipc = gbinder_ipc_new(dev);
if (ipc) {
GBinderRemoteObject* object = gbinder_ipc_get_remote_object
(ipc, klass->handle);
if (object) {
/* Lock */
g_mutex_lock(&klass->mutex);
if (klass->table) {
self = g_hash_table_lookup(klass->table, dev);
}
if (self) {
gbinder_servicemanager_ref(self);
} else {
char* key = g_strdup(dev); /* Owned by the hashtable */
GVERBOSE_("%s", dev);
self = g_object_new(type, NULL);
self->client = gbinder_client_new(object, klass->iface);
self->dev = gbinder_remote_object_dev(object);
if (!klass->table) {
klass->table = g_hash_table_new_full(g_str_hash,
g_str_equal, g_free, NULL);
}
g_hash_table_replace(klass->table, key, self);
}
g_mutex_unlock(&klass->mutex);
/* Unlock */
gbinder_remote_object_unref(object);
}
gbinder_ipc_unref(ipc);
}
g_type_class_unref(klass);
}
return self;
}
typedef struct gbinder_servicemanager_list_tx_data {
GBinderServiceManager* sm;
GBinderServiceManagerListFunc func;
char** result;
void* user_data;
} GBinderServiceManagerListTxData;
static
void
gbinder_servicemanager_list_tx_exec(
const GBinderIpcTx* tx)
{
GBinderServiceManagerListTxData* data = tx->user_data;
data->result = GBINDER_SERVICEMANAGER_GET_CLASS(data->sm)->list(data->sm);
}
static
void
gbinder_servicemanager_list_tx_done(
const GBinderIpcTx* tx)
{
GBinderServiceManagerListTxData* data = tx->user_data;
if (!data->func(data->sm, data->result, data->user_data)) {
g_strfreev(data->result);
}
}
static
void
gbinder_servicemanager_list_tx_free(
gpointer user_data)
{
GBinderServiceManagerListTxData* data = user_data;
gbinder_servicemanager_unref(data->sm);
g_slice_free(GBinderServiceManagerListTxData, data);
}
typedef struct gbinder_servicemanager_get_service_tx {
GBinderServiceManager* sm;
GBinderServiceManagerGetServiceFunc func;
GBinderRemoteObject* obj;
int status;
char* name;
void* user_data;
} GBinderServiceManagerGetServiceTxData;
static
void
gbinder_servicemanager_get_service_tx_exec(
const GBinderIpcTx* tx)
{
GBinderServiceManagerGetServiceTxData* data = tx->user_data;
data->obj = GBINDER_SERVICEMANAGER_GET_CLASS(data->sm)->get_service
(data->sm, data->name, &data->status);
}
static
void
gbinder_servicemanager_get_service_tx_done(
const GBinderIpcTx* tx)
{
GBinderServiceManagerGetServiceTxData* data = tx->user_data;
data->func(data->sm, data->obj, data->status, data->user_data);
}
static
void
gbinder_servicemanager_get_service_tx_free(
gpointer user_data)
{
GBinderServiceManagerGetServiceTxData* data = user_data;
gbinder_servicemanager_unref(data->sm);
gbinder_remote_object_unref(data->obj);
g_free(data->name);
g_slice_free(GBinderServiceManagerGetServiceTxData, data);
}
typedef struct gbinder_servicemanager_add_service_tx {
GBinderServiceManager* sm;
GBinderServiceManagerAddServiceFunc func;
GBinderLocalObject* obj;
int status;
char* name;
void* user_data;
} GBinderServiceManagerAddServiceTxData;
static
void
gbinder_servicemanager_add_service_tx_exec(
const GBinderIpcTx* tx)
{
GBinderServiceManagerAddServiceTxData* data = tx->user_data;
data->status = GBINDER_SERVICEMANAGER_GET_CLASS(data->sm)->add_service
(data->sm, data->name, data->obj);
}
static
void
gbinder_servicemanager_add_service_tx_done(
const GBinderIpcTx* tx)
{
GBinderServiceManagerAddServiceTxData* data = tx->user_data;
data->func(data->sm, data->status, data->user_data);
}
static
void
gbinder_servicemanager_add_service_tx_free(
gpointer user_data)
{
GBinderServiceManagerAddServiceTxData* data = user_data;
gbinder_servicemanager_unref(data->sm);
gbinder_local_object_unref(data->obj);
g_free(data->name);
g_slice_free(GBinderServiceManagerAddServiceTxData, data);
}
/*==========================================================================*
* Interface
*==========================================================================*/
GBinderServiceManager*
gbinder_servicemanager_new(
const char* dev)
{
if (!g_strcmp0(dev, GBINDER_DEFAULT_HWBINDER)) {
return gbinder_hwservicemanager_new(dev);
} else {
return gbinder_defaultservicemanager_new(dev);
}
}
GBinderLocalObject*
gbinder_servicemanager_new_local_object(
GBinderServiceManager* self,
const char* iface,
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 NULL;
}
GBinderServiceManager*
gbinder_servicemanager_ref(
GBinderServiceManager* self)
{
if (G_LIKELY(self)) {
g_object_ref(GBINDER_SERVICEMANAGER(self));
}
return self;
}
void
gbinder_servicemanager_unref(
GBinderServiceManager* self)
{
if (G_LIKELY(self)) {
g_object_unref(GBINDER_SERVICEMANAGER(self));
}
}
gulong
gbinder_servicemanager_list(
GBinderServiceManager* self,
GBinderServiceManagerListFunc func,
void* user_data)
{
if (G_LIKELY(self) && func) {
GBinderServiceManagerListTxData* data =
g_slice_new0(GBinderServiceManagerListTxData);
data->sm = gbinder_servicemanager_ref(self);
data->func = func;
data->user_data = user_data;
return gbinder_ipc_transact_custom(gbinder_client_ipc(self->client),
gbinder_servicemanager_list_tx_exec,
gbinder_servicemanager_list_tx_done,
gbinder_servicemanager_list_tx_free, data);
}
return 0;
}
char**
gbinder_servicemanager_list_sync(
GBinderServiceManager* self)
{
if (G_LIKELY(self)) {
return GBINDER_SERVICEMANAGER_GET_CLASS(self)->list(self);
}
return NULL;
}
gulong
gbinder_servicemanager_get_service(
GBinderServiceManager* self,
const char* name,
GBinderServiceManagerGetServiceFunc func,
void* user_data)
{
if (G_LIKELY(self) && func && name) {
GBinderServiceManagerGetServiceTxData* data =
g_slice_new0(GBinderServiceManagerGetServiceTxData);
data->sm = gbinder_servicemanager_ref(self);
data->func = func;
data->name = g_strdup(name);
data->user_data = user_data;
data->status = (-EFAULT);
return gbinder_ipc_transact_custom(gbinder_client_ipc(self->client),
gbinder_servicemanager_get_service_tx_exec,
gbinder_servicemanager_get_service_tx_done,
gbinder_servicemanager_get_service_tx_free, data);
}
return 0;
}
GBinderRemoteObject* /* autoreleased */
gbinder_servicemanager_get_service_sync(
GBinderServiceManager* self,
const char* name,
int* status)
{
GBinderRemoteObject* obj = NULL;
if (G_LIKELY(self) && name) {
obj = GBINDER_SERVICEMANAGER_GET_CLASS(self)->get_service
(self, name, status);
if (!self->pool) {
self->pool = gutil_idle_pool_new();
}
gutil_idle_pool_add_object(self->pool, obj);
} else if (status) {
*status = (-EINVAL);
}
return obj;
}
gulong
gbinder_servicemanager_add_service(
GBinderServiceManager* self,
const char* name,
GBinderLocalObject* obj,
GBinderServiceManagerAddServiceFunc func,
void* user_data)
{
if (G_LIKELY(self) && func && name) {
GBinderServiceManagerAddServiceTxData* data =
g_slice_new0(GBinderServiceManagerAddServiceTxData);
data->sm = gbinder_servicemanager_ref(self);
data->obj = gbinder_local_object_ref(obj);
data->func = func;
data->name = g_strdup(name);
data->user_data = user_data;
data->status = (-EFAULT);
return gbinder_ipc_transact_custom(gbinder_client_ipc(self->client),
gbinder_servicemanager_add_service_tx_exec,
gbinder_servicemanager_add_service_tx_done,
gbinder_servicemanager_add_service_tx_free, data);
}
return 0;
}
int
gbinder_servicemanager_add_service_sync(
GBinderServiceManager* self,
const char* name,
GBinderLocalObject* obj)
{
if (G_LIKELY(self) && name && obj) {
return GBINDER_SERVICEMANAGER_GET_CLASS(self)->add_service
(self, name, obj);
} else {
return (-EINVAL);
}
}
void
gbinder_servicemanager_cancel(
GBinderServiceManager* self,
gulong id)
{
if (G_LIKELY(self)) {
gbinder_ipc_cancel(gbinder_client_ipc(self->client), id);
}
}
/*==========================================================================*
* Internals
*==========================================================================*/
static
void
gbinder_servicemanager_init(
GBinderServiceManager* self)
{
}
static
void
gbinder_servicemanager_dispose(
GObject* object)
{
GBinderServiceManager* self = GBINDER_SERVICEMANAGER(object);
GBinderServiceManagerClass* klass =
GBINDER_SERVICEMANAGER_GET_CLASS(self);
GVERBOSE_("%s", self->dev);
/* Lock */
g_mutex_lock(&klass->mutex);
/*
* The follow can happen:
*
* 1. Last reference goes away.
* 2. gbinder_servicemanager_dispose() is invoked by glib
* 3. Before gbinder_servicemanager_dispose() grabs the
* lock, gbinder_servicemanager_new() gets there first,
* finds the object in the hashtable, bumps its refcount
* (under the lock) and returns the reference to the caller.
* 4. gbinder_servicemanager_dispose() gets its lock, finds
* that the object's refcount is greater than zero and leaves
* the object in the table.
*
* It's OK for a GObject to get re-referenced in dispose.
* glib will recheck the refcount once dispose returns,
* gbinder_servicemanager_finalize() will not be called
* this time around.
*/
if (klass->table && object->ref_count == 0) {
g_hash_table_remove(klass->table, self->dev);
if (g_hash_table_size(klass->table) == 0) {
g_hash_table_unref(klass->table);
klass->table = NULL;
}
}
g_mutex_unlock(&klass->mutex);
/* Unlock */
G_OBJECT_CLASS(PARENT_CLASS)->dispose(object);
}
static
void
gbinder_servicemanager_finalize(
GObject* object)
{
GBinderServiceManager* self = GBINDER_SERVICEMANAGER(object);
gutil_idle_pool_drain(self->pool);
gutil_idle_pool_unref(self->pool);
gbinder_client_unref(self->client);
G_OBJECT_CLASS(PARENT_CLASS)->finalize(object);
}
static
void
gbinder_servicemanager_class_init(
GBinderServiceManagerClass* klass)
{
GObjectClass* object_class = G_OBJECT_CLASS(klass);
g_mutex_init(&klass->mutex);
object_class->dispose = gbinder_servicemanager_dispose;
object_class->finalize = gbinder_servicemanager_finalize;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,83 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_SERVICEMANAGER_PRIVATE_H
#define GBINDER_SERVICEMANAGER_PRIVATE_H
#include "gbinder_types_p.h"
#include <gbinder_servicemanager.h>
#include <glib-object.h>
typedef struct gbinder_servicemanager {
GObject parent;
const char* dev;
GBinderClient* client;
GUtilIdlePool* pool;
} GBinderServiceManager;
typedef struct gbinder_servicemanager_class {
GObjectClass parent;
GMutex mutex;
GHashTable* table;
guint32 handle;
const char* iface;
const char* default_device;
/* Methods (synchronous) */
char** (*list)(GBinderServiceManager* self);
GBinderRemoteObject* (*get_service)
(GBinderServiceManager* self, const char* name, int* status);
int (*add_service)
(GBinderServiceManager* self, const char* name,
GBinderLocalObject* obj);
} GBinderServiceManagerClass;
GType gbinder_servicemanager_get_type(void);
#define GBINDER_TYPE_SERVICEMANAGER (gbinder_servicemanager_get_type())
GBinderServiceManager*
gbinder_servicemanager_new_with_type(
GType type,
const char* dev);
#endif /* GBINDER_SERVICEMANAGER_PRIVATE_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

88
src/gbinder_system.c Normal file
View File

@@ -0,0 +1,88 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Contact: 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 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.
*
* 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_system.h"
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
int
gbinder_system_open(
const char* path,
int flags)
{
return open(path, flags);
}
int
gbinder_system_close(
int fd)
{
return close(fd);
}
int
gbinder_system_ioctl(
int fd,
int request,
void* data)
{
return ioctl(fd, request, data);
}
void*
gbinder_system_mmap(
size_t length,
int prot,
int flags,
int fd)
{
return mmap(NULL, length, prot, flags, fd, 0);
}
int
gbinder_system_munmap(
void* addr,
size_t length)
{
return munmap(addr, length);
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

73
src/gbinder_system.h Normal file
View File

@@ -0,0 +1,73 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Contact: 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 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_SYSTEM_H
#define GBINDER_SYSTEM_H
#include "gbinder_types_p.h"
int
gbinder_system_open(
const char* path,
int flags);
int
gbinder_system_close(
int fd);
int
gbinder_system_ioctl(
int fd,
int request,
void* data);
void*
gbinder_system_mmap(
size_t length,
int prot,
int flags,
int fd);
int
gbinder_system_munmap(
void* addr,
size_t length);
#endif /* GBINDER_SYSTEM_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

99
src/gbinder_types_p.h Normal file
View File

@@ -0,0 +1,99 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_TYPES_PRIVATE_H
#define GBINDER_TYPES_PRIVATE_H
#include <gbinder_types.h>
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;
typedef struct hidl_vec {
union {
guint64 value;
const void* ptr;
} data;
guint32 count;
guint32 owns_buffer;
} HidlVec;
#define HIDL_VEC_BUFFER_OFFSET (0)
typedef struct hidl_string {
union {
guint64 value;
const char* str;
} data;
guint32 len;
guint32 owns_buffer;
} HidlString;
#define HIDL_STRING_BUFFER_OFFSET (0)
#define GBINDER_INLINE_FUNC static inline
#define GBINDER_TRANSACTION(c2,c3,c4) GBINDER_FOURCC('_',c2,c3,c4)
#define GBINDER_PING_TRANSACTION GBINDER_TRANSACTION('P','N','G')
#define GBINDER_DUMP_TRANSACTION GBINDER_TRANSACTION('D','M','P')
#define GBINDER_SHELL_COMMAND_TRANSACTION GBINDER_TRANSACTION('C','M','D')
#define GBINDER_INTERFACE_TRANSACTION GBINDER_TRANSACTION('N','T','F')
#define GBINDER_SYSPROPS_TRANSACTION GBINDER_TRANSACTION('S','P','R')
/* platform/system/tools/hidl/Interface.cpp */
#define HIDL_FOURCC(c2,c3,c4) GBINDER_FOURCC(0x0f,c2,c3,c4)
#define HIDL_PING_TRANSACTION HIDL_FOURCC('P','N','G')
#define HIDL_DESCRIPTOR_CHAIN_TRANSACTION HIDL_FOURCC('C','H','N')
#define HIDL_GET_DESCRIPTOR_TRANSACTION HIDL_FOURCC('D','S','C')
#define HIDL_SYSPROPS_CHANGED_TRANSACTION HIDL_FOURCC('S','Y','S')
#define HIDL_LINK_TO_DEATH_TRANSACTION HIDL_FOURCC('L','T','D')
#define HIDL_UNLINK_TO_DEATH_TRANSACTION HIDL_FOURCC('U','T','D')
#define HIDL_SET_HAL_INSTRUMENTATION_TRANSACTION HIDL_FOURCC('I','N','T')
#define HIDL_GET_REF_INFO_TRANSACTION HIDL_FOURCC('R','E','F')
#define HIDL_DEBUG_TRANSACTION HIDL_FOURCC('D','B','G')
#define HIDL_HASH_CHAIN_TRANSACTION HIDL_FOURCC('H','S','H')
#endif /* GBINDER_TYPES_PRIVATE_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

569
src/gbinder_writer.c Normal file
View File

@@ -0,0 +1,569 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Contact: 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 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.
*
* 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_writer_p.h"
#include "gbinder_io.h"
#include "gbinder_log.h"
#include <gutil_intarray.h>
#include <gutil_macros.h>
#include <gutil_strv.h>
#include <stdint.h>
typedef struct gbinder_writer_priv {
GBinderWriterData* data;
} GBinderWriterPriv;
G_STATIC_ASSERT(sizeof(GBinderWriter) >= sizeof(GBinderWriterPriv));
GBINDER_INLINE_FUNC GBinderWriterPriv* gbinder_writer_cast(GBinderWriter* pub)
{ return (GBinderWriterPriv*)pub; }
GBINDER_INLINE_FUNC GBinderWriterData* gbinder_writer_data(GBinderWriter* pub)
{ return G_LIKELY(pub) ? gbinder_writer_cast(pub)->data : NULL; }
static
void
gbinder_writer_data_record_offset(
GBinderWriterData* data,
guint offset)
{
if (!data->offsets) {
data->offsets = gutil_int_array_new();
}
gutil_int_array_append(data->offsets, offset);
}
static
void
gbinder_writer_data_write_buffer_object(
GBinderWriterData* data,
const void* ptr,
gsize size,
const GBinderParent* parent)
{
GByteArray* dest = data->bytes;
const guint offset = dest->len;
guint n;
/* Preallocate enough space */
g_byte_array_set_size(dest, offset + GBINDER_MAX_BUFFER_OBJECT_SIZE);
/* Write the object */
n = data->io->encode_buffer_object(dest->data + offset, ptr, size, parent);
/* Fix the data size */
g_byte_array_set_size(dest, offset + n);
/* Record the offset */
gbinder_writer_data_record_offset(data, offset);
/* The driver seems to require each buffer to be 8-byte aligned */
data->buffers_size += G_ALIGN8(size);
}
void
gbinder_writer_init(
GBinderWriter* self,
GBinderWriterData* data)
{
memset(self, 0, sizeof(*self));
gbinder_writer_cast(self)->data = data;
}
void
gbinder_writer_append_int32(
GBinderWriter* self,
guint32 value)
{
GBinderWriterData* data = gbinder_writer_data(self);
if (G_LIKELY(data)) {
gbinder_writer_data_append_int32(data, value);
}
}
void
gbinder_writer_data_append_int32(
GBinderWriterData* data,
guint32 value)
{
guint32* ptr;
g_byte_array_set_size(data->bytes, data->bytes->len + sizeof(*ptr));
ptr = (void*)(data->bytes->data + (data->bytes->len - sizeof(*ptr)));
*ptr = value;
}
void
gbinder_writer_append_int64(
GBinderWriter* self,
guint64 value)
{
GBinderWriterData* data = gbinder_writer_data(self);
if (G_LIKELY(data)) {
gbinder_writer_data_append_int64(data, value);
}
}
void
gbinder_writer_data_append_int64(
GBinderWriterData* data,
guint64 value)
{
guint64* ptr;
g_byte_array_set_size(data->bytes, data->bytes->len + sizeof(*ptr));
ptr = (void*)(data->bytes->data + (data->bytes->len - sizeof(*ptr)));
*ptr = value;
}
void
gbinder_writer_append_string8(
GBinderWriter* self,
const char* str)
{
gbinder_writer_append_string8_len(self, str, str ? strlen(str) : 0);
}
void
gbinder_writer_append_string8_len(
GBinderWriter* self,
const char* str,
gsize len)
{
GBinderWriterData* data = gbinder_writer_data(self);
if (G_LIKELY(data)) {
gbinder_writer_data_append_string8_len(data, str, len);
}
}
void
gbinder_writer_data_append_string8(
GBinderWriterData* data,
const char* str)
{
gbinder_writer_data_append_string8_len(data, str, str ? strlen(str) : 0);
}
void
gbinder_writer_data_append_string8_len(
GBinderWriterData* data,
const char* str,
gsize len)
{
if (G_LIKELY(str)) {
const gsize old_size = data->bytes->len;
gsize padded_len = G_ALIGN4(len + 1);
guint32* dest;
/* Preallocate space */
g_byte_array_set_size(data->bytes, old_size + padded_len);
/* Zero the last word */
dest = (guint32*)(data->bytes->data + old_size);
dest[padded_len/4 - 1] = 0;
/* Copy the data */
memcpy(dest, str, len);
}
}
void
gbinder_writer_append_string16(
GBinderWriter* self,
const char* utf8)
{
gbinder_writer_append_string16_len(self, utf8, utf8 ? strlen(utf8) : 0);
}
void
gbinder_writer_append_string16_len(
GBinderWriter* self,
const char* utf8,
gssize num_bytes)
{
GBinderWriterData* data = gbinder_writer_data(self);
if (G_LIKELY(data)) {
gbinder_writer_data_append_string16_len(data, utf8, num_bytes);
}
}
void
gbinder_writer_data_append_string16(
GBinderWriterData* data,
const char* utf8)
{
gbinder_writer_data_append_string16_len(data, utf8, utf8? strlen(utf8) : 0);
}
void
gbinder_writer_data_append_string16_len(
GBinderWriterData* data,
const char* utf8,
gssize num_bytes)
{
const gsize old_size = data->bytes->len;
if (utf8) {
const char* end = utf8;
g_utf8_validate(utf8, num_bytes, &end);
num_bytes = end - utf8;
} else {
num_bytes = 0;
}
if (num_bytes > 0) {
glong len = g_utf8_strlen(utf8, num_bytes);
gsize padded_len = G_ALIGN4((len+1)*2);
guint32* len_ptr;
gunichar2* utf16_ptr;
/* Preallocate space */
g_byte_array_set_size(data->bytes, old_size + padded_len + 4);
len_ptr = (guint32*)(data->bytes->data + old_size);
utf16_ptr = (gunichar2*)(len_ptr + 1);
/* TODO: this could be optimized for ASCII strings, i.e. if
* len equals num_bytes */
if (len > 0) {
glong utf16_len = 0;
gunichar2* utf16 = g_utf8_to_utf16(utf8, num_bytes, NULL,
&utf16_len, NULL);
if (utf16) {
len = utf16_len;
padded_len = G_ALIGN4((len+1)*2);
memcpy(utf16_ptr, utf16, (len+1)*2);
g_free(utf16);
}
}
/* Actual length */
*len_ptr = len;
/* Zero padding */
if (padded_len - (len + 1)*2) {
memset(utf16_ptr + (len + 1), 0, padded_len - (len + 1)*2);
}
/* Correct the packet size if necessaary */
g_byte_array_set_size(data->bytes, old_size + padded_len + 4);
} else if (utf8) {
/* Empty string */
guint16* ptr16;
g_byte_array_set_size(data->bytes, old_size + 8);
ptr16 = (guint16*)(data->bytes->data + old_size);
ptr16[0] = ptr16[1] = ptr16[2] = 0; ptr16[3] = 0xffff;
} else {
/* NULL string */
gbinder_writer_data_append_int32(data, -1);
}
}
void
gbinder_writer_append_bool(
GBinderWriter* self,
gboolean value)
{
guint8 padded[4];
/* Boolean values are padded to 4-byte boundary */
padded[0] = (value != FALSE);
padded[1] = padded[2] = padded[3] = 0xff;
gbinder_writer_append_bytes(self, padded, sizeof(padded));
}
void
gbinder_writer_append_bytes(
GBinderWriter* self,
const void* ptr,
gsize size)
{
GBinderWriterData* data = gbinder_writer_data(self);
if (G_LIKELY(data)) {
g_byte_array_append(data->bytes, ptr, size);
}
}
static
guint
gbinder_writer_data_prepare(
GBinderWriterData* data)
{
if (!data->offsets) {
data->offsets = gutil_int_array_new();
}
return data->offsets->count;
}
guint
gbinder_writer_append_buffer_object_with_parent(
GBinderWriter* self,
const void* buf,
gsize len,
const GBinderParent* parent)
{
GBinderWriterData* data = gbinder_writer_data(self);
if (G_LIKELY(data)) {
return gbinder_writer_data_append_buffer_object(data, buf, len, parent);
}
return 0;
}
guint
gbinder_writer_append_buffer_object(
GBinderWriter* self,
const void* buf,
gsize len)
{
GBinderWriterData* data = gbinder_writer_data(self);
if (G_LIKELY(data)) {
return gbinder_writer_data_append_buffer_object(data, buf, len, NULL);
}
return 0;
}
guint
gbinder_writer_data_append_buffer_object(
GBinderWriterData* data,
const void* ptr,
gsize size,
const GBinderParent* parent)
{
guint index = gbinder_writer_data_prepare(data);
gbinder_writer_data_write_buffer_object(data, ptr, size, parent);
return index;
}
void
gbinder_writer_append_hidl_string(
GBinderWriter* self,
const char* str)
{
GBinderWriterData* data = gbinder_writer_data(self);
if (G_LIKELY(data)) {
gbinder_writer_data_append_hidl_string(data, str);
}
}
void
gbinder_writer_data_append_hidl_string(
GBinderWriterData* data,
const char* str)
{
GBinderParent str_parent;
HidlString* hidl_string = g_new0(HidlString, 1);
const gsize len = str ? strlen(str) : 0;
/* Prepare parent descriptor for the string data */
str_parent.index = gbinder_writer_data_prepare(data);
str_parent.offset = HIDL_STRING_BUFFER_OFFSET;
/* Fill in the string descriptor and store it */
hidl_string->data.str = str;
hidl_string->len = len;
hidl_string->owns_buffer = TRUE;
data->cleanup = gbinder_cleanup_add(data->cleanup, g_free, hidl_string);
/* Write the buffer object pointing to the string descriptor */
gbinder_writer_data_write_buffer_object(data, hidl_string,
sizeof(*hidl_string), NULL);
/* Not sure what's the right way to deal with NULL strings... */
if (str) {
/* Write the buffer pointing to the string data including the
* NULL terminator, referencing string descriptor as a parent. */
gbinder_writer_data_write_buffer_object(data, str, len+1, &str_parent);
GVERBOSE_("\"%s\" %u %u %u", str, (guint)len, (guint)str_parent.index,
(guint)data->buffers_size);
}
}
void
gbinder_writer_append_hidl_string_vec(
GBinderWriter* self,
const char* strv[],
gssize count)
{
GBinderWriterData* data = gbinder_writer_data(self);
if (G_LIKELY(data)) {
gbinder_writer_data_append_hidl_string_vec(data, strv, count);
}
}
void
gbinder_writer_data_append_hidl_string_vec(
GBinderWriterData* data,
const char* strv[],
gssize count)
{
GBinderParent vec_parent;
HidlVec* vec = g_new0(HidlVec, 1);
HidlString* strings = NULL;
int i;
if (count < 0) {
/* Assume NULL terminated array */
count = gutil_strv_length((char**)strv);
}
/* Prepare parent descriptor for the vector data */
vec_parent.index = gbinder_writer_data_prepare(data);
vec_parent.offset = HIDL_VEC_BUFFER_OFFSET;
/* Fill in the vector descriptor */
if (count > 0) {
strings = g_new0(HidlString, count);
vec->data.ptr = strings;
data->cleanup = gbinder_cleanup_add(data->cleanup, g_free, strings);
}
vec->count = count;
vec->owns_buffer = TRUE;
data->cleanup = gbinder_cleanup_add(data->cleanup, g_free, vec);
/* Fill in string descriptors */
for (i = 0; i < count; i++) {
const char* str = strv[i];
HidlString* hidl_str = strings + i;
if ((hidl_str->data.str = str) != NULL) {
hidl_str->len = strlen(str);
hidl_str->owns_buffer = TRUE;
}
}
/* Write the vector object */
gbinder_writer_data_write_buffer_object(data, vec, sizeof(*vec), NULL);
if (strings) {
GBinderParent str_parent;
/* Prepare parent descriptor for the string data */
str_parent.index = data->offsets->count;
str_parent.offset = HIDL_STRING_BUFFER_OFFSET;
/* Write the vector data (it's parent for the string data) */
gbinder_writer_data_write_buffer_object(data, strings,
sizeof(*strings) * count, &vec_parent);
/* Write the string data */
for (i = 0; i < count; i++) {
HidlString* hidl_str = strings + i;
if (hidl_str->data.str) {
gbinder_writer_data_write_buffer_object(data,
hidl_str->data.str, hidl_str->len + 1, &str_parent);
GVERBOSE_("%d. \"%s\" %u %u %u", i + 1, hidl_str->data.str,
(guint)hidl_str->len, (guint)str_parent.index,
(guint)data->buffers_size);
}
str_parent.offset += sizeof(HidlString);
}
}
}
void
gbinder_writer_append_local_object(
GBinderWriter* self,
GBinderLocalObject* obj)
{
GBinderWriterData* data = gbinder_writer_data(self);
if (G_LIKELY(data)) {
gbinder_writer_data_append_local_object(data, obj);
}
}
void
gbinder_writer_data_append_local_object(
GBinderWriterData* data,
GBinderLocalObject* obj)
{
GByteArray* dest = data->bytes;
const guint offset = dest->len;
guint n;
/* Preallocate enough space */
g_byte_array_set_size(dest, offset + GBINDER_MAX_BINDER_OBJECT_SIZE);
/* Write the object */
n = data->io->encode_local_object(dest->data + offset, obj);
/* Fix the data size */
g_byte_array_set_size(dest, offset + n);
/* Record the offset */
gbinder_writer_data_record_offset(data, offset);
}
void
gbinder_writer_append_remote_object(
GBinderWriter* self,
GBinderRemoteObject* obj)
{
GBinderWriterData* data = gbinder_writer_data(self);
if (G_LIKELY(data)) {
gbinder_writer_data_append_remote_object(data, obj);
}
}
void
gbinder_writer_data_append_remote_object(
GBinderWriterData* data,
GBinderRemoteObject* obj)
{
GByteArray* dest = data->bytes;
const guint offset = dest->len;
guint n;
/* Preallocate enough space */
g_byte_array_set_size(dest, offset + GBINDER_MAX_BINDER_OBJECT_SIZE);
/* Write the object */
n = data->io->encode_remote_object(dest->data + offset, obj);
/* Fix the data size */
g_byte_array_set_size(dest, offset + n);
/* Record the offset */
gbinder_writer_data_record_offset(data, offset);
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

121
src/gbinder_writer_p.h Normal file
View File

@@ -0,0 +1,121 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Copyright (C) 2018 Slava Monich <slava.monich@jolla.com>
*
* You may use this file under the terms of BSD license as follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef GBINDER_WRITER_PRIVATE_H
#define GBINDER_WRITER_PRIVATE_H
#include <gbinder_writer.h>
#include "gbinder_cleanup.h"
typedef struct gbinder_writer_data {
const GBinderIo* io;
GByteArray* bytes;
GUtilIntArray* offsets;
gsize buffers_size;
GBinderCleanup* cleanup;
} GBinderWriterData;
void
gbinder_writer_init(
GBinderWriter* writer,
GBinderWriterData* data);
void
gbinder_writer_data_append_int32(
GBinderWriterData* data,
guint32 value);
void
gbinder_writer_data_append_int64(
GBinderWriterData* data,
guint64 value);
void
gbinder_writer_data_append_string8(
GBinderWriterData* data,
const char* str);
void
gbinder_writer_data_append_string8_len(
GBinderWriterData* data,
const char* str,
gsize len);
void
gbinder_writer_data_append_string16(
GBinderWriterData* data,
const char* utf8);
void
gbinder_writer_data_append_string16_len(
GBinderWriterData* data,
const char* utf8,
gssize num_bytes);
guint
gbinder_writer_data_append_buffer_object(
GBinderWriterData* data,
const void* ptr,
gsize size,
const GBinderParent* parent);
void
gbinder_writer_data_append_hidl_string(
GBinderWriterData* data,
const char* str);
void
gbinder_writer_data_append_hidl_string_vec(
GBinderWriterData* data,
const char* strv[],
gssize count);
void
gbinder_writer_data_append_local_object(
GBinderWriterData* data,
GBinderLocalObject* obj);
void
gbinder_writer_data_append_remote_object(
GBinderWriterData* data,
GBinderRemoteObject* obj);
#endif /* GBINDER_WRITER_PRIVATE_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

8
test/Makefile Normal file
View File

@@ -0,0 +1,8 @@
# -*- Mode: makefile-gmake -*-
all:
%:
@$(MAKE) -C binder-client $*
@$(MAKE) -C binder-list $*
@$(MAKE) -C binder-service $*
@$(MAKE) -C rild-card-status $*

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

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

View File

@@ -0,0 +1,331 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Contact: 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 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.
*
* 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>
#include <glib-unix.h>
#define RET_OK (0)
#define RET_NOTFOUND (1)
#define RET_INVARG (2)
#define RET_ERR (3)
#define DEFAULT_DEVICE "/dev/binder"
#define DEFAULT_NAME "test"
#define DEFAULT_IFACE "test@1.0"
typedef struct app_options {
char* dev;
char* iface;
char* fqname;
const char* name;
} AppOptions;
typedef struct app {
const AppOptions* opt;
GMainLoop* loop;
GBinderServiceManager* sm;
GBinderLocalObject* local;
GBinderClient* client;
int ret;
} App;
typedef struct app_input {
App* app;
char* str;
} AppInput;
static const char pname[] = "binder-client";
static
gboolean
app_signal(
gpointer user_data)
{
App* app = user_data;
GINFO("Caught signal, shutting down...");
g_main_loop_quit(app->loop);
return G_SOURCE_CONTINUE;
}
static
void
app_remote_died(
GBinderRemoteObject* obj,
void* user_data)
{
App* app = user_data;
GINFO("Remote has died, exiting...");
g_main_loop_quit(app->loop);
}
static
void
app_call(
App* app,
char* str)
{
GBinderLocalRequest* req = gbinder_client_new_request(app->client);
GBinderRemoteReply* reply;
int status;
gbinder_local_request_append_string16(req, str);
reply = gbinder_client_transact_sync_reply(app->client,
GBINDER_FIRST_CALL_TRANSACTION, req, &status);
gbinder_local_request_unref(req);
if (status == GBINDER_STATUS_OK) {
GBinderReader reader;
char* ret;
gbinder_remote_reply_init_reader(reply, &reader);
ret = gbinder_reader_read_string16(&reader);
GDEBUG_("Reply: \"%s\"", ret);
g_free(ret);
} else {
GERR_("status %d", status);
}
gbinder_remote_reply_unref(reply);
}
static
gboolean
app_input(
void* user_data)
{
AppInput* input = user_data;
GDEBUG_("\"%s\"", input->str);
app_call(input->app, input->str);
g_free(input->str);
g_free(input);
return G_SOURCE_REMOVE;
}
static
gpointer
app_input_thread(
gpointer data)
{
int c;
App* app = data;
GString* buf = g_string_new("");
while ((c = getc(stdin)) != EOF) {
if (c == '\n' || c == '\r') {
AppInput* input = g_new0(AppInput, 1);
input->app = app;
input->str = g_strdup(buf->str);
g_idle_add(app_input, input);
g_string_truncate(buf, 0);
while (c == '\n' || c == '\r') c = getc(stdin);
if (c == EOF) {
break;
} else {
ungetc(c, stdin);
continue;
}
} else {
g_string_append_c(buf, (char)c);
}
}
GDEBUG_("Input thread exiting...");
g_string_free(buf, TRUE);
return NULL;
}
static
void
app_run(
App* app)
{
const AppOptions* opt = app->opt;
char* fqname = opt->fqname ? g_strdup(opt->fqname) :
strchr(opt->name, '/') ? g_strdup(opt->name) :
g_strconcat(opt->iface, "/", opt->name, NULL);
int status = 0;
GBinderRemoteObject* remote = gbinder_remote_object_ref
(gbinder_servicemanager_get_service_sync(app->sm, fqname, &status));
if (remote) {
guint sigtrm = g_unix_signal_add(SIGTERM, app_signal, app);
guint sigint = g_unix_signal_add(SIGINT, app_signal, app);
gulong death_id = gbinder_remote_object_add_death_handler
(remote, app_remote_died, app);
GThread* thread = g_thread_new("input", app_input_thread, app);
GINFO("Connected to %s\n", fqname);
app->client = gbinder_client_new(remote, opt->iface);
app->ret = RET_OK;
app->loop = g_main_loop_new(NULL, TRUE);
g_main_loop_run(app->loop);
g_source_remove(sigtrm);
g_source_remove(sigint);
g_main_loop_unref(app->loop);
gbinder_remote_object_remove_handler(remote, death_id);
gbinder_remote_object_unref(remote);
/* Not the cleanest exit, just dropping the thread... */
g_thread_unref(thread);
app->loop = NULL;
} else {
GERR("No such service: %s (%d)", fqname, status);
}
g_free(fqname);
}
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_ERR;
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_DEVICE "]", "DEVICE" },
{ "interface", 'i', 0, G_OPTION_ARG_STRING, &opt->iface,
"Interface name [" DEFAULT_IFACE "]", "IFACE" },
{ "fqname", 'n', 0, G_OPTION_ARG_STRING, &opt->fqname,
"Fully qualified name [IFACE/NAME]", "FQNAME" },
{ NULL }
};
GError* error = NULL;
GOptionContext* options = g_option_context_new("[NAME]");
memset(opt, 0, sizeof(*opt));
gutil_log_timestamp = FALSE;
gutil_log_set_type(GLOG_TYPE_STDERR, pname);
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)) {
char* help;
if (!opt->dev || !opt->dev[0]) opt->dev = g_strdup(DEFAULT_DEVICE);
if (!opt->iface || !opt->iface[0]) opt->iface = g_strdup(DEFAULT_IFACE);
switch (argc) {
case 2:
opt->name = argv[1];
ok = TRUE;
break;
case 1:
opt->name = DEFAULT_NAME;
ok = TRUE;
break;
default:
help = g_option_context_get_help(options, TRUE, NULL);
fprintf(stderr, "%s", help);
g_free(help);
break;
}
} else {
GERR("%s", error->message);
g_error_free(error);
}
g_option_context_free(options);
return ok;
}
int main(int argc, char* argv[])
{
App app;
AppOptions opt;
memset(&app, 0, sizeof(app));
app.ret = RET_INVARG;
app.opt = &opt;
if (app_init(&opt, argc, argv)) {
app.sm = gbinder_servicemanager_new(opt.dev);
if (app.sm) {
app.local = gbinder_servicemanager_new_local_object(app.sm,
NULL, NULL, NULL);
app_run(&app);
gbinder_local_object_unref(app.local);
gbinder_client_unref(app.client);
gbinder_servicemanager_unref(app.sm);
}
}
g_free(opt.fqname);
g_free(opt.iface);
g_free(opt.dev);
return app.ret;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

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

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

View File

@@ -0,0 +1,267 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Contact: 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 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.
*
* 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 DEV_DEFAULT "/dev/binder"
typedef struct app_options {
char* dev;
const char* service;
gboolean async;
} AppOptions;
typedef struct app {
const AppOptions* opt;
GMainLoop* loop;
GBinderServiceManager* sm;
int ret;
} App;
static const char pname[] = "binder-list";
static
void
app_print_strings(
char** strv)
{
if (strv) {
while (*strv) {
printf("%s\n", *strv);
strv++;
}
}
}
static
gboolean
app_list_done(
GBinderServiceManager* sm,
char** services,
void* user_data)
{
App* app = user_data;
if (services) {
app_print_strings(services);
app->ret = RET_OK;
}
g_main_loop_quit(app->loop);
return FALSE;
}
static
void
app_get_service_done(
GBinderServiceManager* sm,
GBinderRemoteObject* obj,
int status,
void* user_data)
{
App* app = user_data;
if (obj) {
printf("%s\n", app->opt->service);
app->ret = RET_OK;
} else {
GERR("No such service: %s (%d)", app->opt->service, status);
}
g_main_loop_quit(app->loop);
}
static
void
app_async(
App* app)
{
const char* name = app->opt->service;
app->loop = g_main_loop_new(NULL, TRUE);
if (name) {
gbinder_servicemanager_get_service(app->sm, name,
app_get_service_done, app);
} else {
gbinder_servicemanager_list(app->sm, app_list_done, app);
}
g_main_loop_run(app->loop);
g_main_loop_unref(app->loop);
app->loop = NULL;
}
static
void
app_sync(
App* app)
{
const AppOptions* opt = app->opt;
if (opt->service) {
int status = 0;
GBinderRemoteObject* obj = gbinder_servicemanager_get_service_sync
(app->sm, opt->service, &status);
if (obj) {
printf("%s\n", opt->service);
app->ret = RET_OK;
} else {
GERR("No such service: %s (%d)", opt->service, status);
}
} else {
char** services = gbinder_servicemanager_list_sync(app->sm);
if (services) {
app_print_strings(services);
g_strfreev(services);
app->ret = RET_OK;
}
}
}
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_ERR;
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 },
{ "async", 'a', 0, G_OPTION_ARG_NONE, &opt->async,
"Parform operations asynchronously", NULL },
{ "device", 'd', 0, G_OPTION_ARG_STRING, &opt->dev,
"Binder device [" DEV_DEFAULT "]", "DEVICE" },
{ NULL }
};
GError* error = NULL;
GOptionContext* options = g_option_context_new("[SERVICE]");
memset(opt, 0, sizeof(*opt));
gutil_log_timestamp = FALSE;
gutil_log_set_type(GLOG_TYPE_STDERR, pname);
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)) {
char* help;
if (!opt->dev || !opt->dev[0]) opt->dev = g_strdup(DEV_DEFAULT);
switch (argc) {
case 2:
opt->service = argv[1];
/* no break */
case 1:
ok = TRUE;
break;
default:
help = g_option_context_get_help(options, TRUE, NULL);
fprintf(stderr, "%s", help);
g_free(help);
break;
}
} else {
GERR("%s", error->message);
g_error_free(error);
}
g_option_context_free(options);
return ok;
}
int main(int argc, char* argv[])
{
App app;
AppOptions opt;
memset(&app, 0, sizeof(app));
app.ret = RET_INVARG;
app.opt = &opt;
if (app_init(&opt, argc, argv)) {
app.sm = gbinder_servicemanager_new(opt.dev);
if (app.sm) {
if (opt.async) {
app_async(&app);
} else {
app_sync(&app);
}
gbinder_servicemanager_unref(app.sm);
}
}
g_free(opt.dev);
return app.ret;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

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

View File

@@ -0,0 +1,248 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Contact: 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 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.
*
* 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>
#include <glib-unix.h>
#define RET_OK (0)
#define RET_NOTFOUND (1)
#define RET_INVARG (2)
#define RET_ERR (3)
#define DEFAULT_DEVICE "/dev/binder"
#define DEFAULT_NAME "test"
#define DEFAULT_IFACE "test@1.0"
typedef struct app_options {
char* dev;
char* iface;
const char* name;
} AppOptions;
typedef struct app {
const AppOptions* opt;
GMainLoop* loop;
GBinderServiceManager* sm;
GBinderLocalObject* obj;
int ret;
} App;
static const char pname[] = "binder-service";
static
gboolean
app_signal(
gpointer user_data)
{
App* app = user_data;
GINFO("Caught signal, shutting down...");
g_main_loop_quit(app->loop);
return G_SOURCE_CONTINUE;
}
static
GBinderLocalReply*
app_reply(
GBinderLocalObject* obj,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status,
void* user_data)
{
char* str = gbinder_remote_request_read_string16(req);
GBinderLocalReply* reply = gbinder_local_object_new_reply(obj);
GVERBOSE("\"%s\" %u", gbinder_remote_request_interface(req), code);
GDEBUG("\"%s\"", str);
gbinder_local_reply_append_string16(reply, str);
g_free(str);
*status = 0;
return reply;
}
static
void
app_add_service_done(
GBinderServiceManager* sm,
int status,
void* user_data)
{
App* app = user_data;
if (status == GBINDER_STATUS_OK) {
printf("Added \"%s\"\n", app->opt->name);
app->ret = RET_OK;
} else {
GERR("Failed to add \"%s\" (%d)", app->opt->name, status);
g_main_loop_quit(app->loop);
}
}
static
void
app_run(
App* app)
{
const char* name = app->opt->name;
guint sigtrm = g_unix_signal_add(SIGTERM, app_signal, app);
guint sigint = g_unix_signal_add(SIGINT, app_signal, app);
app->loop = g_main_loop_new(NULL, TRUE);
gbinder_servicemanager_add_service(app->sm, name, app->obj,
app_add_service_done, app);
g_main_loop_run(app->loop);
if (sigtrm) g_source_remove(sigtrm);
if (sigint) g_source_remove(sigint);
g_main_loop_unref(app->loop);
app->loop = NULL;
}
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_ERR;
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_DEVICE "]", "DEVICE" },
{ "interface", 'i', 0, G_OPTION_ARG_STRING, &opt->iface,
"Local interface [" DEFAULT_IFACE "]", "IFACE" },
{ NULL }
};
GError* error = NULL;
GOptionContext* options = g_option_context_new("[NAME]");
memset(opt, 0, sizeof(*opt));
gutil_log_timestamp = FALSE;
gutil_log_set_type(GLOG_TYPE_STDERR, pname);
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)) {
char* help;
if (!opt->dev || !opt->dev[0]) opt->dev = g_strdup(DEFAULT_DEVICE);
if (!opt->iface) opt->iface = g_strdup(DEFAULT_IFACE);
switch (argc) {
case 2:
opt->name = argv[1];
ok = TRUE;
break;
case 1:
opt->name = DEFAULT_NAME;
ok = TRUE;
break;
default:
help = g_option_context_get_help(options, TRUE, NULL);
fprintf(stderr, "%s", help);
g_free(help);
break;
}
} else {
GERR("%s", error->message);
g_error_free(error);
}
g_option_context_free(options);
return ok;
}
int main(int argc, char* argv[])
{
App app;
AppOptions opt;
memset(&app, 0, sizeof(app));
app.ret = RET_INVARG;
app.opt = &opt;
if (app_init(&opt, argc, argv)) {
app.sm = gbinder_servicemanager_new(opt.dev);
if (app.sm) {
app.obj = gbinder_servicemanager_new_local_object
(app.sm, opt.iface, app_reply, &app);
app_run(&app);
gbinder_local_object_unref(app.obj);
gbinder_servicemanager_unref(app.sm);
}
}
g_free(opt.iface);
g_free(opt.dev);
return app.ret;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

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

View File

@@ -0,0 +1,440 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Contact: 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 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.
*
* 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_misc.h>
#include <gutil_log.h>
#include <glib-unix.h>
#define RET_OK (0)
#define RET_NOTFOUND (1)
#define RET_INVARG (2)
#define RET_ERR (3)
#define DEFAULT_DEVICE "/dev/hwbinder"
#define DEFAULT_NAME "slot1"
#define IFACE_RADIO "android.hardware.radio@1.0::IRadio"
#define IFACE_RESPONSE "android.hardware.radio@1.0::IRadioResponse"
#define IFACE_INDICATION "android.hardware.radio@1.0::IRadioIndication"
/* android.hardware.radio@1.0::IRadio */
#define REQ_RADIO_SET_RESPONSE_FUNCTIONS (1)
#define REQ_RADIO_GET_ICC_CARD_STATUS (2)
/* android.hardware.radio@1.0::IRadioResponse */
#define RESP_GET_ICC_CARD_STATUS_RESPONSE (1)
typedef struct app_options {
char* dev;
char* fqname;
const char* name;
} AppOptions;
typedef struct app {
const AppOptions* opt;
GMainLoop* loop;
GBinderServiceManager* sm;
GBinderLocalObject* response;
GBinderLocalObject* indication;
int ret;
} App;
typedef struct radio_response_info {
guint32 type;
guint32 serial;
guint32 error;
} RadioResponseInfo;
typedef struct radio_string {
union {
guint64 value;
const char* str;
} data;
guint32 len;
guint32 owns_buffer;
} RadioString;
typedef struct radio_app_status {
guint32 appType;
guint32 appState;
guint32 persoSubstate;
guint32 unused1;
RadioString aid;
RadioString label;
guint32 pinReplaced;
guint32 pin1;
guint32 pin2;
guint32 unused2;
} RadioAppStatus;
typedef struct radio_card_status {
guint32 cardState;
guint32 universalPinState;
guint32 gsmUmtsSubscriptionAppIndex;
guint32 cdmaSubscriptionAppIndex;
guint32 imsSubscriptionAppIndex;
guint32 unused1;
union {
guint64 value;
const RadioAppStatus* array;
} apps;
guint32 numApps;
guint32 unused2;
} RadioCardStatus;
static const char pname[] = "binder-client";
static
gboolean
app_signal(
gpointer user_data)
{
App* app = user_data;
GINFO("Caught signal, shutting down...");
g_main_loop_quit(app->loop);
return G_SOURCE_CONTINUE;
}
static
void
app_remote_died(
GBinderRemoteObject* obj,
void* user_data)
{
App* app = user_data;
GINFO("Remote has died, exiting...");
g_main_loop_quit(app->loop);
}
static
void
app_dump(
const void* buf,
gsize len)
{
const guint8* ptr = buf;
while (len > 0) {
char line[GUTIL_HEXDUMP_BUFSIZE];
const guint consumed = gutil_hexdump(line, ptr, len);
GDEBUG(" %s", line);
len -= consumed;
ptr += consumed;
}
}
static
void
app_decode_card_status(
GBinderRemoteRequest* req)
{
GBinderReader reader;
GBinderBuffer* buf;
gbinder_remote_request_init_reader(req, &reader);
/* RadioResponseInfo */
buf = gbinder_reader_read_buffer(&reader);
if (buf) {
const RadioResponseInfo* info = buf->data;
GASSERT(sizeof(*info) == buf->size);
GDEBUG("RadioResponseInfo: type=%d serial=%d error=%d",
(int)info->type, (int)info->serial, (int)info->error);
app_dump(buf->data, buf->size);
gbinder_buffer_free(buf);
/* CardStatus */
buf = gbinder_reader_read_buffer(&reader);
if (buf) {
guint i;
const RadioCardStatus* status = buf->data;
GINFO("CardStatus: state=%d pinState=%d gsmSubIndex=%d "
"cdmsSubIndex=%d imsSubIndex=%d appCount=%u",
(int)status->cardState, (int)status->universalPinState,
(int)status->gsmUmtsSubscriptionAppIndex,
(int)status->cdmaSubscriptionAppIndex,
(int)status->imsSubscriptionAppIndex, status->numApps);
GASSERT(sizeof(*status) == buf->size);
app_dump(buf->data, buf->size);
gbinder_buffer_free(buf);
for (i = 0; i < status->numApps; i++) {
const RadioAppStatus* app = status->apps.array + i;
buf = gbinder_reader_read_buffer(&reader);
GASSERT(buf->size == sizeof(RadioAppStatus));
GINFO("AppStatus: type=%u state=%u substate=%u aid=%s "
"label=%s pin_replaced=%u pin1=%u pin2=%u",
app->appType, app->appState, app->persoSubstate,
app->aid.data.str, app->label.data.str,
app->pinReplaced, app->pin1, app->pin2);
app_dump(buf->data, buf->size);
gbinder_buffer_free(buf);
}
}
}
}
static
GBinderLocalReply*
IRadioIndication_transact(
GBinderLocalObject* obj,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status,
void* user_data)
{
const char* iface = gbinder_remote_request_interface(req);
GDEBUG("%s %u", iface, code);
if (!g_strcmp0(iface, IFACE_INDICATION)) {
/* Those should all be one-way */
GASSERT(flags & GBINDER_TX_FLAG_ONEWAY);
*status = GBINDER_STATUS_OK;
} else {
*status = GBINDER_STATUS_FAILED;
}
return NULL;
}
static
GBinderLocalReply*
IRadioResponse_transact(
GBinderLocalObject* obj,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status,
void* user_data)
{
App* app = user_data;
const char* iface = gbinder_remote_request_interface(req);
if (!g_strcmp0(iface, IFACE_RESPONSE)) {
/* Those should all be one-way */
GASSERT(flags & GBINDER_TX_FLAG_ONEWAY);
if (code == RESP_GET_ICC_CARD_STATUS_RESPONSE) {
GDEBUG("%s getIccCardStatusResponse", iface);
*status = GBINDER_STATUS_OK;
app_decode_card_status(req);
g_main_loop_quit(app->loop);
return NULL;
}
}
GDEBUG("%s %u", iface, code);
*status = GBINDER_STATUS_FAILED;
return NULL;
}
static
void
app_run(
App* app)
{
const AppOptions* opt = app->opt;
char* fqname = opt->fqname ? g_strdup(opt->fqname) :
strchr(opt->name, '/') ? g_strdup(opt->name) :
g_strconcat(IFACE_RADIO "/", opt->name, NULL);
int status = 0;
GBinderRemoteObject* remote = gbinder_remote_object_ref
(gbinder_servicemanager_get_service_sync(app->sm, fqname, &status));
if (remote) {
guint sigtrm = g_unix_signal_add(SIGTERM, app_signal, app);
guint sigint = g_unix_signal_add(SIGINT, app_signal, app);
gulong death_id = gbinder_remote_object_add_death_handler
(remote, app_remote_died, app);
GBinderClient* client = gbinder_client_new(remote, IFACE_RADIO);
GBinderLocalRequest* req;
GBinderRemoteReply* reply;
int status;
GINFO("Connected to %s", fqname);
app->ret = RET_OK;
app->loop = g_main_loop_new(NULL, TRUE);
/* IRadio::setResponseFunctions */
req = gbinder_client_new_request(client);
gbinder_local_request_append_local_object(req, app->response);
gbinder_local_request_append_local_object(req, app->indication);
reply = gbinder_client_transact_sync_reply(client,
REQ_RADIO_SET_RESPONSE_FUNCTIONS, req, &status);
GDEBUG("setResponseFunctions status %d", status);
gbinder_local_request_unref(req);
gbinder_remote_reply_unref(reply);
/* IRadio::getIccCardStatus */
req = gbinder_client_new_request(client);
gbinder_local_request_append_int32(req, 1 /* serial */);
status = gbinder_client_transact_sync_oneway(client,
REQ_RADIO_GET_ICC_CARD_STATUS, req);
GDEBUG("getIccCardStatus status %d", status);
gbinder_local_request_unref(req);
g_main_loop_run(app->loop);
g_source_remove(sigtrm);
g_source_remove(sigint);
g_main_loop_unref(app->loop);
gbinder_remote_object_remove_handler(remote, death_id);
gbinder_remote_object_unref(remote);
gbinder_client_unref(client);
app->loop = NULL;
} else {
GERR("No such service: %s (%d)", fqname, status);
}
g_free(fqname);
}
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_ERR;
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_DEVICE "]", "DEVICE" },
{ "fqname", 'n', 0, G_OPTION_ARG_STRING, &opt->fqname,
"Fully qualified name", "FQNAME" },
{ NULL }
};
GError* error = NULL;
GOptionContext* options = g_option_context_new("[NAME]");
memset(opt, 0, sizeof(*opt));
gutil_log_timestamp = FALSE;
gutil_log_set_type(GLOG_TYPE_STDERR, pname);
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)) {
char* help;
if (!opt->dev || !opt->dev[0]) opt->dev = g_strdup(DEFAULT_DEVICE);
switch (argc) {
case 2:
opt->name = argv[1];
ok = TRUE;
break;
case 1:
opt->name = DEFAULT_NAME;
ok = TRUE;
break;
default:
help = g_option_context_get_help(options, TRUE, NULL);
fprintf(stderr, "%s", help);
g_free(help);
break;
}
} else {
GERR("%s", error->message);
g_error_free(error);
}
g_option_context_free(options);
return ok;
}
int main(int argc, char* argv[])
{
App app;
AppOptions opt;
memset(&app, 0, sizeof(app));
app.ret = RET_INVARG;
app.opt = &opt;
if (app_init(&opt, argc, argv)) {
app.sm = gbinder_servicemanager_new(opt.dev);
if (app.sm) {
app.indication = gbinder_servicemanager_new_local_object(app.sm,
IFACE_INDICATION, IRadioIndication_transact, &app);
app.response = gbinder_servicemanager_new_local_object(app.sm,
IFACE_RESPONSE, IRadioResponse_transact, &app);
app_run(&app);
gbinder_local_object_unref(app.indication);
gbinder_local_object_unref(app.response);
gbinder_servicemanager_unref(app.sm);
}
}
g_free(opt.fqname);
g_free(opt.dev);
return app.ret;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

21
unit/Makefile Normal file
View File

@@ -0,0 +1,21 @@
# -*- Mode: makefile-gmake -*-
all:
%:
@$(MAKE) -C unit_buffer $*
@$(MAKE) -C unit_client $*
@$(MAKE) -C unit_driver $*
@$(MAKE) -C unit_ipc $*
@$(MAKE) -C unit_local_object $*
@$(MAKE) -C unit_local_reply $*
@$(MAKE) -C unit_local_request $*
@$(MAKE) -C unit_protocol $*
@$(MAKE) -C unit_reader $*
@$(MAKE) -C unit_remote_object $*
@$(MAKE) -C unit_remote_reply $*
@$(MAKE) -C unit_remote_request $*
@$(MAKE) -C unit_writer $*
clean: unitclean
rm -f coverage/*.gcov
rm -fr coverage/report

185
unit/common/Makefile Normal file
View File

@@ -0,0 +1,185 @@
# -*- Mode: makefile-gmake -*-
.PHONY: clean all debug release coverage
.PHONY: debug_lib release_lib coverage_lib
#
# Real test makefile defines EXE (and possibly SRC) and includes this one.
#
ifndef EXE
${error EXE not defined}
endif
SRC ?= $(EXE).c
COMMON_SRC ?= test_binder.c test_main.c
#
# Required packages
#
PKGS += libglibutil glib-2.0 gobject-2.0
#
# Default target
#
all: debug release
#
# Directories
#
SRC_DIR = .
LIB_DIR = ../..
COMMON_DIR = ../common
BUILD_DIR = build
DEBUG_BUILD_DIR = $(BUILD_DIR)/debug
RELEASE_BUILD_DIR = $(BUILD_DIR)/release
COVERAGE_BUILD_DIR = $(BUILD_DIR)/coverage
#
# Tools and flags
#
CC = $(CROSS_COMPILE)gcc
LD = $(CC)
WARNINGS += -Wall
INCLUDES += -I$(COMMON_DIR) -I$(LIB_DIR)/src -I$(LIB_DIR)/include
BASE_FLAGS = -fPIC
BASE_LDFLAGS = $(BASE_FLAGS) $(LDFLAGS)
BASE_CFLAGS = $(BASE_FLAGS) $(CFLAGS)
FULL_CFLAGS = $(BASE_CFLAGS) $(DEFINES) $(WARNINGS) $(INCLUDES) -MMD -MP \
$(shell pkg-config --cflags $(PKGS))
FULL_LDFLAGS = $(BASE_LDFLAGS)
LIBS = $(shell pkg-config --libs $(PKGS))
QUIET_MAKE = make --no-print-directory
DEBUG_FLAGS = -g
RELEASE_FLAGS =
COVERAGE_FLAGS = -g
DEBUG_LDFLAGS = $(FULL_LDFLAGS) $(DEBUG_FLAGS)
RELEASE_LDFLAGS = $(FULL_LDFLAGS) $(RELEASE_FLAGS)
COVERAGE_LDFLAGS = $(FULL_LDFLAGS) $(COVERAGE_FLAGS) --coverage
DEBUG_CFLAGS = $(FULL_CFLAGS) $(DEBUG_FLAGS) -DDEBUG
RELEASE_CFLAGS = $(FULL_CFLAGS) $(RELEASE_FLAGS) -O2
COVERAGE_CFLAGS = $(FULL_CFLAGS) $(COVERAGE_FLAGS) --coverage
DEBUG_LIB_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_debug_lib)
RELEASE_LIB_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_release_lib)
COVERAGE_LIB_FILE := $(shell $(QUIET_MAKE) -C $(LIB_DIR) print_coverage_lib)
DEBUG_LIB = $(LIB_DIR)/$(DEBUG_LIB_FILE)
RELEASE_LIB = $(LIB_DIR)/$(RELEASE_LIB_FILE)
COVERAGE_LIB = $(LIB_DIR)/$(COVERAGE_LIB_FILE)
DEBUG_LIBS = $(DEBUG_LIB) $(LIBS)
RELEASE_LIBS = $(RELEASE_LIB) $(LIBS)
COVERAGE_LIBS = $(COVERAGE_LIB) $(LIBS)
#
# Files
#
DEBUG_OBJS = \
$(COMMON_SRC:%.c=$(DEBUG_BUILD_DIR)/common_%.o) \
$(SRC:%.c=$(DEBUG_BUILD_DIR)/%.o)
RELEASE_OBJS = \
$(COMMON_SRC:%.c=$(RELEASE_BUILD_DIR)/common_%.o) \
$(SRC:%.c=$(RELEASE_BUILD_DIR)/%.o)
COVERAGE_OBJS = \
$(COMMON_SRC:%.c=$(COVERAGE_BUILD_DIR)/common_%.o) \
$(SRC:%.c=$(COVERAGE_BUILD_DIR)/%.o)
#
# Dependencies
#
DEPS = $(DEBUG_OBJS:%.o=%.d) $(RELEASE_OBJS:%.o=%.d)
ifneq ($(MAKECMDGOALS),clean)
ifneq ($(strip $(DEPS)),)
-include $(DEPS)
endif
endif
$(DEBUG_EXE) $(DEBUG_OBJS): | $(DEBUG_BUILD_DIR)
$(RELEASE_EXE) $(RELEASE_OBJS): | $(RELEASE_BUILD_DIR)
$(COVERAGE_EXE) $(COVERAGE_OBJS): | $(COVERAGE_BUILD_DIR)
#
# Rules
#
DEBUG_EXE = $(DEBUG_BUILD_DIR)/$(EXE)
RELEASE_EXE = $(RELEASE_BUILD_DIR)/$(EXE)
COVERAGE_EXE = $(COVERAGE_BUILD_DIR)/$(EXE)
debug: debug_lib $(DEBUG_EXE)
release: release_lib $(RELEASE_EXE)
coverage: coverage_lib $(COVERAGE_EXE)
unitclean:
rm -f *~
rm -fr $(BUILD_DIR)
clean: unitclean
cleaner: unitclean
@make -C $(LIB_DIR) clean
test_banner:
@echo "===========" $(EXE) "=========== "
test: test_banner debug
@LD_LIBRARY_PATH="$(LIB_DIR)/$(DEBUG_LIB_PATH)" $(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)
$(DEBUG_BUILD_DIR):
mkdir -p $@
$(RELEASE_BUILD_DIR):
mkdir -p $@
$(COVERAGE_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 $@
$(COVERAGE_BUILD_DIR)/%.o : $(SRC_DIR)/%.c
$(CC) -c $(COVERAGE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
$(DEBUG_BUILD_DIR)/common_%.o : $(COMMON_DIR)/%.c
$(CC) -c $(DEBUG_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
$(RELEASE_BUILD_DIR)/common_%.o : $(COMMON_DIR)/%.c
$(CC) -c $(RELEASE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
$(COVERAGE_BUILD_DIR)/common_%.o : $(COMMON_DIR)/%.c
$(CC) -c $(COVERAGE_CFLAGS) -MT"$@" -MF"$(@:%.o=%.d)" $< -o $@
$(DEBUG_EXE): $(DEBUG_PLUGIN_LIB) $(DEBUG_OBJS)
$(LD) $(DEBUG_LDFLAGS) $(DEBUG_OBJS) $(DEBUG_LIBS) -o $@
$(RELEASE_EXE): $(RELEASE_PLUGIN_LIB) $(RELEASE_OBJS)
$(LD) $(RELEASE_LDFLAGS) $(RELEASE_OBJS) $(RELEASE_LIBS) -o $@
$(COVERAGE_EXE): $(COVERAGE_PLUGIN_LIB) $(COVERAGE_OBJS)
$(LD) $(COVERAGE_LDFLAGS) $(COVERAGE_OBJS) $(COVERAGE_LIBS) -o $@
debug_lib:
$(MAKE) -C $(LIB_DIR) $@
release_lib:
$(MAKE) -C $(LIB_DIR) $@
coverage_lib:
$(MAKE) -C $(LIB_DIR) $@

548
unit/common/test_binder.c Normal file
View File

@@ -0,0 +1,548 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Contact: 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 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.
*
* 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_system.h"
#include <gutil_log.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
static GHashTable* test_fd_map = NULL;
static GHashTable* test_node_map = NULL;
#define public_fd fd[0]
#define private_fd fd[1]
#define BINDER_VERSION _IOWR('b', 9, gint32)
#define BINDER_SET_MAX_THREADS _IOW('b', 5, guint32)
#define TF_ONE_WAY 0x01
#define TF_ROOT_OBJECT 0x04
#define TF_STATUS_CODE 0x08
#define TF_ACCEPT_FDS 0x10
typedef struct test_binder_io TestBinderIo;
typedef struct test_binder_node {
char* path;
int refcount;
const TestBinderIo* io;
} TestBinderNode;
typedef struct test_binder {
TestBinderNode* node;
int fd[2];
} TestBinder;
struct test_binder_io {
int version;
int write_read_request;
int (*handle_write_read)(TestBinder* binder, void* data);
};
typedef struct binder_write_read_64 {
guint64 write_size;
guint64 write_consumed;
guint64 write_buffer;
guint64 read_size;
guint64 read_consumed;
guint64 read_buffer;
} BinderWriteRead64;
typedef struct binder_transaction_data_64 {
guint64 handle;
guint64 cookie;
guint32 code;
guint32 flags;
gint32 sender_pid;
gint32 sender_euid;
guint64 data_size;
guint64 offsets_size;
guint64 data_buffer;
guint64 data_offsets;
} BinderTransactionData64;
typedef struct binder_pre_cookie_64 {
guint64 ptr;
guint64 cookie;
} BinderPtrCookie64;
#define BC_TRANSACTION_64 _IOW('c', 0, BinderTransactionData64)
#define BC_REPLY_64 _IOW('c', 1, BinderTransactionData64)
#define BC_FREE_BUFFER_64 _IOW('c', 3, guint64)
#define BC_INCREFS _IOW('c', 4, guint32)
#define BC_ACQUIRE _IOW('c', 5, guint32)
#define BC_RELEASE _IOW('c', 6, guint32)
#define BC_DECREFS _IOW('c', 7, guint32)
#define BC_ENTER_LOOPER _IO('c', 12)
#define BC_EXIT_LOOPER _IO('c', 13)
#define BR_TRANSACTION_64 _IOR('r', 2, BinderTransactionData64)
#define BR_REPLY_64 _IOR('r', 3, BinderTransactionData64)
#define BR_DEAD_REPLY _IO('r', 5)
#define BR_TRANSACTION_COMPLETE _IO('r', 6)
#define BR_INCREFS_64 _IOR('r', 7, BinderPtrCookie64)
#define BR_ACQUIRE_64 _IOR('r', 8, BinderPtrCookie64)
#define BR_RELEASE_64 _IOR('r', 9, BinderPtrCookie64)
#define BR_DECREFS_64 _IOR('r', 10, BinderPtrCookie64)
#define BR_NOOP _IO('r', 12)
#define BR_DEAD_BINDER_64 _IOR('r', 15, guint64)
#define BR_FAILED_REPLY _IO('r', 17)
static
int
test_io_handle_write_read_64(
TestBinder* binder,
void* data)
{
int err, bytes_available = 0;
BinderWriteRead64* wr = data;
gssize bytes_left = wr->write_size - wr->write_consumed;
const guint8* write_ptr = (void*)(gsize)
(wr->write_buffer + wr->write_consumed);
while (bytes_left >= sizeof(guint32)) {
const guint cmd = *(guint32*)write_ptr;
const guint cmdsize = _IOC_SIZE(cmd);
GASSERT(bytes_left >= (sizeof(guint32) + cmdsize));
if (bytes_left >= (sizeof(guint32) + cmdsize)) {
wr->write_consumed += sizeof(guint32);
write_ptr += sizeof(guint32);
bytes_left -= sizeof(guint32);
switch (cmd) {
case BC_TRANSACTION_64:
case BC_REPLY_64:
/* Is there anything special about transactions and replies? */
break;
case BC_FREE_BUFFER_64:
g_free((void*)(gsize)(*(guint64*)write_ptr));
break;
case BC_INCREFS:
case BC_ACQUIRE:
case BC_RELEASE:
case BC_DECREFS:
case BC_ENTER_LOOPER:
case BC_EXIT_LOOPER:
break;
default:
#pragma message("TODO: implement more BINDER_WRITE_READ commands")
GDEBUG("Unhandled command 0x%08x", cmd);
break;
}
wr->write_consumed += cmdsize;
write_ptr += cmdsize;
bytes_left -= cmdsize;
} else {
/* Partial command in the buffer */
errno = EINVAL;
return -1;
}
}
/* Now read the data from the socket */
err = ioctl(binder->public_fd, FIONREAD, &bytes_available);
if (err >= 0) {
int bytes_read = 0;
if (bytes_available > 0) {
bytes_read = read(binder->public_fd,
(void*)(gsize)(wr->read_buffer + wr->read_consumed),
wr->read_size - wr->read_consumed);
}
if (bytes_read >= 0) {
wr->read_consumed += bytes_read;
return 0;
} else {
err = bytes_read;
}
}
return err;
}
static const TestBinderIo test_io_64 = {
.version = 8,
.write_read_request = _IOWR('b', 1, BinderWriteRead64),
.handle_write_read = test_io_handle_write_read_64
};
static
int
test_binder_ioctl_version(
TestBinder* binder,
int* version)
{
*version = binder->node->io->version;
return 0;
}
static
void
test_binder_node_unref(
TestBinderNode* node)
{
node->refcount--;
if (!node->refcount) {
g_hash_table_remove(test_node_map, node->path);
g_free(node->path);
g_free(node);
}
if (!g_hash_table_size(test_node_map)) {
g_hash_table_unref(test_node_map);
test_node_map = NULL;
}
}
static
gboolean
test_binder_push_data(
int fd,
const void* data)
{
GASSERT(test_fd_map);
if (test_fd_map) {
gpointer key = GINT_TO_POINTER(fd);
TestBinder* binder = g_hash_table_lookup(test_fd_map, key);
GASSERT(binder);
if (binder) {
const guint32* cmd = data;
const int len = sizeof(*cmd) + _IOC_SIZE(*cmd);
return write(binder->private_fd, data, len) == len;
}
}
return FALSE;
}
static
void
test_binder_fill_transaction_data(
BinderTransactionData64* tr,
guint64 handle,
guint32 code,
const GByteArray* bytes)
{
g_assert(bytes);
memset(tr, 0, sizeof(*tr));
tr->handle = handle;
tr->code = code;
tr->data_size = bytes->len;
/* This memory should eventually get deallocated with BC_FREE_BUFFER_64 */
tr->data_buffer = (gsize)g_memdup(bytes->data, bytes->len);
}
gboolean
test_binder_push_ptr_cookie(
int fd,
guint32 cmd,
void* ptr)
{
guint8 buf[sizeof(guint32) + sizeof(BinderPtrCookie64)];
BinderPtrCookie64* data = (void*)(buf + sizeof(cmd));
memcpy(buf, &cmd, sizeof(cmd));
memset(data, 0, sizeof(*data));
data->ptr = (gsize)ptr;
return test_binder_push_data(fd, buf);
}
gboolean
test_binder_br_noop(
int fd)
{
guint32 cmd = BR_NOOP;
return test_binder_push_data(fd, &cmd);
}
gboolean
test_binder_br_increfs(
int fd,
void* ptr)
{
return test_binder_push_ptr_cookie(fd, BR_INCREFS_64, ptr);
}
gboolean
test_binder_br_acquire(
int fd,
void* ptr)
{
return test_binder_push_ptr_cookie(fd, BR_ACQUIRE_64, ptr);
}
gboolean
test_binder_br_release(
int fd,
void* ptr)
{
return test_binder_push_ptr_cookie(fd, BR_RELEASE_64, ptr);
}
gboolean
test_binder_br_decrefs(
int fd,
void* ptr)
{
return test_binder_push_ptr_cookie(fd, BR_DECREFS_64, ptr);
}
gboolean
test_binder_br_transaction_complete(
int fd)
{
guint32 cmd = BR_TRANSACTION_COMPLETE;
return test_binder_push_data(fd, &cmd);
}
gboolean
test_binder_br_dead_binder(
int fd,
guint handle)
{
const guint64 handle64 = handle;
guint32 buf[3];
buf[0] = BR_DEAD_BINDER_64;
memcpy(buf + 1, &handle64, sizeof(handle64));
return test_binder_push_data(fd, buf);
}
gboolean
test_binder_br_dead_reply(
int fd)
{
guint32 cmd = BR_DEAD_REPLY;
return test_binder_push_data(fd, &cmd);
}
gboolean
test_binder_br_failed_reply(
int fd)
{
guint32 cmd = BR_FAILED_REPLY;
return test_binder_push_data(fd, &cmd);
}
gboolean
test_binder_br_transaction(
int fd,
void* target,
guint32 code,
const GByteArray* bytes)
{
guint32 cmd = BR_TRANSACTION_64;
guint8 buf[sizeof(guint32) + sizeof(BinderTransactionData64)];
memcpy(buf, &cmd, sizeof(cmd));
test_binder_fill_transaction_data((void*)(buf + sizeof(cmd)),
(gsize)target, code, bytes);
return test_binder_push_data(fd, buf);
}
gboolean
test_binder_br_reply(
int fd,
guint32 handle,
guint32 code,
const GByteArray* bytes)
{
guint32 cmd = BR_REPLY_64;
guint8 buf[sizeof(guint32) + sizeof(BinderTransactionData64)];
memcpy(buf, &cmd, sizeof(cmd));
test_binder_fill_transaction_data((void*)(buf + sizeof(cmd)),
handle, code, bytes);
return test_binder_push_data(fd, buf);
}
gboolean
test_binder_br_reply_status(
int fd,
gint32 status)
{
guint8 buf[sizeof(guint32) + sizeof(BinderTransactionData64)];
guint32* cmd = (void*)buf;
BinderTransactionData64* tr = (void*)(buf + sizeof(*cmd));
memset(buf, 0, sizeof(buf));
*cmd = BR_REPLY_64;
tr->flags = TF_STATUS_CODE;
tr->data_size = sizeof(status);
/* This memory should eventually get deallocated with BC_FREE_BUFFER_64 */
tr->data_buffer = (gsize)g_memdup(&status, sizeof(status));
return test_binder_push_data(fd, buf);
}
int
gbinder_system_open(
const char* path,
int flags)
{
if (path && g_str_has_prefix(path, "/dev") &&
g_str_has_suffix(path, "binder")) {
TestBinderNode* node = NULL;
TestBinder* binder = NULL;
int fd;
if (test_node_map) {
node = g_hash_table_lookup(test_node_map, path);
}
if (node) {
node->refcount++;
} else {
node = g_new0(TestBinderNode, 1);
node->path = g_strdup(path);
node->refcount = 1;
node->io = &test_io_64;
if (!test_node_map) {
test_node_map = g_hash_table_new(g_str_hash, g_str_equal);
}
g_hash_table_replace(test_node_map, node->path, node);
}
binder = g_new0(TestBinder, 1);
binder->node = node;
socketpair(AF_UNIX, SOCK_STREAM, 0, binder->fd);
fd = binder->public_fd;
if (!test_fd_map) {
test_fd_map = g_hash_table_new(g_direct_hash, g_direct_equal);
}
g_hash_table_replace(test_fd_map, GINT_TO_POINTER(fd), binder);
return fd;
} else {
errno = ENOENT;
return -1;
}
}
int
gbinder_system_close(
int fd)
{
GASSERT(test_fd_map);
if (test_fd_map) {
gpointer key = GINT_TO_POINTER(fd);
TestBinder* binder = g_hash_table_lookup(test_fd_map, key);
GASSERT(binder);
if (binder) {
g_hash_table_remove(test_fd_map, key);
if (!g_hash_table_size(test_fd_map)) {
g_hash_table_unref(test_fd_map);
test_fd_map = NULL;
}
test_binder_node_unref(binder->node);
close(binder->public_fd);
close(binder->private_fd);
g_free(binder);
return 0;
}
}
errno = EBADF;
return -1;
}
int
gbinder_system_ioctl(
int fd,
int request,
void* data)
{
GASSERT(test_fd_map);
if (test_fd_map) {
gpointer key = GINT_TO_POINTER(fd);
TestBinder* binder = g_hash_table_lookup(test_fd_map, key);
GASSERT(binder);
if (binder) {
const TestBinderIo* io = binder->node->io;
switch (request) {
case BINDER_VERSION:
return test_binder_ioctl_version(binder, data);
case BINDER_SET_MAX_THREADS:
return 0;
default:
if (request == io->write_read_request) {
return io->handle_write_read(binder, data);
} else {
errno = EINVAL;
return -1;
}
}
}
}
errno = EBADF;
return -1;
}
void*
gbinder_system_mmap(
size_t length,
int prot,
int flags,
int fd)
{
return g_malloc(length);
}
int
gbinder_system_munmap(
void* addr,
size_t length)
{
g_free(addr);
return 0;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

106
unit/common/test_binder.h Normal file
View File

@@ -0,0 +1,106 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Contact: 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 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TEST_BINDER_H
#define TEST_BINDER_H
#include "test_common.h"
gboolean
test_binder_br_noop(
int fd);
gboolean
test_binder_br_increfs(
int fd,
void* ptr);
gboolean
test_binder_br_acquire(
int fd,
void* ptr);
gboolean
test_binder_br_release(
int fd,
void* ptr);
gboolean
test_binder_br_decrefs(
int fd,
void* ptr);
gboolean
test_binder_br_transaction_complete(
int fd);
gboolean
test_binder_br_dead_binder(
int fd,
guint handle);
gboolean
test_binder_br_dead_reply(
int fd);
gboolean
test_binder_br_failed_reply(
int fd);
gboolean
test_binder_br_transaction(
int fd,
void* target,
guint32 code,
const GByteArray* bytes);
gboolean
test_binder_br_reply(
int fd,
guint32 handle,
guint32 code,
const GByteArray* bytes);
gboolean
test_binder_br_reply_status(
int fd,
gint32 status);
#endif /* TEST_BINDER_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

102
unit/common/test_common.h Normal file
View File

@@ -0,0 +1,102 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Contact: 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 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TEST_COMMON_H
#define TEST_COMMON_H
#include <gbinder_types.h>
#define TEST_FLAG_DEBUG (0x01)
typedef struct test_opt {
int flags;
} TestOpt;
/* Should be invoked after g_test_init */
void
test_init(
TestOpt* opt,
int argc,
char* argv[]);
/* Run loop with a timeout */
void
test_run(
const TestOpt* opt,
GMainLoop* loop);
/* Quits the event loop on the next iteration */
void
test_quit_later(
GMainLoop* loop);
#define TEST_TIMEOUT_SEC (20)
/* Helper macros */
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
# define TEST_INT16_BYTES(v) \
(guint8)(v), (guint8)((v) >> 8)
# define TEST_INT32_BYTES(v) \
(guint8)(v), (guint8)((v) >> 8), \
(guint8)((v) >> 16), (guint8)((v) >> 24)
# define TEST_INT64_BYTES(v) \
(guint8)(v), (guint8)((v) >> 8), \
(guint8)((v) >> 16), (guint8)((v) >> 24), \
(guint8)(((guint64)(v)) >> 32), (guint8)(((guint64)(v)) >> 40), \
(guint8)(((guint64)(v)) >> 48), (guint8)(((guint64)(v)) >> 56)
#elif G_BYTE_ORDER == G_BIG_ENDIAN
# define TEST_INT16_BYTES(v) \
(guint8)((v) >> 8), (guint8)(v)
# define TEST_INT32_BYTES(v) \
(guint8)((v) >> 24), (guint8)((v) >> 16), \
(guint8)((v) >> 8), (guint8)(v)
# define TEST_INT64_BYTES(v) \
(guint8)(((guint64)(v)) >> 56), (guint8)(((guint64)(v)) >> 48), \
(guint8)(((guint64)(v)) >> 40), (guint8)(((guint64)(v)) >> 32), \
(guint8)((v) >> 24), (guint8)((v) >> 16), \
(guint8)((v) >> 8), (guint8)(v)
#else /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
#error unknown ENDIAN type
#endif /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
#define TEST_ARRAY_AND_COUNT(a) a, G_N_ELEMENTS(a)
#define TEST_ARRAY_AND_SIZE(a) a, sizeof(a)
#endif /* TEST_COMMON_H */
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

116
unit/common/test_main.c Normal file
View File

@@ -0,0 +1,116 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Contact: 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 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_common.h"
#include <gutil_log.h>
static
gboolean
test_timeout_expired(
gpointer data)
{
g_assert(!"TIMEOUT");
return G_SOURCE_REMOVE;
}
static
gboolean
test_quit_later_cb(
gpointer data)
{
g_main_loop_quit((GMainLoop*)data);
return G_SOURCE_REMOVE;
}
void
test_quit_later(
GMainLoop* loop)
{
g_idle_add(test_quit_later_cb, loop);
}
void
test_run(
const TestOpt* opt,
GMainLoop* loop)
{
if (opt->flags & TEST_FLAG_DEBUG) {
g_main_loop_run(loop);
} else {
const guint timeout_id = g_timeout_add_seconds(TEST_TIMEOUT_SEC,
test_timeout_expired, NULL);
g_main_loop_run(loop);
g_source_remove(timeout_id);
}
}
void
test_init(
TestOpt* opt,
int argc,
char* argv[])
{
const char* sep1;
const char* sep2;
int i;
memset(opt, 0, sizeof(*opt));
for (i=1; i<argc; i++) {
const char* arg = argv[i];
if (!strcmp(arg, "-d") || !strcmp(arg, "--debug")) {
opt->flags |= TEST_FLAG_DEBUG;
} else if (!strcmp(arg, "-v")) {
GTestConfig* config = (GTestConfig*)g_test_config_vars;
config->test_verbose = TRUE;
} else {
GWARN("Unsupported command line option %s", arg);
}
}
/* Setup logging */
sep1 = strrchr(argv[0], '/');
sep2 = strrchr(argv[0], '\\');
gutil_log_default.name = (sep1 && sep2) ? (MAX(sep1, sep2) + 1) :
sep1 ? (sep1 + 1) : sep2 ? (sep2 + 1) : argv[0];
gutil_log_default.level = g_test_verbose() ?
GLOG_LEVEL_VERBOSE : GLOG_LEVEL_NONE;
gutil_log_timestamp = FALSE;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

2
unit/coverage/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
report
*.gcov

60
unit/coverage/run Executable file
View File

@@ -0,0 +1,60 @@
#!/bin/bash
#
# This script requires lcov, dirname
#
TESTS="\
unit_buffer \
unit_client \
unit_driver \
unit_ipc \
unit_local_object \
unit_local_reply \
unit_local_request \
unit_protocol \
unit_reader \
unit_remote_object \
unit_remote_reply \
unit_remote_request \
unit_writer"
function err() {
echo "*** ERROR!" $1
exit 1
}
# Check the required tools
which lcov >> /dev/null || err "Please install lcov"
which dirname >> /dev/null || err "Please install dirname"
# LCOV 1.10 has branch coverage disabled per default
# Previous versions didn't have the --rc option
if [ ! -z "$(lcov --help | grep ' --rc ')" ] ; then
LCOV_OPT="--rc lcov_branch_coverage=1"
GENHTML_OPT="--branch-coverage"
fi
pushd `dirname $0` > /dev/null
COV_DIR="$PWD"
pushd .. > /dev/null
TEST_DIR="$PWD"
pushd .. > /dev/null
TOP_DIR="$PWD"
popd > /dev/null
popd > /dev/null
popd > /dev/null
make -C "$TOP_DIR" clean
for t in $TESTS ; do
pushd "$TEST_DIR/$t"
make -C "$TEST_DIR/$t" clean coverage || exit 1
build/coverage/$t || exit 1
popd
done
FULL_COV="$COV_DIR/full.gcov"
LIB_COV="$COV_DIR/lib.gcov"
rm -f "$FULL_COV" "$LIB_COV"
lcov $LCOV_OPT -c -d "$TOP_DIR/build/coverage" -b "$TOP_DIR/src" -o "$FULL_COV" || exit 1
lcov $LCOV_OPT -e "$FULL_COV" "$TOP_DIR/src/*" -o "$LIB_COV" || exit 1
genhtml $GENHTML_OPT "$LIB_COV" -t "libgbinder" --output-directory "$COV_DIR/report" || exit 1

View File

@@ -0,0 +1,5 @@
# -*- Mode: makefile-gmake -*-
EXE = unit_buffer
include ../common/Makefile

View File

@@ -0,0 +1,115 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Contact: 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 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_common.h"
#include "gbinder_driver.h"
#include "gbinder_buffer_p.h"
static TestOpt test_opt;
/*==========================================================================*
* null
*==========================================================================*/
static
void
test_null(
void)
{
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER);
GBinderBuffer* buf = gbinder_buffer_new(NULL, NULL, 0);
GBinderBuffer* buf2;
gbinder_buffer_free(buf);
/* No need to reference the driver if there's no data */
buf = gbinder_buffer_new(driver, NULL, 0);
g_assert(!gbinder_buffer_driver(buf));
gbinder_buffer_free(buf);
buf = gbinder_buffer_new_with_parent(NULL, NULL, 0);
buf2 = gbinder_buffer_new_with_parent(buf, NULL, 0);
g_assert(!gbinder_buffer_driver(buf));
g_assert(!gbinder_buffer_driver(buf2));
gbinder_buffer_free(buf);
gbinder_buffer_free(buf2);
gbinder_buffer_free(NULL);
g_assert(!gbinder_buffer_driver(NULL));
gbinder_driver_unref(driver);
}
/*==========================================================================*
* parent
*==========================================================================*/
static
void
test_parent(
void)
{
static const guint8 data[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
void* ptr = g_memdup(data, sizeof(data));
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER);
GBinderBuffer* parent = gbinder_buffer_new(driver, ptr, sizeof(data));
GBinderBuffer* buf = gbinder_buffer_new_with_parent
(parent, ptr, sizeof(data));
g_assert(gbinder_buffer_driver(buf) == driver);
gbinder_buffer_free(buf);
gbinder_buffer_free(parent);
gbinder_driver_unref(driver);
}
/*==========================================================================*
* Common
*==========================================================================*/
#define TEST_PREFIX "/buffer/"
int main(int argc, char* argv[])
{
g_test_init(&argc, &argv, NULL);
g_test_add_func(TEST_PREFIX "null", test_null);
g_test_add_func(TEST_PREFIX "parent", test_parent);
test_init(&test_opt, argc, argv);
return g_test_run();
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,5 @@
# -*- Mode: makefile-gmake -*-
EXE = unit_client
include ../common/Makefile

View File

@@ -0,0 +1,350 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Contact: 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 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_binder.h"
#include "gbinder_client_p.h"
#include "gbinder_driver.h"
#include "gbinder_ipc.h"
#include "gbinder_local_reply_p.h"
#include "gbinder_local_request.h"
#include "gbinder_object_registry.h"
#include "gbinder_output_data.h"
#include "gbinder_remote_object_p.h"
#include "gbinder_remote_reply.h"
#include <gutil_log.h>
#include <errno.h>
static TestOpt test_opt;
static
GBinderClient*
test_client_new(
guint handle,
const char* iface)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteObject* obj = gbinder_object_registry_get_remote(reg, handle);
GBinderClient* client = gbinder_client_new(obj, iface);
g_assert(client);
gbinder_remote_object_unref(obj);
gbinder_ipc_unref(ipc);
return client;
}
/*==========================================================================*
* null
*==========================================================================*/
static
void
test_null(
void)
{
GBinderClient* null = NULL;
g_assert(!gbinder_client_new(NULL, NULL));
g_assert(!gbinder_client_ref(null));
gbinder_client_unref(null);
g_assert(!gbinder_client_new_request(NULL));
g_assert(!gbinder_client_transact_sync_reply(null, 0, NULL, NULL));
g_assert(gbinder_client_transact_sync_oneway(null, 0, NULL) == (-EINVAL));
g_assert(!gbinder_client_transact(null, 0, 0, NULL, NULL, NULL, NULL));
gbinder_client_cancel(null, 0);
}
/*==========================================================================*
* basic
*==========================================================================*/
static
void
test_basic(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteObject* obj = gbinder_object_registry_get_remote(reg, 0);
GBinderClient* client = gbinder_client_new(obj, "foo");
g_assert(!gbinder_client_new(obj, NULL));
g_assert(client);
g_assert(gbinder_client_ref(client) == client);
gbinder_client_unref(client);
gbinder_client_cancel(client, 0); /* does nothing */
gbinder_client_unref(client);
gbinder_remote_object_unref(obj);
gbinder_ipc_unref(ipc);
}
/*==========================================================================*
* sync_oneway
*==========================================================================*/
static
void
test_sync_oneway(
void)
{
GBinderClient* client = test_client_new(0, "foo");
GBinderLocalRequest* req = gbinder_client_new_request(client);
int fd = gbinder_driver_fd(gbinder_client_ipc(client)->driver);
g_assert(req);
test_binder_br_transaction_complete(fd);
g_assert(gbinder_client_transact_sync_oneway(client, 0, req) ==
GBINDER_STATUS_OK);
gbinder_local_request_unref(req);
/* Same but using the internal (empty) request */
test_binder_br_transaction_complete(fd);
g_assert(gbinder_client_transact_sync_oneway(client, 0, NULL) ==
GBINDER_STATUS_OK);
gbinder_client_unref(client);
}
/*==========================================================================*
* sync_reply
*==========================================================================*/
static
void
test_sync_reply_tx(
GBinderClient* client,
GBinderLocalRequest* req)
{
GBinderDriver* driver = gbinder_client_ipc(client)->driver;
int fd = gbinder_driver_fd(driver);
const GBinderIo* io = gbinder_driver_io(driver);
GBinderLocalReply* reply = gbinder_local_reply_new(io);
GBinderRemoteReply* tx_reply;
GBinderOutputData* data;
const guint32 handle = 0;
const guint32 code = 1;
const char* result_in = "foo";
char* result_out;
int status = INT_MAX;
g_assert(gbinder_local_reply_append_string16(reply, result_in));
data = gbinder_local_reply_data(reply);
g_assert(data);
g_assert(test_binder_br_noop(fd));
g_assert(test_binder_br_transaction_complete(fd));
g_assert(test_binder_br_noop(fd));
g_assert(test_binder_br_reply(fd, handle, code, data->bytes));
tx_reply = gbinder_client_transact_sync_reply(client, 0, req, &status);
g_assert(tx_reply);
g_assert(status == GBINDER_STATUS_OK);
result_out = gbinder_remote_reply_read_string16(tx_reply);
g_assert(!g_strcmp0(result_out, result_in));
g_free(result_out);
gbinder_remote_reply_unref(tx_reply);
gbinder_local_reply_unref(reply);
}
static
void
test_sync_reply(
void)
{
GBinderClient* client = test_client_new(0, "foo");
GBinderLocalRequest* req = gbinder_client_new_request(client);
test_sync_reply_tx(client, req);
gbinder_local_request_unref(req);
/* Same but using the internal (empty) request */
test_sync_reply_tx(client, NULL);
gbinder_client_unref(client);
}
/*==========================================================================*
* reply
*==========================================================================*/
#define TEST_INTERFACE "foo"
#define TEST_REQ_PARAM_STR "bar"
static
void
test_reply_destroy(
void* user_data)
{
test_quit_later((GMainLoop*)user_data);
}
static
void
test_reply_ok_reply(
GBinderClient* client,
GBinderRemoteReply* reply,
int status,
void* user_data)
{
char* result;
GVERBOSE_("%d", status);
g_assert(status == GBINDER_STATUS_OK);
g_assert(reply);
result = gbinder_remote_reply_read_string16(reply);
g_assert(!g_strcmp0(result, TEST_REQ_PARAM_STR));
g_free(result);
}
static
void
test_reply_ok_quit(
GBinderClient* client,
GBinderRemoteReply* reply,
int status,
void* user_data)
{
test_reply_ok_reply(client, reply, status, user_data);
test_reply_destroy(user_data);
}
static
void
test_reply_tx(
GBinderClient* client,
GBinderLocalRequest* req,
GBinderClientReplyFunc done,
GDestroyNotify destroy)
{
GBinderDriver* driver = gbinder_client_ipc(client)->driver;
int fd = gbinder_driver_fd(driver);
const GBinderIo* io = gbinder_driver_io(driver);
GBinderLocalReply* reply = gbinder_local_reply_new(io);
GBinderOutputData* data;
const guint32 handle = 0;
const guint32 code = 1;
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
gulong id;
g_assert(gbinder_local_reply_append_string16(reply, TEST_REQ_PARAM_STR));
data = gbinder_local_reply_data(reply);
g_assert(data);
g_assert(test_binder_br_noop(fd));
g_assert(test_binder_br_transaction_complete(fd));
g_assert(test_binder_br_noop(fd));
g_assert(test_binder_br_reply(fd, handle, code, data->bytes));
id = gbinder_client_transact(client, 0, 0, req, done, destroy, loop);
g_assert(id);
test_run(&test_opt, loop);
gbinder_local_reply_unref(reply);
g_main_loop_unref(loop);
}
static
void
test_reply(
GBinderClientReplyFunc done,
GDestroyNotify destroy)
{
GBinderClient* client = test_client_new(0, TEST_INTERFACE);
GBinderLocalRequest* req = gbinder_client_new_request(client);
test_reply_tx(client, req, done, destroy);
gbinder_local_request_unref(req);
/* Same but using the internal (empty) request */
test_reply_tx(client, NULL, done, destroy);
gbinder_client_unref(client);
}
static
void
test_reply_ok1(
void)
{
test_reply(test_reply_ok_reply, test_reply_destroy);
}
static
void
test_reply_ok2(
void)
{
test_reply(NULL, test_reply_destroy);
}
static
void
test_reply_ok3(
void)
{
test_reply(test_reply_ok_quit, NULL);
}
/*==========================================================================*
* Common
*==========================================================================*/
#define TEST_PREFIX "/client/"
int main(int argc, char* argv[])
{
g_test_init(&argc, &argv, NULL);
g_test_add_func(TEST_PREFIX "null", test_null);
g_test_add_func(TEST_PREFIX "basic", test_basic);
g_test_add_func(TEST_PREFIX "sync_oneway", test_sync_oneway);
g_test_add_func(TEST_PREFIX "sync_reply", test_sync_reply);
g_test_add_func(TEST_PREFIX "reply/ok1", test_reply_ok1);
g_test_add_func(TEST_PREFIX "reply/ok2", test_reply_ok2);
g_test_add_func(TEST_PREFIX "reply/ok3", test_reply_ok3);
test_init(&test_opt, argc, argv);
return g_test_run();
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,5 @@
# -*- Mode: makefile-gmake -*-
EXE = unit_driver
include ../common/Makefile

View File

@@ -0,0 +1,151 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Contact: 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 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_binder.h"
#include "gbinder_driver.h"
#include "gbinder_handler.h"
#include "gbinder_local_request_p.h"
#include "gbinder_output_data.h"
#include <poll.h>
static TestOpt test_opt;
#define STRICT_MODE_PENALTY_GATHER (0x40 << 16)
#define BINDER_RPC_FLAGS (STRICT_MODE_PENALTY_GATHER)
/*==========================================================================*
* basic
*==========================================================================*/
static
void
test_basic(
void)
{
GBinderDriver* driver;
const char* dev = GBINDER_DEFAULT_BINDER;
g_assert(!gbinder_driver_new(""));
driver = gbinder_driver_new(dev);
g_assert(driver);
g_assert(!g_strcmp0(dev, gbinder_driver_dev(driver)));
g_assert(gbinder_driver_ref(driver) == driver);
gbinder_driver_unref(driver);
gbinder_driver_free_buffer(driver, NULL);
g_assert(gbinder_driver_io(driver));
g_assert(gbinder_driver_increfs(driver, 0));
g_assert(gbinder_driver_decrefs(driver, 0));
g_assert(gbinder_driver_acquire(driver, 0));
g_assert(gbinder_driver_release(driver, 0));
g_assert(gbinder_driver_enter_looper(driver));
g_assert(gbinder_driver_exit_looper(driver));
g_assert(!gbinder_driver_request_death_notification(driver, NULL));
g_assert(!gbinder_driver_clear_death_notification(driver, NULL));
gbinder_driver_unref(driver);
g_assert(!gbinder_handler_transact(NULL, NULL, NULL, 0, 0, NULL));
}
/*==========================================================================*
* noop
*==========================================================================*/
static
void
test_noop(
void)
{
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER);
const int fd = gbinder_driver_fd(driver);
g_assert(driver);
g_assert(fd >= 0);
g_assert(test_binder_br_noop(fd));
g_assert(gbinder_driver_poll(driver, NULL) == POLLIN);
g_assert(gbinder_driver_read(driver, NULL, NULL) == 0);
gbinder_driver_unref(driver);
}
/*==========================================================================*
* local_request
*==========================================================================*/
static
void
test_local_request(
void)
{
static const char iface[] = "test";
static const guint8 rpc_header [] = {
TEST_INT32_BYTES(BINDER_RPC_FLAGS),
TEST_INT32_BYTES(4),
TEST_INT16_BYTES('t'), TEST_INT16_BYTES('e'),
TEST_INT16_BYTES('s'), TEST_INT16_BYTES('t'),
0x00, 0x00, 0x00, 0x00
};
GBinderDriver* driver = gbinder_driver_new(GBINDER_DEFAULT_BINDER);
GBinderLocalRequest* req = gbinder_driver_local_request_new(driver, iface);
GBinderOutputData* data = gbinder_local_request_data(req);
g_assert(data->bytes->len == sizeof(rpc_header));
g_assert(!memcmp(data->bytes->data, rpc_header, sizeof(rpc_header)));
gbinder_local_request_unref(req);
gbinder_driver_unref(driver);
}
/*==========================================================================*
* Common
*==========================================================================*/
#define TEST_PREFIX "/driver/"
int main(int argc, char* argv[])
{
g_test_init(&argc, &argv, NULL);
g_test_add_func(TEST_PREFIX "basic", test_basic);
g_test_add_func(TEST_PREFIX "noop", test_noop);
g_test_add_func(TEST_PREFIX "local_request", test_local_request);
test_init(&test_opt, argc, argv);
return g_test_run();
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

5
unit/unit_ipc/Makefile Normal file
View File

@@ -0,0 +1,5 @@
# -*- Mode: makefile-gmake -*-
EXE = unit_ipc
include ../common/Makefile

755
unit/unit_ipc/unit_ipc.c Normal file
View File

@@ -0,0 +1,755 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Contact: 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 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_binder.h"
#include "gbinder_ipc.h"
#include "gbinder_driver.h"
#include "gbinder_local_object.h"
#include "gbinder_local_reply_p.h"
#include "gbinder_local_request_p.h"
#include "gbinder_object_registry.h"
#include "gbinder_output_data.h"
#include "gbinder_remote_reply.h"
#include "gbinder_remote_request.h"
#include "gbinder_rpc_protocol.h"
#include "gbinder_writer.h"
#include <gutil_log.h>
#include <errno.h>
static TestOpt test_opt;
/*==========================================================================*
* null
*==========================================================================*/
static
void
test_null(
void)
{
GBinderIpc* null = NULL;
int status = INT_MAX;
g_assert(!gbinder_ipc_ref(null));
gbinder_ipc_unref(null);
g_assert(!gbinder_ipc_transact_sync_reply(null, 0, 0, NULL, NULL));
g_assert(!gbinder_ipc_transact_sync_reply(null, 0, 0, NULL, &status));
g_assert(status == (-EINVAL));
g_assert(gbinder_ipc_transact_sync_oneway(null, 0, 0, NULL) == (-EINVAL));
g_assert(!gbinder_ipc_transact(null, 0, 0, 0, NULL, NULL, NULL, NULL));
g_assert(!gbinder_ipc_transact_custom(null, NULL, NULL, NULL, NULL));
g_assert(!gbinder_ipc_object_registry(null));
gbinder_ipc_looper_check(null);
gbinder_ipc_cancel(null, 0);
g_assert(!gbinder_object_registry_ref(NULL));
gbinder_object_registry_unref(NULL);
g_assert(!gbinder_object_registry_get_local(NULL, NULL));
g_assert(!gbinder_object_registry_get_remote(NULL, 0));
}
/*==========================================================================*
* basic
*==========================================================================*/
static
void
test_basic(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderIpc* ipc2 = gbinder_ipc_new(GBINDER_DEFAULT_HWBINDER);
g_assert(ipc);
g_assert(ipc2);
g_assert(ipc != ipc2);
gbinder_ipc_cancel(ipc2, 0); /* not a valid transaction */
gbinder_ipc_unref(ipc2);
/* Second gbinder_ipc_new returns the same (default) object */
g_assert(gbinder_ipc_new(NULL) == ipc);
g_assert(gbinder_ipc_new("") == ipc);
gbinder_ipc_unref(ipc);
gbinder_ipc_unref(ipc);
gbinder_ipc_unref(ipc);
/* Invalid path */
g_assert(!gbinder_ipc_new("invalid path"));
}
/*==========================================================================*
* sync_oneway
*==========================================================================*/
static
void
test_sync_oneway(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
const int fd = gbinder_driver_fd(ipc->driver);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
g_assert(test_binder_br_transaction_complete(fd));
g_assert(gbinder_ipc_transact_sync_oneway(ipc, 0, 1, req) ==
GBINDER_STATUS_OK);
gbinder_local_request_unref(req);
gbinder_ipc_unref(ipc);
}
/*==========================================================================*
* sync_reply_ok
*==========================================================================*/
static
void
test_sync_reply_ok_status(
int* status)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
const int fd = gbinder_driver_fd(ipc->driver);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
GBinderLocalReply* reply = gbinder_local_reply_new(io);
GBinderRemoteReply* tx_reply;
GBinderOutputData* data;
const guint32 handle = 0;
const guint32 code = 1;
const char* result_in = "foo";
char* result_out;
g_assert(gbinder_local_reply_append_string16(reply, result_in));
data = gbinder_local_reply_data(reply);
g_assert(data);
g_assert(test_binder_br_noop(fd));
g_assert(test_binder_br_transaction_complete(fd));
g_assert(test_binder_br_noop(fd));
g_assert(test_binder_br_reply(fd, handle, code, data->bytes));
tx_reply = gbinder_ipc_transact_sync_reply(ipc, handle, code, req, status);
g_assert(tx_reply);
result_out = gbinder_remote_reply_read_string16(tx_reply);
g_assert(!g_strcmp0(result_out, result_in));
g_free(result_out);
gbinder_remote_reply_unref(tx_reply);
gbinder_local_request_unref(req);
gbinder_local_reply_unref(reply);
gbinder_ipc_unref(ipc);
}
static
void
test_sync_reply_ok(
void)
{
int status = -1;
test_sync_reply_ok_status(NULL);
test_sync_reply_ok_status(&status);
g_assert(status == GBINDER_STATUS_OK);
}
/*==========================================================================*
* sync_reply_error
*==========================================================================*/
static
void
test_sync_reply_error(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
const int fd = gbinder_driver_fd(ipc->driver);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
const guint32 handle = 0;
const guint32 code = 1;
const gint expected_status = GBINDER_STATUS_FAILED;
int status = INT_MAX;
g_assert(test_binder_br_noop(fd));
g_assert(test_binder_br_transaction_complete(fd));
g_assert(test_binder_br_noop(fd));
g_assert(test_binder_br_reply_status(fd, expected_status));
g_assert(!gbinder_ipc_transact_sync_reply(ipc, handle, code, req, &status));
g_assert(status == expected_status);
gbinder_local_request_unref(req);
gbinder_ipc_unref(ipc);
}
/*==========================================================================*
* transact_ok
*==========================================================================*/
#define TEST_REQ_PARAM_STR "foo"
static
void
test_transact_ok_destroy(
void* user_data)
{
test_quit_later((GMainLoop*)user_data);
}
static
void
test_transact_ok_done(
GBinderIpc* ipc,
GBinderRemoteReply* reply,
int status,
void* user_data)
{
char* result;
GVERBOSE_("");
result = gbinder_remote_reply_read_string16(reply);
g_assert(!g_strcmp0(result, TEST_REQ_PARAM_STR));
g_free(result);
g_assert(status == GBINDER_STATUS_OK);
}
static
void
test_transact_ok(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
const int fd = gbinder_driver_fd(ipc->driver);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
GBinderLocalReply* reply = gbinder_local_reply_new(io);
GBinderOutputData* data;
const guint32 handle = 0;
const guint32 code = 1;
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
gulong id;
g_assert(gbinder_local_reply_append_string16(reply, TEST_REQ_PARAM_STR));
data = gbinder_local_reply_data(reply);
g_assert(data);
g_assert(test_binder_br_noop(fd));
g_assert(test_binder_br_transaction_complete(fd));
g_assert(test_binder_br_noop(fd));
g_assert(test_binder_br_reply(fd, handle, code, data->bytes));
id = gbinder_ipc_transact(ipc, handle, code, 0, req,
test_transact_ok_done, test_transact_ok_destroy, loop);
g_assert(id);
test_run(&test_opt, loop);
/* Transaction id is not valid anymore: */
gbinder_ipc_cancel(ipc, id);
gbinder_local_request_unref(req);
gbinder_local_reply_unref(reply);
gbinder_ipc_unref(ipc);
g_main_loop_unref(loop);
}
/*==========================================================================*
* transact_dead
*==========================================================================*/
static
void
test_transact_dead_done(
GBinderIpc* ipc,
GBinderRemoteReply* reply,
int status,
void* user_data)
{
GVERBOSE_("%d", status);
g_assert(!reply);
g_assert(status == GBINDER_STATUS_DEAD_OBJECT);
test_quit_later((GMainLoop*)user_data);
}
static
void
test_transact_dead(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
const int fd = gbinder_driver_fd(ipc->driver);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
gulong id;
g_assert(test_binder_br_noop(fd));
g_assert(test_binder_br_dead_reply(fd));
id = gbinder_ipc_transact(ipc, 1, 2, 0, req, test_transact_dead_done,
NULL, loop);
g_assert(id);
test_run(&test_opt, loop);
/* Transaction id is not valid anymore: */
gbinder_ipc_cancel(ipc, id);
gbinder_local_request_unref(req);
gbinder_ipc_unref(ipc);
g_main_loop_unref(loop);
}
/*==========================================================================*
* transact_failed
*==========================================================================*/
static
void
test_transact_failed_done(
GBinderIpc* ipc,
GBinderRemoteReply* reply,
int status,
void* user_data)
{
GVERBOSE_("%d", status);
g_assert(!reply);
g_assert(status == GBINDER_STATUS_FAILED);
test_quit_later((GMainLoop*)user_data);
}
static
void
test_transact_failed(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
const int fd = gbinder_driver_fd(ipc->driver);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
gulong id;
g_assert(test_binder_br_noop(fd));
g_assert(test_binder_br_failed_reply(fd));
id = gbinder_ipc_transact(ipc, 1, 2, 0, req, test_transact_failed_done,
NULL, loop);
g_assert(id);
test_run(&test_opt, loop);
/* Transaction id is not valid anymore: */
gbinder_ipc_cancel(ipc, id);
gbinder_local_request_unref(req);
gbinder_ipc_unref(ipc);
g_main_loop_unref(loop);
}
/*==========================================================================*
* transact_status
*==========================================================================*/
#define EXPECTED_STATUS (0x42424242)
static
void
test_transact_status_done(
GBinderIpc* ipc,
GBinderRemoteReply* reply,
int status,
void* user_data)
{
GVERBOSE_("%d", status);
g_assert(!reply);
g_assert(status == EXPECTED_STATUS);
test_quit_later((GMainLoop*)user_data);
}
static
void
test_transact_status(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
const int fd = gbinder_driver_fd(ipc->driver);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
gulong id;
g_assert(test_binder_br_noop(fd));
g_assert(test_binder_br_reply_status(fd, EXPECTED_STATUS));
id = gbinder_ipc_transact(ipc, 1, 2, 0, req, test_transact_status_done,
NULL, loop);
g_assert(id);
test_run(&test_opt, loop);
/* Transaction id is not valid anymore: */
gbinder_ipc_cancel(ipc, id);
gbinder_local_request_unref(req);
gbinder_ipc_unref(ipc);
g_main_loop_unref(loop);
}
/*==========================================================================*
* transact_custom
*==========================================================================*/
static
void
test_transact_custom_done(
const GBinderIpcTx* tx)
{
GVERBOSE_("");
test_quit_later((GMainLoop*)tx->user_data);
}
static
void
test_transact_custom(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
gulong id = gbinder_ipc_transact_custom(ipc, NULL,
test_transact_custom_done, NULL, loop);
g_assert(id);
test_run(&test_opt, loop);
gbinder_ipc_unref(ipc);
g_main_loop_unref(loop);
}
/*==========================================================================*
* transact_custom2
*==========================================================================*/
static
void
test_transact_custom_destroy(
void* user_data)
{
GVERBOSE_("");
test_quit_later((GMainLoop*)user_data);
}
static
void
test_transact_custom2(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
gulong id = gbinder_ipc_transact_custom(ipc, NULL, NULL,
test_transact_custom_destroy, loop);
g_assert(id);
test_run(&test_opt, loop);
gbinder_ipc_unref(ipc);
g_main_loop_unref(loop);
}
/*==========================================================================*
* transact_cancel
*==========================================================================*/
static
void
test_transact_cancel_destroy(
void* user_data)
{
GVERBOSE_("");
test_quit_later((GMainLoop*)user_data);
}
static
void
test_transact_cancel_exec(
const GBinderIpcTx* tx)
{
GVERBOSE_("");
}
static
void
test_transact_cancel_done(
const GBinderIpcTx* tx)
{
GVERBOSE_("");
g_assert(tx->cancelled);
}
static
void
test_transact_cancel(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
gulong id = gbinder_ipc_transact_custom(ipc, test_transact_cancel_exec,
test_transact_cancel_done, test_transact_cancel_destroy, loop);
g_assert(id);
gbinder_ipc_cancel(ipc, id);
test_run(&test_opt, loop);
gbinder_ipc_unref(ipc);
g_main_loop_unref(loop);
}
/*==========================================================================*
* transact_cancel2
*==========================================================================*/
static
gboolean
test_transact_cancel2_cancel(
gpointer data)
{
const GBinderIpcTx* tx = data;
GVERBOSE_("");
gbinder_ipc_cancel(tx->ipc, tx->id);
return G_SOURCE_REMOVE;
}
static
void
test_transact_cancel2_exec(
const GBinderIpcTx* tx)
{
GVERBOSE_("");
g_assert(!tx->cancelled);
g_main_context_invoke(NULL, test_transact_cancel2_cancel, (void*)tx);
}
static
void
test_transact_cancel2(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
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_cancel2_exec,
test_transact_cancel_done, test_transact_cancel_destroy, loop);
g_assert(id);
test_run(&test_opt, loop);
gbinder_ipc_unref(ipc);
g_main_loop_unref(loop);
}
/*==========================================================================*
* transact_incoming
*==========================================================================*/
static
GBinderLocalReply*
test_transact_incoming_proc(
GBinderLocalObject* obj,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status,
void* user_data)
{
GVERBOSE_("\"%s\" %u", gbinder_remote_request_interface(req), code);
g_assert(!flags);
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), "test"));
g_assert(!g_strcmp0(gbinder_remote_request_read_string8(req), "message"));
g_assert(code == 1);
test_quit_later((GMainLoop*)user_data);
*status = GBINDER_STATUS_OK;
return gbinder_local_object_new_reply(obj);
}
static
gboolean
test_transact_unref_ipc(
gpointer ipc)
{
gbinder_ipc_unref(ipc);
return G_SOURCE_REMOVE;
}
static
void
test_transact_done(
gpointer loop,
GObject* ipc)
{
test_quit_later((GMainLoop*)loop);
}
static
void
test_transact_incoming(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
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);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderLocalObject* obj = gbinder_ipc_new_local_object
(ipc, "test", test_transact_incoming_proc, loop);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
GBinderOutputData* data;
GBinderWriter writer;
gbinder_local_request_init_writer(req, &writer);
prot->write_rpc_header(&writer, "test");
gbinder_writer_append_string8(&writer, "message");
data = gbinder_local_request_data(req);
test_binder_br_transaction(fd, obj, 1, data->bytes);
test_run(&test_opt, loop);
/* Now we need to wait until GBinderIpc is destroyed */
GDEBUG("waiting for GBinderIpc to get destroyed");
g_object_weak_ref(G_OBJECT(ipc), test_transact_done, loop);
gbinder_local_object_unref(obj);
gbinder_local_request_unref(req);
g_idle_add(test_transact_unref_ipc, ipc);
test_run(&test_opt, loop);
g_main_loop_unref(loop);
}
/*==========================================================================*
* transact_incoming_status
*==========================================================================*/
static
GBinderLocalReply*
test_transact_status_reply_proc(
GBinderLocalObject* obj,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status,
void* user_data)
{
GVERBOSE_("\"%s\" %u", gbinder_remote_request_interface(req), code);
g_assert(!flags);
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), "test"));
g_assert(!g_strcmp0(gbinder_remote_request_read_string8(req), "message"));
g_assert(code == 1);
test_quit_later((GMainLoop*)user_data);
*status = EXPECTED_STATUS;
return NULL;
}
static
void
test_transact_status_reply(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
const GBinderIo* io = gbinder_driver_io(ipc->driver);
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);
GMainLoop* loop = g_main_loop_new(NULL, FALSE);
GBinderLocalObject* obj = gbinder_ipc_new_local_object
(ipc, "test", test_transact_status_reply_proc, loop);
GBinderLocalRequest* req = gbinder_local_request_new(io, NULL);
GBinderOutputData* data;
GBinderWriter writer;
gbinder_local_request_init_writer(req, &writer);
prot->write_rpc_header(&writer, "test");
gbinder_writer_append_string8(&writer, "message");
data = gbinder_local_request_data(req);
test_binder_br_transaction(fd, obj, 1, data->bytes);
test_run(&test_opt, loop);
/* Now we need to wait until GBinderIpc is destroyed */
GDEBUG("waiting for GBinderIpc to get destroyed");
g_object_weak_ref(G_OBJECT(ipc), test_transact_done, loop);
gbinder_local_object_unref(obj);
gbinder_local_request_unref(req);
g_idle_add(test_transact_unref_ipc, ipc);
test_run(&test_opt, loop);
g_main_loop_unref(loop);
}
/*==========================================================================*
* Common
*==========================================================================*/
#define TEST_PREFIX "/ipc/"
int main(int argc, char* argv[])
{
g_test_init(&argc, &argv, NULL);
g_test_add_func(TEST_PREFIX "null", test_null);
g_test_add_func(TEST_PREFIX "basic", test_basic);
g_test_add_func(TEST_PREFIX "sync_oneway", test_sync_oneway);
g_test_add_func(TEST_PREFIX "sync_reply_ok", test_sync_reply_ok);
g_test_add_func(TEST_PREFIX "sync_reply_error", test_sync_reply_error);
g_test_add_func(TEST_PREFIX "transact_ok", test_transact_ok);
g_test_add_func(TEST_PREFIX "transact_dead", test_transact_dead);
g_test_add_func(TEST_PREFIX "transact_failed", test_transact_failed);
g_test_add_func(TEST_PREFIX "transact_status", test_transact_status);
g_test_add_func(TEST_PREFIX "transact_custom", test_transact_custom);
g_test_add_func(TEST_PREFIX "transact_custom2", test_transact_custom2);
g_test_add_func(TEST_PREFIX "transact_cancel", test_transact_cancel);
g_test_add_func(TEST_PREFIX "transact_cancel2", test_transact_cancel2);
g_test_add_func(TEST_PREFIX "transact_incoming", test_transact_incoming);
g_test_add_func(TEST_PREFIX "transact_status_reply",
test_transact_status_reply);
test_init(&test_opt, argc, argv);
return g_test_run();
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,5 @@
# -*- Mode: makefile-gmake -*-
EXE = unit_local_object
include ../common/Makefile

View File

@@ -0,0 +1,648 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Contact: 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 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_binder.h"
#include "gbinder_buffer_p.h"
#include "gbinder_driver.h"
#include "gbinder_ipc.h"
#include "gbinder_local_object_p.h"
#include "gbinder_local_reply_p.h"
#include "gbinder_object_registry.h"
#include "gbinder_output_data.h"
#include "gbinder_reader_p.h"
#include "gbinder_remote_request_p.h"
#include "gbinder_rpc_protocol.h"
#include <gutil_intarray.h>
#include <gutil_strv.h>
#include <gutil_log.h>
#include <errno.h>
static TestOpt test_opt;
/* android.hidl.base@1.0::IBase */
#define TEST_BASE_INTERFACE_BYTES \
'a', 'n', 'd', 'r', 'o', 'i', 'd', '.', \
'h', 'i', 'd', 'l', '.', 'b', 'a', 's', \
'e', '@', '1', '.', '0', ':', ':', 'I', \
'B', 'a', 's', 'e'
#define TEST_BASE_INTERFACE_HEADER_BYTES \
TEST_BASE_INTERFACE_BYTES, 0x00, 0x00, 0x00, 0x00
static const char base_interface[] = { TEST_BASE_INTERFACE_BYTES, 0x00 };
static
void
test_reader_data_init_for_reply(
GBinderReaderData* data,
GBinderLocalObject* obj,
GBinderLocalReply* reply)
{
GBinderIpc* ipc = obj->ipc;
GBinderOutputData* out = gbinder_local_reply_data(reply);
GUtilIntArray* offsets = gbinder_output_data_offsets(out);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderBuffer* buf = gbinder_buffer_new(ipc->driver,
g_memdup(out->bytes->data, out->bytes->len), out->bytes->len);
memset(data, 0, sizeof(*data));
data->buffer = buf;
data->reg = gbinder_object_registry_ref(reg);
g_assert(!gbinder_object_registry_get_local(reg, NULL));
g_assert(gbinder_object_registry_get_local(reg, obj) == obj);
gbinder_local_object_unref(obj); /* ref added by the above call */
if (offsets && offsets->count > 0) {
guint i;
data->objects = g_new(void*, offsets->count + 1);
for (i = 0; i < offsets->count; i++) {
data->objects[i] = (guint8*)buf->data + offsets->data[i];
}
data->objects[i] = NULL;
}
}
static
void
test_reader_data_cleanup(
GBinderReaderData* data)
{
gbinder_object_registry_unref(data->reg);
gbinder_buffer_free(data->buffer);
g_free(data->objects);
}
/*==========================================================================*
* null
*==========================================================================*/
static
void
test_null(
void)
{
int status = 0;
g_assert(!gbinder_local_object_new(NULL, NULL, NULL, NULL));
g_assert(!gbinder_local_object_ref(NULL));
gbinder_local_object_unref(NULL);
gbinder_local_object_drop(NULL);
g_assert(!gbinder_local_object_new_reply(NULL));
g_assert(!gbinder_local_object_add_weak_refs_changed_handler(NULL,
NULL, NULL));
g_assert(!gbinder_local_object_add_strong_refs_changed_handler(NULL,
NULL, NULL));
gbinder_local_object_remove_handler(NULL, 0);
g_assert(gbinder_local_object_can_handle_transaction(NULL, NULL, 0) ==
GBINDER_LOCAL_TRANSACTION_NOT_SUPPORTED);
g_assert(!gbinder_local_object_handle_transaction(NULL, NULL, 0, 0, NULL));
g_assert(!gbinder_local_object_handle_transaction(NULL, NULL, 0, 0,
&status));
g_assert(!gbinder_local_object_handle_looper_transaction(NULL, NULL, 0, 0,
NULL));
g_assert(!gbinder_local_object_handle_looper_transaction(NULL, NULL, 0, 0,
&status));
g_assert(status == (-EBADMSG));
g_assert(!gbinder_ipc_transact_custom(NULL, NULL, NULL, NULL, NULL));
gbinder_local_object_handle_increfs(NULL);
gbinder_local_object_handle_decrefs(NULL);
gbinder_local_object_handle_acquire(NULL);
gbinder_local_object_handle_release(NULL);
}
/*==========================================================================*
* basic
*==========================================================================*/
static
void
test_basic(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderLocalObject* foo;
GBinderLocalObject* bar;
/* ipc is not a local object */
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);
/* But ipc is still not a local object! */
g_assert(!gbinder_object_registry_get_local(reg, ipc));
gbinder_ipc_unref(ipc);
g_assert(foo);
g_assert(!gbinder_local_object_add_weak_refs_changed_handler(foo,
NULL, NULL));
g_assert(!gbinder_local_object_add_strong_refs_changed_handler(foo,
NULL, NULL));
gbinder_local_object_remove_handler(foo, 0);
g_assert(gbinder_local_object_can_handle_transaction(foo,
base_interface, -1) == GBINDER_LOCAL_TRANSACTION_NOT_SUPPORTED);
gbinder_local_object_handle_increfs(foo);
gbinder_local_object_handle_decrefs(foo);
gbinder_local_object_handle_acquire(foo);
gbinder_local_object_handle_release(foo);
gbinder_local_object_unref(foo);
g_assert(bar);
g_assert(gbinder_local_object_ref(bar) == bar);
gbinder_local_object_drop(bar);
gbinder_local_object_unref(bar);
}
/*==========================================================================*
* get_descriptor
*==========================================================================*/
static
void
test_get_descriptor(
void)
{
static const guint8 req_data [] = {
TEST_BASE_INTERFACE_HEADER_BYTES
};
int status = INT_MAX;
const char* dev = GBINDER_DEFAULT_HWBINDER;
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderRemoteRequest* req = gbinder_remote_request_new
(gbinder_ipc_object_registry(ipc), prot);
GBinderLocalObject* obj =
gbinder_ipc_new_local_object(ipc, NULL, NULL, NULL);
GBinderLocalReply* reply;
gbinder_remote_request_set_data(req, 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));
g_assert(gbinder_local_object_can_handle_transaction(obj, base_interface,
HIDL_GET_DESCRIPTOR_TRANSACTION) == GBINDER_LOCAL_TRANSACTION_LOOPER);
/* If can_handle_transaction() returns TRANSACTION_LOOPER then it must be
* handled by handle_looper_transaction() */
g_assert(!gbinder_local_object_handle_transaction(obj, req,
HIDL_GET_DESCRIPTOR_TRANSACTION, 0, &status));
g_assert(status == (-EBADMSG));
reply = gbinder_local_object_handle_looper_transaction(obj, req,
HIDL_GET_DESCRIPTOR_TRANSACTION, 0, &status);
g_assert(reply);
g_assert(status == GBINDER_STATUS_OK);
/* Unsupported transaction */
g_assert(!gbinder_local_object_handle_looper_transaction
(obj, req, -1, 0, NULL));
g_assert(!gbinder_local_object_handle_looper_transaction
(obj, req, -1, 0, &status));
g_assert(status == (-EBADMSG));
g_assert(!gbinder_local_object_handle_transaction(obj, req, -1, 0, NULL));
g_assert(!gbinder_local_object_handle_transaction(obj, req, -1, 0,
&status));
g_assert(status == (-EBADMSG));
gbinder_ipc_unref(ipc);
gbinder_local_object_unref(obj);
gbinder_local_reply_unref(reply);
gbinder_remote_request_unref(req);
}
/*==========================================================================*
* descriptor_chain
*==========================================================================*/
static
void
test_descriptor_chain(
void)
{
static const guint8 req_data [] = {
TEST_BASE_INTERFACE_HEADER_BYTES
};
int status = INT_MAX;
const char* dev = GBINDER_DEFAULT_HWBINDER;
const GBinderRpcProtocol* prot = gbinder_rpc_protocol_for_device(dev);
GBinderIpc* ipc = gbinder_ipc_new(dev);
GBinderRemoteRequest* req = gbinder_remote_request_new
(gbinder_ipc_object_registry(ipc), prot);
GBinderLocalObject* obj =
gbinder_ipc_new_local_object(ipc, NULL, NULL, NULL);
GBinderLocalReply* reply;
gbinder_remote_request_set_data(req, 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));
g_assert(gbinder_local_object_can_handle_transaction(obj, base_interface,
HIDL_DESCRIPTOR_CHAIN_TRANSACTION) == GBINDER_LOCAL_TRANSACTION_LOOPER);
/* If can_handle_transaction() returns TRANSACTION_LOOPER then it must be
* handled by handle_looper_transaction() */
g_assert(!gbinder_local_object_handle_transaction(obj, req,
HIDL_DESCRIPTOR_CHAIN_TRANSACTION, 0, &status));
g_assert(status == (-EBADMSG));
reply = gbinder_local_object_handle_looper_transaction(obj, req,
HIDL_DESCRIPTOR_CHAIN_TRANSACTION, 0, &status);
g_assert(reply);
g_assert(status == GBINDER_STATUS_OK);
gbinder_ipc_unref(ipc);
gbinder_local_object_unref(obj);
gbinder_local_reply_unref(reply);
gbinder_remote_request_unref(req);
}
/*==========================================================================*
* custom_call
*==========================================================================*/
#define CUSTOM_TRANSACTION (GBINDER_FIRST_CALL_TRANSACTION + 1)
#define CUSTOM_INTERFACE_BYTES 'f', 'o', 'o'
#define CUSTOM_INTERFACE_HEADER_BYTES CUSTOM_INTERFACE_BYTES, 0x00
static const char custom_iface[] = { CUSTOM_INTERFACE_BYTES, 0x00 };
static
GBinderLocalReply*
test_custom_iface_handler(
GBinderLocalObject* obj,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status,
void* user_data)
{
int* count = user_data;
g_assert(!flags);
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), custom_iface));
g_assert(code == CUSTOM_TRANSACTION);
*status = GBINDER_STATUS_OK;
(*count)++;
return gbinder_local_object_new_reply(obj);
}
static
void
test_custom_iface(
void)
{
static const guint8 req_data [] = { CUSTOM_INTERFACE_HEADER_BYTES };
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);
GBinderRemoteRequest* req = gbinder_remote_request_new
(gbinder_ipc_object_registry(ipc), prot);
GBinderLocalObject* obj = gbinder_ipc_new_local_object(ipc, custom_iface,
test_custom_iface_handler, &count);
GBinderLocalReply* reply;
GBinderReaderData reader_data;
GBinderReader reader;
char** strv;
char* str;
gbinder_remote_request_set_data(req, gbinder_buffer_new(ipc->driver,
g_memdup(req_data, sizeof(req_data)), sizeof(req_data)), NULL);
g_assert(gbinder_local_object_can_handle_transaction(obj, base_interface,
HIDL_DESCRIPTOR_CHAIN_TRANSACTION) == GBINDER_LOCAL_TRANSACTION_LOOPER);
g_assert(gbinder_local_object_can_handle_transaction(obj, custom_iface,
HIDL_DESCRIPTOR_CHAIN_TRANSACTION) ==
GBINDER_LOCAL_TRANSACTION_SUPPORTED);
g_assert(gbinder_local_object_can_handle_transaction(obj, custom_iface,
CUSTOM_TRANSACTION) == GBINDER_LOCAL_TRANSACTION_SUPPORTED);
/* This returns the custom interface */
reply = gbinder_local_object_handle_looper_transaction(obj, req,
HIDL_GET_DESCRIPTOR_TRANSACTION, 0, &status);
g_assert(reply);
g_assert(status == GBINDER_STATUS_OK);
/* Parse the reply and check the interface */
test_reader_data_init_for_reply(&reader_data, obj, reply);
gbinder_reader_init(&reader, &reader_data, 0, reader_data.buffer->size);
g_assert(gbinder_reader_read_int32(&reader, &status));
g_assert(status == GBINDER_STATUS_OK);
str = gbinder_reader_read_hidl_string(&reader);
g_assert(!g_strcmp0(str, custom_iface));
g_free(str);
test_reader_data_cleanup(&reader_data);
gbinder_local_reply_unref(reply);
/* And this returns two interfaces */
reply = gbinder_local_object_handle_looper_transaction(obj, req,
HIDL_DESCRIPTOR_CHAIN_TRANSACTION, 0, &status);
g_assert(reply);
g_assert(status == GBINDER_STATUS_OK);
/* Parse the reply and check the interface */
test_reader_data_init_for_reply(&reader_data, obj, reply);
gbinder_reader_init(&reader, &reader_data, 0, reader_data.buffer->size);
g_assert(gbinder_reader_read_int32(&reader, &status));
g_assert(status == GBINDER_STATUS_OK);
strv = gbinder_reader_read_hidl_string_vec(&reader);
g_assert(gutil_strv_length(strv) == 2);
g_assert(!g_strcmp0(strv[0], custom_iface));
g_assert(!g_strcmp0(strv[1], base_interface));
g_strfreev(strv);
test_reader_data_cleanup(&reader_data);
gbinder_local_reply_unref(reply);
/* Execute the custom transaction */
reply = gbinder_local_object_handle_transaction(obj, req,
CUSTOM_TRANSACTION, 0, &status);
g_assert(reply);
g_assert(status == GBINDER_STATUS_OK);
g_assert(count == 1);
gbinder_ipc_unref(ipc);
gbinder_local_object_unref(obj);
gbinder_local_reply_unref(reply);
gbinder_remote_request_unref(req);
}
/*==========================================================================*
* reply_status
*==========================================================================*/
#define EXPECTED_STATUS (424242)
static
GBinderLocalReply*
test_reply_status_handler(
GBinderLocalObject* obj,
GBinderRemoteRequest* req,
guint code,
guint flags,
int* status,
void* user_data)
{
int* count = user_data;
g_assert(!flags);
g_assert(!g_strcmp0(gbinder_remote_request_interface(req), custom_iface));
g_assert(code == CUSTOM_TRANSACTION);
*status = EXPECTED_STATUS;
(*count)++;
return NULL;
}
static
void
test_reply_status(
void)
{
static const guint8 req_data [] = { CUSTOM_INTERFACE_HEADER_BYTES };
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);
GBinderObjectRegistry* reg = gbinder_ipc_object_registry(ipc);
GBinderRemoteRequest* req = gbinder_remote_request_new(reg, prot);
GBinderLocalObject* obj = gbinder_ipc_new_local_object(ipc, custom_iface,
test_reply_status_handler, &count);
gbinder_remote_request_set_data(req, gbinder_buffer_new(ipc->driver,
g_memdup(req_data, sizeof(req_data)), sizeof(req_data)), NULL);
/* Execute the custom transaction */
g_assert(!gbinder_local_object_handle_transaction(obj, req,
CUSTOM_TRANSACTION, 0, &status));
g_assert(status == EXPECTED_STATUS);
g_assert(count == 1);
gbinder_ipc_unref(ipc);
gbinder_local_object_unref(obj);
gbinder_remote_request_unref(req);
}
/*==========================================================================*
* increfs
*==========================================================================*/
static
void
test_increfs_cb(
GBinderLocalObject* obj,
void* user_data)
{
GVERBOSE_("%d", obj->weak_refs);
g_assert(obj->weak_refs == 1);
test_quit_later((GMainLoop*)user_data);
}
static
void
test_increfs(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderLocalObject* obj = gbinder_ipc_new_local_object
(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_weak_refs_changed_handler(obj,
test_increfs_cb, loop);
/* ipc is not an object, will be ignored */
test_binder_br_increfs(fd, ipc);
test_binder_br_increfs(fd, obj);
test_run(&test_opt, loop);
g_assert(obj->weak_refs == 1);
gbinder_local_object_remove_handler(obj, id);
gbinder_local_object_unref(obj);
gbinder_ipc_unref(ipc);
g_main_loop_unref(loop);
}
/*==========================================================================*
* decrefs
*==========================================================================*/
static
void
test_decrefs_cb(
GBinderLocalObject* obj,
void* user_data)
{
GVERBOSE_("%d", obj->weak_refs);
if (!obj->weak_refs) {
test_quit_later((GMainLoop*)user_data);
}
}
static
void
test_decrefs(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderLocalObject* obj = gbinder_ipc_new_local_object
(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_weak_refs_changed_handler(obj,
test_decrefs_cb, loop);
/* ipc is not an object, will be ignored */
test_binder_br_decrefs(fd, ipc);
test_binder_br_increfs(fd, obj);
test_binder_br_decrefs(fd, obj);
test_run(&test_opt, loop);
g_assert(obj->weak_refs == 0);
gbinder_local_object_remove_handler(obj, id);
gbinder_local_object_unref(obj);
gbinder_ipc_unref(ipc);
g_main_loop_unref(loop);
}
/*==========================================================================*
* acquire
*==========================================================================*/
static
void
test_acquire_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_acquire(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderLocalObject* obj = gbinder_ipc_new_local_object
(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_acquire_cb, loop);
/* ipc is not an object, will be ignored */
test_binder_br_acquire(fd, ipc);
test_binder_br_acquire(fd, obj);
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_unref(ipc);
g_main_loop_unref(loop);
}
/*==========================================================================*
* release
*==========================================================================*/
static
void
test_release_cb(
GBinderLocalObject* obj,
void* user_data)
{
GVERBOSE_("%d", obj->strong_refs);
if (!obj->strong_refs) {
test_quit_later((GMainLoop*)user_data);
}
}
static
void
test_release(
void)
{
GBinderIpc* ipc = gbinder_ipc_new(GBINDER_DEFAULT_BINDER);
GBinderLocalObject* obj = gbinder_ipc_new_local_object
(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_release_cb, loop);
/* ipc is not an object, will be ignored */
test_binder_br_release(fd, ipc);
test_binder_br_acquire(fd, obj);
test_binder_br_release(fd, obj);
test_run(&test_opt, loop);
g_assert(obj->strong_refs == 0);
gbinder_local_object_remove_handler(obj, id);
gbinder_local_object_unref(obj);
gbinder_ipc_unref(ipc);
g_main_loop_unref(loop);
}
/*==========================================================================*
* Common
*==========================================================================*/
#define TEST_PREFIX "/local_object/"
int main(int argc, char* argv[])
{
g_test_init(&argc, &argv, NULL);
g_test_add_func(TEST_PREFIX "null", test_null);
g_test_add_func(TEST_PREFIX "basic", test_basic);
g_test_add_func(TEST_PREFIX "get_descriptor", test_get_descriptor);
g_test_add_func(TEST_PREFIX "descriptor_chain", test_descriptor_chain);
g_test_add_func(TEST_PREFIX "custom_iface", test_custom_iface);
g_test_add_func(TEST_PREFIX "reply_status", test_reply_status);
g_test_add_func(TEST_PREFIX "increfs", test_increfs);
g_test_add_func(TEST_PREFIX "decrefs", test_decrefs);
g_test_add_func(TEST_PREFIX "acquire", test_acquire);
g_test_add_func(TEST_PREFIX "release", test_release);
test_init(&test_opt, argc, argv);
return g_test_run();
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

View File

@@ -0,0 +1,5 @@
# -*- Mode: makefile-gmake -*-
EXE = unit_local_reply
include ../common/Makefile

View File

@@ -0,0 +1,382 @@
/*
* Copyright (C) 2018 Jolla Ltd.
* Contact: 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 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test_common.h"
#include "gbinder_local_object.h"
#include "gbinder_local_reply_p.h"
#include "gbinder_output_data.h"
#include "gbinder_writer.h"
#include "gbinder_io.h"
#include "gbinder_ipc.h"
#include <gutil_intarray.h>
static TestOpt test_opt;
#define BUFFER_OBJECT_SIZE_32 (24)
#define BUFFER_OBJECT_SIZE_64 (GBINDER_MAX_BUFFER_OBJECT_SIZE)
#define BINDER_OBJECT_SIZE_32 (16)
#define BINDER_OBJECT_SIZE_64 (GBINDER_MAX_BINDER_OBJECT_SIZE)
static
void
test_int_inc(
void* data)
{
(*((int*)data))++;
}
/*==========================================================================*
* null
*==========================================================================*/
static
void
test_null(
void)
{
GBinderWriter writer;
int count = 0;
g_assert(!gbinder_local_reply_new(NULL));
g_assert(!gbinder_local_reply_ref(NULL));
gbinder_local_reply_unref(NULL);
gbinder_local_reply_init_writer(NULL, NULL);
gbinder_local_reply_init_writer(NULL, &writer);
g_assert(!gbinder_local_reply_data(NULL));
gbinder_local_reply_cleanup(NULL, NULL, &count);
gbinder_local_reply_cleanup(NULL, test_int_inc, &count);
g_assert(count == 1);
g_assert(!gbinder_local_reply_append_int32(NULL, 0));
g_assert(!gbinder_local_reply_append_int64(NULL, 0));
g_assert(!gbinder_local_reply_append_string8(NULL, NULL));
g_assert(!gbinder_local_reply_append_string16(NULL, NULL));
g_assert(!gbinder_local_reply_append_hidl_string(NULL, NULL));
g_assert(!gbinder_local_reply_append_hidl_string_vec(NULL, NULL, 0));
g_assert(!gbinder_local_reply_append_local_object(NULL, NULL));
g_assert(!gbinder_local_reply_append_remote_object(NULL, NULL));
}
/*==========================================================================*
* cleanup
*==========================================================================*/
static
void
test_cleanup(
void)
{
GBinderLocalReply* reply = gbinder_local_reply_new(&gbinder_io_32);
int count = 0;
gbinder_local_reply_cleanup(reply, NULL, &count);
gbinder_local_reply_cleanup(reply, test_int_inc, &count);
gbinder_local_reply_cleanup(reply, test_int_inc, &count);
g_assert(!count);
gbinder_local_reply_unref(reply);
g_assert(count == 2);
}
/*==========================================================================*
* int32
*==========================================================================*/
static
void
test_int32(
void)
{
const guint32 value = 1234567;
GBinderLocalReply* reply = gbinder_local_reply_new(&gbinder_io_32);
GBinderOutputData* data;
GBinderWriter writer;
gbinder_local_reply_append_int32(reply, value);
data = gbinder_local_reply_data(reply);
g_assert(!gbinder_output_data_offsets(data));
g_assert(!gbinder_output_data_buffers_size(data));
g_assert(data->bytes->len == sizeof(value));
g_assert(!memcmp(data->bytes->data, &value, data->bytes->len));
g_assert(gbinder_local_reply_ref(reply) == reply);
gbinder_local_reply_unref(reply);
gbinder_local_reply_unref(reply);
/* Same with writer */
reply = gbinder_local_reply_new(&gbinder_io_32);
gbinder_local_reply_init_writer(reply, &writer);
gbinder_writer_append_int32(&writer, value);
data = gbinder_local_reply_data(reply);
g_assert(!gbinder_output_data_offsets(data));
g_assert(!gbinder_output_data_buffers_size(data));
g_assert(data->bytes->len == sizeof(value));
g_assert(!memcmp(data->bytes->data, &value, data->bytes->len));
gbinder_local_reply_unref(reply);
}
/*==========================================================================*
* int64
*==========================================================================*/
static
void
test_int64(
void)
{
const guint64 value = 123456789;
GBinderLocalReply* reply = gbinder_local_reply_new(&gbinder_io_32);
GBinderOutputData* data;
gbinder_local_reply_append_int64(reply, value);
data = gbinder_local_reply_data(reply);
g_assert(!gbinder_output_data_offsets(data));
g_assert(!gbinder_output_data_buffers_size(data));
g_assert(data->bytes->len == sizeof(value));
g_assert(!memcmp(data->bytes->data, &value, data->bytes->len));
gbinder_local_reply_unref(reply);
}
/*==========================================================================*
* string8
*==========================================================================*/
static
void
test_string8(
void)
{
/* The size of the string gets aligned at 4-byte boundary */
static const char input[] = "test";
static const guint8 output[] = { 't', 'e', 's', 't', 0, 0, 0, 0 };
GBinderLocalReply* reply = gbinder_local_reply_new(&gbinder_io_32);
GBinderOutputData* data;
gbinder_local_reply_append_string8(reply, input);
data = gbinder_local_reply_data(reply);
g_assert(!gbinder_output_data_offsets(data));
g_assert(!gbinder_output_data_buffers_size(data));
g_assert(data->bytes->len == sizeof(output));
g_assert(!memcmp(data->bytes->data, output, data->bytes->len));
gbinder_local_reply_unref(reply);
/* NULL string doesn't get encoded at all (should it be?) */
reply = gbinder_local_reply_new(&gbinder_io_32);
gbinder_local_reply_append_string8(reply, NULL);
data = gbinder_local_reply_data(reply);
g_assert(!gbinder_output_data_offsets(data));
g_assert(!gbinder_output_data_buffers_size(data));
g_assert(!data->bytes->len);
gbinder_local_reply_unref(reply);
}
/*==========================================================================*
* string16
*==========================================================================*/
static
void
test_string16(
void)
{
static const const char input[] = "x";
static const guint8 output[] = {
TEST_INT32_BYTES(1),
TEST_INT16_BYTES('x'), 0x00, 0x00
};
const gint32 null_output = -1;
GBinderLocalReply* reply = gbinder_local_reply_new(&gbinder_io_32);
GBinderOutputData* data;
gbinder_local_reply_append_string16(reply, input);
data = gbinder_local_reply_data(reply);
g_assert(!gbinder_output_data_offsets(data));
g_assert(!gbinder_output_data_buffers_size(data));
g_assert(data->bytes->len == sizeof(output));
g_assert(!memcmp(data->bytes->data, output, data->bytes->len));
gbinder_local_reply_unref(reply);
/* NULL string gets encoded as -1 */
reply = gbinder_local_reply_new(&gbinder_io_32);
gbinder_local_reply_append_string16(reply, NULL);
data = gbinder_local_reply_data(reply);
g_assert(!gbinder_output_data_offsets(data));
g_assert(!gbinder_output_data_buffers_size(data));
g_assert(data->bytes->len == sizeof(null_output));
g_assert(!memcmp(data->bytes->data, &null_output, data->bytes->len));
gbinder_local_reply_unref(reply);
}
/*==========================================================================*
* hidl_string
*==========================================================================*/
static
void
test_hidl_string(
void)
{
GBinderLocalReply* reply = gbinder_local_reply_new(&gbinder_io_32);
GBinderOutputData* data;
GUtilIntArray* offsets;
gbinder_local_reply_append_hidl_string(reply, NULL);
data = gbinder_local_reply_data(reply);
offsets = gbinder_output_data_offsets(data);
g_assert(offsets->count == 1);
g_assert(offsets->data[0] == 0);
g_assert(gbinder_output_data_buffers_size(data) == sizeof(HidlString));
g_assert(data->bytes->len == BUFFER_OBJECT_SIZE_32);
gbinder_local_reply_unref(reply);
}
/*==========================================================================*
* hidl_string_vec
*==========================================================================*/
static
void
test_hidl_string_vec(
void)
{
GBinderLocalReply* reply = gbinder_local_reply_new(&gbinder_io_32);
GBinderOutputData* data;
GUtilIntArray* offsets;
gbinder_local_reply_append_hidl_string_vec(reply, NULL, 0);
data = gbinder_local_reply_data(reply);
offsets = gbinder_output_data_offsets(data);
g_assert(offsets->count == 1);
g_assert(offsets->data[0] == 0);
g_assert(gbinder_output_data_buffers_size(data) == sizeof(HidlVec));
g_assert(data->bytes->len == BUFFER_OBJECT_SIZE_32);
gbinder_local_reply_unref(reply);
}
/*==========================================================================*
* local_object
*==========================================================================*/
static
void
test_local_object(
void)
{
GBinderLocalReply* reply;
GBinderOutputData* data;
GUtilIntArray* offsets;
GBinderIpc* ipc = gbinder_ipc_new(NULL);
GBinderLocalObject* obj =
gbinder_ipc_new_local_object(ipc, "foo", NULL, NULL);
/* Append a real object (64-bit I/O is used by test_binder.c) */
reply = gbinder_local_object_new_reply(obj);
gbinder_local_reply_append_local_object(reply, obj);
data = gbinder_local_reply_data(reply);
offsets = gbinder_output_data_offsets(data);
g_assert(offsets);
g_assert(offsets->count == 1);
g_assert(offsets->data[0] == 0);
g_assert(!gbinder_output_data_buffers_size(data));
g_assert(data->bytes->len == BINDER_OBJECT_SIZE_64);
gbinder_local_reply_unref(reply);
/* Append NULL object (with 32-bit I/O module) */
reply = gbinder_local_reply_new(&gbinder_io_32);
gbinder_local_reply_append_local_object(reply, NULL);
data = gbinder_local_reply_data(reply);
offsets = gbinder_output_data_offsets(data);
g_assert(offsets);
g_assert(offsets->count == 1);
g_assert(offsets->data[0] == 0);
g_assert(!gbinder_output_data_buffers_size(data));
g_assert(data->bytes->len == BINDER_OBJECT_SIZE_32);
gbinder_local_reply_unref(reply);
gbinder_ipc_unref(ipc);
}
/*==========================================================================*
* remote_object
*==========================================================================*/
static
void
test_remote_object(
void)
{
GBinderLocalReply* reply = gbinder_local_reply_new(&gbinder_io_32);
GBinderOutputData* data;
GUtilIntArray* offsets;
gbinder_local_reply_append_remote_object(reply, NULL);
data = gbinder_local_reply_data(reply);
offsets = gbinder_output_data_offsets(data);
g_assert(offsets);
g_assert(offsets->count == 1);
g_assert(offsets->data[0] == 0);
g_assert(!gbinder_output_data_buffers_size(data));
g_assert(data->bytes->len == BINDER_OBJECT_SIZE_32);
gbinder_local_reply_unref(reply);
}
/*==========================================================================*
* Common
*==========================================================================*/
#define TEST_PREFIX "/local_reply/"
int main(int argc, char* argv[])
{
g_test_init(&argc, &argv, NULL);
g_test_add_func(TEST_PREFIX "null", test_null);
g_test_add_func(TEST_PREFIX "cleanup", test_cleanup);
g_test_add_func(TEST_PREFIX "int32", test_int32);
g_test_add_func(TEST_PREFIX "int64", test_int64);
g_test_add_func(TEST_PREFIX "string8", test_string8);
g_test_add_func(TEST_PREFIX "string16", test_string16);
g_test_add_func(TEST_PREFIX "hidl_string", test_hidl_string);
g_test_add_func(TEST_PREFIX "hidl_string_vec", test_hidl_string_vec);
g_test_add_func(TEST_PREFIX "local_object", test_local_object);
g_test_add_func(TEST_PREFIX "remote_object", test_remote_object);
test_init(&test_opt, argc, argv);
return g_test_run();
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/

Some files were not shown because too many files have changed in this diff Show More