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

相关推荐
alexhilton14 分钟前
玩转Shader之学会如何变形画布
android·kotlin·android jetpack
whysqwhw4 小时前
安卓图片性能优化技巧
android
风往哪边走5 小时前
自定义底部筛选弹框
android
Yyyy4825 小时前
MyCAT基础概念
android
Android轮子哥6 小时前
尝试解决 Android 适配最后一公里
android
雨白7 小时前
OkHttp 源码解析:enqueue 非同步流程与 Dispatcher 调度
android
风往哪边走7 小时前
自定义仿日历组件弹框
android
没有了遇见8 小时前
Android 外接 U 盘开发实战:从权限到文件复制
android
Monkey-旭9 小时前
Android 文件存储机制全解析
android·文件存储·kolin
zhangphil9 小时前
Android Coil 3拦截器Interceptor计算单次请求耗时,Kotlin
android·kotlin