测试某机器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 传输大小限制可能因设备和系统版本的不同而有所差异。

相关推荐
硬件学长森哥1 天前
Android影像基础--cameraAPI2核心流程
android·计算机视觉
前行的小黑炭1 天前
Android 协程的使用:结合一个环境噪音检查功能的例子来玩玩
android·java·kotlin
阿华的代码王国1 天前
【Android】内外部存储的读写
android·内外存储的读写
inmK11 天前
蓝奏云官方版不好用?蓝云最后一版实测:轻量化 + 不限速(避更新坑) 蓝云、蓝奏云第三方安卓版、蓝云最后一版、蓝奏云无广告管理工具、安卓网盘轻量化 APP
android·工具·网盘工具
giaoho1 天前
Android 热点开发的相关api总结
android
咖啡の猫1 天前
Android开发-常用布局
android·gitee
程序员老刘1 天前
Google突然“变脸“,2026年要给全球开发者上“紧箍咒“?
android·flutter·客户端
Tans51 天前
Androidx Lifecycle 源码阅读笔记
android·android jetpack·源码阅读
雨白1 天前
实现双向滑动的 ScalableImageView(下)
android
峥嵘life1 天前
Android Studio新版本编译release版本apk实现
android·ide·android studio