Activity底层知识之Binder透彻分析

前言:

apk是怎么安装的?资源是怎么加载的?AIDL究竟是什么?Binder又是啥?等等这样的疑问,今天起就开始一一揭开。
先来一张图(网络图)感受一下:

今天重点先分析Binder。

知识准备

在讲解Binder前,我们先了解一些Linux的基础知识。

进程空间划分

  • 一个进程空间分为 用户空间 & 内核空间(Kernel),即把进程内 用户 & 内核 隔离开来。
  • 二者区别:进程间,用户空间的数据不可共享,所以用户空间 = 不可共享空间;进程间,内核空间的数据可共享,所以内核空间 = 可共享空间 。

    所有进程共用1个内核空间

  • 进程内 用户空间 & 内核空间 进行交互 需通过 系统调用,主要通过函数:
    • [x] copy_from_user():将用户空间的数据拷贝到内核空间
    • [x] copy_to_user():将内核空间的数据拷贝到用户空间

image

进程隔离 & 跨进程通信( IPC )

  • 进程隔离
    为了保证 安全性 & 独立性,一个进程 不能直接操作或者访问另一个进程,即Android的进程是相互独立、隔离的
  • 跨进程通信( IPC )
    即进程间需进行数据交互、通信
  • 跨进程通信的基本原理

image

a. 而Binder的作用则是:连接 两个进程,实现了mmap()系统调用,主要负责 创建数据接收的缓存空间 & 管理数据接收缓存

b. 注:传统的跨进程通信需拷贝数据2次,但Binder机制只需1次,主要是使用到了内存映射。

Binder 跨进程通信机制

image

模型原理步骤说明

image

以上内容参考:Android跨进程通信:图文详解 Binder机制 原理,如若侵权,请联系作者删除

Binder组成

(划重点了,作为APP开发人员👆上面的内容不是非必须的,下面的知识点是必须掌握的)

  • Binder分为Client和Server两个进程
    • [x] Client和Server是相对的,谁发消息,谁就是Client,谁接受消息,谁就是Server。
  • Binder组成。

整个通信过程过程可以看做一个拨打电话进行通信的过程,ServericeManager相当于一个电话局,张三(Client)给李四(Server)打电话,电话局先解析电话号码的地址。有的话就可以拨通,没有的话,就报错。

  • Binder通信过程

AIDL原理

AIDL是Binder的延伸。
Android系统中很多系统服务都是AIDL,比如剪切板,双进程守护。这里举例一下双进程守护:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: /Users/huangchen/workspace/web/yhparter/yh-partner-app/android/app/src/main/aidl/com/yonghuivip/partner/Service_1.aidl
*/
package com.yonghuivip.partner;
// Declare any non-default types here with import statements
public interface Service_1 extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.yonghuivip.partner.Service_1 {
private static final java.lang.String DESCRIPTOR = "com.yonghuivip.partner.Service_1";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.yonghuivip.partner.Service_1 interface,
* generating a proxy if needed.
*/
public static com.yonghuivip.partner.Service_1 asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.yonghuivip.partner.Service_1))) {
return ((com.yonghuivip.partner.Service_1) iin);
}
return new com.yonghuivip.partner.Service_1.Stub.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
//收到Binder驱动通知后,Server 进程通过回调Binder对象onTransact()进行数据解包 & 调用目标方法
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
// code即在transact()中约定的目标方法的标识符
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getName: {
// a. 解包Parcel中的数据
// a1. 解析目标方法对象的标识符
data.enforceInterface(DESCRIPTOR);
// a2. 获得目标方法的参数
java.lang.String _result = this.getName();
reply.writeNoException();
// c. 将计算结果写入到reply
reply.writeString(_result);
return true;
}
}
// 2. 将结算结果返回 到Binder驱动
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.yonghuivip.partner.Service_1 {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
// 注:在发送数据后,Client进程的该线程会暂时被挂起
// 所以,若Server进程执行的耗时操作,请不要使用主线程,以防止ANR
@Override
public java.lang.String getName() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
//通过 调用代理对象的transact() 将 上述数据发送到Binder驱动
mRemote.transact(Stub.TRANSACTION_getName, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_getName = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public java.lang.String getName() throws android.os.RemoteException;
}

AIDL重要的几个类:

  • IBinder
  • IInterface
  • Stub
  • Binder
  • Proxy

AIDL中涉及到的类图:

  • 1
    2
    3
    4
    MyService.asInterface(service).getName()
    ```
    asInteface作用是判断当前进程是否和自己再同一个进程。Stub调用自己的asInterface方法发现不在同一个进程之内,就调用Proxy的getName()
    - Proxy在自己的getName方法中,会使用Parceable来准备数据,把函数名称、函数参数都写入_data,让_reply接受函数返回值,最后调用IBinder的transact,就可以把数据传递给Binder的Server端。

    //通过 调用代理对象的transact() 将 上述数据发送到Binder驱动
    mRemote.transact(Stub.TRANSACTION_getName, _data, _reply, 0);

    1
    2
    - Server通过onTransact方法接受Client传递过来的数据,包括函数名称、函数参数,找到对应的函数,这里是getName(),把参数传递过去。所以onTransact方法经历了:读数据、执行要调用的函数、把执行结果再写入数据。

    //收到Binder驱动通知后,Server 进程通过回调Binder对象onTransact()进行数据解包 & 调用目标方法

    @Override
    public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
        // code即在transact()中约定的目标方法的标识符
        switch (code) {
            case INTERFACE_TRANSACTION: {
                reply.writeString(DESCRIPTOR);
                return true;
            }
            case TRANSACTION_getName: {
                // a. 解包Parcel中的数据
                // a1. 解析目标方法对象的标识符
                data.enforceInterface(DESCRIPTOR);
                // a2. 获得目标方法的参数
                java.lang.String _result = this.getName();
                reply.writeNoException();
                // c. 将计算结果写入到reply
                reply.writeString(_result);
                return true;
            }
        }
        // 2. 将结算结果返回 到Binder驱动
        return super.onTransact(code, data, reply, flags);
    }
    

    ```

四大组件的启动和后续流程,都是在和AMS打交道,四大组件给AMS发消息,四大组件就是Client Binder , AMS就是Server Binder,反之,角色替换。

参考:

声明:此为原创,转载请联系作者


作者:微信公众号添加公众号-遛狗的程序员 ,或者可以扫描以下二维码关注相关技术文章。

qrcode_for_gh_1ba0785324d6_430.jpg

当然喜爱技术,乐于分享的你也可以可以添加作者微信号:

WXCD.jpeg

文章目录
  1. 1. 前言:
  2. 2. 知识准备
    1. 2.1. 进程空间划分
    2. 2.2. 进程隔离 & 跨进程通信( IPC )
  3. 3. Binder 跨进程通信机制
    1. 3.1. 模型原理步骤说明
  4. 4. Binder组成
  5. 5. AIDL原理
|