Android源代码中大小设置

http://androidxref.com/9.0.0_r3/xref/frameworks/native/libs/binder/ProcessState.cpp#43
默认的page size是4k(4096), 查询命令为getconf PAGE_SIZE
所以,binder的数据大小限制一般为1M-8k

43#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)
44#define DEFAULT_MAX_BINDER_THREADS 15
...
425        // mmap the binder, providing a chunk of virtual address space to receive transactions.
426        mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);

Framework错误提示相关代码

http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/jni/android_util_Binder.cpp#794
代码中可以看到:
只有binder transaction失败的情况下,才会进行错误提示。如果整个进程传输数据使用binder的总大小超过1M - 8k的情况下,会失败。
如果判断本次AIDL调用的数据量大于200k,提示TransactionTooLargeException
否则,提示Transaction failed on small parcel; remote process probably died

如果binder transaction成功的话,即使本次AIDL调用数据量超过200k,也是不会有错误的,如下面的case2
当然,从这里可以看出,进行AIDL设计时,需要尽量减小大数据通过AIDL参数传输,以及直接在AIDL中进行长时间的操作,避免binder空间耗尽

771        case FAILED_TRANSACTION: {
772            ALOGE("!!! FAILED BINDER TRANSACTION !!!  (parcel size = %d)", parcelSize);
773            const char* exceptionToThrow;
774            char msg[128];
775            // TransactionTooLargeException is a checked exception, only throw from certain methods.
776            // FIXME: Transaction too large is the most common reason for FAILED_TRANSACTION
777            //        but it is not the only one.  The Binder driver can return BR_FAILED_REPLY
778            //        for other reasons also, such as if the transaction is malformed or
779            //        refers to an FD that has been closed.  We should change the driver
780            //        to enable us to distinguish these cases in the future.
781            if (canThrowRemoteException && parcelSize > 200*1024) {
782                // bona fide large payload
783                exceptionToThrow = "android/os/TransactionTooLargeException";
784                snprintf(msg, sizeof(msg)-1, "data parcel size %d bytes", parcelSize);
785            } else {
786                // Heuristic: a payload smaller than this threshold "shouldn't" be too
787                // big, so it's probably some other, more subtle problem.  In practice
788                // it seems to always mean that the remote process died while the binder
789                // transaction was already in flight.
790                exceptionToThrow = (canThrowRemoteException)
791                        ? "android/os/DeadObjectException"
792                        : "java/lang/RuntimeException";
793                snprintf(msg, sizeof(msg)-1,
794                        "Transaction failed on small parcel; remote process probably died");
795            }
796            jniThrowException(env, exceptionToThrow, msg);
797        } break;

传输数据大小限制的理解

1M-8k=1016k大小是所以一个进程中所有binder线程加起来的大小的限制。
比如,一个进程里面已经有3个binder线程,占用了900k。那么,后面一个binder线程,只要传输167k,就会报错。后面会有这个例子的演示。
接下来在虚拟机Android P上面进行实验。

本文代码位置

https://github.com/romulus1985/BinderTransaction

服务器端代码

服务器端的方法长时间不会退出
注意每个testCase运行后,需要重启server app。

    private IBinder mMyAidlInterface = new IMyAidlInterface.Stub() {
        @Override
        public void hello(byte[] data) throws RemoteException {
            log("hello enter.");
            try {
                final long time = 60 * 60 * 1000; // 1 day
                Thread.sleep(time);
            } catch (InterruptedException e) {
                e.printStackTrace();

客户端通信工具API

在多个线程中调用AIDL,发送指定byte的数据

    private void sendBytes(final int size, final int count) throws RemoteException {
        final byte[] bytes = new byte[size];
        for (int i = 0; i < count; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        mMyAidlInterface.hello(bytes);
                    } catch (RemoteException e) {
                        e.printStackTrace();
            }).start();

客户端case1

可以看到提示FAILED BINDER TRANSACTION !!! (parcel size = 1048672)。
android.os.TransactionTooLargeException:提示数据量太大了
这里客户端输出的数据是1M = 1024 * 1024 = 1,048,576‬, 系统提示的数据比较1M略大96byte,说明binder调用时,除了方法参数,还会占用另外部分空间。

    private void testCase1() throws RemoteException {
        final int size = 1024 * 1024; // 1M
        sendBytes(size, 1);
2020-07-19 23:53:40.183 4198-4198/com.example.binderclient E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!  (parcel size = 1048672)
2020-07-19 23:53:40.183 4198-4198/com.example.binderclient W/System.err: android.os.TransactionTooLargeException: data parcel size 1048672 bytes
2020-07-19 23:53:40.184 4198-4198/com.example.binderclient W/System.err:     at android.os.BinderProxy.transactNative(Native Method)
2020-07-19 23:53:40.185 4198-4198/com.example.binderclient W/System.err:     at android.os.BinderProxy.transact(Binder.java:1127)
2020-07-19 23:53:40.185 4198-4198/com.example.binderclient W/System.err:     at com.example.binderserver.IMyAidlInterface$Stub$Proxy.hello(IMyAidlInterface.java:107)
2020-07-19 23:53:40.185 4198-4198/com.example.binderclient W/System.err:     at com.example.binderclient.MainActivity.testCase1(MainActivity.java:63)
2020-07-19 23:53:40.186 4198-4198/com.example.binderclient W/System.err:     at com.example.binderclient.MainActivity.testCases(MainActivity.java:54)
2020-07-19 23:53:40.186 4198-4198/com.example.binderclient W/System.err:     at com.example.binderclient.MainActivity.access$200(MainActivity.java:16)
2020-07-19 23:53:40.186 4198-4198/com.example.binderclient W/System.err:     at com.example.binderclient.MainActivity$1.onServiceConnected(MainActivity.java:26)
2020-07-19 23:53:40.186 4198-4198/com.example.binderclient W/System.err:     at android.app.LoadedApk$ServiceDispatcher.doConnected(LoadedApk.java:1730)
2020-07-19 23:53:40.187 4198-4198/com.example.binderclient W/System.err:     at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:1762)
2020-07-19 23:53:40.187 4198-4198/com.example.binderclient W/System.err:     at android.os.Handler.handleCallback(Handler.java:873)
2020-07-19 23:53:40.187 4198-4198/com.example.binderclient W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:99)
2020-07-19 23:53:40.187 4198-4198/com.example.binderclient W/System.err:     at android.os.Looper.loop(Looper.java:193)
2020-07-19 23:53:40.188 4198-4198/com.example.binderclient W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:6669)
2020-07-19 23:53:40.188 4198-4198/com.example.binderclient W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
2020-07-19 23:53:40.188 4198-4198/com.example.binderclient W/System.err:     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
2020-07-19 23:53:40.188 4198-4198/com.example.binderclient W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

客户端case2

300k x 3 = 900K可以正常运行

    private void testCase2() throws RemoteException {
        log("testCase2 enter.");
        final int size = 300 * 1024; // 300k
        sendBytes(size, 3); // 300k x 3
        log("testCase2 exit.");

客户端case3

可以看到提示:FAILED BINDER TRANSACTION !!! (parcel size = 171104)
在testCase2的900K的基础上,再次传输116k=116 *1024=118,784‬,系统提示这次调用的binder数据大小为118880,仍然是比方法参数大96byte

   private void testCase3() throws RemoteException {
        log("testCase3 enter.");
        testCase2();
        try {
            Thread.sleep(3 * 1000); // 3s
        } catch (InterruptedException e) {
            e.printStackTrace();
        final int size = 116 * 1024; // 116k, crash
        byte[] bytes = new byte[size];
        log("send " + size + " bytes");
        mMyAidlInterface.hello(bytes);
2020-07-20 00:20:05.890 5064-5064/com.example.binderclient E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!  (parcel size = 118880)
2020-07-20 00:20:05.891 5064-5064/com.example.binderclient W/System.err: android.os.DeadObjectException: Transaction failed on small parcel; remote process probably died
2020-07-20 00:20:05.891 5064-5064/com.example.binderclient W/System.err:     at android.os.BinderProxy.transactNative(Native Method)
2020-07-20 00:20:05.892 5064-5064/com.example.binderclient W/System.err:     at android.os.BinderProxy.transact(Binder.java:1127)
2020-07-20 00:20:05.892 5064-5064/com.example.binderclient W/System.err:     at com.example.binderserver.IMyAidlInterface$Stub$Proxy.hello(IMyAidlInterface.java:107)
2020-07-20 00:20:05.892 5064-5064/com.example.binderclient W/System.err:     at com.example.binderclient.MainActivity.testCase3(MainActivity.java:91)
2020-07-20 00:20:05.893 5064-5064/com.example.binderclient W/System.err:     at com.example.binderclient.MainActivity.testCases(MainActivity.java:56)
2020-07-20 00:20:05.893 5064-5064/com.example.binderclient W/System.err:     at com.example.binderclient.MainActivity.access$200(MainActivity.java:16)
2020-07-20 00:20:05.893 5064-5064/com.example.binderclient W/System.err:     at com.example.binderclient.MainActivity$1.onServiceConnected(MainActivity.java:26)
2020-07-20 00:20:05.893 5064-5064/com.example.binderclient W/System.err:     at android.app.LoadedApk$ServiceDispatcher.doConnected(LoadedApk.java:1730)
2020-07-20 00:20:05.894 5064-5064/com.example.binderclient W/System.err:     at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:1762)
2020-07-20 00:20:05.894 5064-5064/com.example.binderclient W/System.err:     at android.os.Handler.handleCallback(Handler.java:873)
2020-07-20 00:20:05.894 5064-5064/com.example.binderclient W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:99)
2020-07-20 00:20:05.894 5064-5064/com.example.binderclient W/System.err:     at android.os.Looper.loop(Looper.java:193)
2020-07-20 00:20:05.907 5064-5064/com.example.binderclient W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:6669)
2020-07-20 00:20:05.907 5064-5064/com.example.binderclient W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
2020-07-20 00:20:05.907 5064-5064/com.example.binderclient W/System.err:     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
2020-07-20 00:20:05.908 5064-5064/com.example.binderclient W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

客户端case4

比testCase3传输数据总量,小1k,可以正常调用。

    private  void testCase4() throws RemoteException {
        log("testCase4 enter.");
        testCase2();
        try {
            Thread.sleep(3 * 1000); // 3s
        } catch (InterruptedException e) {
            e.printStackTrace();
        final int size = 115 * 1024; // 115k, ok
        byte[] bytes = new byte[size];
        log("send " + size + " bytes");
        mMyAidlInterface.hello(bytes);

客户端case5

比testCase4大632字节,正常调用

    private  void testCase5() throws RemoteException {
        log("testCase5 enter.");
        testCase2();
        try {
            Thread.sleep(3 * 1000); // 3s
        } catch (InterruptedException e) {
            e.printStackTrace();
        final int size = 115 * 1024 + 632; // 115k + 632, ok
        byte[] bytes = new byte[size];
        log("send " + size + " bytes");
        mMyAidlInterface.hello(bytes);

客户端case6

比testCase5大1字节,发送错误。

   private  void testCase6() throws RemoteException {
        log("testCase5 enter.");
        testCase2();
        try {
            Thread.sleep(3 * 1000); // 3s
        } catch (InterruptedException e) {
            e.printStackTrace();
        final int size = 115 * 1024 + 633; // 115k + 633, crash
        byte[] bytes = new byte[size];
        log("send " + size + " bytes");
        mMyAidlInterface.hello(bytes);
2020-07-20 23:26:14.929 6128-6128/com.example.binderclient E/JavaBinder: !!! FAILED BINDER TRANSACTION !!!  (parcel size = 118492)
2020-07-20 23:26:14.930 6128-6128/com.example.binderclient W/System.err: android.os.DeadObjectException: Transaction failed on small parcel; remote process probably died
2020-07-20 23:26:14.931 6128-6128/com.example.binderclient W/System.err:     at android.os.BinderProxy.transactNative(Native Method)
2020-07-20 23:26:14.931 6128-6128/com.example.binderclient W/System.err:     at android.os.BinderProxy.transact(Binder.java:1127)
2020-07-20 23:26:14.932 6128-6128/com.example.binderclient W/System.err:     at com.example.binderserver.IMyAidlInterface$Stub$Proxy.hello(IMyAidlInterface.java:107)
2020-07-20 23:26:14.932 6128-6128/com.example.binderclient W/System.err:     at com.example.binderclient.MainActivity.testCase6(MainActivity.java:146)
2020-07-20 23:26:14.933 6128-6128/com.example.binderclient W/System.err:     at com.example.binderclient.MainActivity.testCases(MainActivity.java:75)
2020-07-20 23:26:14.933 6128-6128/com.example.binderclient W/System.err:     at com.example.binderclient.MainActivity.access$200(MainActivity.java:16)
2020-07-20 23:26:14.933 6128-6128/com.example.binderclient W/System.err:     at com.example.binderclient.MainActivity$1.onServiceConnected(MainActivity.java:26)
2020-07-20 23:26:14.936 6128-6128/com.example.binderclient W/System.err:     at android.app.LoadedApk$ServiceDispatcher.doConnected(LoadedApk.java:1730)
2020-07-20 23:26:14.937 6128-6128/com.example.binderclient W/System.err:     at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:1762)
2020-07-20 23:26:14.937 6128-6128/com.example.binderclient W/System.err:     at android.os.Handler.handleCallback(Handler.java:873)
2020-07-20 23:26:14.938 6128-6128/com.example.binderclient W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:99)
2020-07-20 23:26:14.938 6128-6128/com.example.binderclient W/System.err:     at android.os.Looper.loop(Looper.java:193)
2020-07-20 23:26:14.939 6128-6128/com.example.binderclient W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:6669)
2020-07-20 23:26:14.939 6128-6128/com.example.binderclient W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
2020-07-20 23:26:14.939 6128-6128/com.example.binderclient W/System.err:     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
2020-07-20 23:26:14.940 6128-6128/com.example.binderclient W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
在sendBroadcast,startActivity时,我们会用到Intent。
Intent可以携带一些数据,比如基本类型数据int、Boolean,或是String,或是序列化对象,Parcelable与Serializable。
Intent传递数据时,如果数据太大,可能会出现异常。比如App闪退,或是Intent发送不成功,logcat报错等等。
这就牵涉到一个问题:Intent 传递数据大小限制。
Intent到底能够携带多少数据呢?
使用Intent传送数据时,可能会出现异常
在Intent中传入一个Parcelable对象;例如传入一个bitmap对象。
				
碰到一个异常,具有随机性:     android.os.DeadObjectException: Transaction failed on small parcel; remote process probably died         at android.os.BinderProxy.transactNative(Native Method)         at android.o...
Binder做为Android中核心机制,对于理解Android系统是必不可少的,关于binder的文章也有很多,但是每次看总感觉看的不是很懂,到底什么才是binder机制?为什么要使用binder机制?binder机制又是怎样运行的呢?这些问题只是了解binder机制是不够的,需要从Android的整体系统出发来分析,在我找了很多资料后,真正的弄懂了binder机制,相信看完这篇文章大家也可以弄懂binder机制。要理解binder,先要知道IPC,Inter-processcommunication,也就是进程中相互通信,BinderAndroid提供的一套进程间相互通信框架。用来多进程
出现异常如下: System.err: android.os.DeadObjectException: Transaction failed on small parcel; remote process probably died 10-30 09:51:08.151  3664  3682 W System.err:     at android.os.BinderProxy.transac...
W/System.err: java.lang.SecurityException W/System.err: at android.os.BinderProxy.transactNative(Native Method) W/System.err: at android.os.Binde...
Android内核是基于Linux系统,而Linux现存多种进程间IPC方式:管道,消息队列,共享内存,套接字,信号量,信号.为什么Android非要用Binder来进行进程间通信呢.从我个人的理解角度,曾尝试着在知乎回答同样一个问题为什么Android要采用Binder作为IPC机制?.这是我第一次认认真真地在知乎上回答问题,收到很多网友的点赞与回复,让我很受鼓舞,也决心分享更多优先地文章回报读者和粉丝,为Android圈贡献自己的微薄之力.在说到Binder架构之前,先简单说说大家熟悉的TCP/IP的五层通信体系结构:应用层:直接为用户提供服务;传输层:传输的是报文(TCP数据)或者用户数
BinderAndroid系统进程间通信(IPC)方式之一。Linux已经拥有管道,systemVIPC,socket等IPC手段,却还要倚赖Binder来实现进程间通信,说明Binder具有无可比拟的优势。深入了解Binder并将之与传统IPC做对比有助于我们深入领会进程间通信的实现和性能优化。本文将对Binder的设计细节做一个全面的阐述,首先通过介绍Binder通信模型和Binder通信协议了解Binder的设计需求;然后分别阐述Binder在系统不同部分的表述方式和起的作用;最后还会解释Binder在数据接收端的设计考虑,包括线程池管理,内存映射和等待队列管理等。通过本文对Binde
Binder是什么?Binder是一种进程间通信机制为什么是BinderBinder通信机制采用C/S架构,这很重要!!!@Binder架构|centerBinder框架中主要涉及到4个角色Client、Server、ServiceManagerBinder驱动,其中Client、Server、ServiceManager运行在用户空间Binder驱动运行在内核空间Client代表客户端进程,Server代表客户端进程提供各种服务,如音视频等ServiceManager用来管理各种系统服务Binder驱动提供进程间通信的能力用户空间的Client、Server、ServiceManage
应用层:Binder是一个能发起进程间通信的JAVA类 Binder就是Android中的血管,在Android中使用Activity、Service等组件时都需要和AMS(system_server)进行通信,这种跨进程的通信都是通过Binder完成。 Activity、Service等组件和AMS不是同一个进程,其实也是多进程通信。 ②为什么要用多进程?
java.lang.IllegalStateException: android.os.DeadObjectException: Transaction failed on small parcel@ remote process probably died 今天在工作中遇到一个crash问题,也是第一次遇到这种类型的问题,下面是相关的部分log: java.lang.RuntimeException: Unable to create service com.android.systemui.System
csdn在线学习课程,课程咨询答疑和新课信息:QQ交流群:422901085进行课程讨论 android跨进程通信实战视频课程(加群获取优惠) 千里马android framework实战开发-binder驱动之oneway导致的transaction failed 首先来看错误: 06-15 12:10:36.686 31395 31507 W System.err: android.os.DeadObjectException: Transaction failed on small parcel; r
JavaBinder: !!! FAILED BINDER TRANSACTION !!! 是一种异常,它通常在Android开发中出现。这个异常的原因可以有多种。根据引用和引用,一种可能的原因是在绑定的事务过程中传递的数据量过大引起的。换句话说,当尝试传递大量数据时,系统无法处理,导致出现此异常。要解决这个问题,可以考虑减少传递的数据量,或者使用其他方法来传递数据,例如使用文件或数据库等。另外,根据引用,在处理数据时,也可以尝试将数据拆分成多个较小的部分进行传递,以避免出现此异常。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [JavaBinder: !!! FAILED BINDER TRANSACTION !!! 异常的解决方案分析](https://blog.csdn.net/wudongjiang333/article/details/78122234)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]