Android从程序员到架构师之路2

本文探讨了Android中IPC(Inter-Process Communication)的概念,解释了IPC通信在不同进程间的作用,强调了其相比同一进程中通信的效率差异。文章还介绍了Android进程的基本概念,每个进程的主线程、Looper和MQ消息队列的角色,并阐述了如何通过AndroidManifest.xml设置进程。重点讨论了Android IPC通信依赖的IBinder接口,以及其在跨进程通信中的作用和实现机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文学习自高焕堂老师的Android从程序员到架构师之路系列教学视频

33 - 认识进程(Process)与IPC架构a

1.什么是IPC通信

IPC(Inter-Process Communication)通信,是跨越两个不同进程(Process)之通信。一般而言,一个Android应用程序里的各组件(如Activity、Service等)都在同一个进程里执行。这种在同一进程内的通信,又称为短程通信,意味着,两个Activity在同一个进程(Process)里执行
相对地,远程(Remote)通信的意思是:两个组件(如Activity或Service)分别在不同的进程里执行;两者之间是IPC通信,又称远程通信

IPC通信效率

1.1当我们启动某一支应用程序(App)时,Android系统里的Zygote服务孵化(Fork)一个新进程(Process)给它,然后将它(该App)加载到这个新诞生的进程里
1.2基于Linux的安全限制,以及进程的基本特性(例如,不同进程的地址空间是独立的),如果两个类(或其对象)在同一个进程里执行时,两者沟通方便也快速。但是,当它们分别在不同的进程里执行时,两者沟通就属于IPC跨进程沟通了,不如前者方便,也慢些

2 复习:Android的进程概念
2.1一个进程是一个独立的执行空间,不会被正在其它进程里的程序所侵犯。这种保护方法是Android的重要安全机制。于是,得先认识进程的内涵,才能进一步了解跨进程IPC机制
2.2在Android的进程里,有一个虚拟机(Virtual Machine,简称VM)的对象,可执行Java代码,也引导JNI本地程序的执行,实现Java与C/C++之间的沟通
在这里插入图片描述
每一个进程在诞生时,都会诞生一个主线程(Main Thread),以及诞生一个Looper类的对象和一个MQ(Message Queue)数据结构。每当主线程作完事情,就会去执行Looper类。此时,不断地观察MQ的动态。
主线程最主要的工作就是处理UI画面的事件(Event),每当UI事件发生时,Android框架会丢信息(Message)到MQ里。主线程看到MQ有新的信息时,就取出信息,然后依据信息内容而去执行特定的函数。执行完毕,就再继续执行Looper类,不断地观察MQ的动态。
刚才说明了,当两个类都在同一个进程里执行时,两者之间的沟通,只要采取一般的函数调用(Function Call)就行了,既快速又方便。一旦两个类分别在不同的进程里执行时,两者之间的沟通,就不能采取一般的函数调用途径了,只好采取IPC沟通途径。
在这里插入图片描述
34 - 认识进程(Process)与IPC架构b
3.设定IPC通信-- 使用AndroidManifest.xml文件
在Android框架里,一个应用(程序)套件(Application Package)通常含有多个Java类(Class),这些类可以在同一个进程(Process)里执行;也可以在不同的进程里执行 。 通常,一个进程只会摆一支App。但是一支App可占用多个进程。例如有一个App的AndroidManifest.xml
文件内容如下:

<activity android:name=".FirstActivity" >
 <intent-filter>
 <action android:name="android.intent.action.MAIN" />
 <category android:name
 ="android.intent.category.LAUNCHER" />
 </intent-filter> </activity>
 <activity android:name=".LoadActivity">
 </activity>
 
 <service android:name=".LoadService" android:process=":remote" >
 <intent-filter>
 <action android:name
 ="com.misoo.pkm.REMOTE_SERVICE" />
 </intent-filter></service>
</manifest>

在这里插入图片描述
其中,FirstActivity和LoadActivity两个类别会加载预设的进程里。而LoadService则会加载于名为“remote”的独立进程里。
并且,由进程#1的主线程去执行FirstActivity和LoadActivity(的函数)。而由进程#2的主线程去执行LoadService。上图也可简化而表达如下图
在这里插入图片描述
在Android的各进程里,都有一个VM对象,执行Java代码,也引导JNI本地程序的执行,实现Java与C/C++程序之间的沟通。

35 - 认识进程(Process)与IPC架构c

4 IPC的IBinder接口-- 定义与实现
大家都知道,当两个类都在同一个进程里执行时,两者之间的沟通,只要采取一般的函数调用(Function Call)就行了,既快速又方便。一旦两个类分别在不同的进程里执行时,两者之间的沟通,就不能采取一般的函数调用途径了。只好采取IPC沟通途径。

Android框架的IPC沟通仰赖单一的IBinder接口。此时Client端调用IBinder接口的transact()函数,透过IPC机制而调用到远方(Remote)的onTransact()函数。
在Android的源代码里,Java层的IBinder接口是定义于IBinder.java代码文档里。此程序文件如下

frameworks\base\core\java\android\os\IBinder.java
public interface IBinder {
    public boolean transact(int code, Parcel data, Parcel reply, int flags)
        throws RemoteException;
}

IBinder接口定义了一些函数,可以让Client程序可以进行跨进程的調用(当然也能支持同进程的短程調用)。其中,最主要的一个函数就是:transact()函数。于此,以图形来表达IBinder接口与transact()函数之间的关系。如下述的UML图
在这里插入图片描述
基于这个IBinder.java定义档,我们就可以开发类别来实作(Implement)它,然后提供给其它App来調用了。在Android的框架里,也撰写了Binder基类和BinderProxy类别来实作 IBinder接口。
在这里插入图片描述

frameworks\base\core\java\android\os\IBinder.java
public class Binder implements IBinder {
    public Binder() {
        init();
		......
    }
    
    public final boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
		 ......调用onTransact
		boolean r = onTransact(code, data, reply, flags);
        return r;
	}
    
    private boolean execTransact(int code, long dataObj, long replyObj, int flags) {
        Parcel data = Parcel.obtain(dataObj);
        Parcel reply = Parcel.obtain(replyObj);
        ......
        res = onTransact(code, data, reply, flags);
        ......
        return res;
	}
    protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException
    private native final void init();

在这里插入图片描述
Binder基类的主要函数是
transact()函数 — 用来实作IBinder的transact()函数接口。
execTransact()函数 — 其角色与transact()函数是相同的,只是这是用来让C/C++本地程序来調用的
onTransact()函数 — 这是一个抽象函数,让应用子类来覆写(Override)的。上述的transact()和execTransact()两者都是調用onTransact()
函数来实现反向調用(IoC, Inversion of Control)的。
init()函数 — 这是一个本地(Native)函数,让JNI模块来实现这个函数。Binder()构造函数(Constructor)会調用这个init()本地函数。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

// Binder.java
// ………
final class BinderProxy implements IBinder {
 private int mObject;
 // ..........
 BinderProxy() {
 // .........
 }
 public native boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException;
 private int mObject;
}

当我们看到类别名称是 XXXProxy时,就自然会联想到它是摆在Client进程里,担任Service端的分身(Proxy)。
由于跨进程沟通时,并不是从Java层直接沟通的,而是透过底层的Binder Driver驱动来沟通的,所以Client端的Java类别(如Activity)必须透过BinderProxy分身的IBinder接口,转而調用JNI本地模块来衔接到底层Binder Driver驱动服务,进而調用到正在另一个进程里执行Service。
在这里插入图片描述
当Client透过IBinder接口而調用到BinderProxy的transact()函数,就調用到其 JNI本地模块的transact()函数,就能进而衔接到底层Binder Driver驱动服务了。
在这里插入图片描述
在上图里,从JNI本地模块拉了一条红色虚线,表示这并非直接的通信途径。也就是,实际上是透过底层Binder Driver驱动才調用到BBinder的IBinder接口。如下图:
在这里插入图片描述
5 使用IBinder接口

  1. IPC通信的三步骤
  2. 短程通信vs. 远程通信
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值