测试某机器Android系统Binder数据传输大小限制

以下是一个简单的 Android 示例,用于测试 Binder 传输数据限制。该示例包含一个服务(Service),通过 Binder 机制与客户端(Activity)进行通信,并逐步增加传输的数据量,以确定触发 TransactionTooLargeException 异常(表示超过 Binder 传输限制)时的数据大小。

1. 创建 AIDL 文件

在 Android Studio 中,右键点击 app/src/main 目录,选择 New -> AIDL -> AIDL File,创建一个名为 IBinderTest.aidl 的文件,内容如下:

aidl 复制代码
// IBinderTest.aidl
package com.example.binderlimitdemo;

interface IBinderTest {
    void sendLargeData(in byte[] data);
}

AIDL(Android Interface Definition Language)用于定义跨进程通信的接口,这里定义了一个方法 sendLargeData 用于接收字节数组数据。

2. 创建服务类

创建一个继承自 Service 的类 BinderTestService,实现上述 AIDL 定义的接口:

java 复制代码
package com.example.binderlimitdemo;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

public class BinderTestService extends Service {
    private static final String TAG = "BinderTestService";

    // 继承自AIDL生成的Stub类,实现接口方法
    private final IBinderTest.Stub binder = new IBinderTest.Stub() {
        @Override
        public void sendLargeData(byte[] data) throws RemoteException {
            // 这里可以添加实际的业务逻辑,我们测试时只打印数据长度
            Log.d(TAG, "Received data length: " + data.length);
        }
    };

    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }
}

3. 在 AndroidManifest.xml 中注册服务

app/src/main/AndroidManifest.xml 文件中添加服务的注册声明:

注意:BinderTestService要设置独立进程,否则不会触发binder大小限制,试过不设置进程demo干到anr了。

ini 复制代码
<service
    android:name=".BinderTestService"
    android:enabled="true"
    android:process=":binder_test"
    android:exported="true">
</service>

4. 创建测试 Activity

创建一个 MainActivity 用于测试 Binder 传输,逐步增加数据量并尝试发送:

java 复制代码
package com.example.binderlimitdemo;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private IBinderTest binderTest;
    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName className, IBinder service) {
            binderTest = IBinderTest.Stub.asInterface(service);
            testBinderLimit();
        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            binderTest = null;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button startButton = findViewById(R.id.start_button);
        startButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this, BinderTestService.class);
                bindService(intent, connection, Context.BIND_AUTO_CREATE);
            }
        });
    }

    private void testBinderLimit() {
        int size = 1024 * 100; // 初始数据大小设为100KB,可根据需要调整起始值
        while (true) {
            byte[] data = new byte[size];
            try {
                binderTest.sendLargeData(data);
                Log.d(TAG, "Successfully sent data of size: " + size + " bytes");
                size += 1024 * 100; // 每次增加100KB
            } catch (RemoteException e) {
                if (e instanceof android.os.TransactionTooLargeException) {
                    Log.e(TAG, "Reached Binder transaction size limit at size: " + size + " bytes", e);
                } else {
                    Log.e(TAG, "RemoteException", e);
                }
                break;
            }
        }
        unbindService(connection);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (connection != null) {
            unbindService(connection);
        }
    }
}

5. 布局文件(activity_main.xml)

res/layout 目录下的 activity_main.xml 文件中,添加一个按钮用于启动测试:

xml

ini 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center">

    <Button
        android:id="@+id/start_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Start Binder Limit Test" />

</LinearLayout>

运行该应用,点击按钮后,应用会逐步增加通过 Binder 传输的数据量,直到触发 TransactionTooLargeException 异常,此时日志中会记录下达到 Binder 传输大小限制时的数据量。

测试log如下,该系统上限制是 1024000 bytes左右,系统提示限制1040384 bytes,真实限制在1040288 bytes,比系统提示少 96 bytes 。
text 复制代码
int size = 1024 * 1015;
Successfully sent data of size: 1039360 bytes
int size = 1024 * 1016;
com.example.myapplication            E  !!! FAILED BINDER TRANSACTION !!!  (parcel size = 1040480)
com.example.myapplication            E  Reached Binder transaction size limit at size: 1040384 bytes

请注意,以上代码基于 Android 平台,运行时需要 Android 设备或模拟器,并且实际的 Binder 传输大小限制可能因设备和系统版本的不同而有所差异。

相关推荐
一起搞IT吧44 分钟前
Camera相机人脸识别系列专题分析之十九:MTK ISP6S平台FDNode传递三方FFD到APP流程解析
android·图像处理·人工智能·数码相机·计算机视觉
wyjcxyyy1 小时前
打靶日记-RCE-labs
android
一笑的小酒馆10 小时前
Android12去掉剪贴板复制成功的Toast
android
一笑的小酒馆11 小时前
Android12App启动图标自适应
android
程序员江同学12 小时前
Kotlin 技术月报 | 2025 年 7 月
android·kotlin
某空m13 小时前
【Android】内容提供器
android
Greenland_1214 小时前
Android 编译报错 Null extracted folder for artifact: xxx activity:1.8.0
android
ZhuYuxi33314 小时前
【Kotlin】const 修饰的编译期常量
android·开发语言·kotlin
Bryce李小白14 小时前
Kotlin 实现 MVVM 架构设计总结
android·开发语言·kotlin
Kiri霧14 小时前
Kotlin位运算
android·开发语言·kotlin