【底层机制】【Android】Binder架构与原理

一、Binder 整体架构

1. 架构组成

  • Client:服务调用方
  • Server:服务提供方
  • ServiceManager:服务管理器,Android 系统启动时初始化的特殊 Binder 服务
  • Binder 驱动:内核空间的核心组件,负责进程间通信

2. 通信模型

sql 复制代码
Client Process      Kernel Space       Server Process
    |                   |                   |
    | -- IBinder.Proxy ->|                   |
    |                   | -- Binder Driver ->|
    |                   |                   | -- IBinder.Stub
    |                   | <- Transaction ---|
    | <- Result --------|                   |

二、Binder 驱动核心机制

1. 内存映射(mmap)

c 复制代码
// Binder 驱动关键数据结构
struct binder_proc {
    struct hlist_node proc_node;
    struct rb_root threads;        // 线程红黑树
    struct rb_root nodes;          // Binder 节点
    struct list_head delivered_death; // 死亡通知列表
};

struct binder_thread {
    struct binder_proc *proc;      // 所属进程
    wait_queue_head_t wait;        // 等待队列
    struct binder_transaction *transaction_stack; // 事务栈
};

mmap 工作原理

  • 进程打开 /dev/binder 设备后调用 mmap()
  • Binder 驱动在内核空间分配缓冲区
  • 同时映射到内核空间和用户空间
  • 一次拷贝机制:数据从客户端用户空间拷贝到内核缓冲区,服务端直接读取

2. 数据传输流程

  1. Client 发送数据

    • 数据打包为 binder_transaction_data
    • 通过 ioctl(BC_TRANSACTION) 发送到驱动
    • 驱动查找目标 Binder 实体
  2. Server 接收数据

    • 服务线程通过 ioctl(BC_ENTER_LOOPER) 进入循环
    • 调用 ioctl(BINDER_WRITE_READ) 读取事务
    • 驱动唤醒等待的服务线程

三、AIDL 本质解析

1. AIDL 生成的代码结构

java 复制代码
// 自动生成的 Binder 接口
public interface IMyService extends android.os.IInterface {
    // Binder 本地对象(服务端实现)
    public static abstract class Stub extends android.os.Binder implements IMyService {
        @Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) {
            switch (code) {
                case INTERFACE_TRANSACTION:
                    reply.writeString(DESCRIPTOR);
                    return true;
                case TRANSACTION_doSomething:
                    data.enforceInterface(DESCRIPTOR);
                    int _arg0 = data.readInt();
                    String _result = this.doSomething(_arg0);
                    reply.writeNoException();
                    reply.writeString(_result);
                    return true;
            }
            return super.onTransact(code, data, reply, flags);
        }
    }

    // Binder 代理对象(客户端使用)
    private static class Proxy implements IMyService {
        private android.os.IBinder mRemote;
        
        @Override
        public String doSomething(int param) {
            android.os.Parcel _data = android.os.Parcel.obtain();
            android.os.Parcel _reply = android.os.Parcel.obtain();
            String _result;
            try {
                _data.writeInterfaceToken(DESCRIPTOR);
                _data.writeInt(param);
                mRemote.transact(Stub.TRANSACTION_doSomething, _data, _reply, 0);
                _reply.readException();
                _result = _reply.readString();
            } finally {
                _reply.recycle();
                _data.recycle();
            }
            return _result;
        }
    }
}

2. AIDL 本质

  • 代码生成工具:将接口定义转换为 Binder 通信代码
  • Proxy-Stub 模式实现
    • Proxy:客户端代理,序列化参数并调用 transact()
    • Stub:服务端基类,反序列化参数并调用实际方法
  • 接口描述符机制:确保客户端和服务端接口版本一致

startActivity 的 Binder 调用全过程

一、进程内准备阶段

1. 发起调用

java 复制代码
// Activity.java
public void startActivity(Intent intent) {
    // 调用 ActivityTaskManager 服务
    ActivityTaskManager.getService().startActivity(
        mMainThread.getApplicationThread(), 
        mToken, 
        intent, 
        intent.resolveTypeIfNeeded(getContentResolver()),
        null, // resultTo
        null, // resultWho
        0,    // requestCode
        FLAG_ACTIVITY_NEW_TASK,
        null, // options
        null  // userId
    );
}

二、Binder 调用链详细流程

1. 客户端到系统进程(第一次 Binder 调用)

arduino 复制代码
Client Process (App) → System Server Process (AMS)

调用路径

  • Activity.startActivity()
  • ActivityTaskManager.getService().startActivity()
  • IActivityTaskManager.Stub.Proxy.startActivity()

Binder 事务

java 复制代码
// IActivityTaskManager.aidl 生成的 Proxy 类
public int startActivity(IApplicationThread caller, String callingPackage,
        Intent intent, ...) {
    Parcel data = Parcel.obtain();
    Parcel reply = Parcel.obtain();
    data.writeStrongBinder(caller != null ? caller.asBinder() : null);
    data.writeString(callingPackage);
    intent.writeToParcel(data, 0);
    // ... 其他参数序列化
    mRemote.transact(TRANSACTION_startActivity, data, reply, 0);
    reply.readException();
    int result = reply.readInt();
    return result;
}

2. 系统进程处理(AMS 侧)

AMS 处理逻辑

java 复制代码
// ActivityTaskManagerService.java
public final int startActivity(IApplicationThread caller, ...) {
    return getActivityStartController().obtainStarter(intent, ...)
        .setCaller(caller)
        .execute();
}

关键步骤

  1. 权限验证:检查调用者权限
  2. Intent 解析:解析目标 Activity 信息
  3. 进程检查:判断目标 Activity 所在进程是否已启动
  4. 栈管理:确定 Activity 应该放入哪个 Task

3. 暂停当前 Activity(第二次 Binder 调用)

arduino 复制代码
System Server Process (AMS) → Client Process (App)

AMS 调用应用进程

java 复制代码
// 通过 ApplicationThread 的 Binder 接口
app.thread.schedulePauseActivity(token, finished, userLeaving, configChanges);

应用进程处理

java 复制代码
// ActivityThread.java - ApplicationThread 内部类
public final void schedulePauseActivity(IBinder token, ...) {
    sendMessage(H.PAUSE_ACTIVITY, token);
}

// H(Handler)处理消息
case PAUSE_ACTIVITY: {
    handlePauseActivity((IBinder)msg.obj, ...);
    break;
}

private void handlePauseActivity(IBinder token, ...) {
    ActivityClientRecord r = mActivities.get(token);
    if (r != null) {
        // 调用 Activity 的 onPause()
        performPauseActivity(r, finished, reason, pendingActions);
    }
}

4. 启动目标进程(如果需要)

进程创建流程

  1. AMS 通过 Process.start() 请求 Zygote
  2. Zygote fork 新进程
  3. 新进程入口:ActivityThread.main()

5. 启动目标 Activity(第三次 Binder 调用)

java 复制代码
System Server Process (AMS) → Target Process (App)

AMS 调用目标进程

java 复制代码
// 通过目标进程的 ApplicationThread
thread.scheduleLaunchActivity(new Intent(r.intent), ...);

目标进程处理

java 复制代码
// ActivityThread.java
private void handleLaunchActivity(ActivityClientRecord r, ...) {
    // 1. 创建 Activity 实例
    Activity activity = mInstrumentation.newActivity(
        cl, component.getClassName(), r.intent);
    
    // 2. 创建 Application(如果不存在)
    Application app = r.packageInfo.makeApplication(false, mInstrumentation);
    
    // 3. 关联 Context
    activity.attach(appContext, ...);
    
    // 4. 调用 onCreate()
    mInstrumentation.callActivityOnCreate(activity, r.state);
    
    // 5. 调用 onStart()
    activity.performStart();
    
    // 6. 调用 onResume()
    activity.performResume();
}

三、Window 管理相关的 Binder 调用

1. 窗口创建(第四次 Binder 调用)

scss 复制代码
Target Process (App) → WindowManagerService (WMS)

调用流程

java 复制代码
// ActivityThread.handleResumeActivity()
final void handleResumeActivity(IBinder token, ...) {
    // 调用 Activity.onResume()
    ActivityClientRecord r = performResumeActivity(token, ...);
    
    if (r.activity.mVisibleFromClient) {
        // 添加窗口到 WMS
        ViewManager wm = r.activity.getWindowManager();
        wm.addView(decorView, layoutParams);
    }
}

// WindowManagerGlobal.addView()
public void addView(View view, ViewGroup.LayoutParams params, ...) {
    ViewRootImpl root = new ViewRootImpl(view.getContext(), display);
    root.setView(view, wparams, panelParentView);
}

ViewRootImpl 与 WMS 通信

java 复制代码
// ViewRootImpl.java
public void setView(View view, ...) {
    // 通过 Session 与 WMS 通信
    res = mWindowSession.addToDisplay(mWindow, ...);
}

四、Binder 驱动中的关键数据结构

1. 事务处理

c 复制代码
struct binder_transaction_data {
    union {
        size_t handle;    // 对 Server 的引用
        void *ptr;        // Server 的本地地址
    } target;
    void *data.ptr;       // 数据缓冲区
    size_t data_size;     // 数据大小
};

// Binder 驱动处理事务
static void binder_transaction(struct binder_proc *proc,
                   struct binder_thread *thread,
                   struct binder_transaction_data *tr) {
    // 查找目标 Binder 节点
    target_node = binder_get_node(proc, tr->target.handle);
    // 分配事务缓冲区
    t = kzalloc(sizeof(*t), GFP_KERNEL);
    // 拷贝数据到目标进程
    t->buffer = binder_alloc_buf(target_proc, tr->data_size);
}

五、完整调用时序总结

scss 复制代码
[Client Process]           [Binder Driver]        [System Server]        [Target Process]
      |                           |                       |                       |
      |--- startActivity() ------>|                       |                       |
      |                           |-- TRANSACTION ------->|                       |
      |                           |                       |-- AMS.startActivity() |
      |                           |                       |                       |
      |                           |<-- schedulePauseActivity --|                  |
      |<-- onPause() ------------|                       |                       |
      |                           |                       |                       |
      |                           |                       |-- (如果需要)创建进程 -|
      |                           |                       |                       |
      |                           |<-- scheduleLaunchActivity -|                  |
      |                           |                       |                  |-- onCreate()
      |                           |                       |                  |-- onStart()  
      |                           |                       |                  |-- onResume()
      |                           |                       |                  |-- addView()
      |                           |                       |                  |   (WMS调用)

六、性能优化关键点

  1. 一次拷贝优势:相比其他 IPC(如 Socket 需要 4 次拷贝),Binder 只需 1 次用户空间到内核空间的拷贝
  2. 引用计数:Binder 对象自动管理生命周期,避免内存泄漏
  3. 线程池管理:Binder 驱动维护线程池,避免频繁创建销毁线程
  4. 死亡通知 :通过 linkToDeath() 监控 Binder 服务状态,及时清理资源

整个 startActivity 过程涉及 3-4 次主要的 Binder 调用,通过精心设计的异步回调机制和状态管理,实现了跨进程的 Activity 启动流程。

相关推荐
友人.22721 小时前
Android 底部导航栏 (BottomNavigationView) 制作教程
android
努力学习的小廉21 小时前
初识MYSQL —— 事务
android·mysql·adb
阿里云云原生21 小时前
深度解析 Android 崩溃捕获原理及从崩溃到归因的闭环实践
android
.豆鲨包21 小时前
【Android】Android内存缓存LruCache与DiskLruCache的使用及实现原理
android·java·缓存
JulyYu1 天前
【Android】针对非SDK接口的限制解决方案
android·客户端
猪哥帅过吴彦祖1 天前
Flutter 系列教程:应用导航 - Navigator 1.0 与命名路由
android·flutter·ios
南山安1 天前
面试必考:从setTimeout到Promise和fetch
javascript·面试
程序员爱钓鱼1 天前
Python编程实战 - Python实用工具与库 - 正则表达式匹配(re 模块)
后端·python·面试
2501_916008891 天前
iOS 跨平台开发实战指南,从框架选择到开心上架(Appuploader)跨系统免 Mac 发布全流程解析
android·macos·ios·小程序·uni-app·iphone·webview
程序员爱钓鱼1 天前
Python编程实战 - Python实用工具与库 - 爬取并存储网页数据
后端·python·面试