美文网首页安卓学习笔记
android中的IPC机制

android中的IPC机制

作者: 笑羋 | 来源:发表于2017-12-02 14:57 被阅读0次

    前言:碎片化学习是不好的习惯,必须整理总结成自己的知识体系

    一.进程,线程

    1.进程与线程之间的关系

    从操作系统的角度来说:进程是系统资源分配的基本单位,线程是CPU调度最小的调度单位.一个进程可以包含多个线程。

    从应用进程的角度来说:一个应用进程被Zygote fork出来,就已经有了一些默认的线程,比如最重要的a)主线程:应用的生命周期函数都是在主线程中调用;b)binder线程:binder线程是应用中最重要的基础线程,它负责与ams跨进程沟通,完成组件的创建,启动,销毁,同时请求系统的服务,如JobSchecduleService.

    eg-1:system_server进程中的众多线程

    system 2050 632 2381384 148564 unix_strea 0000000000 S system_server

    system 2052 2050 2381384 148564 do_sigtime 0000000000 S Signal Catcher

    system 2054 2050 2381384 148564 futex_wait 0000000000 S ReferenceQueueD

    system 2056 2050 2381384 148564 futex_wait 0000000000 S FinalizerDaemon

    system 2058 2050 2381384 148564 futex_wait 0000000000 S FinalizerWatchd

    system 2060 2050 2381384 148564 futex_wait 0000000000 S HeapTaskDaemon

    system 2593 2050 2381384 148564 binder_thr 0000000000 S Binder:2050_1

    system 2600 2050 2381384 148564 binder_thr 0000000000 S Binder:2050_2

    system 2938 2050 2381384 148564 SyS_epoll_ 0000000000 S android.bg

    system 2939 2050 2381384 148564 SyS_epoll_ 0000000000 SActivityManager

    system 2940 2050 2381384 148564 SyS_epoll_ 0000000000 S android.ui

    system 2941 2050 2381384 148564 SyS_epoll_ 0000000000 S ActivityManager

    system 2942 2050 2381384 148564 SyS_epoll_ 0000000000 S android.fg

    system 2943 2050 2381384 148564 inotify_re 0000000000 S FileObserver

    system 2944 2050 2381384 148564 SyS_epoll_ 0000000000 S android.io

    system 2945 2050 2381384 148564 SyS_epoll_ 0000000000 S android.display

    system 2946 2050 2381384 148564 futex_wait 0000000000 S CpuTracker

    system 2947 2050 2381384 148564 SyS_epoll_ 0000000000 SPowerManagerSer

    system 2948 2050 2381384 148564 pm_get_wak 0000000000 S system_server

    system 2949 2050 2381384 148564 futex_wait 0000000000 S BatteryStats_wa

    system 3005 2050 2381384 148564 SyS_epoll_ 0000000000 SPackageManager

    eg-2:一个应用进程中的众多线程

    USER PID PPID VSIZE RSS WCHAN PC NAME

    u0_a55 4104 308 772924 28336 sys_epoll_ b6d2999c S com.xxx.xxx

    u0_a55 4109 4104 772924 28336 do_sigtime b6d29c70 S Signal Catcher   这个线程是用来捕获linux信号和做一些后续处理的。如SIGBUS

    u0_a55 4110 4104 772924 28336 poll_sched b6d29b8c S JDWP

    u0_a55 4111 4104 772924 28336 futex_wait b6d00644 S ReferenceQueueD

    u0_a55 4112 4104 772924 28336 futex_wait b6d00644 S FinalizerDaemon

    u0_a55 4113 4104 772924 28336 futex_wait b6d00644 S FinalizerWatchd

    u0_a55 4114 4104 772924 28336 futex_wait b6d00644 S HeapTaskDaemon

    u0_a55 4115 4104 772924 28336 binder_thr b6d29ac8 S Binder:4104_1   binder线程池

    u0_a55 4116 4104 772924 28336 binder_thr b6d29ac8 S Binder:4104_2

    u0_a55 4121 4104 772924 28336 inotify_re b6d2a978 S FileObserver

    u0_a55 4124 4104 772924 28336 sys_epoll_ b6d2999c S local_job_dispa

    u0_a55 4164 4104 772924 28336 sys_epoll_ b6d2999c S remote_job_disp

    2.Android中的多线程模型

    [2.1]Android 中的多进程一般指一个应用中存在多个进程的情况。我们可以通过指定

    android :process属性,让一个应用的不同组件运行在指定进程。

    以“:”开头的进程属于当前应用的私有进程,其它应用的组件不能通过ShareUID与它跑在一个进程

    指定全名的进程属于全局进程。其它应用的组件可以通过ShareUID与它跑在一个进程.

    [2.2]多进程带来的问题

    Android 为每个应用进程分配了一个独立的虚拟机,不同的虚拟机在内存分配上有不同的地址空间,所以运行在不同进程中的四大组件是不同通过内存来共享数据。多进程之间组件一定要共享数据吗?不一定,但是我们只要使用多进程模型,一般都是需要跨进程通信的。

    一般来说,使用多进程会造成以下几个问题:(参考任玉刚老师的书):

    1.静态成员和单例完全失效

    解释:同一个类在不同进程中拥有不同的地址空间,虽然类名,类变量一样,但是分配的地址不一样,所以同一个类(指类名称)在不同的进程中是完全不同的类了。

    2.线程同步机制失效

    解释:不同地址空间,不同类,所以锁对象,锁全局类都不同了

    3.Application会多次创建

    当指定一个组件跑在另外一个进程中时,Zygote会fork新的进程,当然会分配独立的虚拟机,整个过程就是启动了一个应用的过程。创建了一个新的Application对象。

    总结:运行在同一个进程中的组件属于同一个虚拟机同一个Application。多进程中不同进程的组件拥有不同的虚拟机,不同的Application,不同的内存地址。

    [2.3]多进程之间的通信

    由于不同进程所拥有的地址是两块不同的地址空间,所以不能直接通过共享内存共享数据了。直接上Linux,Android的通信方式:

    Linux常用跨进程通信方式:管道,信号量,共享内存,socket 。。。

    Android常用跨进程通信方式:Intent ,共享文件,SharedPreferences,Binder,socket,基于Binder的Messenger.下面详细学习进程间的通信方式。

    二,进程之间的通信方式

    1.Binder

    Binder

    是安卓中最重要的IPC通信方式了,一个应用进程的创建,应用进程中组件的生命周期的调度,系统服务的使用...处处都是binder,从而也可以看出,

    安卓中进程间的通信是非常频繁的,一句话来说,在Binder通信机制的强有力支持下,安卓进程间进行了友好的数据交互。

    Binder

    Binder印象

    Binder是进程间通信的一种架构,这个架构分为服务端接口,客户端接口,Binder驱动

    1.1

    aidl工具会把应用程序中的aidl文件生成一个非常复杂的java类。拆分

    由aidl生成的java文件(一个接口文件;该接口文件中嵌套一个抽象的类Stub,该类实现外边的接口文件,没有实现具体接口方法,接口方法由其子类

    实现;抽象类中有一个proxy类,该类是抽象Stub的代理类,同时也实现了最外层的接口文件,proxy文件的作用是将客户端的输入包装成统一形式,

    具体的业务实现在服务端

    Stub的子类中)

    由aidl文件系统帮我们生成的三个文件,

    a) 接口 IXXX extends IInterface

    b) abstract class Stub extends Binder imp IXXX

    该类重载了binder的 OnTransact方法:

    public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags){

    .................

    case TRANSACTION_startScan:

    {

    data.enforceInterface(DESCRIPTOR);  //校验

    java.lang.String[] _arg0;

    _arg0= data.createStringArray(); //读取参数

    com.miui.guardprovider.aidl.IVirusObserver _arg1;

    _arg1= com.miui.guardprovider.aidl.IVirusObserver.Stub.asInterface(data.readStrongBinder());//读取参数

    boolean _arg2;

    _arg2= (0!=data.readInt());//读取参数

    int _result = this.startScan(_arg0, _arg1, _arg2);//调用服务端服务函数

    reply.writeNoException();

    reply.writeInt(_result);//返回给客户端的结果

    return true;

    }

    ............................

    }

    c) static class Proxy imp IXXX

    服务端的代理类,跨进程通信中,客户端使用代理类访问服务。要想使用服务端,首先要获取服务端在Binder驱动中对应的mRemote变量的引用

    int

    startScan(java.lang.String[] paths,

    com.miui.guardprovider.aidl.IVirusObserver virusObserver, boolean

    isCloud) throws android.os.RemoteException

    {

    android.os.Parcel _data = android.os.Parcel.obtain();

    android.os.Parcel _reply = android.os.Parcel.obtain();

    int _result;

    try {

    _data.writeInterfaceToken(DESCRIPTOR);//对应服务端data.enforceInterface(DESCRIPTOR)

    _data.writeStringArray(paths);//写入参数

    _data.writeStrongBinder((((virusObserver!=null))?(virusObserver.asBinder()):(null)));////写入参数

    _data.writeInt(((isCloud)?(1):(0)));////写入参数

    mRemote.transact(Stub.TRANSACTION_startScan, _data, _reply, 0);//调用

    _reply.readException();

    _result = _reply.readInt();

    }

    finally {

    _reply.recycle();

    _data.recycle();

    }

    return _result;

    }

    一个完整的通信过程:客户端获取服务端的Binder对象引用 ,然后调用相关服务。

    客户端得到binder对象引用,通过 transact()将调用目标函数的参数写入包裹,再通过底层binder驱动转发到服务端,经过OnTransact分发调用具体实现,最终调用到service中的具体业务实现。

    a)客户端如何获得服务端的Binder对象引用

    系统服务:使用getSystemService()方法获取的服务,系统服务一般不使用Service类实现,一般都是基于binder类,可以仅使用Binder类扩展系统服务。系统服务由ServiceManager来管理,系统服务在使用前向ServiceManager进行注册,客户端使用服务时向ServiceManager获取服务的引用。注意ServiceManager也是一个系统服务,它的代理架构跟其他系统服务一样的

    应用程序自定义服务:客户端服务则必须基于Service类来编写,通过bindService获取相关服务的binder引用,asInterface提供了统一的查询接口,如果IPC通信,返回Proxy对象引用,如果进程内部使用服务则返回 Stub的具体实现类对象引用。

    自定义服务需要注册吗?

    两种获取方式最终都是通过AMS服务查询得到服务端的Binder引用

    b)binder 和 Service的关系

    在Service中实现具体的业务,然后通过Binder载体将具体业务的实现暴露给客户端。binder框架在整个通信过程中不做具体的业务实现,整

    个框架只负责运输数据,将客户端的请求精确传达给服务端,同时将服务端的处理结果传递给客户端。只做数据传输不做具体业务

    c)Framework层的binder架构与native层的binder架构之间的关系

    framework

    层的binder通过JNI调用native的binder架构,所以framework层(Java层)对native层(c/c++层)进行了一层包

    装,提供给应用层进行调用。native层binder是C/S架构,framework层的架构与相关类的设计原理与native层类似。所以理解了任

    意一层都很好理解另一层.

    1.2   binder的死亡监听

    onServiceDisconnected()

    1.3   aidl的权限验证

    androidmanifest.xml文件中定义permission.在onBind函数中进行权限校验

    2.ContentProvider

    ContentProvider底层实现是binder

    ContentProvider的唯一标识android:authorities="xxx"

    ContentProvider是对外界提供数据的,为了对数据进行保护,所以需要相关权限验证

    第三方应用进程访问时需要声明访问权限。(由此想到,不管是service,ContentProvider,还是broadcast,对访问者来说他们都是一种受保护的资源,所以整个访问过程中需要添加权限校验。不能随便访问。要安全的获取数据和服务,android是一个开源的系统,在开源的系统上防范变得很重要)

    contentprovider是提供数据访问的接口,至于底层数据的组织可以由Sqlite数据库存储组织,内存List组织,MatrixCursor组织

    contentprovider通过Uri来区分外界要访问的数据集合

    一般为了区分要访问的数据:定义唯一的Uri 和Uri_code,再通过UriMatcher将两者关联起来。

    数据访问流程:根据Uri--->Uri_code--->表名--->访问数据

    需要注意的是CRUP四大方法是存在多线程并发访问,因此方法内部要做好线程同步。

    如果底层数据是一块内存的话,如List,特别要做好数据同步。

    3.Socket

    通过Socket套接字进行跨进程的通信,eg:让服务端循环监听一个端口,客户端请求连接服务端。Socket本身支持传输任意字节流

    4.文件

    相关文章

      网友评论

        本文标题:android中的IPC机制

        本文链接:https://www.haomeiwen.com/subject/pdunbxtx.html