From 771444a8acdcb59cd9ddc24b6d9e702df6931493 Mon Sep 17 00:00:00 2001 From: gary-wzl77 Date: Thu, 25 Nov 2021 10:25:11 +0800 Subject: [PATCH 1/3] [gbinder] Add "aidl4" variant of service manager Introduce "aidl4" variant of service manager to adapt the change to service related protocol for Android 12. From Android 12, when reading nullable strong binder, the format of the `stability` field passed on the wire was changed and evolved to `struct Category`, which consists of the following members with 4 bytes long. ``` struct Category { uint8_t version; uint8_t reserved[2]; Level level; <- bitmask of Stability::Level } ``` Please check the following link for details: https://cs.android.com/android/platform/superproject/+/android-12.0.0_r3:frameworks/native/libs/binder/include/binder/Stability.h;l=140 To honor the change on AOSP side for Android 12, we need to adapt the protocol change in Service Manager. --- Makefile | 1 + src/gbinder_servicemanager.c | 3 +- src/gbinder_servicemanager_aidl.h | 7 + src/gbinder_servicemanager_aidl3.c | 53 +- src/gbinder_servicemanager_aidl4.c | 110 ++++ src/gbinder_servicemanager_aidl_p.h | 61 +++ src/gbinder_servicemanager_p.h | 1 + unit/Makefile | 1 + unit/coverage/run | 1 + .../unit_servicemanager/unit_servicemanager.c | 8 + .../unit_servicemanager_aidl.c | 8 + unit/unit_servicemanager_aidl4/Makefile | 5 + .../unit_servicemanager_aidl4.c | 488 ++++++++++++++++++ .../unit_servicemanager_hidl.c | 8 + unit/unit_servicename/unit_servicename.c | 6 + unit/unit_servicepoll/unit_servicepoll.c | 6 + 16 files changed, 735 insertions(+), 32 deletions(-) create mode 100644 src/gbinder_servicemanager_aidl4.c create mode 100644 src/gbinder_servicemanager_aidl_p.h create mode 100644 unit/unit_servicemanager_aidl4/Makefile create mode 100644 unit/unit_servicemanager_aidl4/unit_servicemanager_aidl4.c diff --git a/Makefile b/Makefile index bae841c..d001939 100644 --- a/Makefile +++ b/Makefile @@ -105,6 +105,7 @@ SRC += \ gbinder_servicemanager_aidl.c \ gbinder_servicemanager_aidl2.c \ gbinder_servicemanager_aidl3.c \ + gbinder_servicemanager_aidl4.c \ gbinder_servicemanager_hidl.c SRC += \ diff --git a/src/gbinder_servicemanager.c b/src/gbinder_servicemanager.c index c5ab815..0acc52b 100644 --- a/src/gbinder_servicemanager.c +++ b/src/gbinder_servicemanager.c @@ -83,11 +83,12 @@ static const GBinderServiceManagerType gbinder_servicemanager_types[] = { { "aidl", gbinder_servicemanager_aidl_get_type }, { "aidl2", gbinder_servicemanager_aidl2_get_type }, { "aidl3", gbinder_servicemanager_aidl3_get_type }, + { "aidl4", gbinder_servicemanager_aidl4_get_type }, { "hidl", gbinder_servicemanager_hidl_get_type } }; #define SERVICEMANAGER_TYPE_AIDL (gbinder_servicemanager_types + 0) -#define SERVICEMANAGER_TYPE_HIDL (gbinder_servicemanager_types + 3) +#define SERVICEMANAGER_TYPE_HIDL (gbinder_servicemanager_types + 4) #define SERVICEMANAGER_TYPE_DEFAULT SERVICEMANAGER_TYPE_AIDL static GHashTable* gbinder_servicemanager_map = NULL; diff --git a/src/gbinder_servicemanager_aidl.h b/src/gbinder_servicemanager_aidl.h index c5b7c4f..0c48243 100644 --- a/src/gbinder_servicemanager_aidl.h +++ b/src/gbinder_servicemanager_aidl.h @@ -66,6 +66,13 @@ enum gbinder_servicemanager_aidl_calls { LIST_SERVICES_TRANSACTION }; +enum gbinder_stability_level { + UNDECLARED = 0, + VENDOR = 0b000011, + SYSTEM = 0b001100, + VINTF = 0b111111 +}; + #define DUMP_FLAG_PRIORITY_DEFAULT (0x08) #define DUMP_FLAG_PRIORITY_ALL (0x0f) diff --git a/src/gbinder_servicemanager_aidl3.c b/src/gbinder_servicemanager_aidl3.c index 82038fc..31e26b3 100644 --- a/src/gbinder_servicemanager_aidl3.c +++ b/src/gbinder_servicemanager_aidl3.c @@ -32,7 +32,7 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#include "gbinder_servicemanager_aidl.h" +#include "gbinder_servicemanager_aidl_p.h" #include "gbinder_client_p.h" #include "gbinder_reader_p.h" @@ -50,14 +50,6 @@ G_DEFINE_TYPE(GBinderServiceManagerAidl3, #define PARENT_CLASS gbinder_servicemanager_aidl3_parent_class -enum gbinder_stability_level { - UNDECLARED = 0, - VENDOR = 0b000011, - SYSTEM = 0b001100, - VINTF = 0b111111 -}; - -static GBinderRemoteObject* gbinder_servicemanager_aidl3_get_service( GBinderServiceManager* self, @@ -84,28 +76,6 @@ gbinder_servicemanager_aidl3_get_service( return obj; } -static -GBinderLocalRequest* -gbinder_servicemanager_aidl3_add_service_req( - GBinderClient* client, - const char* name, - GBinderLocalObject* obj) -{ - GBinderLocalRequest* req = gbinder_client_new_request(client); - - gbinder_local_request_append_string16(req, name); - gbinder_local_request_append_local_object(req, obj); - /* - * Starting from Android 11, to add a service, Android framework requires - * an additional field `stability` when reading a strong binder. - */ - gbinder_local_request_append_int32(req, SYSTEM); - gbinder_local_request_append_int32(req, 0); - gbinder_local_request_append_int32(req, DUMP_FLAG_PRIORITY_DEFAULT); - return req; -} - -static char** gbinder_servicemanager_aidl3_list( GBinderServiceManager* manager, @@ -148,6 +118,27 @@ gbinder_servicemanager_aidl3_list( return (char**)g_ptr_array_free(list, FALSE); } +static +GBinderLocalRequest* +gbinder_servicemanager_aidl3_add_service_req( + GBinderClient* client, + const char* name, + GBinderLocalObject* obj) +{ + GBinderLocalRequest* req = gbinder_client_new_request(client); + + gbinder_local_request_append_string16(req, name); + gbinder_local_request_append_local_object(req, obj); + /* + * Starting from Android 11, to add a service, Android framework requires + * an additional field `stability` when reading a strong binder. + */ + gbinder_local_request_append_int32(req, SYSTEM); + gbinder_local_request_append_int32(req, 0); + gbinder_local_request_append_int32(req, DUMP_FLAG_PRIORITY_DEFAULT); + return req; +} + static void gbinder_servicemanager_aidl3_init( diff --git a/src/gbinder_servicemanager_aidl4.c b/src/gbinder_servicemanager_aidl4.c new file mode 100644 index 0000000..e33e761 --- /dev/null +++ b/src/gbinder_servicemanager_aidl4.c @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2020 Jolla Ltd. + * Copyright (C) 2020 Slava Monich + * Copyright (C) 2021 Gary Wang + * Copyright (C) 2021 Madhushan Nishantha + * + * You may use this file under the terms of BSD license as follows: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "gbinder_servicemanager_aidl_p.h" +#include "gbinder_client_p.h" +#include "gbinder_reader_p.h" +#include "binder.h" + +#include +#include + +/* Variant of AIDL servicemanager appeared in Android 12 (API level 31) */ + +typedef GBinderServiceManagerAidl GBinderServiceManagerAidl4; +typedef GBinderServiceManagerAidlClass GBinderServiceManagerAidl4Class; + +G_DEFINE_TYPE(GBinderServiceManagerAidl4, + gbinder_servicemanager_aidl4, + GBINDER_TYPE_SERVICEMANAGER_AIDL) + +#define PARENT_CLASS gbinder_servicemanager_aidl4_parent_class + +#define BINDER_WIRE_FORMAT_VERSION (1) + +static +GBinderLocalRequest* +gbinder_servicemanager_aidl4_add_service_req( + GBinderClient* client, + const char* name, + GBinderLocalObject* obj) +{ + GBinderLocalRequest* req = gbinder_client_new_request(client); + + gbinder_local_request_append_string16(req, name); + gbinder_local_request_append_local_object(req, obj); + /* + * When reading nullable strong binder, from Android 12, the format of + * the `stability` field passed on the wire was changed and evolved to + * `struct Category`, which consists of the following members with 4 bytes long. + * + * struct Category { + * uint8_t version; + * uint8_t reserved[2]; + * Level level; <- bitmask of Stability::Level + * } + */ + gbinder_local_request_append_int32(req, B_PACK_CHARS(SYSTEM, 0, 0, BINDER_WIRE_FORMAT_VERSION)); + gbinder_local_request_append_int32(req, 0); + gbinder_local_request_append_int32(req, DUMP_FLAG_PRIORITY_DEFAULT); + + return req; +} + +static +void +gbinder_servicemanager_aidl4_init( + GBinderServiceManagerAidl* self) +{ +} + +static +void +gbinder_servicemanager_aidl4_class_init( + GBinderServiceManagerAidl4Class* cls) +{ + GBinderServiceManagerClass* manager = GBINDER_SERVICEMANAGER_CLASS(cls); + cls->add_service_req = gbinder_servicemanager_aidl4_add_service_req; + manager->list = gbinder_servicemanager_aidl3_list; + manager->get_service = gbinder_servicemanager_aidl3_get_service; +} + +/* + * Local Variables: + * mode: C + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ + diff --git a/src/gbinder_servicemanager_aidl_p.h b/src/gbinder_servicemanager_aidl_p.h new file mode 100644 index 0000000..6a00ac9 --- /dev/null +++ b/src/gbinder_servicemanager_aidl_p.h @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2018-2021 Jolla Ltd. + * Copyright (C) 2018-2021 Slava Monich + * Copyright (C) 2021 Gary Wang + * + * You may use this file under the terms of BSD license as follows: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GBINDER_SERVICEMANAGER_AIDL_PRIVATE_H +#define GBINDER_SERVICEMANAGER_AIDL_PRIVATE_H + +#include "gbinder_servicemanager_aidl.h" + +char** +gbinder_servicemanager_aidl3_list( + GBinderServiceManager* manager, + const GBinderIpcSyncApi* api) + GBINDER_INTERNAL; + +GBinderRemoteObject* +gbinder_servicemanager_aidl3_get_service( + GBinderServiceManager* manager, + const char* name, + int* status, + const GBinderIpcSyncApi* api) + GBINDER_INTERNAL; + +#endif /* GBINDER_SERVICEMANAGER_AIDL_PRIVATE_H */ + +/* + * Local Variables: + * mode: C + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/src/gbinder_servicemanager_p.h b/src/gbinder_servicemanager_p.h index 4b45836..8e02721 100644 --- a/src/gbinder_servicemanager_p.h +++ b/src/gbinder_servicemanager_p.h @@ -112,6 +112,7 @@ gbinder_servicemanager_exit( GType gbinder_servicemanager_aidl_get_type(void) GBINDER_INTERNAL; GType gbinder_servicemanager_aidl2_get_type(void) GBINDER_INTERNAL; GType gbinder_servicemanager_aidl3_get_type(void) GBINDER_INTERNAL; +GType gbinder_servicemanager_aidl4_get_type(void) GBINDER_INTERNAL; GType gbinder_servicemanager_hidl_get_type(void) GBINDER_INTERNAL; #endif /* GBINDER_SERVICEMANAGER_PRIVATE_H */ diff --git a/unit/Makefile b/unit/Makefile index b5ef2a3..7fab42b 100644 --- a/unit/Makefile +++ b/unit/Makefile @@ -25,6 +25,7 @@ all: @$(MAKE) -C unit_servicemanager_aidl $* @$(MAKE) -C unit_servicemanager_aidl2 $* @$(MAKE) -C unit_servicemanager_aidl3 $* + @$(MAKE) -C unit_servicemanager_aidl4 $* @$(MAKE) -C unit_servicemanager_hidl $* @$(MAKE) -C unit_servicename $* @$(MAKE) -C unit_servicepoll $* diff --git a/unit/coverage/run b/unit/coverage/run index ab20d0a..fe6ff60 100755 --- a/unit/coverage/run +++ b/unit/coverage/run @@ -27,6 +27,7 @@ unit_servicemanager \ unit_servicemanager_aidl \ unit_servicemanager_aidl2 \ unit_servicemanager_aidl3 \ +unit_servicemanager_aidl4 \ unit_servicemanager_hidl \ unit_servicename \ unit_servicepoll \ diff --git a/unit/unit_servicemanager/unit_servicemanager.c b/unit/unit_servicemanager/unit_servicemanager.c index bc8d1d8..4dda717 100644 --- a/unit/unit_servicemanager/unit_servicemanager.c +++ b/unit/unit_servicemanager/unit_servicemanager.c @@ -399,6 +399,14 @@ gbinder_servicemanager_aidl3_get_type() return 0; } +GType +gbinder_servicemanager_aidl4_get_type() +{ + /* Dummy function to avoid pulling in gbinder_servicemanager_aidl4 */ + g_assert_not_reached(); + return 0; +} + /*==========================================================================* * null *==========================================================================*/ diff --git a/unit/unit_servicemanager_aidl/unit_servicemanager_aidl.c b/unit/unit_servicemanager_aidl/unit_servicemanager_aidl.c index 556f230..2e8bd97 100644 --- a/unit/unit_servicemanager_aidl/unit_servicemanager_aidl.c +++ b/unit/unit_servicemanager_aidl/unit_servicemanager_aidl.c @@ -71,6 +71,14 @@ gbinder_servicemanager_aidl3_get_type() return 0; } +GType +gbinder_servicemanager_aidl4_get_type() +{ + /* Dummy function to avoid pulling in gbinder_servicemanager_aidl4 */ + g_assert_not_reached(); + return 0; +} + /*==========================================================================* * Test service manager *==========================================================================*/ diff --git a/unit/unit_servicemanager_aidl4/Makefile b/unit/unit_servicemanager_aidl4/Makefile new file mode 100644 index 0000000..d9f6d59 --- /dev/null +++ b/unit/unit_servicemanager_aidl4/Makefile @@ -0,0 +1,5 @@ +# -*- Mode: makefile-gmake -*- + +EXE = unit_servicemanager_aidl4 + +include ../common/Makefile diff --git a/unit/unit_servicemanager_aidl4/unit_servicemanager_aidl4.c b/unit/unit_servicemanager_aidl4/unit_servicemanager_aidl4.c new file mode 100644 index 0000000..a0e0464 --- /dev/null +++ b/unit/unit_servicemanager_aidl4/unit_servicemanager_aidl4.c @@ -0,0 +1,488 @@ +/* + * Copyright (C) 2020-2021 Jolla Ltd. + * Copyright (C) 2020-2021 Slava Monich + * + * You may use this file under the terms of BSD license as follows: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "test_binder.h" + +#include "gbinder_driver.h" +#include "gbinder_config.h" +#include "gbinder_ipc.h" +#include "gbinder_reader.h" +#include "gbinder_servicemanager_p.h" +#include "gbinder_rpc_protocol.h" +#include "gbinder_local_object_p.h" +#include "gbinder_local_reply.h" +#include "gbinder_remote_request.h" +#include "gbinder_remote_object.h" +#include "gbinder_writer.h" + +#include +#include + +static TestOpt test_opt; +static const char TMP_DIR_TEMPLATE[] = + "gbinder-test-servicemanager_aidl4-XXXXXX"; + +enum gbinder_stability_level { + UNDECLARED = 0, + VENDOR = 0b000011, + SYSTEM = 0b001100, + VINTF = 0b111111 +}; + +GType +gbinder_servicemanager_hidl_get_type() +{ + /* Dummy function to avoid pulling in gbinder_servicemanager_hidl */ + g_assert_not_reached(); + return 0; +} + +/*==========================================================================* + * Test service manager + *==========================================================================*/ + +#define SVCMGR_HANDLE (0) +static const char SVCMGR_IFACE[] = "android.os.IServiceManager"; +enum servicemanager_aidl_tx { + GET_SERVICE_TRANSACTION = GBINDER_FIRST_CALL_TRANSACTION, + CHECK_SERVICE_TRANSACTION, + ADD_SERVICE_TRANSACTION, + LIST_SERVICES_TRANSACTION +}; + +const char* const servicemanager_aidl_ifaces[] = { SVCMGR_IFACE, NULL }; + +typedef GBinderLocalObjectClass ServiceManagerAidl4Class; +typedef struct service_manager_aidl4 { + GBinderLocalObject parent; + GHashTable* objects; + gboolean handle_on_looper_thread; +} ServiceManagerAidl4; + +#define SERVICE_MANAGER_AIDL4_TYPE (service_manager_aidl4_get_type()) +#define SERVICE_MANAGER_AIDL4(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), \ + SERVICE_MANAGER_AIDL4_TYPE, ServiceManagerAidl4)) +G_DEFINE_TYPE(ServiceManagerAidl4, service_manager_aidl4, \ + GBINDER_TYPE_LOCAL_OBJECT) + +/* This is the format of stability passed on the wire. */ +typedef struct category { + /* + * This is the version of the wire protocol associated with the host + * process of a particular binder. As the wire protocol changes, if + * sending a transaction to a binder with an old version, the Parcel + * class must write parcels according to the version documented here. + */ + gint8 version; + gint8 reserved[2]; + gint8 level; /* bitmask of Stability::Level */ +} Category; + +static +GBinderLocalReply* +servicemanager_aidl4_handler( + GBinderLocalObject* obj, + GBinderRemoteRequest* req, + guint code, + guint flags, + int* status, + void* user_data) +{ + ServiceManagerAidl4* self = user_data; + GBinderLocalReply* reply = NULL; + GBinderReader reader; + GBinderRemoteObject* remote_obj; + guint32 allow_isolated, dumpsys_priority; + char* str; + Category category; + + g_assert(!flags); + GDEBUG("%s %u", gbinder_remote_request_interface(req), code); + g_assert_cmpstr(gbinder_remote_request_interface(req), == ,SVCMGR_IFACE); + *status = -1; + switch (code) { + case GET_SERVICE_TRANSACTION: + case CHECK_SERVICE_TRANSACTION: + gbinder_remote_request_init_reader(req, &reader); + str = gbinder_reader_read_string16(&reader); + if (str) { + reply = gbinder_local_object_new_reply(obj); + remote_obj = g_hash_table_lookup(self->objects, str); + if (remote_obj) { + GBinderWriter writer; + + GDEBUG("Found name '%s' => %p", str, remote_obj); + gbinder_local_reply_init_writer(reply, &writer); + gbinder_writer_append_int32(&writer, UNDECLARED); + gbinder_writer_append_remote_object(&writer, remote_obj); + } else { + GDEBUG("Name '%s' not found", str); + gbinder_local_reply_append_int32(reply, GBINDER_STATUS_OK); + } + g_free(str); + } + break; + case ADD_SERVICE_TRANSACTION: + gbinder_remote_request_init_reader(req, &reader); + str = gbinder_reader_read_string16(&reader); + remote_obj = gbinder_reader_read_object(&reader); + gbinder_reader_read_uint32(&reader, (guint32*)&category); + if (str && remote_obj && + category.level == SYSTEM && + category.version == 1 && + gbinder_reader_read_uint32(&reader, &allow_isolated) && + gbinder_reader_read_uint32(&reader, &dumpsys_priority)) { + GDEBUG("Adding '%s'", str); + g_hash_table_replace(self->objects, str, remote_obj); + remote_obj = NULL; + str = NULL; + reply = gbinder_local_object_new_reply(obj); + *status = GBINDER_STATUS_OK; + } + g_free(str); + gbinder_remote_object_unref(remote_obj); + break; + case LIST_SERVICES_TRANSACTION: + gbinder_remote_request_init_reader(req, &reader); + if (gbinder_reader_read_uint32(&reader, &dumpsys_priority)) { + if (g_hash_table_size(self->objects) == 1) { + GList* keys = g_hash_table_get_keys(self->objects); + GList* l = g_list_nth(keys, 0); + gint32 srv_size = 1; + GBinderWriter writer; + + reply = gbinder_local_object_new_reply(obj); + gbinder_local_reply_init_writer(reply, &writer); + gbinder_writer_append_int32(&writer, GBINDER_STATUS_OK); + gbinder_writer_append_int32(&writer, srv_size); + gbinder_writer_append_string16(&writer, l->data); + g_list_free(keys); + *status = GBINDER_STATUS_OK; + } else { + GDEBUG("Incorrect number of services %u", + g_hash_table_size(self->objects)); + } + } + break; + default: + GDEBUG("Unhandled command %u", code); + break; + } + return reply; +} + +static +ServiceManagerAidl4* +servicemanager_aidl4_new( + const char* dev, + gboolean handle_on_looper_thread) +{ + ServiceManagerAidl4* self = g_object_new(SERVICE_MANAGER_AIDL4_TYPE, NULL); + GBinderLocalObject* obj = GBINDER_LOCAL_OBJECT(self); + GBinderIpc* ipc = gbinder_ipc_new(dev, NULL); + const int fd = gbinder_driver_fd(ipc->driver); + + self->handle_on_looper_thread = handle_on_looper_thread; + gbinder_local_object_init_base(obj, ipc, servicemanager_aidl_ifaces, + servicemanager_aidl4_handler, self); + test_binder_set_looper_enabled(fd, TEST_LOOPER_ENABLE); + test_binder_register_object(fd, obj, SVCMGR_HANDLE); + gbinder_ipc_register_local_object(ipc, obj); + gbinder_ipc_unref(ipc); + return self; +} + +static +GBINDER_LOCAL_TRANSACTION_SUPPORT +service_manager_aidl4_can_handle_transaction( + GBinderLocalObject* object, + const char* iface, + guint code) +{ + ServiceManagerAidl4* self = SERVICE_MANAGER_AIDL4(object); + + if (self->handle_on_looper_thread && !g_strcmp0(SVCMGR_IFACE, iface)) { + return GBINDER_LOCAL_TRANSACTION_LOOPER; + } else { + return GBINDER_LOCAL_OBJECT_CLASS(service_manager_aidl4_parent_class)-> + can_handle_transaction(object, iface, code); + } +} + +static +GBinderLocalReply* +service_manager_aidl4_handle_looper_transaction( + GBinderLocalObject* object, + GBinderRemoteRequest* req, + guint code, + guint flags, + int* status) +{ + if (!g_strcmp0(gbinder_remote_request_interface(req), SVCMGR_IFACE)) { + return GBINDER_LOCAL_OBJECT_CLASS(service_manager_aidl4_parent_class)-> + handle_transaction(object, req, code, flags, status); + } else { + return GBINDER_LOCAL_OBJECT_CLASS(service_manager_aidl4_parent_class)-> + handle_looper_transaction(object, req, code, flags, status); + } +} + +static +void +service_manager_aidl4_finalize( + GObject* object) +{ + ServiceManagerAidl4* self = SERVICE_MANAGER_AIDL4(object); + + g_hash_table_destroy(self->objects); + G_OBJECT_CLASS(service_manager_aidl4_parent_class)->finalize(object); +} + +static +void +service_manager_aidl4_init( + ServiceManagerAidl4* self) +{ + self->objects = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, + (GDestroyNotify) gbinder_remote_object_unref); +} + +static +void +service_manager_aidl4_class_init( + ServiceManagerAidl4Class* klass) +{ + GObjectClass* object = G_OBJECT_CLASS(klass); + GBinderLocalObjectClass* local_object = GBINDER_LOCAL_OBJECT_CLASS(klass); + + object->finalize = service_manager_aidl4_finalize; + local_object->can_handle_transaction = + service_manager_aidl4_can_handle_transaction; + local_object->handle_looper_transaction = + service_manager_aidl4_handle_looper_transaction; +} + +/*==========================================================================* + * Test context + *==========================================================================*/ + +typedef struct test_context { + const char* default_config_dir; + const char* default_config_file; + char* config_dir; + char* config_subdir; + char* config_file; + GBinderLocalObject* object; + ServiceManagerAidl4* service; + GBinderServiceManager* client; + int fd; +} TestContext; + +static +void +test_context_init( + TestContext* test) +{ + const char* dev = GBINDER_DEFAULT_BINDER; + const char* other_dev = GBINDER_DEFAULT_BINDER "-private"; + /* + * Also set defaults so that both /dev/binder and /dev/binder-private + * use the same protocol. + */ + const char* config = + "[Protocol]\n" + "Default = aidl3\n" + "/dev/binder = aidl3\n" + "[ServiceManager]\n" + "Default = aidl4\n" + "/dev/binder = aidl4\n"; + GBinderIpc* ipc; + + memset(test, 0, sizeof(*test)); + test->default_config_dir = gbinder_config_dir; + test->default_config_file = gbinder_config_file; + test->config_dir = g_dir_make_tmp(TMP_DIR_TEMPLATE, NULL); + test->config_subdir = g_build_filename(test->config_dir, "d", NULL); + test->config_file = g_build_filename(test->config_dir, "test.conf", NULL); + g_assert(g_file_set_contents(test->config_file, config, -1, NULL)); + GDEBUG("Config file %s", test->config_file); + gbinder_config_dir = test->config_subdir; /* Doesn't exist */ + gbinder_config_file = test->config_file; + + ipc = gbinder_ipc_new(dev, NULL); + test->fd = gbinder_driver_fd(ipc->driver); + test->object = gbinder_local_object_new(ipc, NULL, NULL, NULL); + + /* Set up binder simulator */ + test_binder_register_object(test->fd, test->object, AUTO_HANDLE); + test_binder_set_passthrough(test->fd, TRUE); + + test->service = servicemanager_aidl4_new(other_dev, TRUE); + test->client = gbinder_servicemanager_new(dev); + gbinder_ipc_unref(ipc); +} + +static +void +test_context_deinit( + TestContext* test) +{ + test_binder_unregister_objects(test->fd); + gbinder_local_object_unref(test->object); + gbinder_local_object_drop(GBINDER_LOCAL_OBJECT(test->service)); + gbinder_servicemanager_unref(test->client); + gbinder_ipc_exit(); + test_binder_exit_wait(&test_opt, NULL); + remove(test->config_file); + remove(test->config_dir); + g_free(test->config_file); + g_free(test->config_subdir); + g_free(test->config_dir); + gbinder_config_dir = test->default_config_dir; + gbinder_config_file = test->default_config_file; + gbinder_config_exit(); +} + +/*==========================================================================* + * get + *==========================================================================*/ + +static +void +test_get_run() +{ + TestContext test; + const char* name = "name"; + int status = -1; + + test_context_init(&test); + + /* Query the object (it's not there yet) */ + GDEBUG("Querying '%s'", name); + g_assert(!gbinder_servicemanager_get_service_sync(test.client, + name, &status)); + g_assert_cmpint(status, == ,GBINDER_STATUS_OK); + + /* Register object */ + GDEBUG("Registering object '%s' => %p", name, test.object); + g_assert_cmpint(gbinder_servicemanager_add_service_sync(test.client, + name, test.object), == ,GBINDER_STATUS_OK); + + g_assert_cmpuint(g_hash_table_size(test.service->objects), == ,1); + g_assert(g_hash_table_contains(test.service->objects, name)); + + /* Query the object (this time it must be there) */ + GDEBUG("Querying '%s' again", name); + g_assert(gbinder_servicemanager_get_service_sync(test.client, name, + &status)); + g_assert_cmpint(status, == ,GBINDER_STATUS_OK); + + test_context_deinit(&test); +} + +static +void +test_get() +{ + test_run_in_context(&test_opt, test_get_run); +} + +/*==========================================================================* + * list + *==========================================================================*/ + +static +void +test_list_run() +{ + TestContext test; + const char* name = "name"; + char** list; + + test_context_init(&test); + + /* Request the list */ + list = gbinder_servicemanager_list_sync(test.client); + + /* There's nothing there yet */ + g_assert(list); + g_assert(!list[0]); + g_strfreev(list); + + /* Register object */ + GDEBUG("Registering object '%s' => %p", name, test.object); + g_assert_cmpint(gbinder_servicemanager_add_service_sync(test.client, + name, test.object), == ,GBINDER_STATUS_OK); + + /* Request the list again */ + list = gbinder_servicemanager_list_sync(test.client); + + /* Now the name must be there */ + g_assert_cmpuint(gutil_strv_length(list), == ,1); + g_assert_cmpstr(list[0], == ,name); + g_strfreev(list); + + test_context_deinit(&test); +} + +static +void +test_list() +{ + test_run_in_context(&test_opt, test_list_run); +} + +/*==========================================================================* + * Common + *==========================================================================*/ + +#define TEST_(t) "/servicemanager_aidl4/" t + +int main(int argc, char* argv[]) +{ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS; + g_type_init(); + G_GNUC_END_IGNORE_DEPRECATIONS; + g_test_init(&argc, &argv, NULL); + g_test_add_func(TEST_("get"), test_get); + g_test_add_func(TEST_("list"), test_list); + test_init(&test_opt, argc, argv); + return g_test_run(); +} + +/* + * Local Variables: + * mode: C + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/unit/unit_servicemanager_hidl/unit_servicemanager_hidl.c b/unit/unit_servicemanager_hidl/unit_servicemanager_hidl.c index 1e5ea07..58d0712 100644 --- a/unit/unit_servicemanager_hidl/unit_servicemanager_hidl.c +++ b/unit/unit_servicemanager_hidl/unit_servicemanager_hidl.c @@ -82,6 +82,14 @@ gbinder_servicemanager_aidl3_get_type() return 0; } +GType +gbinder_servicemanager_aidl4_get_type() +{ + /* Dummy function to avoid pulling in gbinder_servicemanager_aidl4 */ + g_assert_not_reached(); + return 0; +} + /*==========================================================================* * Common *==========================================================================*/ diff --git a/unit/unit_servicename/unit_servicename.c b/unit/unit_servicename/unit_servicename.c index 45332f8..30dc387 100644 --- a/unit/unit_servicename/unit_servicename.c +++ b/unit/unit_servicename/unit_servicename.c @@ -240,6 +240,12 @@ gbinder_servicemanager_aidl3_get_type() return TEST_TYPE_SERVICEMANAGER; } +GType +gbinder_servicemanager_aidl4_get_type() +{ + return TEST_TYPE_SERVICEMANAGER; +} + GType gbinder_servicemanager_hidl_get_type() { diff --git a/unit/unit_servicepoll/unit_servicepoll.c b/unit/unit_servicepoll/unit_servicepoll.c index c7f79d6..285b1a6 100644 --- a/unit/unit_servicepoll/unit_servicepoll.c +++ b/unit/unit_servicepoll/unit_servicepoll.c @@ -206,6 +206,12 @@ gbinder_servicemanager_aidl3_get_type() return TEST_TYPE_SERVICEMANAGER; } +GType +gbinder_servicemanager_aidl4_get_type() +{ + return TEST_TYPE_SERVICEMANAGER; +} + GType gbinder_servicemanager_hidl_get_type() { From ede15da9e2d60e7389bca0260a7faa6a7c0da5ee Mon Sep 17 00:00:00 2001 From: gary-wzl77 Date: Thu, 25 Nov 2021 11:02:45 +0800 Subject: [PATCH 2/3] [gbinder] Add preset gbinder config to support Android API version 31 --- src/gbinder_config.c | 15 +++++++++++++++ unit/unit_config/unit_config.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/src/gbinder_config.c b/src/gbinder_config.c index 41eb1b8..b467ac5 100644 --- a/src/gbinder_config.c +++ b/src/gbinder_config.c @@ -133,9 +133,24 @@ static const GBinderConfigPresetGroup gbinder_config_30[] = { { NULL, NULL } }; +/* API level 31 */ + +static const GBinderConfigPresetEntry gbinder_config_31_servicemanager[] = { + { "/dev/binder", "aidl4" }, + { "/dev/vndbinder", "aidl4" }, + { NULL, NULL } +}; + +static const GBinderConfigPresetGroup gbinder_config_31[] = { + { GBINDER_CONFIG_GROUP_PROTOCOL, gbinder_config_30_protocol }, + { GBINDER_CONFIG_GROUP_SERVICEMANAGER, gbinder_config_31_servicemanager }, + { NULL, NULL } +}; + /* Presets sorted by API level in descending order */ static const GBinderConfigPreset gbinder_config_presets[] = { + { 31, gbinder_config_31 }, { 30, gbinder_config_30 }, { 29, gbinder_config_29 }, { 28, gbinder_config_28 } diff --git a/unit/unit_config/unit_config.c b/unit/unit_config/unit_config.c index 7df2c28..cf60fda 100644 --- a/unit/unit_config/unit_config.c +++ b/unit/unit_config/unit_config.c @@ -231,6 +231,7 @@ test_dirs( char* file1 = g_build_filename(subdir, "a.conf", NULL); char* file2 = g_build_filename(subdir, "b.conf", NULL); char* file3 = g_build_filename(subdir, "c.conf", NULL); + char* file4 = g_build_filename(subdir, "d.conf", NULL); char* random_file = g_build_filename(subdir, "foo", NULL); static const char garbage[] = "foo"; static const char config[] = @@ -252,6 +253,11 @@ test_dirs( "/dev/binder3 = aidl3\n" "[ServiceManager]\n" "/dev/binder3 = aidl3\n"; + static const char config4[] = + "[Protocol]\n" + "/dev/binder4 = aidl3\n" + "[ServiceManager]\n" + "/dev/binder4 = aidl4\n"; g_assert_cmpint(mkdir(subdir, 0700), == ,0); g_assert_cmpint(mkdir(notafile, 0700), == ,0); @@ -259,6 +265,7 @@ test_dirs( g_assert(g_file_set_contents(file1, config1, -1, NULL)); g_assert(g_file_set_contents(file2, config2, -1, NULL)); g_assert(g_file_set_contents(file3, config3, -1, NULL)); + g_assert(g_file_set_contents(file4, config4, -1, NULL)); g_assert(g_file_set_contents(random_file, garbage, -1, NULL)); /* Reset the state */ @@ -271,10 +278,12 @@ test_dirs( g_assert(k); g_assert_cmpstr(test_value(k,"Protocol","/dev/binder",b), == ,"aidl2"); g_assert_cmpstr(test_value(k,"Protocol","/dev/binder3",b), == ,"aidl3"); + g_assert_cmpstr(test_value(k,"Protocol","/dev/binder4",b), == ,"aidl3"); g_assert_cmpstr(test_value(k,"Protocol","/dev/hbinder",b), == ,"hidl"); g_assert_cmpstr(test_value(k,"Protocol","/dev/hwbinder",b), == ,"hidl"); g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder",b),==,"aidl2"); g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder3",b),==,"aidl3"); + g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder4",b),==,"aidl4"); /* Remove the default file and try again */ gbinder_config_exit(); @@ -284,9 +293,11 @@ test_dirs( g_assert(!test_value(k,"Protocol","/dev/hbinder",b)); g_assert_cmpstr(test_value(k,"Protocol","/dev/binder",b), == ,"aidl2"); g_assert_cmpstr(test_value(k,"Protocol","/dev/binder3",b), == ,"aidl3"); + g_assert_cmpstr(test_value(k,"Protocol","/dev/binder4",b), == ,"aidl3"); g_assert_cmpstr(test_value(k,"Protocol","/dev/hwbinder",b), == ,"hidl"); g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder",b),==,"aidl2"); g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder3",b),==,"aidl3"); + g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder4",b),==,"aidl4"); /* Damage one of the files and try again */ gbinder_config_exit(); @@ -297,8 +308,10 @@ test_dirs( g_assert(!test_value(k,"Protocol","/dev/hwbinder",b)); g_assert_cmpstr(test_value(k,"Protocol","/dev/binder",b), == ,"aidl2"); g_assert_cmpstr(test_value(k,"Protocol","/dev/binder3",b), == ,"aidl3"); + g_assert_cmpstr(test_value(k,"Protocol","/dev/binder4",b), == ,"aidl3"); g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder",b),==,"aidl2"); g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder3",b),==,"aidl3"); + g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder4",b),==,"aidl4"); /* Disallow access to one of the files and try again */ gbinder_config_exit(); @@ -309,14 +322,17 @@ test_dirs( g_assert(!test_value(k,"Protocol","/dev/hwbinder",b)); g_assert_cmpstr(test_value(k,"Protocol","/dev/binder",b), == ,"aidl2"); g_assert_cmpstr(test_value(k,"Protocol","/dev/binder3",b), == ,"aidl3"); + g_assert_cmpstr(test_value(k,"Protocol","/dev/binder4",b), == ,"aidl3"); g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder",b),==,"aidl2"); g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder3",b),==,"aidl3"); + g_assert_cmpstr(test_value(k,"ServiceManager","/dev/binder4",b),==,"aidl4"); /* Delete the remaining files and try again */ gbinder_config_exit(); g_assert_cmpint(remove(file1), == ,0); g_assert_cmpint(remove(file2), == ,0); g_assert_cmpint(remove(file3), == ,0); + g_assert_cmpint(remove(file4), == ,0); g_assert(!gbinder_config_get()); /* Undo all the damage */ @@ -329,6 +345,7 @@ test_dirs( g_free(file1); g_free(file2); g_free(file3); + g_free(file4); g_free(random_file); remove(notafile); @@ -495,6 +512,20 @@ static const TestPresetsData test_presets_data [] = { "[ServiceManager]\n" "/dev/binder = aidl3\n" "/dev/vndbinder = aidl3\n" + },{ + "31", + + "[General]\n" + "ApiLevel = 31", + + "[General]\n" + "ApiLevel = 31\n" + "[Protocol]\n" + "/dev/binder = aidl3\n" + "/dev/vndbinder = aidl3\n" + "[ServiceManager]\n" + "/dev/binder = aidl4\n" + "/dev/vndbinder = aidl4\n" } }; From 3742e2ca8e86d0d8a6cd050b4978cb9c19261c65 Mon Sep 17 00:00:00 2001 From: gary-wzl77 Date: Fri, 26 Nov 2021 00:12:56 +0800 Subject: [PATCH 3/3] [test] make the binder device configurable for binder-dump test --- test/binder-dump/binder-dump.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/binder-dump/binder-dump.c b/test/binder-dump/binder-dump.c index 867f5ca..fccd7e6 100644 --- a/test/binder-dump/binder-dump.c +++ b/test/binder-dump/binder-dump.c @@ -171,6 +171,8 @@ app_init( 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 [" DEV_DEFAULT "]", "DEVICE" }, { NULL } }; @@ -187,7 +189,7 @@ app_init( if (g_option_context_parse(options, &argc, &argv, &error)) { char* help; - opt->dev = g_strdup(DEV_DEFAULT); + if (!opt->dev || !opt->dev[0]) opt->dev = g_strdup(DEV_DEFAULT); switch (argc) { case 2: opt->service = argv[1];