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

相关推荐
摆烂积极分子2 小时前
安卓开发学习-安卓版本
android·学习
n***26563 小时前
MySQL JSON数据类型全解析(JSON datatype and functions)
android·mysql·json
t***82113 小时前
mysql的主从配置
android·mysql·adb
YF02115 小时前
Frida如何稳定连接PC端跟Android手机端
android·mac·xposed
O***P5716 小时前
【MySQL】MySQL内置函数--日期函数字符串函数数学函数其他相关函数
android·mysql·adb
z***43846 小时前
MySQL-mysql zip安装包配置教程
android·mysql·adb
无心水7 小时前
【Python实战进阶】7、Python条件与循环实战详解:从基础语法到高级技巧
android·java·python·python列表推导式·python条件语句·python循环语句·python实战案例
g***78918 小时前
鸿蒙NEXT(五):鸿蒙版React Native架构浅析
android·前端·后端
Bervin1213814 小时前
Flutter Android环境的搭建
android·flutter
e***877021 小时前
windows配置永久路由
android·前端·后端