二.Binder原理分析

Android系统使用进程有什么优点?

  1. 安全性
    • 每个进程都是单独运行的,可以保证应用层对系统层的隔离
  2. 稳定性
    • 某个进程崩溃了不会导致其他进程崩溃
  3. 内存分配
    • 进程不需要了可以从内存用移除并回收进程占用的内存空间

1个App采用多进程实现的优点?
1个App使用多进程的原因:
虚拟机分配给每个进程的资源是有限的,LMK(Low Memory Killer)优先回收系统资源占用多的进程.

查看微信App运行了几个进程的命令:
adb shell ps -A |grep tencent
查询结果:

HWLLD-H:/ $ ps -A |grep tencent                                                                                                                                                                    
u0_a121      12781   545 27892876 436924 0                  0 S com.tencent.mm
u0_a121      13092   545 5677120 106016 0                   0 S com.tencent.mm:push
u0_a121      13285   545 238093944 234700 0                 0 S com.tencent.mm:appbrand0
u0_a121      13299   545 10023996 152260 0                  0 S com.tencent.mm:appbrand1
u0_a121      14284   545 22470288 113608 0                  0 S com.tencent.mm:xweb_privileged_process_0
u0_i22       14297   545 21911432 249268 0                  0 S com.tencent.mm:xweb_sandboxed_process_0

App使用多进程的优点:

  • 突破1个进程内存限制
    • 比如:微信图库(tools)占用内存过多,图库的在一个单独的进程中
  • 功能稳定性,独立的通信进程保持长连接的稳定性
    • 比如:微信的消息推送(push)采用一个单独的进程来处理,防止消息丢失
  • 规避系统内存泄漏
    • WebView默认是内存泄漏的,可以将WebView放在一个单独的进程中来隔离内存泄漏.
  • 隔离风险
    • 把存在安全隐患的逻辑放在一个单独的进程中去做处理

Binder是什么呢?
在android中我们所使用的Activity、Service等组件都需要和AMS(SystemServer进程中的一个服务AMS)通信,这种跨进程的通信都是通过Binder完成.

  • 机制:Binder是一种跨进程通信的机制
  • 驱动:Binder是一个虚拟物理设备驱动
  • 应用层:Binder是一个能发起通信的java类
  • Framework/Native:Binder连接了Client和Server、ServiceManager和Binder驱动程序,形成了一套C/S通信架构.

为什么要学习Binder?

  • startActivity的时候,会获取AMS服务,调用AMS服务的startActivity方法
  • startActivity传递的对象为什么需要序列化
  • bindService为什么回调的是1个lbinder对象
  • 多进程应用,各个进程之间如何通信
  • AIDL的使用

跨进程通信IPC有哪些实现方案?

跨进程通信都要通过内核空间,才能实现进程间的通信

  • 管道
    • 两个进程间通信,进程A通过管道的写段写入数据,进程B通过管道的读段读取数据.
    • 缺点:缓存区数据大小限制影响性能
  • 消息队列
    • 两个进程间通信,进程A往消息队列中发送消息,进程B从消息队列中读取消息,消息包含了消息类型和消息正文,通过消息类型就能拿到消息正文,并且是可以可以同时实现多个进程往消息队列发送消息.
    • 缺点:由于需要通过消息类型才能获取到对应的消息正文,所以两个通信的进程必须约定好发送的消息类型.
  • 内存共享
    • 两个进程间通信,进程A和进程B共享同一块内存空间,进程A更改共享空间中的数据,进程B就能获取到共享空间中新的数据
    • 优点:速度快,性能最好
    • 缺点:没有同步控制,容易造成数据紊乱;简单来说就是并发问题
  • Soket
    • 两个进程间通信,进程A(Client)将数据写入输出缓冲区,进程B(Server)从输入缓冲区读取数据;C/S模式
    • 缺点:存在两次拷贝
  • Binder
    • 两个进程间通信,进程B(Server)的内存空间与一块物理内存通过mmap建立内存映射,而这块物理内存通过mmap与内核空间中一块内存建立内存映射;当进程A(Client)要与进程B(Server)通信,进程A(Client)将数据拷贝到内核空间中映射过的那块内存上,由于mmap映射关系,进程B(Server)会拿到拷贝的那个数据,从而实现了进程间通信.
    • 优点:存在1次拷贝,C/S模式

几种常用进程间通信机制的比较:
二.Binder原理分析_第1张图片

内存在操作系统中的划分

  • 用户空间
    • Native层、App Framework层和App层
  • 内核空间
    • Linux Kernel层

Binder是如何管理的?

  • SystemServer
    • 在main()函数中调用run()方法,初始化SystemServiceManager,同时在主线程中创建Looper并轮询,接着会启动一些服务.
    • 初始化SystemServiceManager代码如下:
      mSystemServiceManager = new SystemServiceManager(mSystemContext);
    • 启动了哪些服务?
      //启动引导程序(辅助程序)服务,
      //如:ATMS(ActivityTaskManagerService)、PowerManagerService、SystemServiceManager等
      //ActivityManagerService 在这里初始化
      //mActivityManagerService = ActivityManagerService.Lifecycle.startService(mSystemServiceManager, atm);
      startBootstrapServices(t);
      //启动核心服务,比如:电池服务、
      startCoreServices(t);
      //启动一些别的服务,比如:闹钟服务
      startOtherServices(t);
      
  • SystemServiceManager
    • 用于启动服务,通过调用startService()方法去启动我们的抽象类服务SystemService,最终调用SystemService的onStart()方法,具体的实现交给具体的服务(如:AMS).
  • SystemService
    • 抽象类
      对一些共有的操作抽离出来(如:onStart()).
  • ActivityTaskManagerService 等(如:AMS、ATMS、WMS、PKMS、PMS…)
    • 实现类
      具体的实现类服务,通过继承自SystemService,或者内部类Lifecycle继承自SystemService,在onStart方法中,最终通过ServiceManager.addService(String name, IBinder service)方法,将服务添加到ServiceManager中去.
  • ServiceManager
    • 存储服务器实现类,以Map的形式存储服务,key是服务的名称,value是服务(Binder);这里的服务器要么继承自Binder,要么继承自Stub,Stub继承自Binder,所以最终也是继承自Binder;Binder类实现类IBinder接口.

Binder驱动是什么时候创建的?
进程在创建的同时就会创建Binder驱动,这里我们拿ServiceManager进程创建过程举例:
入口:
系统源码中,servicemanager路径下的main.cpp文件中,main函数中会在ServiceManager进程创建时,做一些初始化操作:

  1. 会通过ProcessState::initWithDriver(driver)方法初始化Binder驱动,并在ProcessState中将驱动打开open_driver(driver);
  2. 同时还会初始化ServiceManager,代码如下:
    sp manager = new ServiceManager(std::make_unique());
  3. 以及创建Looper对象并执行loop轮询,代码如下:
    sp looper = Looper::prepare(false /*allowNonCallbacks*/);
    Looper一直轮询:
    looper->pollAll(-1);

总结:
Binder驱动是在Zygote进程创建后创建的,每一个进程创建的同时都会创建Binder驱动,用于与别的进程实现跨进程通信.
在Zygote进程初始化的时候,会在ZygoteInitmain()函数中创建一个Soket通信Server服务器ZygoteServer,通过一个while死循环轮询否有AMS发送过来的消息,接收到消息则会通过fork()创建一个进程,代码如下:
Zygote.forkAndSpecialize(...)
进程创建完成,接下来会走到native层的文件中去打开Binder驱动,流程如下:
ZygoteInit.main()
->zygoteServer.runSelectLoop(abiList)
->(ZygoteConnection)connection.processOneCommand(this)
->handleChildProc(…)
->ZygoteInit.zygoteInit()
->ZygoteInit.nativeZygoteInit();
这个ZygoteInit.nativeZygoteInit本地方法最终会在AndroidRuntime.cpp中注册,最终在app_main.cpp文件中onZygoteInit()方法中调用,该方法中会调用ProcessState::self(),这个方法中会创建一个ProcessState,这里面就包含了打开驱动的业务逻辑open_driver(driver).

Service的启动方式

Service是四大组件之一,使用的时候需要像Activity一样在清单文件中注册

  • startService
    • 多次通过startService()方法启动服务只会调用一次onCreate()生命周期方法,但是会多次调用onStart()方法
    • 在页面销毁的时候需要调用stopService(intent)停止服务
    • 停止服务会调用onDestory生命周期方法
  • bindService
    • 多次通过bindService()方法启动服务只会调用一次onCreate()和onBind()生命周期方法
    • 绑定服务的时候需要传入ServiceConnection用于在回调方法中监听服务连接和断开连接方法
    • 在页面销毁的时候需要调用unbindService(serviceConnection)解绑服务
    • 解绑服务会调用onUnbind()和onDestory()生命周期方法

AIDL (Android Interface Define Language/安卓接口定义语言)
Client端和Server端通过AIDL实现进程间通信,Client端和Server端都需要创建.aidl文件,同时这个文件的类名和包名都必须相同,这个.aidl文件可以编译成Java文件(还可以可以通过命令生成c++文件),我们通过Java文件就可以实现进程间通信,这个由.aidl文件生成的Java文件中,包含了内部类Stub,而Stub包含了子类Proxy,Stub类继承自Binder,而Binder实现了IBinder,所以我们在Client端在绑定Server端的服务,在ServiceConnection的回调方法中,可以拿到Server端返回的IBinder对象,然后在Client端通过对IBinder对象进行转换后就可以和Server端进程通信.
实现步骤:

  1. Server端:
    • 创建aidl文件,里面封装了自己接口和方法,然后build生成Java文件;
    • 创建自定义Service,并创建内部类继承自aidl接口的Stub类,在接口回调方法中实现自己的业务;
    • 启动自定义Service,采用startService().
  2. Client端:
    • 将Server端的aidl文件拷贝过来,注意包名和Server端包名保持一致;同样build生成Java文件;
    • 采用bindService()绑定Server端服务器,通过服务端包名的形式,然后在ServiceConnection中监听Server端返回的IBinder对象,对该IBinder对象进行转换即可实现与Server端跨进程通信,
      IAidl iAidl = IAidl.Stub.asInterface(service);// proxy
      利用iAidl就可以和Server端进行通信.

bindService流程分析

  • bindService() @ContextWrapper
  • bindService() @ContextImpl
    • 调用Activity的超类Context的实现类ContextImpl的绑定服务方法
  • bindServiceCommon()
  • ActivityManager.getService().bindIsolatedService(...)
    • 这里从ServiceManager列表中,根据名称获取到AMS的IBinder对象,并把这个IBinder对象转换成Proxy对象,然后通过代理类调用里面具体接口;也就是是说最终是调用Proxy代理对象中的bindIsolatedService()方法.代码如下:
        //ActivityManager.java
      
        public static IActivityManager getService() {
          //这里的get()方法最终会调用Singleton中的create()方法,
          //创建一个Proxy代理对象
          return IActivityManagerSingleton.get();
        }
      
        private static final Singleton<IActivityManager> IActivityManagerSingleton =
          new Singleton<IActivityManager>() {
              @Override
              protected IActivityManager create() {
                  //根据名称获取到ServiceManager列表中存储的AMS的IBinder对象
                  final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                  //将IBinder对象通过按照AIDL生成的Java类中的代理Proxy方式,
                  //通过Interface的Stub类的asInterface方法,
                  //将IBinder对象转换成Proxy对象,
                  //通过Proxy对象就可以调用Interface中的方法,
                  //从而实现跨进程通信
                  final IActivityManager am = IActivityManager.Stub.asInterface(b);
                  return am;
              }
          };
      
  • bindIsolatedService() @ActivityManagerService
    • Isolated/ˈaɪsəleɪtɪd/单独的,只出现一次的,隔离的
    • 最终会走到Proxy代理类ActivityManagerService的bindIsolatedService()方法
  • bindServiceLocked() @ActiveServices
    • Service热启动,调用如下方法:
      c.conn.connected(s.name, b.intent.binder, false);
    • Service冷启动,调用如下代码:
      requestServiceBindingLocked()
      • r.app.thread.scheduleBindService()
        • r:是ServiceRecord,
          app:是ProcessRecord,
          thread:是IApplicationThread,他的实现类是ActivityThread.ApplicationThread;但是最终传递进来的thread对象其实是ActivityThread,所以我们查看ActivityThread中的scheduleBindService方法
        • ActivityThread的main()方法中,会创建一个ActiivtyThread对象并调用attach方法,在这个方法中将ActivityThread赋值给了这个(IApplicationThread)thread变量,代码如下:
          private void attach(boolean system, long startSeq) {
          	//省略无关代码...
              //这里的ActivityManager.getService()返回是AMS
              final IActivityManager mgr = ActivityManager.getService();
              //所以最终调用AMS的attachApplication方法,将ApplicaitonThread的IBinder对象绑定到AMS
              mgr.attachApplication(mAppThread, startSeq);
          }
          
      • scheduleBindService() @ActivityThread
        • 这里会通过Handler发送消息,发送BIND_SERVICE的消息,并且这是一个异步消息
        • 然后会走到Hanler的handleMessage方法,然后我们根据BIND_SERVICE查看对应代码块
      • handleBindService @ActivityThread
        • IBinder binder = s.onBind(data.intent);//在我们自定义Service的生命周期方法onBind()中,将创建的Stub类的对象传入作为返回值,构建出IBinder对象
        • ActivityManager.getService().publishService(data.token, data.intent, binder);
      • publishService() @ActivityManagerService
      • publishServiceLocked() @ActiveServices
      • c.conn.connected(r.name, service, false); @ActiveServices
        • 这里c是ConnectionRecord,conn是IServiceConnection,
          最终是调用ServiceConnection的onServiceConnected(ComponentName name, IBinder service)方法,将IBinder对象返回,我们可以通过将IBinder对象转换成Proxy代理对象,调用里面的接口方法.
      • LoadedApk.ServiceDispatcher.InnerConnection.connected()
        • IServiceConnection.Stub的实现类InnerConnection,是LoadedApk类的一个内部类,这个类InnerConnection重写了connected()方法,这个方法中包含如下代码:
          LoadedApk.ServiceDispatcher sd = mDispatcher.get();
          if (sd != null) {
              sd.connected(name, service, dead);
          }
          
      • LoadedApk.ServiceDispatcher.connected()
      • doConnected() @LoadedApk.ServiceDispatcher
        • (ServiceConnection)mConnection.onServiceConnected(name, service);//服务已连接
        • (ServiceConnection)mConnection.onServiceDisconnected(name);//服务断开

总结:

  1. 客户端进程与ServiceManager通信,获取AMS的IBinder;
  2. 客户端通过AMS的IBinder与AMS进行通信,请求AMS去执行bindService这个请求;
  3. AMS与服务端进程通信,执行服务端Service的onBind方法;

流程图如下:
二.Binder原理分析_第2张图片

进程间通信Native层逻辑

  • Client端往Binder驱动中写入数据
    • ActivityManager.getService()
    • ServiceManager.getService()//这个SDK30到这里,方法就直接返回null,也不知道是不是版本差异
    • Binder.allowBlocking(rawGetService(name))
    • rawGetService()
    • IBinder binder = getIServiceManager().getService(name);
      • ServiceManagerProxy.getService()
        • 这是由IServiceManager.aidl文件生成的Java文件中的这是由IServiceManager.Stub.Proxy中的getService方法,所以ServiceManagerProxy等于IServiceManager.Stub.Proxy
    • IServiceManager.Stub.Proxy.getService()
    • (IBinder)mRemote.transact()
      • 这里的mRemote是IBinder,需要使用该接口代理类中的方法来完成,IBinder的代理类是BinderProxy,所以最终调用的是BinderProxy.transact()方法
    • BinderProxy.transact()
    • transactNative
      • 这是一个Native方法,需要查看Native中该方法
        public native boolean transactNative(int code, Parcel data, Parcel reply, int flags) throws RemoteException
    • android_os_BinderProxy_transact() @android_util_Binder.cpp
      • 该方法中会将Java层数据,转换成native可以识别的Parcel数据,通过如下代码:
        Parcel * parcel = parcelForJavaObject(env, dataObj);
    • transact() @BpBinder.cpp
    • IPCThreadState::transact()
    • writeTransactionData() @IPCThreadState.cpp
      • 将数据写到一个native层对象中去
    • waitForResponse() @IPCThreadState.cpp
      • 等待数据返回
    • talkWithDriver() @IPCThreadState.cpp
    • ioctl()
      • 将数据写入到Binder驱动中去
    • Binder驱动设备

    总结:
    ServiceManagerProxy(Java层)->BinderProxy(Framework层)->BpBinder(Native层)->ioctl->Binder驱动(Linux内核层)

  • Server端从Binder驱动中读取数据

    这里我们将ServiceManager作为一个BBinder的实现类来研究,因为ServiceManager的超类的BBinder

    • main() @servicemanager/main.cpp
      • 这个main函数中做了三件事情:
        1. 初始化Binder驱动
        2. 构建BBinder对象
        3. 通过Looper不停轮询Binder驱动发送来的消息并处理消息
    • BinderCallback::setupTo(looper);@servicemanager/main.cpp
      • 通过Looper不停的轮询是否有Binder驱动发送过来的消息,通过BinderCallBack监听并在回调方法handleEvent()方法中进行消息处理;
    • handleEvent() @servicemanager/main.cpp BinderCallBack
    • IPCThreadState::self()->handlePolledCommands();
    •   //一直轮询,直至获取到消息,并处理消息
        do {
          result = getAndExecuteCommand();//获取到消息,则执行命令
        } while (mIn.dataPosition() < mIn.dataSize());
      
    • executeCommand(cmd);
      • 从Binder驱动中读取命令(这个命令就是客户端Client发送来的消息),然后执行命令
    • transact() @IPCThreadState.cpp
      • error = reinterpret_cast(tr.cookie)->transact(tr.code, buffer, &reply, tr.flags);这里会执行BBinder的transact()这个方法
    • BBinder.transact() @Binder.cpp
    • BBinder.onTransact() @Binder.cpp
      • 这个超类BBinder中,并没有对这个onTransact方法做什么处理,具体实现是在子类BnServiceManager中的onTransact方法中处理的
    • onTransact() @BnServiceManager.cpp
      • android::binder::Status _aidl_status(getService(in_name, &aidl_return));//举例,这里用getService方法对应的case代码举例
      • 这个子类中的onTransact方法中,会调用getService()/addService/checkService等方法,而具体的getService()方法是交给子类ServiceManager来完成的
    • getService() @ServiceManager
      • 从ServiceManager的map集合中,通过名称获取到IBinder对象,最终将这个IBinder对象返回出去

    总结:
    Binder驱动通过ioctl将消息发送出来 -> BBinder通过Loop轮询Binder驱动发送来的消息并处理 -> 交给BnServiceManager的onTransact()方法处理 -> 最终通过ServiceManager.getService方法获取IBinder对象

Server端ServiceManager是什么?

ServiceManager是一个Native层的进程,由init进程创建,早于zygote进程启动.

ServiceManager进程启动做了三件事情:

  1. 初始化binder驱动
    • sp ps = ProcessState::initWithDriver(driver);
  2. 实例化ServiceManager,并构建BBinder对象
    • 这里我们就可以将ServiceManager当作是BBinder的一种实现,因为ServiceManager的超类是BBinder
    • sp manager = new ServiceManager(std::make_unique());//实例化ServiceManager构建成BBinder对象,因为ServiceManager的超类的BBinder
    • IPCThreadState::self()->setTheContextObject(manager);//将BBinder对象设置到线程中
  3. Binder驱动发送消息给BBinder,BBinder监听发送来的消息
    • BinderCallback::setupTo(looper);//Binder发送消息给ServiceManager/BBinder,ServiceManager/BBinder监听Binder驱动发送过来的消息
      • Native层servicemanager/Main.cpp文件中,在BinderCallBack类的回调方法handleEvent()方法中监听消息
      • Android11/framework/native/cmds/servicemanager/Main.cpp
        class BinderCallback : public LooperCallback {
        public:
            static sp<BinderCallback> setupTo(const sp<Looper>& looper) {
                ...代码省略
            }
        
            int handleEvent(int /* fd */, int /* events */, void* /* data */) override {
                //从Binder驱动接收到消息并处理
                IPCThreadState::self()->handlePolledCommands();
                return 1;  // Continue receiving callbacks.
            }
        };
        
    • ClientCallbackCallback::setupTo(looper, manager);//在Looper循环中监听Binder驱动发送来的消息

ServiceManager父类之间的关系:

  • IServiceManager/BBinder
  • <-BnInterface< IServiceManager>
  • <-BnServiceManager
  • <-ServiceManager

一个Service类中实现了.Stub类,Stub类继承自Binder类,Binder类实现了IBinder接口,我们就可以将他当作是一个Server服务端,用于提供给客户端Client使用.

你可能感兴趣的:(Android,Framework,binder,android,安卓Framework)