Skip to content

Binder 与 Handler 原理深入详解

更新: 5/15/2026 字数: 0 字 时长: 0 分钟

1. Binder 驱动层原理

1.1 Binder 通信模型

用户空间                          内核空间                        用户空间
┌──────────┐                  ┌──────────────┐              ┌──────────┐
│ Client   │  ① transact     │              │              │ Server   │
│          │ ──────────────→  │              │              │          │
│ Proxy    │  copy_from_user  │ Binder 驱动   │  ② 唤醒      │ Stub     │
│          │                  │              │ ──────────→  │          │
│          │                  │ 内核缓冲区    │              │ onTransact│
│          │  ④ 返回          │ (mmap 映射到  │  ③ 直接读取   │          │
│          │ ←──────────────  │  Server 用户  │ ←──────────  │          │
│          │  copy_to_user    │  空间)        │  无需拷贝!    │          │
└──────────┘                  └──────────────┘              └──────────┘

关键:Server 进程通过 mmap 将内核缓冲区映射到自己的用户空间,所以 Server 读取数据时不需要 copy_to_user,实现了"一次拷贝"。

1.2 mmap 一次拷贝详解

c
// binder_mmap() - Binder 驱动中的 mmap 实现
static int binder_mmap(struct file *filp, struct vm_area_struct *vma) {
    struct binder_proc *proc = filp->private_data;

    // 1. 在内核虚拟地址空间分配一块区域
    area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP);
    proc->buffer = area->addr;

    // 2. 分配物理页面
    page = alloc_page(GFP_KERNEL);

    // 3. 将物理页面同时映射到:
    //    a) 内核虚拟地址空间(Binder 驱动可以访问)
    //    b) 用户虚拟地址空间(Server 进程可以访问)
    map_kernel_range_noflush(...)  // 映射到内核
    vm_insert_page(vma, ...)       // 映射到用户空间

    // 结果:内核缓冲区和 Server 用户空间指向同一块物理内存
}

数据传输过程:

1. Client 调用 transact(),数据在 Client 用户空间
2. Binder 驱动调用 copy_from_user(),将数据拷贝到内核缓冲区 ← 唯一的一次拷贝
3. 由于 mmap,Server 用户空间直接映射到这块内核缓冲区
4. Server 直接读取数据,无需再次拷贝

1.3 Binder 线程池

Server 进程
├── 主线程(UI 线程)
├── Binder 线程 1  ← 处理 Client A 的请求
├── Binder 线程 2  ← 处理 Client B 的请求
├── ...
└── Binder 线程 N  ← 最多 15 个(默认)

// ProcessState.cpp
#define DEFAULT_MAX_BINDER_THREADS 15

// 线程池启动
void ProcessState::startThreadPool() {
    spawnPooledThread(true);  // 创建第一个 Binder 线程
}

void IPCThreadState::joinThreadPool(bool isMain) {
    do {
        // 循环读取 Binder 驱动的命令
        result = getAndExecuteCommand();

        // 如果线程不够用,驱动会通知创建新线程
        // BR_SPAWN_LOOPER → spawnPooledThread(false)
    } while (result != -ECONNREFUSED && result != -EBADF);
}

1.4 AIDL 深入

oneway 关键字

aidl
// 普通调用:同步阻塞,Client 等待 Server 返回
interface IMyService {
    String getData();  // Client 线程阻塞直到 Server 返回
}

// oneway 调用:异步非阻塞,Client 不等待
oneway interface IMyCallback {
    void onResult(String data);  // Client 发完就返回,不等 Server 处理
}

oneway 的限制:

  • 不能有返回值(void)
  • 不能有 out/inout 参数
  • 异常不会传回 Client

in/out/inout 参数

aidl
interface IMyService {
    // in:Client → Server(默认,只传过去)
    void sendData(in MyParcelable data);

    // out:Server → Client(传过去的是空对象,Server 填充后传回)
    void receiveData(out MyParcelable data);

    // inout:双向传递(Client 传过去,Server 修改后传回)
    void processData(inout MyParcelable data);
}

Binder 死亡通知

kotlin
// 监听 Server 进程死亡
val deathRecipient = IBinder.DeathRecipient {
    // Server 进程死了,在这里重连
    reconnectService()
}

// 注册死亡通知
serviceBinder.linkToDeath(deathRecipient, 0)

// 取消注册
serviceBinder.unlinkToDeath(deathRecipient, 0)

原理:Binder 驱动维护了每个 Binder 引用的死亡通知列表。当 Server 进程退出时,驱动遍历列表,向所有注册了 DeathRecipient 的 Client 发送 BR_DEAD_BINDER 命令。

1.5 ServiceManager

ServiceManager 是 Binder 的"DNS",管理所有系统服务的注册和查找:

注册服务:
  SystemServer 启动时
    → AMS.addService("activity", ams)
    → WMS.addService("window", wms)
    → PMS.addService("package", pms)
    → ... 通过 Binder 调用 ServiceManager.addService()

查找服务:
  App 进程
    → ServiceManager.getService("activity")
    → 返回 AMS 的 Binder 代理对象
    → App 通过代理对象调用 AMS 的方法

ServiceManager 自身的 Binder 引用是固定的(handle = 0),所有进程都知道怎么找到它。

2. Handler 机制深入

2.1 epoll 机制

MessageQueue.next() 在没有消息时会阻塞,底层使用 Linux 的 epoll 机制:

c
// Looper.cpp (Native 层)
Looper::Looper() {
    mWakeEventFd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);  // 创建 eventfd
    mEpollFd = epoll_create1(EPOLL_CLOEXEC);                 // 创建 epoll

    // 监听 eventfd
    epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeEventFd, &eventItem);
}

// 等待消息
int Looper::pollInner(int timeoutMillis) {
    // epoll_wait 阻塞,直到:
    // 1. 超时(延迟消息到时间了)
    // 2. eventfd 可读(有新消息写入)
    int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);

    // 被唤醒后处理事件
    for (int i = 0; i < eventCount; i++) {
        if (eventItems[i].data.fd == mWakeEventFd) {
            awoken();  // 读取 eventfd,清除唤醒标记
        }
    }
}

// 唤醒
void Looper::wake() {
    uint64_t inc = 1;
    write(mWakeEventFd, &inc, sizeof(uint64_t));  // 向 eventfd 写入,触发 epoll_wait 返回
}

2.2 同步屏障详解

java
// 插入同步屏障(target == null 的 Message)
// 这是一个 hide 方法,只有 Framework 内部使用
int postSyncBarrier() {
    synchronized (this) {
        Message msg = Message.obtain();
        msg.markInUse();
        msg.when = SystemClock.uptimeMillis();
        msg.arg1 = token;
        // 注意:没有设置 target!普通 Message 的 target 是 Handler

        // 按时间插入队列
        Message prev = null;
        Message p = mMessages;
        while (p != null && p.when <= msg.when) {
            prev = p;
            p = p.next;
        }
        if (prev != null) {
            msg.next = p;
            prev.next = msg;
        } else {
            msg.next = p;
            mMessages = msg;
        }
        return token;
    }
}

// next() 中处理同步屏障
Message next() {
    for (;;) {
        nativePollOnce(ptr, nextPollTimeoutMillis);

        synchronized (this) {
            Message msg = mMessages;

            // 遇到同步屏障(target == null)
            if (msg != null && msg.target == null) {
                // 跳过所有同步消息,找异步消息
                do {
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
                // 只有异步消息能通过屏障
            }

            if (msg != null) {
                if (now < msg.when) {
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    // 取出消息
                    return msg;
                }
            }
        }
    }
}

使用场景:ViewRootImpl 在 scheduleTraversals() 时插入同步屏障,确保 UI 绘制的异步消息优先执行:

java
// ViewRootImpl.java
void scheduleTraversals() {
    if (!mTraversalScheduled) {
        mTraversalScheduled = true;

        // 1. 插入同步屏障
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();

        // 2. 发送异步消息(Choreographer 回调)
        mChoreographer.postCallback(
            Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        // Choreographer 内部发送的是异步消息(msg.setAsynchronous(true))
    }
}

void doTraversal() {
    mTraversalScheduled = false;

    // 3. 移除同步屏障
    mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);

    // 4. 执行绘制
    performTraversals();
}

2.3 IdleHandler 详解

java
// MessageQueue.java
Message next() {
    int pendingIdleHandlerCount = -1;

    for (;;) {
        nativePollOnce(ptr, nextPollTimeoutMillis);

        synchronized (this) {
            // ... 取消息的逻辑 ...

            // 没有消息或下一条消息还没到时间
            if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) {
                pendingIdleHandlerCount = mIdleHandlers.size();
            }

            if (pendingIdleHandlerCount <= 0) {
                mBlocked = true;
                continue; // 没有 IdleHandler,继续等待
            }

            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
        }

        // 执行 IdleHandler(在 synchronized 外面,不持有锁)
        for (int i = 0; i < pendingIdleHandlerCount; i++) {
            IdleHandler idler = mPendingIdleHandlers[i];
            boolean keep = idler.queueIdle();  // 执行回调

            if (!keep) {
                // 返回 false,执行一次后移除
                synchronized (this) {
                    mIdleHandlers.remove(idler);
                }
            }
        }

        pendingIdleHandlerCount = 0; // 本轮已执行,不再重复
    }
}

实际应用:

kotlin
// 1. 延迟初始化(首帧绘制完成后的空闲时间)
Looper.myQueue().addIdleHandler {
    // 在主线程空闲时执行,不影响 UI 流畅度
    Analytics.init(application)
    false // 只执行一次
}

// 2. 监控主线程卡顿
Looper.myQueue().addIdleHandler {
    // 每次主线程空闲时记录时间
    lastIdleTime = SystemClock.uptimeMillis()
    true // 保持,每次空闲都执行
}

// 3. Activity 泄漏检测(LeakCanary 的做法)
// 在 onDestroy 后添加 IdleHandler,空闲时检查 Activity 是否被回收

2.4 Handler 内存泄漏完整防护

kotlin
// 方案1:静态内部类 + WeakReference(Java 传统方案)
class MyActivity : AppCompatActivity() {
    private class SafeHandler(activity: MyActivity) : Handler(Looper.getMainLooper()) {
        private val ref = WeakReference(activity)

        override fun handleMessage(msg: Message) {
            val activity = ref.get() ?: return
            when (msg.what) {
                MSG_UPDATE -> activity.updateUI()
            }
        }
    }

    private val handler = SafeHandler(this)

    override fun onDestroy() {
        super.onDestroy()
        handler.removeCallbacksAndMessages(null)
    }
}

// 方案2:Lifecycle 感知(推荐)
class MyActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // 使用 lifecycleScope,Activity 销毁时自动取消
        lifecycleScope.launch {
            delay(60_000)
            updateUI()
        }
    }
}

// 方案3:自定义 LifecycleHandler
class LifecycleHandler(
    private val lifecycleOwner: LifecycleOwner,
    looper: Looper = Looper.getMainLooper()
) : Handler(looper), LifecycleEventObserver {

    init {
        lifecycleOwner.lifecycle.addObserver(this)
    }

    override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
        if (event == Lifecycle.Event.ON_DESTROY) {
            removeCallbacksAndMessages(null)
            lifecycleOwner.lifecycle.removeObserver(this)
        }
    }
}

3. App 启动流程源码级分析

3.1 Zygote fork 过程

java
// ZygoteInit.java
public static void main(String[] argv) {
    // 1. 预加载资源(所有 App 共享)
    preload();  // 加载 Framework 类、资源、OpenGL 等

    // 2. 启动 SystemServer
    if (startSystemServer) {
        Runnable r = forkSystemServer();
        if (r != null) r.run();  // 在 SystemServer 进程中执行
    }

    // 3. 进入循环,等待 AMS 的 fork 请求
    caller = zygoteServer.runSelectLoop(abiList);
}

// ZygoteConnection.java
Runnable processOneCommand() {
    // 读取 AMS 发来的参数
    Arguments args = readArgumentList();

    // fork 子进程
    pid = Zygote.forkAndSpecialize(uid, gid, ...);

    if (pid == 0) {
        // 子进程
        return handleChildProc(args);  // → ActivityThread.main()
    } else {
        // Zygote 进程
        handleParentProc(pid);
        return null;
    }
}

3.2 ActivityThread.main()

java
// ActivityThread.java
public static void main(String[] args) {
    // 1. 准备主线程 Looper
    Looper.prepareMainLooper();

    // 2. 创建 ActivityThread 实例
    ActivityThread thread = new ActivityThread();

    // 3. 向 AMS 注册(Binder 调用)
    thread.attach(false);
    // attach 内部:
    //   IActivityManager mgr = ActivityManager.getService();
    //   mgr.attachApplication(mAppThread);  // mAppThread 是 ApplicationThread(Binder 服务端)

    // 4. 获取主线程 Handler
    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();  // H 类,处理所有生命周期回调
    }

    // 5. 开始消息循环
    Looper.loop();  // 永不返回

    throw new RuntimeException("Main thread loop unexpectedly exited");
}

3.3 Application 创建过程

java
// AMS 收到 attachApplication 后回调
// ActivityThread.handleBindApplication()
private void handleBindApplication(AppBindData data) {
    // 1. 创建 Application 的 Context
    ContextImpl appContext = ContextImpl.createAppContext(this, data.info);

    // 2. 创建 Instrumentation
    mInstrumentation = new Instrumentation();

    // 3. 创建 Application
    Application app = data.info.makeApplication(false, mInstrumentation);
    // makeApplication 内部:
    //   app = mActivityThread.mInstrumentation.newApplication(cl, className, appContext);
    //   app.attach(context);  // → attachBaseContext()

    // 4. 初始化所有 ContentProvider
    installContentProviders(app, data.providers);
    // 遍历所有 Provider,依次调用 provider.attachInfo() → onCreate()

    // 5. 调用 Application.onCreate()
    mInstrumentation.callApplicationOnCreate(app);
}

注意顺序:attachBaseContext()ContentProvider.onCreate()Application.onCreate()

这就是为什么在 attachBaseContext 中不能使用 ContentProvider,而很多 SDK 利用 ContentProvider 做自动初始化(在 Application.onCreate 之前就执行了)。