hello_service initialization fails on Android 36, but works on Android 34/35
Hi, thank you for the great work on this project!
I'm testing rsbinder on a new device running Android 36, and encountered a problem where hello_service fails to initialize. The same code works fine on Android 34 and Android 35.
I've verified that the Binder protocol version is 8 on all systems. Also, creating a custom binder device using rsb_device hihix works successfully.
Here are the relevant logs during the failure on Android 16:
[2025-05-12T00:38:47Z TRACE rsbinder::thread_state] Size of receive buffer: 0, need_read: true, do_receive: false
[2025-05-12T00:38:47Z TRACE rsbinder::thread_state] write consumed: 8 of 8, read consumed: 0 of 0
[2025-05-12T00:38:47Z TRACE rsbinder::thread_state] write_transaction_data: BC_TRANSACTION 30 0 3
Parcel: pos 132, len 132
Object count 1
Length: 8 (0x8) bytes
0000: 60 00 00 00 00 00 00 00 .......
Length: 132 (0x84) bytes
0000: 00 00 00 80 ff ff ff ff 54 53 59 53 1a 00 00 00 ........TSYS....
0010: 61 00 6e 00 64 00 72 00 6f 00 69 00 64 00 2e 00 a.n.d.r.o.i.d...
0020: 6f 00 73 00 2e 00 49 00 53 00 65 00 72 00 76 00 o.s...I.S.e.r.v.
0030: 69 00 63 00 65 00 4d 00 61 00 6e 00 61 00 67 00 i.c.e.M.a.n.a.g.
0040: 65 00 72 00 00 00 00 00 08 00 00 00 6d 00 79 00 e.r.........m.y.
0050: 2e 00 68 00 65 00 6c 00 6c 00 6f 00 00 00 00 00 ..h.e.l.l.o.....
0060: 85 2a 62 73 13 01 00 00 60 56 c0 40 73 00 00 b4 .*bs....V.@s...
0070: 08 95 70 f6 63 00 00 00 0c 00 00 00 00 00 00 00 ..p.c...........
0080: 08 00 00 00 ....
[2025-05-12T00:38:47Z TRACE rsbinder::thread_state] Sending command to driver:
Parcel: pos 68, len 68
Length: 68 (0x44) bytes
0000: 00 63 40 40 00 00 00 00 00 00 00 00 00 00 00 00 .c@@............
0010: 00 00 00 00 03 00 00 00 30 00 00 00 00 00 00 00 ........0.......
0020: 00 00 00 00 84 00 00 00 00 00 00 00 08 00 00 00 ................
0030: 00 00 00 00 c0 97 c0 a0 73 00 00 b4 50 55 c0 70 ........s...PU.p
0040: 72 00 00 b4 r...
[2025-05-12T00:38:47Z TRACE rsbinder::thread_state] Size of receive buffer: 256, need_read: true, do_receive: true
[2025-05-12T00:38:47Z TRACE rsbinder::thread_state] write consumed: 68 of 68, read consumed: 76 of 256
[2025-05-12T00:38:47Z TRACE rsbinder::thread_state] Received commands from driver:
Parcel: pos 0, len 76
Length: 76 (0x4c) bytes
0000: 0c 72 00 00 06 72 00 00 03 72 40 80 00 00 00 00 .r...r...r@.....
0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0020: 20 00 00 00 00 00 00 00 e8 03 00 00 6c 00 00 00 ...........l...
0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 20 90 b0 ............. ..
0040: 71 00 00 00 70 20 90 b0 71 00 00 00 q...p ..q...
[2025-05-12T00:38:47Z TRACE rsbinder::thread_state] "BR_NOOP"
[2025-05-12T00:38:47Z TRACE rsbinder::thread_state] "BR_TRANSACTION_COMPLETE"
[2025-05-12T00:38:47Z TRACE rsbinder::thread_state] "BR_REPLY"
[2025-05-12T00:38:47Z TRACE rsbinder::thread_state] Sending command to driver:
Parcel: pos 12, len 12
Length: 12 (0xc) bytes
0000: 03 63 08 40 00 20 90 b0 71 00 00 00 .c.@. ..q...
[2025-05-12T00:38:47Z TRACE rsbinder::thread_state] Size of receive buffer: 0, need_read: true, do_receive: false
[2025-05-12T00:38:47Z TRACE rsbinder::thread_state] write consumed: 12 of 12, read consumed: 0 of 0
Error: BadParcelable / Ok: Parcel data not fully consumed, unread size: 36
XXXX:/data/local/tmp # ./rsb_device hihix
[OK] /dev/binderfs already exists
[OK] BinderFS is already mounted on /dev/binderfs
[OK] New binder device allocated:
- Device name: hihix
- Accessible path: /dev/binderfs/hihix
[OK] Permission set to 0666 for /dev/binderfs/hihix
[OK] Symlink created from /dev/binderfs/hihix to /dev/hihix
Summary:
The binder device 'hihix' has been successfully created and is accessible at /dev/binderfs/hihix with full permissions (read/write by all users). This setup facilitates IPC mechanisms within the Linux kernel.
XXXX:/data/local/tmp # ./hello_client
list services:
[2025-05-12T01:57:30Z ERROR rsbinder::hub::servicemanager] Failed to list services: NullPointer / Ok:
[2025-05-12T01:57:30Z WARN rsbinder::thread_state] binder::BR_REPLY (NotEnoughData)
Error: NotEnoughData
It seems the parcel reply has 36 bytes left unread. I'm wondering if this is due to a change in the IServicemanager reply structure on Android 16?
Do you have any advice or workaround for this issue?
Thanks in advance!
Sorry for the typo โ I meant Android 36, not 16. now I debug with kernel code. I think i need to look https://android.googlesource.com/platform/frameworks/native to find anwser.
Thanks for sharing. I haven't tested compatibility with the latest Android yet. I'll check it out.
๐งต Binder Transaction Not Fully Consumed โ 36 Bytes Left
Parcel data not fully consumed, unread size: 36
Trace log:
[2025-05-13T09:26:42Z TRACE rsbinder::thread_state] write_transaction_data: BC_TRANSACTION 30 0 3
Parcel: pos 132, len 132
Object count 1
Length: 8 (0x8) bytes
0000: 60 00 00 00 00 00 00 00 `.......
Length: 132 (0x84) bytes
0000: 00 00 00 80 ff ff ff ff 54 53 59 53 1a 00 00 00 ........TSYS....
0010: 61 00 6e 00 64 00 72 00 6f 00 69 00 64 00 2e 00 a.n.d.r.o.i.d...
0020: 6f 00 73 00 2e 00 49 00 53 00 65 00 72 00 76 00 o.s...I.S.e.r.v.
0030: 69 00 63 00 65 00 4d 00 61 00 6e 00 61 00 67 00 i.c.e.M.a.n.a.g.
0040: 65 00 72 00 00 00 00 00 08 00 00 00 6d 00 79 00 e.r.........m.y.
0050: 2e 00 68 00 65 00 6c 00 6c 00 6f 00 00 00 00 00 ..h.e.l.l.o.....
0060: 85 2a 62 73 13 01 00 00 e0 f6 80 c8 73 00 00 b4 .*bs........s...
0070: 20 1b dd c0 57 00 00 00 0c 00 00 00 00 00 00 00 ...W...........
0080: 08 00 00 00 ....
๐ฆ Final 36 Bytes Breakdown
0060: 85 2a 62 73 13 01 00 00 e0 f6 80 c8 73 00 00 b4
0070: 20 1b dd c0 57 00 00 00 0c 00 00 00 00 00 00 00
0080: 08 00 00 00
| Offset | Field | Value | Explanation |
|---|---|---|---|
0x0060 |
flat_binder_object |
24 bytes | Contains binder pointer and cookie |
0x0078 |
stability (expected) |
0c 00 00 00 โ
|
System => 0b001100, |
0x007C |
allowIsolated |
00 00 00 00 โ
|
false (bool โ int32) |
0x0080 |
dumpPriority |
08 00 00 00 โ
|
dump flag 8 |
โ Why Were These Not Consumed?
I have no idea now.
Maybe readStrongBinder() failed, the Parcel read cursor (dataPosition) did not advance, leaving the last 36 bytes untouched.
The latest AOSP corresponding to Android 16 has not been released yet. The current issue occurred while the service_manager was interpreting a packet sent by the client. Something in the packet did not conform to the expected format, which triggered a BadParcelable exception. The related message was then sent back to the client, and rsbinder printed that message. The BadParcelable originated from the service_manager side, and it indicates that the packet generated by rsbinder is not compatible with the latest Android 16. At this point, there's no way to analyze the issue until the AOSP source code is released. Once the source is made available in June 2025, Iโll check the changes and analyze it again.
ok I know, because IServiceManager.aidl is update.
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.os;
import android.os.IClientCallback;
import android.os.IServiceCallback;
import android.os.Service;
import android.os.ServiceDebugInfo;
import android.os.ConnectionInfo;
/**
* Basic interface for finding and publishing system services.
*
* You likely want to use android.os.ServiceManager in Java or
* android::IServiceManager in C++ in order to use this interface.
*
* @hide
*/
interface IServiceManager {
/*
* Must update values in IServiceManager.h
*/
/* Allows services to dump sections according to priorities. */
const int DUMP_FLAG_PRIORITY_CRITICAL = 1 << 0;
const int DUMP_FLAG_PRIORITY_HIGH = 1 << 1;
const int DUMP_FLAG_PRIORITY_NORMAL = 1 << 2;
/**
* Services are by default registered with a DEFAULT dump priority. DEFAULT priority has the
* same priority as NORMAL priority but the services are not called with dump priority
* arguments.
*/
const int DUMP_FLAG_PRIORITY_DEFAULT = 1 << 3;
const int DUMP_FLAG_PRIORITY_ALL =
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_HIGH
| DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PRIORITY_DEFAULT;
const int FLAG_IS_LAZY_SERVICE = 1 << 30;
/* Allows services to dump sections in protobuf format. */
const int DUMP_FLAG_PROTO = 1 << 4;
/**
* Retrieve an existing service called @a name from the
* service manager.
*
* This is the same as checkService (returns immediately) but
* exists for legacy purposes.
*
* Returns null if the service does not exist.
*
* @deprecated TODO(b/355394904): Use getService2 instead. This does not return metadata
* that is included in ServiceWithMetadata
*/
@UnsupportedAppUsage
@nullable IBinder getService(@utf8InCpp String name);
/**
* Retrieve an existing service called @a name from the
* service manager.
*
* This is the same as checkService (returns immediately) but
* exists for legacy purposes.
*
* Returns an enum Service that can be of different types. The
* enum value is null if the service does not exist.
*/
Service getService2(@utf8InCpp String name);
/**
* Retrieve an existing service called @a name from the service
* manager. Non-blocking. Returns null if the service does not exist.
*
* @deprecated TODO(b/355394904): Use checkService2 instead. This does not
* return metadata that is included in ServiceWithMetadata
*/
@UnsupportedAppUsage
@nullable IBinder checkService(@utf8InCpp String name);
/**
* Retrieve an existing service called @a name from the service
* manager. Non-blocking. Returns null if the service does not
* exist.
*/
Service checkService2(@utf8InCpp String name);
/**
* Place a new @a service called @a name into the service
* manager.
*/
void addService(@utf8InCpp String name, IBinder service,
boolean allowIsolated, int dumpPriority);
/**
* Return a list of all currently running services.
*/
@utf8InCpp String[] listServices(int dumpPriority);
/**
* Request a callback when a service is registered.
*/
void registerForNotifications(@utf8InCpp String name, IServiceCallback callback);
/**
* Unregisters all requests for notifications for a specific callback.
*/
void unregisterForNotifications(@utf8InCpp String name, IServiceCallback callback);
/**
* Returns whether a given interface is declared on the device, even if it
* is not started yet. For instance, this could be a service declared in the VINTF
* manifest.
*/
boolean isDeclared(@utf8InCpp String name);
/**
* Returns all declared instances for a particular interface.
*
* For instance, if 'android.foo.IFoo/foo' is declared, and 'android.foo.IFoo' is
* passed here, then ["foo"] would be returned.
*/
@utf8InCpp String[] getDeclaredInstances(@utf8InCpp String iface);
/**
* If updatable-via-apex, returns the APEX via which this is updated.
*/
@nullable @utf8InCpp String updatableViaApex(@utf8InCpp String name);
/**
* Returns all instances which are updatable via the APEX. Instance names are fully qualified
* like `pack.age.IFoo/default`.
*/
@utf8InCpp String[] getUpdatableNames(@utf8InCpp String apexName);
/**
* If connection info is available for the given instance, returns the ConnectionInfo
*/
@nullable ConnectionInfo getConnectionInfo(@utf8InCpp String name);
/**
* Request a callback when the number of clients of the service changes.
* Used by LazyServiceRegistrar to dynamically stop services that have no clients.
*/
void registerClientCallback(@utf8InCpp String name, IBinder service, IClientCallback callback);
/**
* Attempt to unregister and remove a service. Will fail if the service is still in use.
*/
void tryUnregisterService(@utf8InCpp String name, IBinder service);
/**
* Get debug information for all currently registered services.
*/
ServiceDebugInfo[] getServiceDebugInfo();
}
Service.aidl
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.os;
import android.os.ServiceWithMetadata;
/**
* Service is a union of different service types that can be returned
* by the internal {@link ServiceManager#getService(name)} API.
*
* @hide
*/
union Service {
ServiceWithMetadata serviceWithMetadata;
@nullable IBinder accessor;
}
[2025-05-19T08:39:06Z TRACE rsbinder::thread_state] "BR_NOOP"
[2025-05-19T08:39:06Z TRACE rsbinder::thread_state] "BR_INCREFS"
[2025-05-19T08:39:06Z TRACE rsbinder::thread_state] "BR_ACQUIRE"
[2025-05-19T08:39:06Z TRACE rsbinder::thread_state] "BR_TRANSACTION_COMPLETE"
[2025-05-19T08:39:06Z TRACE rsbinder::thread_state] "BR_REPLY"
[2025-05-19T08:39:06Z TRACE rsbinder::thread_state] Sending command to driver:
Parcel: pos 52, len 52
Length: 52 (0x34) bytes
0000: 08 63 10 40 60 97 e0 f0 77 00 00 b4 d0 57 93 ba .c.@...w....W.. 0010: 55 00 00 00 09 63 10 40 60 97 e0 f0 77 00 00 b4 U....c.@...w...
0020: d0 57 93 ba 55 00 00 00 03 63 08 40 00 20 b0 f0 .W..U....c.@. ..
0030: 76 00 00 00 v...
[2025-05-19T08:39:06Z TRACE rsbinder::thread_state] Size of receive buffer: 0, need_read: true, do_receive: false
[2025-05-19T08:39:06Z TRACE rsbinder::thread_state] write consumed: 52 of 52, read consumed: 0 of 0
[2025-05-19T08:39:06Z INFO hello_service] โ
Service 'my.hello' registered
[2025-05-19T08:39:06Z DEBUG rsbinder::thread_state] **** THREAD ThreadId(1) (PID 6979) IS JOINING THE THREAD POOL
[2025-05-19T08:39:06Z TRACE rsbinder::thread_state] Sending command to driver:
Parcel: pos 4, len 4
Length: 4 (0x4) bytes
0000: 0c 63 00 00 .c..
[2025-05-19T08:39:06Z TRACE rsbinder::thread_state] Size of receive buffer: 256, need_read: true, do_receive: true
ok now I fix old function, but 3 new function not implement. checkService2 getService2 getUpdatableNames
Since it's incompatible with older versions of Android and only works on Android 16, I've created a separate branch to make the necessary updates. For your reference: https://github.com/damody/rsbinder/commit/3cafb4ff84d4f40fda0db960ae448cce29fee4df
Now my question is: how should an rsbinder client handle different Android versions (13, 14, 15, 16)? If I'm writing a service, I can control the version it runs on, but Android apps may run on a wide range of versions. The challenge is that AIDL behavior differs between Android versions.
I think we need to maintain multi version service_manager.rs and aidl files.
There are two Android version related functions. rsbinder::set_android_version() and rsbinder::get_android_version()
This compatibility issue seems to have arisen due to changes in the AIDL specification related to the ServiceManager.
I think it could be resolved by calling set_android_version() to explicitly specify the Android version, and then adding code that only runs on Android 16 or higher inside the newly added APIs (such as getService2()) using get_android_version().
https://github.com/damody/rsbinder/tree/android16 I already implement choose aidl version in runtime, now its' work on api 35 & 36.
Now rsbinder supports Android 16. It has now been merged into the master branch, and after testing in a wider variety of environments, it is planned to be included in the 0.3 release.