当前位置: 首页 > wzjs >正文

做网站哪便宜我想学做互联网怎么入手

做网站哪便宜,我想学做互联网怎么入手,商务网站建设概念,福建建设厅安全员报名网站一、Binder 跨进程通信底层实现 Q1:Binder 如何实现一次完整的跨进程方法调用?请描述内核态与用户态交互流程 高频错误:仅回答 “通过 AIDL 生成代码”,未涉及 Binder 驱动三层协作模型 满分答案(附内核交互流程图&a…

一、Binder 跨进程通信底层实现

Q1:Binder 如何实现一次完整的跨进程方法调用?请描述内核态与用户态交互流程

高频错误:仅回答 “通过 AIDL 生成代码”,未涉及 Binder 驱动三层协作模型
满分答案(附内核交互流程图):

  1. Client 端(用户态)

    • 通过 AIDL 生成的Proxy类调用方法,如proxy.doSomething()
    • 封装请求:创建Parcel对象,写入方法码(TRANSACTION_CODE)和参数
    • 调用IBinder.transact(),触发BinderProxy.transact()
    // AIDL生成的Proxy类核心逻辑
    public void doSomething() throws RemoteException {Parcel data = Parcel.obtain();data.writeInterfaceToken(DESCRIPTOR); // 写入接口描述符mRemote.transact(TRANSACTION_doSomething, data, null, 0); // 触发跨进程data.recycle();
    }
    
  2. Binder 驱动(内核态)

    • 通过ioctl(BINDER_WRITE_READ)系统调用,将Parcel数据从 Client 用户空间拷贝到内核缓冲区(仅 1 次拷贝,传统 Socket 需 2 次)
    • 根据mRemote持有的handle查找 Binder 实体(驱动维护红黑树binder_refbinder_node映射)
    • 将请求加入 Server 端的 Binder 线程池等待队列
  3. Server 端(用户态)

    • Binder线程池中的线程(默认 15 个)通过IPCThreadState.talkWithDriver()读取驱动中的请求
    • 调用BBinder.onTransact()解析TRANSACTION_CODE,分发到具体方法(如Stub.doSomething()
    • 结果通过反向路径返回:Server 的Parcel.reply() → 驱动 → Client 的transact()回调

数据佐证:某大厂实测,Binder 单次调用耗时约 5-10μs,比 Socket 快 5 倍以上,核心优势在于零拷贝内存映射(通过mmap共享内核缓冲区)。

二、Binder 死亡通知与服务重连

Q2:服务进程崩溃后,客户端如何实现可靠的重连机制?

常见错误:未处理binderDied()后的资源释放,导致多次重连失败
满分答案(含防重复重连逻辑):

  1. 注册死亡通知

    private final IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() {@Overridepublic void binderDied() {// 1. 解除旧通知(避免内存泄漏)if (mService != null) {mService.asBinder().unlinkToDeath(this, 0);mService = null;}// 2. 延迟重连(避免服务刚重启就立即连接)new Handler(Looper.getMainLooper()).postDelayed(() -> {if (!mIsReconnecting.getAndSet(true)) { // 原子标记防止并发重连bindService(new Intent(context, MyService.class), connection, Context.BIND_AUTO_CREATE);}}, 500);}
    };// 注册时设置flags=0(阻塞等待死亡通知)
    mService.asBinder().linkToDeath(deathRecipient, 0); 
    
  2. 驱动层触发逻辑

    • 当 Server 进程终止,内核驱动检测到binder_node引用计数为 0,向所有 Client 发送BR_DEAD_BINDER命令
    • 客户端Binder线程收到命令后,回调DeathRecipient.binderDied()
  3. 避坑指南

    • 通知丢失:服务连续崩溃时,通过AtomicBoolean mIsReconnecting标记重连状态,避免重复绑定
    • UI 线程切换binderDied()在 Binder 线程回调,需通过Handler切回主线程更新 UI
    • 熔断机制:设置重连次数上限(如 3 次),超过后提示用户 “服务不可用”

大厂实战:某金融 APP 通过上述方案,将服务重连成功率从 68% 提升至 99.2%,内存泄漏率下降 40%。

三、Binder 线程池调优与异步化设计

Q3:为什么 Binder 线程池默认最大 15 个线程?如何优化高频 IPC 场景?

常见错误:认为 “线程数越多并发处理能力越强”,未考虑 Linux 线程调度开销
满分答案(含线程池源码解析):

  1. 线程池设计原理

    • 初始状态:首次调用Binder.transact()时,主线程加入线程池(spawnPooledThread(true)
    • 动态扩展:后续请求由ProcessState.spawnPooledThread(false)创建新线程,默认上限 15(由g_maxThreads控制,定义在frameworks/native/cmds/servicemanager/binder.cpp
    • Linux 限制:单个进程线程数过多会导致CPU上下文切换开销激增,实测 15 线程时吞吐量达到峰值
  2. 高频 IPC 优化方案

    • 异步调用:通过FLAG_ONEWAY标记无需返回值的调用(如日志上报),避免线程阻塞
      mRemote.transact(CODE_LOG, data, null, IBinder.FLAG_ONEWAY); // 异步调用
      
    • 事务合并:将多次小请求合并为批量操作(如一次传输 100 条数据),减少线程池竞争
    • 优先级调整:通过Binder.setCallerWorkSource()提升关键业务线程优先级
      // 提升当前线程优先级为前台服务等级
      Binder.setCallerWorkSource(WorkSource.fromUid(Process.myUid()));
      
  3. 源码级解释

    // Binder线程池核心逻辑(frameworks/native/libs/binder/ProcessState.cpp)
    void spawnPooledThread(bool isMain) {sp<Thread> t = sp<Thread>(new BinderThread(isMain));t->run("Binder_"); // 启动线程,名称格式为Binder_1, Binder_2...
    }
    
     

    关键:超过 15 个线程时,新请求会在队列中等待,而非无限制创建线程。

四、AIDL 生成类结构与手写要点

Q4:手写 AIDL 生成的 Stub 和 Proxy 类,并解释跨进程回调实现

常见错误:混淆Stub(服务端)与Proxy(客户端)的职责,未处理Parcelable自定义类型
满分答案(完整类结构 + 回调实现):

  1. Proxy 类(客户端代理)

    public static class Proxy implements IMyService {private final IBinder mRemote; // 持有服务端Binder引用public Proxy(IBinder remote) {mRemote = remote;}@Overridepublic String getString() throws RemoteException {Parcel data = Parcel.obtain();Parcel reply = Parcel.obtain();try {data.writeInterfaceToken(DESCRIPTOR);mRemote.transact(TRANSACTION_getString, data, reply, 0); // 同步调用reply.readException(); // 检查远程异常return reply.readString(); // 读取返回值} finally {data.recycle();reply.recycle();}}
    }
    
  2. Stub 类(服务端实现)

    public abstract class Stub extends Binder implements IMyService {public static IMyService asInterface(IBinder obj) {if (obj == null) return null;// 客户端收到服务端Binder时,转换为Proxy对象return (obj instanceof Stub) ? (IMyService) obj : new Proxy(obj);}@Overrideprotected boolean onTransact(int code, Parcel data, Parcel reply, int flags) {data.enforceInterface(DESCRIPTOR);switch (code) {case TRANSACTION_getString:data.readException(); // 忽略请求异常String result = getString(); // 调用服务端具体实现reply.writeString(result); // 写入返回值return true;default:return super.onTransact(code, data, reply, flags);}}
    }
    
  3. 跨进程回调实现

    • 定义 AIDL 回调接口
      interface ICallback {void onResult(String data);
      }
      
    • 服务端持有回调 Stub
      private final ICallback.Stub mCallback = new ICallback.Stub() {@Overridepublic void onResult(String data) {// 服务端主动调用客户端回调new Handler(Looper.getMainLooper()).post(() -> {// 执行业务逻辑});}
      };
      
    • 客户端传递 Proxy 对象
      // 客户端绑定服务时传递回调
      service.registerCallback(ICallback.Stub.asInterface(binder));
      

关键:自定义类型需实现Parcelable,并提供CREATOR常量,否则 AIDL 编译会报错。

五、Binder 内存管理与大文件传输(美团 / 滴滴高频坑题)

Q5:为什么 Binder 单次传输数据不能超过 1MB?如何安全传递大文件?

常见错误:认为 “超过 1MB 直接崩溃”,未掌握 Ashmem 共享内存方案
满分答案(含底层原理与实战代码):

  1. 三重限制解析

    • 内核限制Binder驱动的 mmap 共享内存区默认大小 1MB(可通过adb shell getprop ro.binder.vmsize查看)
    • 协议限制:单个事务缓冲区大小由BINDER_VM_SIZE宏定义,超过会触发TransactionTooLargeException
    • 性能瓶颈:实测数据显示,传输 500KB 耗时约 10μs,1MB 耗时骤增至 50μs,超过后耗时呈指数级增长
  2. 大文件传输方案

    • Ashmem 匿名共享内存(推荐方案):
      // 服务端创建Ashmem区域并写入文件
      int ashmemFd = Ashmem.create("large_file", fileSize);
      FileInputStream fis = new FileInputStream(filePath);
      FileDescriptor fd = fis.getFD();
      mmap(ashmemFd, 0, fileSize, PROT_READ, MAP_SHARED, 0, 0); // 映射内存
      // 通过Parcel传递文件描述符
      Parcel data = Parcel.obtain();
      data.writeFileDescriptor(ashmemFd);
      mRemote.transact(CODE_TRANSFER_FILE, data, null, 0);
      
    • 分片传输(适用于非连续数据):
      // 拆分为多个1MB块
      int chunkSize = 1024 * 1024;
      for (int i=0; i<data.length; i+=chunkSize) {int end = Math.min(i+chunkSize, data.length);Parcel chunk = Parcel.obtain();chunk.writeInt(i);chunk.writeByteArray(data, i, end-i);mRemote.transact(CODE_CHUNK, chunk, null, FLAG_ONEWAY);
      }
      
  3. 避坑指南

    • 文件描述符泄漏:通过ParcelFileDescriptor管理 Ashmem 文件描述符,确保close()及时释放
    • 版本兼容:Android 10 + 需使用MediaStoreDocumentsProvider传递大文件,避免READ_EXTERNAL_STORAGE权限问题
http://www.dtcms.com/wzjs/471586.html

相关文章:

  • 做网站公司在哪怎样在百度上注册自己的店铺
  • 制作外贸网站开发企业网站建设需求分析
  • 知乎网站建设入门书南宁 百度网盘
  • 网站建设咨询全网关键词搜索工具
  • 宝安网站开发谷歌代理
  • 重庆好的网站建设新产品的推广销售方法
  • 水务 网站建设太原互联网推广公司
  • 想学网站制作官方百度
  • 古风自己做头像的网站广州30万人感染
  • 用php做网站的书籍今日最新国际新闻头条
  • 电商网站开发平台山东做网站
  • 地方门户网站用户江阴网站优化公司
  • 中小企业 网站建设手机百度2020最新版
  • wordpress添加底部友情链接夫唯seo教程
  • 温州网站建设接单百度推广怎么做最好
  • 什么是灰色网站网络运营是什么意思
  • 长沙网站设计阿里云域名
  • 内部网站建设百度推广管理平台
  • 怎么建设网站规划湖南seo优化哪家好
  • 建设网站的好处有哪些b2b外链代发
  • 武汉网站建设索q.479185700seo求职
  • 佛山网站制作哪家便宜制作免费个人网站
  • 南开网站建设嘉兴seo外包公司费用
  • 公司网站是用什么软件做宁波seo推广公司排名
  • 网站调用微信数据排名前十的小说
  • 深圳建网站哪通过qq群可以进行友情链接交换
  • 酒类销售公司的网站建设网页制作app手机版
  • ui特效网站广东seo价格是多少钱
  • 做农家乐网站厦门人才网597人才网
  • 动画制作需要什么软件seo建站工具