Android---认识进程与IPC架构

1、什么是IPC通信

  • IPC(Inter-Process Communication)通信,是跨越两个不同进程之间的通信
  • 一般而言,一个Android应用程序里的各个组件(如activity、service)都在同一个进程里执行。这种在同一进程内的通信,又称短程通信,意味着两个activity在同一个进程里执行。
  • 相对地:远程(Remote)通信的意思是:两个组件(activity或service)分别在不同的进程执行,两者之间的IPC通信又称远程通信。
默认情况下一个android程序运行在同一个进程中,但是可以通过预设将不同的组件运行在不同的进程中。
IPC通信的效率
  • 当我们启动某一应用程序时,Android系统里的Zygote服务孵化(Fork)一个新的进程给它,让后将它(该App)加载到这个新诞生的进程里。
  • 基于Linux的安全限制,以及进程的基本特性(不同进程的地址空间是独立的)。如果两个类(或其对象)在同一个进程里执行时,两者沟通方便也快速。
  • 但是,当他们分别在不同的进程里执行时,两者沟通就属于IPC跨进程沟通了(转地址),不如前者方便,也慢些。
2、Android的进程概念
  • 一个进程就是一个独立的执行空间,不回被正在其它进程里地程序所侵犯。这种保护方法是Android的重要安全机制。
  • 在Android的进程里,有一个虚拟机 (Virtual Machine,简称VM)的对象,可执行Java代码,也引导JNI本地程序的执行, 实现Java与C/C++之间的沟通;如下图:

        每一进程有:一个VM对象、主线程、 MQ和Looper

      

  • 每一个进程在诞生时,都会诞生一个主线程(Main Thread),以及诞生一个Looper类 的对象和一个MQ(Message Queue)数据 结构。每当主线程作完事情,就会去执行 Looper类。此时,不断地观察MQ的动态。 如下图:
          不同进程的地址空间是独立的


  

  • 主线程最主要的工作就是处理UI画面的事 件(Event),每当UI事件发生时,Android 框架会丢信息(Message)到MQ里。主线程 看到MQ有新的信息时,就取出信息,然后 依据信息内容而去执行特定的函数。执行 完毕,就再继续执行Looper类,不断地观 察MQ的动态。
  • 当两个类都在同一个进程里 执行时,两者之间的沟通,只要采取一般 的函数调用(Function Call)就行了,既快速 又方便。一旦两个类分别在不同的进程里 执行时,两者之间的沟通,就不能采取一 般的函数调用途径了,只好采取IPC沟通途径。
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。
 4IPC的IBinder接口-- 定义与实现

  • Android框架的IPC沟通仰赖单一的IBinder 接口。此时Client端调用IBinder接口的 transact()函数,透过IPC机制而调用到远方 (Remote)的onTransact()函数。
  • 在Android的源代码里,Java层的IBinder 接口是定义于IBinder.java代码文档里。此 程序文件如下:
  // IBinder.java
     // .......
     public interface IBinder {
          // ..........
          public boolean transact(int code, Parcel data, Parcel reply, int flags)
               throws RemoteException; // ...........
     }

  • 基于这个IBinder.java定义档,我们就可以 开发类来实现(Implement)它,然后提供 给其它App来调用了。在Android的框架里, 也撰写了Binder基类和BinderProxy类来实现IBinder接口。

       Java层的Binder基类定义

         

  • Binder基类的很重要目的是支持跨进程調 用Service,也就是让远程的Client可以跨 进程調用某个Service。
/ Binder.java
/ / .......public class Binder implements IBinder {
    // ..........
    private int mObject;
    public Binder() {
        init();
        // ........... }
        public final boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            // ................
            boolean r = onTransact(code, data, reply, flags);
            return r;
        }
        private boolean execTransact(int code, int dataObj, int replyObj, int flags) {
            Parcel data = Parcel.obtain(dataObj);
            Parcel reply = Parcel.obtain(replyObj);
            boolean res;
            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的子类别诞生对象时,会調用到 Binder()构造函数。此时,Binder()会调用到init()本地函数

Java层的BinderProxy基类定义

/ 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、IPC通信的三步骤

  • Step-1. Activity使用startService()函数来启动Service。
  • Step-2. Activity调用bindService()来绑定 Service。亦即,Activity建立与Service之 间的连结(Connection)。
  • Step-3. Activity调用IBinder接口的transact() 函数,透过底层Binder Driver驱动而间接调用到Binder基类的execTransact()函数, 转而调用 myBinder的onTransact()函数。
// myActivity.java
public class myActivity extends Activity implements OnClickListener {
    public void onCreate(Bundle icicle) {
        startService(new Intent("com.misoo.pk01.REMOTE_SERVICE"));
        bindService(new Intent("com.misoo.pk01.REMOTE_SERVICE"), mConnection, Context.BIND_AUTO_CREATE);
    }
    private ServiceConnection mConnection = new ServiceConnection() {
		public void onServiceConnected(ComponentName className, IBinder ibinder) {
    		mb = ibinder;
		}
	};
}
// myService.java
public class myService extends Service {
    private IBinder mb = null;

    @Override 
    public void onStart() {
        mb = new myBinder();
    }
    @Override 
    public IBinder onBind(Intent intent){
    	return mb;
    }
}
// myBinder.java
public class myBinder extends Binder {
    private Context ctx;
    public myBinder(Context cx) {
        ctx = cx;
    }
    @Override 
    public boolean onTransact(int code, Parcel data, Parcel reply, int flags) {
    
    }
}

Step-1:调用startService()

  •  当myActivity调用startService()时,就调用Service.onStart()函数,执行到指令:mb = new myBinder()
  • 接着,调用myBinder()构造(Constructor);进而调用父类别Binder()构造,转而调用JNI本地的init()函数。
  • 此刻执行init()函数时,会在C/C++层里诞 生一个JavaBBinderHolder类别的对象, 并且将这JavaBBinderHolder对象的指针 存入到myBinder对象里,让myBinder对 象指向JavaBBinderHolder对象。

Step-2:调用bindService()

  • 目前,已经执行完startService()函数了。 接着,myActivity继续调用bindService() 函数,想去绑定Service服务。如果找到该服务,且它尚未被任何Client所绑定的话, 就会調用myService的onBind()函数。此时, 执行到指令:return mb;
  • 如下述的程序码: 这onBind()函数将mb(即myBinder对象的 IBinder接口)回传Android框架(其实是框架 里的AMS(ActivityManagerService)。
  • 当AMS接到回传来的myBinder对象指针 (即其IBinder接口)时,就可以找到其在 C/C++层所对映的JavaBBinderHolder对 象。接着,调用JavaBBinderHolder的 get()函数去诞生一个JavaBBinder对象。

  • 接着,AMS在Client端进程的java层里诞生 一个BinderProxy对象来代表JavaBBinder的分身,也就是代表了myBinder的分身。 最后将BinderProxy的IBinder接口回传给 myActivity。

  • 此时完成了跨进程的服务绑定(Bind),如下图:


Step-3:调用IBinder接口的transact()

  • 所谓建好了服务绑定(Bind)之后,就如同 建好了跨进程的桥梁。之后,就能随时透过这桥梁而进行从myActivity调用到myService的跨进程IPC通信。绑定了服务之后,就能从myActivity调用BinderProxy(透过IBinder接口)的IBinder 接口,执行了transact()函数。如下图:


  • 在上图里,从JNI本地模块拉了一条红色虚 线,表示这并非直接的通信途径。也就是, 实际上是透过底层Binder Driver驱动才调用到BBinder的IBinder接口。







  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值