Android Binder传输大文件

0 问题和解决方案

想要在自定义安卓系统服务中传输较大的数据,由于系统服务使用binder进行IPC,而binder最大只能传输(1mb-8kb)的数据,目前想到的解决方案是把数据拆分为多份,然后多次传输。本文记录这个解决方案遇到的一些坑

先放上关键的代码:

c++ 复制代码
auto myService = aidl::android::MyService::fromBinder(ndk::SpAIBinder(AServiceManager_getService("myservice")));
int pack_size = 0x7E000;  // 必须为4kb整数倍,且长度最好在1mb-8kb的一半以内
int count = (size / pack_size); // size是数据长度
if(count >= 255){
    return false;
}

// 分块传输, binder限制,每次只能传输1mb不到的数据
for(int i=0; i < count; i++){
    // begin是要传输的数据的首地址, size是数据长度
    std::vector<uint8_t> buff(begin + i*pack_size, begin + (i+1)*pack_size);
    // 传输pid、begin等参数,用于标记具体数据来源,传输参数i,用于标记块的顺序,方便服务端进行文件重组
    myService->trans_data(pid, begin, size, i, buff);
    usleep(5); //第二章会说明为什么要sleep
}
std::vector<uint8_t> buff(begin + count*pack_size, begin + size);
// 这里别忘了把额外的数据也补齐到4kb的整数倍,这里略过了补齐的代码
myService->trans_data(pid, begin, size, count, buff);
usleep(5);

1 数据必须为4kb的整数倍

刚开始我把数据拆分为每块1000000byte,可是服务端只接收到了999424byte数据,接收到的部分数据我保存为文件之后,如下所示:

diff 复制代码
-rw-rw---- 1 root root 999424 2023-08-09 16:24 part_2
-rw-rw---- 1 root root 999424 2023-08-09 16:24 part_3
-rw-rw---- 1 root root 999424 2023-08-09 16:24 part_4
-rw-rw---- 1 root root 999424 2023-08-09 16:24 part_5

999424换成16进制,就是0xF4000,是4kb的整数倍,这里我没有进一步确认是vector的问题还是binder的问题(也不知道为啥要舍弃掉多余的字符,而不是填充0补齐到整数倍,想弄懂原理估计很麻烦,这里先放着了),总之先把每块的数据调整为4kb的倍数。

调整后客户端发送的和服务端接收到的数据都是999424byte,保持一致,这个问题解决。

2 buffer释放问题

服务端处理数据的速度过慢时,会导致buffer来不及释放的问题。

比如每次只传999504byte数据,此时一个binder的buffer还会剩下40880byte内存,如果下一条数据已经准备开始传输了,同时上一条数据还没有处理完,buffer没有释放,这时只能在剩下的40880byte内存中申请999504byte的数据,很明显是不够的

注:我每块大小为999424byte,但是log显示要申请999504byte数据,猜测是其他的参数或者某些额外的数据结构多占了部分空间,这个对我最终目标没影响所以也不过多研究了

仔细观察报错,可以发现正常传输数据的间隔大概在3ms,而报错的地方与上一条log只差了1ms,于是修改代码,在每次循环中加入5ms的等待时间

yaml 复制代码
15:46:26.473  1258  1310 W         ==Mytag==
15:46:26.476  1258  1310 W         ==Mytag==
15:46:26.475     0     0 E         : c4   5038 binder_alloc: 1258: binder_alloc_buf size 999504 failed, no address space
15:46:26.475     0     0 E         : c4   5038 binder_alloc: allocated: 999504 (num: 1 largest: 999504), free: 40880 (num: 1 largest: 40880)
15:46:26.475     0     0 I         : c4   5038 binder: 5038:5038 transaction failed 29201/-28, size 999504-0 line 3317
15:46:26.480  1258  1310 W         ==Mytag==
15:46:26.483  1258  1310 W         ==Mytag==
15:46:26.486  1258  1310 W         ==Mytag==

但是修改之后还是会报同样的错,只不过频率低了很多,连续多次传输只报了一次错误,没修改之前几乎每次都会报错。而且观察修改后的log,其中的Mytag的时间间隔依旧在3ms,那么剩下的问题肯定不在我们客户端的数据传输间隔上了

重点转移到服务端,众所周知,binder服务端是可以多线程处理任务的,binder多个线程是共用一块buffer内存,所以减少多线程数量,即可减少多个线程争抢一块内存的情况。我这里用的是android系统服务的ndk后端,使用ABinderProcess_setThreadPoolMaxThreadCount 来设置最大线程数,我这里设定为5,但是依旧会出现上面的报错。

最后想到一个办法:把每块的大小限制在(1mb-8kb)的一半以内(一半是0x7F000,我最终设定为0x7E000),那么即使出现了上面没有及时释放buffer的情况,剩下的一半空间也能够支持一次数据传输。在循环加入等待时间之后,出现报错的频率已经大幅减少,在加上大小限制在一半的操作,最后终于稳定的通过了测试,多轮数据传输测试下来,基本没有再出现过报错了。

相关推荐
雨白7 小时前
Jetpack系列(二):Lifecycle与LiveData结合,打造响应式UI
android·android jetpack
kk爱闹9 小时前
【挑战14天学完python和pytorch】- day01
android·pytorch·python
每次的天空10 小时前
Android-自定义View的实战学习总结
android·学习·kotlin·音视频
恋猫de小郭11 小时前
Flutter Widget Preview 功能已合并到 master,提前在体验毛坯的预览支持
android·flutter·ios
断剑重铸之日12 小时前
Android自定义相机开发(类似OCR扫描相机)
android
随心最为安12 小时前
Android Library Maven 发布完整流程指南
android
岁月玲珑12 小时前
【使用Android Studio调试手机app时候手机老掉线问题】
android·ide·android studio
还鮟16 小时前
CTF Web的数组巧用
android
小蜜蜂嗡嗡17 小时前
Android Studio flutter项目运行、打包时间太长
android·flutter·android studio
aqi0017 小时前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体