nashcft's blog

時々何か書く。

Binder transaction buffer は1MBとは限らないかもしれない話

今開発しているアプリで特定の端末・条件でとある画面への遷移時に画面が真っ暗になって操作を受け付けなくなったり、該当する中で古い端末だとアプリが強制終了したりしてしまうという現象に出くわして、ログを眺めてみたら以下の例外が出続けていた:

Exception thrown launching activities in ProcessRecord{(略)}
    android.os.TransactionTooLargeException: data parcel size 645548 bytes
        at android.os.BinderProxy.transactNative(Native Method)
        at android.os.BinderProxy.transact(Binder.java:615)
        at android.app.ApplicationThreadProxy.scheduleLaunchActivity(ApplicationThreadNative.java:893)
        at com.android.server.am.ActivityStackSupervisor.realStartActivityLocked(ActivityStackSupervisor.java:1330)
        at com.android.server.am.ActivityStackSupervisor.attachApplicationLocked(ActivityStackSupervisor.java:892)
        at com.android.server.am.ActivityManagerService.attachApplicationLocked(ActivityManagerService.java:7116)
        at com.android.server.am.ActivityManagerService.attachApplication(ActivityManagerService.java:7194)
        at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:542)
        at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:3032)
        at com.android.server.am.ActivityManagerServiceEx.onTransact(ActivityManagerServiceEx.java:594)
        at android.os.Binder.execTransact(Binder.java:565)

それでリファレンスを読んだりQiitaの記事を漁ったりして、上記の例外は Binder transaction buffer に対して上限を超えたサイズのデータをやりとりしようとした時に発生するっぽいことがわかった。

読んだ記事: qiita.com

qiita.com

確かに問題の画面遷移では Intent にそれなりなサイズになるデータを1つ保持させるのでそれかなーと納得しかけたが、ちょっと変なことに気がついた。
読んだページの中で Binder transaction buffer の上限は1MBと書かれているが、上の例外には data parcel size 645548 bytes とある。つまり読み方が間違ってなければだいたい650KB弱のデータで音を上げていることになる。さっきの「それなりなサイズのデータ」以外に保持させている大きなデータは無いし、そうなると transaction buffer の上限が1MBならばこれで too large と判断されるのはおかしいはず。

それで気になってググってみたら StackOverFlow の以下の記事がすぐに引っかかった:

stackoverflow.com

The limit is supposed to be 1MB but it varies by device from little less than 512KB up to almost a full 1MB.

質問は2013年、上で一部引用したベストアンサーの回答も2015年とやや古いが、端末によって transaction buffer のサイズが異なるとある。それで "binder transaction buffer size vary" とかでさらにググってみたら他にもいくらか引っかかる様子。

https://www.neotechsoftware.com/blog/android-intent-size-limit

リファレンスはまるで一律1MBだと定めているように読めるのでなんだかなーという気持ちになった。リファレンスの記述は以下の通り:

The Binder transaction buffer has a limited fixed size, currently 1Mb, which is shared by all transactions in progress for the process.

さてどうやって対応したものかね...