1. ホーム
  2. アンドロイド

FAILED BINDER TRANSACTION (Android Binderの転送データサイズ制限)

2022-03-16 04:49:16
<パス

Androidのソースコードにおけるサイズ設定

http://androidxref.com/9.0.0_r3/xref/frameworks/native/libs/binder/ProcessState.cpp#43



デフォルトのページサイズは4k(4096)で、問い合わせコマンドは getconf PAGE_SIZE です。



つまり、バインダーのデータサイズの上限は、通常1M~8Kです

  view.setAlpha(float alpha) parameter range is 0~1; and view.getBackground().setAlpha(int alpha) passed in is an integer number from 0~255 (eventually they will both be converted to hexadecimal transparency, the former will first convert the parameter alpha*255 to int type )

フレームワークエラー警告関連コード

http://androidxref.com/9.0.0_r3/xref/frameworks/base/core/jni/android_util_Binder.cpp#794



コードを見ていただくとわかるように



バインダーのトランザクションに失敗した場合のみ、エラーメッセージが表示されます。バインダーを使用してデータを転送するプロセス全体のサイズの合計が1M~8kを超えると失敗します。



このAIDL呼び出しのデータ量が200kを超えると判断された場合、TransactionTooLargeExceptionがプロンプトされる



そうでない場合は、「Transaction failed on small parcel; remote process probably died」というプロンプトが表示されます。

バインダートランザクションが成功した場合 このAIDLコールが200k以上のデータを持っていても、エラーは発生しない 次のケースのように2



もちろん、ここから明らかなように、AIDLの設計では、バインダーの容量が不足しないように、AIDLパラメーターによる大きなデータの転送や、AIDLで直接長い演算を最小限にする必要があります

view.setAlpha(float alpha) sets the transparency of the entire view (including its children). view and its children disappear when setAlpha(0).

view.getBackground().setAlpha(int alpha) is to set the background transparency, view.getBackground().setAlpha(0) is the background full transparency, its child view does not receive the effect.

転送データサイズ制限の把握

1M-8k=1016kのサイズは、プロセス内のすべてのバインダースレッドを合わせたサイズの制限となります。



例えば、あるプロセス内に既に3つのバインダースレッドがあり、900kを占有している場合、後から167kを転送したバインダースレッドはエラーを報告します。この例のデモを以下に示します。



次に、仮想マシンAndroid Pの上で実験します。

この記事のコード位置

https://github.com/romulus1985/BinderTransaction

サーバーサイドのコード

サーバーサイドのメソッドが長時間終了しない



テストケースを実行するたびに、サーバーアプリを再起動する必要があることに注意してください。

In the use of view.getBackground().setAlpha(int alpha) to give transparent value is to make the same color straight to the other interface is affected. The solution is as follows

view.getBackground().mutate().setAlpha(int alpha) Just add .mutate() to the end of getBackground to fix it.

クライアント側通信ツールAPI

複数のスレッドでAIDLを呼び出し、指定したバイトのデータを送信する

    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();
        }
    }



クライアント事例1

FAILED BINDER TRANSACTION !!!」というプロンプトが表示されているのがわかると思います。(区画サイズ = 1048672)と表示されています。



android.os.TransactionTooLargeException: データ量が多すぎるため、プロンプトが表示される



ここでは、クライアントの出力は1M = 1024 * 1024 = 1,048,576 で、システムヒントは1Mよりわずかに大きい96byteで、バインダー呼び出しがメソッドパラメータに加えて別の部分の領域を占有することを示すものである。

    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 )


クライアント事例2

300k x 3 = 900K works fine

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


クライアント事例3

プロンプトが表示されます。バインダー取引に失敗しました! (区画サイズ = 171104)



testCase2の900Kに加え、116Kを再度転送すると、116 * 1024 = 118,784となり、この呼び出しのバインダーデータサイズは118,880であり、メソッドパラメータよりまだ96バイト大きいことがシステムからプロンプトが表示されます。

   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 )





クライアント事例4

転送されたデータの総量は、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);
    }


クライアント事例5

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);
    }


クライアント事例6

testCase5 より 1 byte 大きい、エラーを送信する。

   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 )