[Marco] Cómo funciona Android Binder

BinderEs Androidel principal IPCmétodo de comunicación del sistema y su rendimiento es excelente. Sin embargo, muchos desarrolladores, incluido yo mismo, nos sentimos intimidados por esto. Es realmente difícil. Cada vez que lo leo, me olvido de leerlo. Sin embargo, a medida que trabajo cada vez más, aprendo algo nuevo cada vez que lo leo Binder. Lo sé, así que esta vez registraré algo de mi comprensión.

Mirando Binder desde Framework/Driver

BinderC/SEl diseño es una arquitectura clásica , que Clientsolicita y responde Serveractivamente Serverdespués de recibir el mensaje. Se Serverpueden servir varios mensajes Clientpero no se pueden enviar mensajes Serverde forma activa .Client

Todos los procesos comenzarán bind_openabriendo binderel controlador y mmapcompletando el mapeo de memoria. Después de que diferentes procesos abran el controlador, binderel controlador creará un binder_procnodo para representar el proceso. Cuando el proceso tenga un nuevo nodo Server, será binder_procagregado binder_nodepara representar Para este servicio, cuando el proceso quiere Servercomunicarse , binder_procagrega un binder_ref(incluido handle, este valor se incrementa secuencialmente en el mismo proceso, y el mismo servicio en diferentes procesos handletambién es diferente, ServiceManageres handleuna excepción, que es fijado en 0) para describir Serverla referencia al objetivo, binder_procy binder_nodetodos binder_refse almacenan en forma de una lista vinculada.

Supervisor

ServerLa gestión de es a través de ServiceManager, y él mismo también es un binder. ServerSi desea agregar otros servicios, debe pasar su addServicemétodo. Si desea obtener el método, debe pasar su getServicemétodo. También analizamos estos dos métodos.
Cuando un proceso quiere registrarse , llamará al método Servera través de binderla comunicación IPC y también se incluirán los parámetros , que llegarán primero al controlador y el conductor verificará si hay un servicio correspondiente en el proceso , porque es La primera vez, este servicio no existe, luego el conductor creará un correspondiente para representar este servicio, el conductor debe notificar esto al proceso donde se encuentra, pero no puede usar el correspondiente directamente , pero debe agregue un en el correspondiente para señalar eso , y (incluido ) puede regresar al proceso correspondiente, y el nombre y otra información de este se registrarán en el proceso . Esto completa la adición de un servicio.ServiceManageraddServiceServerServerbinderbinder_nodebinder_procbinder_nodebinderServerServiceManagerbinder_nodeServiceManagerbinder_procbinder_refBinder Serverbinder_refhandleServiceManagerServiceManagerServerhandle

Cuando un proceso quiere comunicarse con un método, llamará al método del método Servera través de binderla comunicación IPC . Los parámetros de este método contienen el nombre (cadena) del servicio. Después de que la solicitud llegue al proceso a través de IPC , pasará esto nombre. Para encontrar el correspondiente , si se encuentra el servicio, responderá al proceso de destino a través de IPC. Como se mencionó anteriormente, lo que se guarda en el proceso es solo una referencia ( ). Cuando el controlador reciba esta respuesta, Obtenga el correspondiente a través de esta referencia. Sí , el controlador comparará el proceso de envío y el proceso de recepción. En la lógica de la respuesta, el proceso de envío es y el proceso de recepción es el proceso que obtiene este servicio. Definitivamente son diferentes. .Como se mencionó anteriormente, incluso si el mismo está en diferentes procesos también son diferentes, por lo que el en el proceso no puede ser utilizado directamente por el proceso que obtiene el servicio. Es necesario crear otro para el proceso que obtiene el servicio. al mismo tiempo, esto también apunta al objetivo , y luego regresa esto ( ) al proceso que solicitó el servicio. Eso es genial, todas las comunicaciones posteriores dependerán de esto ( ).ServiceManagergetServicebinderServiceManagerServerbinderServieManagerbinder_refhandlebinderServerbinder_nodeServiceManagerServiceManagerServerbinder_refServiceManagerbinder_refbinder_refbinder_refServerbinder_nodebinder_refhandleServerbinder_refhandle

Como se mencionó anteriormente , ServiceManagertambién es un binder, Serverya sea agregando Servero obteniendo Server, debe pasar por él. Nuestro proceso ServiceManagerdebe corresponder a la comunicación handle, pero ¿cómo obtenemos esto handle? Aquí binderqueda una puerta trasera , ServcieManagerque handlees la misma para todos los procesos, es 0, por lo que no es necesario obtenerla, solo úsala directamente.

El secreto de Binder para la alta velocidad

Como se mencionó anteriormente, los métodos y se llamarán cuando se inicie el proceso, y binderel proceso es la razón de la rápida velocidad. Durante el proceso de comunicación, solo habrá una copia de datos entre el espacio del usuario y el espacio del kernel, mientras que la mayoría de los demás métodos de comunicación tendrán dos o más copias. En asignará una parte de la memoria física para el proceso, y la memoria virtual de y apuntará a esta memoria, es decir, esta memoria física es compartida por ellos. Al enviar un mensaje a , copiará el mensaje enviado a la memoria asignada por y luego notificará que lo use. Una vez completado el procesamiento, el mensaje de respuesta también se escribirá en esta memoria, notificará la respuesta y luego copiará el Responder mensaje a la ubicación Procesar, responder Llamada completa. El valor máximo de este espacio de memoria es .bind_openmmapmmapmmapIPC
mmapbinderbinderServerClientServerBinderClientmmapbinderServerServerbinderClientbinderClientClient1MB - 8KB

Proceso de comunicación de Binder IPC

Se requieren algunos protocolos durante el proceso de comunicación. Aquí hay diferentes protocolos. Los protocolos generalmente se dividen en protocolos de control y protocolos de accionamiento.
El protocolo de control es ioctl(“/dev/binder”)un método mediante el cual otros procesos envían comandos al controlador, incluidos los siguientes:

Orden ilustrar Tipo de parámetro
BINDER_WRITE_READ Operaciones de lectura y escritura, los comandos más utilizados. El proceso de IPC consiste en transferir datos a través de este comando. binder_write_read
BINDER_SET_MAX_THREADS Establecer el número máximo de subprocesos admitidos por el proceso. tamaño_t
BINDER_SET_CONTEXT_MGR Establecete como ServiceManager ninguno
BINDER_THREAD_EXIT El hilo del cuaderno del controlador de notificación sale ninguno
BINDER_VERSION Obtenga el número de versión del controlador de Binder versión_carpeta

El protocolo del controlador incluye los siguientes dos protocolos enviados por el proceso al controlador ( binder_driver_command_protocol) y el protocolo enviado por el controlador al proceso ( binder_driver_return_protocol).

binder_driver_command_protocol:

Orden ilustrar Tipo de parámetro
BC_TRANSACTION Transacción de carpeta, es decir: solicitud del cliente al servidor binder_transaction_data
BC_REPLY Respuesta de transacción, es decir: respuesta del servidor al cliente binder_transaction_data
BC_FREE_BUFFER Notificar al conductor que libere el buffer binder_uintptr_t
BC_ACQUIRE Fuerte recuento de referencias +1 __u32
BC_RELEASE Fuerte recuento de referencias -1 __u32
BC_INCREFS Recuento de referencias débiles +1 __u32
BC_DECREFS Recuento de referencia débil -1 __u32
BC_ACQUIRE_DONE La respuesta de BR_ACQUIRE cookie_ptr_binder
BC_INCREFS_DONE Respuesta de BR_INCREFS cookie_ptr_binder
BC_ENTER_LOOPER Notificar al hilo principal del controlador que está listo vacío
BC_REGISTER_LOOPER Notificar al controlador que el subproceso secundario está listo vacío
BC_EXIT_LOOPER Notificar al hilo del controlador que ha salido vacío
BC_REQUEST_DEATH_NOTIFICATION Solicitud para recibir notificaciones de defunción binder_handle_cookie
BC_CLEAR_DEATH_NOTIFICATION Eliminar notificaciones de muerte binder_handle_cookie
BC_DEAD_BINDER_DONE Se ha procesado la notificación de defunción. binder_uintptr_t

binder_driver_return_protocol:

Tipo de devolución ilustrar Tipo de parámetro
BR_OK Operación completada vacío
BR_NOOP Operación completada vacío
BR_ERROR Ocurrió un error __s32
BR_TRANSACCIÓN El proceso de notificación recibe una solicitud de Binder (lado del servidor) binder_transaction_data
BR_REPLY Proceso de notificación recibe respuesta a solicitud de Binder (Cliente) binder_transaction_data
BR_TRANSACTION_COMPLETE Respuesta de confirmación del conductor para aceptar la solicitud. vacío
BR_FAILED_REPLY Informar al remitente que el destino de la comunicación no existe vacío
BR_SPAWN_LOOPER Notificar al proceso de Binder para crear un nuevo hilo. vacío
BR_ACQUIRE Fuerte recuento de referencias +1 solicitud cookie_ptr_binder
BR_RELEASE Fuerte recuento de referencias: 1 solicitud cookie_ptr_binder
BR_INCREFS Recuento de referencias débiles +1 solicitud cookie_ptr_binder
BR_DECREFS Recuento de referencias débil: 1 solicitud cookie_ptr_binder
BR_DEAD_BINDER Enviar notificación de muerte binder_uintptr_t
BR_CLEAR_DEATH_NOTIFICATION_DONE Se completó la limpieza de notificaciones de defunción binder_uintptr_t
BR_DEAD_REPLY Informar al remitente que la otra parte está muerta. vacío

在上面介绍了一些命令后,你可能还是不怎么清楚具体怎么通信的,我这里描述一次简单的 binder IPC 通信:
Client 通过 ServiceManager 获取到目标 Serverhandle 后,底层调用 ioctl 方法,对应的 ioctl 命令是 BINDER_WRITE_READ,其中还传递了发送给服务端的包裹的数据,也包含了 binder 驱动命令, 这个命令是 BC_TRANSACTIONbinder 驱动收到后会向 Client 线程回复 BR_TRANSACTION_COMPLETE 表示已经收到请求,binder 驱动会将 Client 传递过来的数据拷贝到对应 Servermmap 内存空间,然后向 Server 发送 BR_TRANSACTION 命令,表示有新的 Client 请求,Server 会读取对应存在 mmap 中的 Client 请求数据,然后解析请求内容,Server 完成请求后,会把返回的数据封装在 reply 中,然后同样通过 ioctlBINDER_WRITE_READ 命令封装回复的数据和驱动指令,驱动指令是 BC_REPLYbinder 驱动收到后会向 Server 发送 BR_TRANSACTION_COMPLETE 命令,表示已经收到给 Client 的回复,在 binder 驱动中会将 Server 的回复数据拷贝到 Client 所在的进程,然后向 Client 发送 BR_REPLY 表示请求成功,Client 最后解析出 Server 发送来的数据,这样就完成了一次请求。

在 Android 中 ClientServer 对象的命名通常有有以下规律:

- C/C++ Java AIDL
Server BnXXX XXXNative IXXX.Stub
Client BpXXX XXXProxy IXXX.Stub.Proxy

从 Service 和 AIDL 来看 binder

Android 中官方提供的唯一使用 binder 的接口就是使用四大组件之一的 Service 了,在 onBind() 回调中返回 BinderServer,客户端启动 Service 的方式修改成 bindService(),其中 Service 中的 BinderServer 准备就绪后会传给启动进程的 Connection 回调,当然启动进程收到的 IBinder 对象只是一个代理而已。
Android 为了让开发者能够更容易地使用 binder,创造了 AIDL 这语言,应用在编译时,编译器会把我们声明的 AIDL 文件编译成 Java 源码文件,通过生成的源码文件我们能够像在调用本地方法代码一样调用其他进程的 Server,当然实际上是使用的 binder IPC。有人说 AIDL 是一种 IPC 的通信方式,我反正感觉怪怪的,它只是简化了 binder 的使用,而不是一种通信方式,binder 才是它的通信方式。

AIDL

这里简单描述一下 AIDL 特殊的关键字:

  • oneway
    标记到方法中,表明这个方法只需要发送数据给 Server,而不需要 Server 的回复(前面说到 Client 发送数据给 Server 后,需要等待 Server 再返回数据给 Client,这只是一般情况。);通常这样的话方法的调用耗时就更短,有人把这个说成是异步调用,合理地使用 oneway 能够提高程序的性能.

  • in
    标记到方法参数中,表明这个参数只是当输入发送给 Server,当服务端修改这个对象里面的参数后不会同步到 Client

  • out
    标记到方法参数中,表明这个参数只是当输出发送给 ServerServer 会把返回结果写入到这个对象的参数里,写入后会同步到 Client

  • inout
    标记到方法参数中,也就是同时满足 inout 的特点。

后续我就通过一个 AIDL 例子来介绍一下。

这是我的 AIDL 文件:


interface IPlayingMusicService {
    PlayingMusicModel getPlayingMusicModel();
    void pause();
    void stop();
    void start();
    void addProgressCallback(MusicPlayingCallback callback);
    void removeProgressCallback(long callbackId);
    void newPlayingMusicModel(PlayingMusicModel newMusic);
}

除了 Java 中的 8 种基本类型、String 和 Binder 以外,其他的使用到的对象都要实现 Parcelable 接口,这也很好理解,跨进程传输数据肯定需要序列化和反序列化了。

用到的对象需要用 AIDL 文件描述下:

package com.example.aidldemo;
parcelable PlayingMusicModel;

总的来说 AIDL 就是定义了一堆服务的接口,我们来看看它生成的 Java 源码:

public interface IPlayingMusicService extends android.os.IInterface
{
  // ...
  public static abstract class Stub extends android.os.Binder implements com.example.aidldemo.IPlayingMusicService
  {
    private static final java.lang.String DESCRIPTOR = "com.example.aidldemo.IPlayingMusicService";
    /** Construct the stub at attach it to the interface. */
    public Stub()
    {
      this.attachInterface(this, DESCRIPTOR);
    }
    /**
     * Cast an IBinder object into an com.example.aidldemo.IPlayingMusicService interface,
     * generating a proxy if needed.
     */
    public static com.example.aidldemo.IPlayingMusicService asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof com.example.aidldemo.IPlayingMusicService))) {
        return ((com.example.aidldemo.IPlayingMusicService)iin);
      }
      return new com.example.aidldemo.IPlayingMusicService.Stub.Proxy(obj);
    }
    @Override public android.os.IBinder asBinder()
    {
      return this;
    }
    @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
    { 
      // ..
    }
    private static class Proxy implements com.example.aidldemo.IPlayingMusicService
    {
      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;
      }
      @Override public com.example.aidldemo.PlayingMusicModel getPlayingMusicModel() throws android.os.RemoteException
      {
        // ...
      }
      @Override public void pause() throws android.os.RemoteException
      {
        // ...
      }
      @Override public void stop() throws android.os.RemoteException
      {
        // ...
      }
      @Override public void start() throws android.os.RemoteException
      {
        // ...
      }
      @Override public void addProgressCallback(com.example.aidldemo.MusicPlayingCallback callback) throws android.os.RemoteException
      {
        // ...
      }
      @Override public void removeProgressCallback(long callbackId) throws android.os.RemoteException
      {
        // ...
      }
      @Override public void newPlayingMusicModel(com.example.aidldemo.PlayingMusicModel newMusic) throws android.os.RemoteException
      {
        // ...
      }
      public static com.example.aidldemo.IPlayingMusicService sDefaultImpl;
    }
    static final int TRANSACTION_getPlayingMusicModel = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_pause = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    static final int TRANSACTION_stop = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
    static final int TRANSACTION_start = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
    static final int TRANSACTION_addProgressCallback = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4);
    static final int TRANSACTION_removeProgressCallback = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5);
    static final int TRANSACTION_newPlayingMusicModel = (android.os.IBinder.FIRST_CALL_TRANSACTION + 6);
    public static boolean setDefaultImpl(com.example.aidldemo.IPlayingMusicService impl) {
      // Only one user of this interface can use this function
      // at a time. This is a heuristic to detect if two different
      // users in the same process use this function.
      if (Stub.Proxy.sDefaultImpl != null) {
        throw new IllegalStateException("setDefaultImpl() called twice");
      }
      if (impl != null) {
        Stub.Proxy.sDefaultImpl = impl;
        return true;
      }
      return false;
    }
    public static com.example.aidldemo.IPlayingMusicService getDefaultImpl() {
      return Stub.Proxy.sDefaultImpl;
    }
  }
  public com.example.aidldemo.PlayingMusicModel getPlayingMusicModel() throws android.os.RemoteException;
  public void pause() throws android.os.RemoteException;
  public void stop() throws android.os.RemoteException;
  public void start() throws android.os.RemoteException;
  public void addProgressCallback(com.example.aidldemo.MusicPlayingCallback callback) throws android.os.RemoteException;
  public void removeProgressCallback(long callbackId) throws android.os.RemoteException;
  public void newPlayingMusicModel(com.example.aidldemo.PlayingMusicModel newMusic) throws android.os.RemoteException;
}

IPlayingMusicService 是一个接口,也就是我们在 AIDL 中定义的那些方法,除此之外其中的静态类 StubStub.Proxy 他们占据了大部分的篇幅,Stub 其实就是表示 binderServerStub.Proxy 就是 binderClient,他们也都添加了 IPlayingMusicService 接口,Stub.Proxy 是个普通类,已经把接口实现好了,Stub 是一个抽象类 IplayingMusicService 的接口需要我们自己实现,这也很好理解,Server 的这些方法当然需要我们自己去定义了,Client 当然不用在定义了,因为它最终就是会调用 Server 中的这些方法。

我们自己的 Server 实现就类似以下代码:


val binder: IBinder = object : IPlayingMusicService.Stub() {

    override fun pause() { 
        // TODO:
    }

    override fun newPlayingMusicModel(newMusic: PlayingMusicModel) {
        // TODO:
    }

    override fun start() { 
        // TODO:
    }

    override fun stop() { 
        // TODO:
    }

    override fun getPlayingMusicModel(): PlayingMusicModel? {
        // TODO:
    }

    override fun addProgressCallback(callback: MusicPlayingCallback?) {
        // TODO:
    }

    override fun removeProgressCallback(callbackId: Long) {
        // TODO:
    }

}

然后我们需要把这个对象在四大组建之一的 ServiceonBind 回调中返回给系统:

// ...
override fun onBind(intent: Intent?): IBinder = binder
// ...

这个 Server 会通过 binder 转到 AMS,然后通过 AMS 再通过 binder 传递到启动的进程。
也就是回到以下回调:


bindService(
    Intent(this@MainActivity, MusicPlayingService::class.java),
    object : ServiceConnection {
        
        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
            val binderProxy = IPlayingMusicService.Stub.asInterface(service)
        }
        override fun onServiceDisconnected(name: ComponentName?) {
            
        }
    },
    Context.BIND_AUTO_CREATE
)

回调中的 IBinder 对象是其一个代理对象,也就是前面提到的 handler 封装过的对象。我们会使用 IPlayingMusicService.Stub.asInterface 方法把 IBinder 对象封装成拥有 IPlyaingMusicService 接口的对象。我们去看看这个方法的实现:


 public static com.example.aidldemo.IPlayingMusicService asInterface(android.os.IBinder obj)
 {
   if ((obj==null)) {
     return null;
   }
   android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
   if (((iin!=null)&&(iin instanceof com.example.aidldemo.IPlayingMusicService))) {
     return ((com.example.aidldemo.IPlayingMusicService)iin);
   }
   return new com.example.aidldemo.IPlayingMusicService.Stub.Proxy(obj);
 }

这里很重要他首先会调用 IBinderqueryLocalInterface 方法去查询一下这个服务是否在当前进程中,如果不为空就是表示在当前进程中,然后会直接使用,其实这个对象就是 onBind() 中的那个 Server 对象,也就是 Stub 对象,也就是说直接拿那个对象调用方法,也就没有通过 binder 进行 IPC 通信,就和普通的对象调用没有区别;但是如果 queryLocalInterface 方法返回为空,表示这个 Server 是别的进程中的,这时会生成一个 Stub.Proxy 对象,通过这个对象的方法调用就是通过 binder IPC 实现的。

我们看看 Stub.Proxy 对象中的 newPlayingMusicModel 方法实现(其他方法也大同小异):


@Override public void newPlayingMusicModel(com.example.aidldemo.PlayingMusicModel newMusic) throws android.os.RemoteException
{
  android.os.Parcel _data = android.os.Parcel.obtain();
  android.os.Parcel _reply = android.os.Parcel.obtain();
  try {
    _data.writeInterfaceToken(DESCRIPTOR);
    if ((newMusic!=null)) {
      _data.writeInt(1);
      newMusic.writeToParcel(_data, 0);
    }
    else {
      _data.writeInt(0);
    }
    boolean _status = mRemote.transact(Stub.TRANSACTION_newPlayingMusicModel, _data, _reply, 0);
    if (!_status && getDefaultImpl() != null) {
      getDefaultImpl().newPlayingMusicModel(newMusic);
      return;
    }
    _reply.readException();
  }
  finally {
    _reply.recycle();
    _data.recycle();
  }
}

使用的是 Parcel 来传输数据,首先写入一个 Token 来表示这个请求,我这里的 demo 就是 com.example.aidldemo.IPlayingMusicService,然后在把参数写入,然后调用 mRemote (这个就是 bindServer 传过来的 IBinder 对象) 的 transact 方法来发送数据,这里还通过 TRANSACTION_newPlayingMusicModel 标记了要请求的方法,Server 回复的数据放在 _reply 中,这个 transact 方法最后也会走到上面说过的 ioctl 方法,命令是 BINDER_WRITE_READ,由于上面已经描述过了,就不再多说,等待 Server 回复后检查是否有异常,然后解析返回结果。(我的这个方法返回为 void,所以不用解析)

我们继续来看服务端 Stub 是怎么来处理这个 Stub.Proxy 发送过来的消息的,处理的入口函数是 onTransact 方法:

// ...
case TRANSACTION_newPlayingMusicModel:
{
  data.enforceInterface(descriptor);
  com.example.aidldemo.PlayingMusicModel _arg0;
  if ((0!=data.readInt())) {
    _arg0 = com.example.aidldemo.PlayingMusicModel.CREATOR.createFromParcel(data);
  }
  else {
    _arg0 = null;
  }
  this.newPlayingMusicModel(_arg0);
  reply.writeNoException();
  return true;
}
// ...

首先根据 Code 来判断调用的哪个方法,然后校验 Token,继续解析 Stub.Proxy 传递过来的参数,最后调用我们自己实现的 newPlayingMusicModel 方法,再将返回结果写入到 reply 中(我们这个方法没有返回值)。

到此我们就跑通了整个 AIDL 通信的流程。
AIDL Demo

Binder 对象在 Framework 中如何传递到调用方

我们的 Service#onBind 回调对象 Binder 会在 ActivityThreadhandBindService 方法中被调用:


private void handleBindService(BindServiceData data) {
  Service s = mServices.get(data.token);
  if (s != null) {
    try {
      data.intent.setExtrasClassLoader(s.getClassLoader());
      data.intent.prepareToEnterProcess();
      if (!data.rebind) {
        IBinder binder = s.onBind(data.intent);
        ActivityManagerNative.getDefault().publishService(
                data.token, data.intent, binder);
      } else {
        s.onRebind(data.intent);
        ActivityManagerNative.getDefault().serviceDoneExecuting(
                data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
      }
      ensureJitEnabled();
    } catch (Exception e) {
          ...
    }
  }
}

我们看到把我们的 binder 传递给 ActivityManagerNativepublishService 方法,其实 ActivityManagerNative 也是一个 binder 代理,而这个 Server 也就是大名鼎鼎的 ActivityManagerService (AMS), 后续的处理也就到了系统进程。


public void publishService(IBinder token, Intent intent, IBinder service) {
  ...
  synchronized(this) {
    if (!(token instanceof ServiceRecord)) {
      throw new IllegalArgumentException("Invalid service token");
    }
    mServices.publishServiceLocked((ServiceRecord)token, intent, service);
  }
}


void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
  final long origId = Binder.clearCallingIdentity();
  try {
    if (r != null) {
      Intent.FilterComparison filter = new Intent.FilterComparison(intent);
      IntentBindRecord b = r.bindings.get(filter);
      if (b != null && !b.received) {
        b.binder = service;
        b.requested = true;
        b.received = true;
        for (int conni=r.connections.size()-1; conni>=0; conni--) {
          ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
          for (int i=0; i<clist.size(); i++) {
            ConnectionRecord c = clist.get(i);
            if (!filter.equals(c.binding.intent.intent)) {
              continue;
            }
            try {
              c.conn.connected(r.name, service);
            } catch (Exception e) {
                          ...
            }
          }
        }
      }
      serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
    }
  } finally {
    Binder.restoreCallingIdentity(origId);
  }
}

我们看到调用了 Connection 的 connected 方法,其实这个 conn 也是一个 binder 的代理,真正的 Server 实现是调用的 bindService 的进程,也就由 AMS 又传递到了调用的进程。实现 conn 的 Server 代码:

private static class InnerConnection extends IServiceConnection.Stub {
  final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;

  InnerConnection(LoadedApk.ServiceDispatcher sd) {
    mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
  }

  public void connected(ComponentName name, IBinder service) throws RemoteException {
    LoadedApk.ServiceDispatcher sd = mDispatcher.get();
    if (sd != null) {
      sd.connected(name, service); 
    }
  }
}

最后调用到我们的回调:


public void doConnected(ComponentName name, IBinder service) {
  ServiceDispatcher.ConnectionInfo old;
  ServiceDispatcher.ConnectionInfo info;

  synchronized (this) {
    if (mForgotten) {
      return;
    }
    old = mActiveConnections.get(name);
    if (old != null && old.binder == service) {
      return;
    }

    if (service != null) {
      mDied = false;
      info = new ConnectionInfo();
      info.binder = service;
      //创建死亡监听对象
      info.deathMonitor = new DeathMonitor(name, service);
      try {
        //建立死亡通知
        service.linkToDeath(info.deathMonitor, 0);
        mActiveConnections.put(name, info);
      } catch (RemoteException e) {
        mActiveConnections.remove(name);
        return;
      }

    } else {
      mActiveConnections.remove(name);
    }

    if (old != null) {
      old.binder.unlinkToDeath(old.deathMonitor, 0);
    }
  }

  if (old != null) {
    mConnection.onServiceDisconnected(name);
  }
  if (service != null) {
    //回调用户定义的ServiceConnection()
    mConnection.onServiceConnected(name, service);
  }
}

所以这个 Binder 由服务所在的进程 -> AMS -> 调用所在的进程,这个过程中没有经过 ServiceManager 进行注册哦。

Android 学习笔录

Android Framework底层原理篇:https://qr18.cn/AQpN4J
Android 性能优化篇:https://qr18.cn/FVlo89
Android 车载篇:https://qr18.cn/F05ZCM
Android 逆向安全学习笔记:https://qr18.cn/CQ5TcL
Android 音视频篇:https://qr18.cn/Ei3VPD
Jetpack全家桶篇(内含Compose):https://qr18.cn/A0gajp
OkHttp 源码解析笔记:https://qr18.cn/Cw0pBD
Kotlin 篇:https://qr18.cn/CdjtAF
Gradle 篇:https://qr18.cn/DzrmMB
Flutter 篇:https://qr18.cn/DIvKma
Android 八大知识体:https://qr18.cn/CyxarU
Android 核心笔记:https://qr21.cn/CaZQLo
Android 往年面试题锦:https://qr18.cn/CKV8OZ
2023年最新Android 面试题集:https://qr18.cn/CgxrRy
Android 车载开发岗位面试习题:https://qr18.cn/FTlyCJ
音视频面试题锦:https://qr18.cn/AcV6Ap

Supongo que te gusta

Origin blog.csdn.net/weixin_61845324/article/details/133382448
Recomendado
Clasificación