Binder
É Android
o principal IPC
meio de comunicação do sistema e seu desempenho é excelente. No entanto, muitos desenvolvedores, inclusive eu, ficam assustados com isso. É realmente difícil. Toda vez que leio, esqueço de lê-lo. No entanto, à medida que trabalho cada vez mais, aprendo algo novo toda vez que leio Binder
. sei disso, então desta vez vou registrar um pouco do meu entendimento.
Olhando para o Binder do Framework/Driver
Binder
C/S
O design é uma arquitetura clássica , que Client
solicita e responde Server
ativamente Server
após receber a mensagem. Server
Pode-se servir vários Client
, mas não é possível enviar mensagens Server
ativamente .Client
Todos os processos começarão bind_open
abrindo binder
o driver e mmap
completando o mapeamento de memória completando o mapeamento de memória. Após diferentes processos abrirem o driver, binder
o driver criará um binder_proc
nó para representar o processo. Quando o processo tiver um novo nó Server
, ele será binder_proc
adicionado binder_node
para representar Para este serviço, quando o processo deseja se Server
comunicar , binder_proc
ele adiciona um binder_ref
(inclusive handle
, esse valor é aumentado sequencialmente no mesmo processo, e o mesmo serviço em processos diferentes handle
também é diferente, ServiceManager
é handle
uma exceção, que é fixado em 0) para descrever Server
a referência ao destino, binder_proc
e binder_node
todos binder_ref
eles são armazenados na forma de uma lista vinculada.
Gerenciador de serviços
Server
O gerenciamento de é através de ServiceManager
, e ele próprio também é um binder
. Server
Se quiser adicionar outros serviços, você precisa passar addService
o método dele. Se quiser obter o método, você precisa passar o getService
método dele. Também analisamos esses dois métodos.
Quando um processo quiser se registrar , ele chamará o método Server
através binder
da comunicação IPC , e os parâmetros também serão incluídos.Isso chegará primeiro ao driver, e o driver verificará se há um serviço correspondente no processo , porque é nas primeiras vezes, este serviço não existe, e então o driver irá criar um no correspondente para representar este serviço. O driver precisa notificar isso ao processo onde está localizado, mas não pode usar o correspondente diretamente , mas precisa adicione um no correspondente para apontar para isso , e (inclusive ) pode ser retornado ao processo correspondente, e o nome e outras informações deste serão registrados no processo . Isso conclui a adição de um serviço.ServiceManager
addService
Server
Server
binder
binder_node
binder_proc
binder_node
binder
Server
ServiceManager
binder_node
ServiceManager
binder_proc
binder_ref
Binder Server
binder_ref
handle
ServiceManager
ServiceManager
Server
handle
Quando um processo deseja se comunicar com um método, ele chamará o método do método Server
através binder
da comunicação IPC . Os parâmetros deste método contêm o nome (string) do serviço. Após a solicitação chegar ao processo através do IPC , ele passará este nome. Para encontrar o correspondente , se o serviço for encontrado, ele responderá ao processo alvo através do IPC. Como mencionado anteriormente, o que é salvo no processo é apenas uma referência ( ). Quando o driver receber esta resposta, ele irá obtenha o correspondente através desta referência. Sim , o driver irá comparar o processo de envio e o processo de recebimento. Na lógica da resposta, o processo de envio é , e o processo de recebimento é o processo que obtém este serviço. Eles são definitivamente diferentes . Como mencionado anteriormente, mesmo que um mesmo esteja em processos diferentes também são diferentes, portanto o in the process não pode ser utilizado diretamente pelo processo que obtém o serviço. É necessário criar outro para o processo que obtém o serviço. ao mesmo tempo, isso também aponta para o alvo e depois retorna isso ( ) para o processo que solicitou o serviço. Isso é ótimo, todas as comunicações subsequentes com dependerão disso ( ).ServiceManager
getService
binder
ServiceManager
Server
binder
ServieManager
binder_ref
handle
binder
Server
binder_node
ServiceManager
ServiceManager
Server
binder_ref
ServiceManager
binder_ref
binder_ref
binder_ref
Server
binder_node
binder_ref
handle
Server
binder_ref
handle
Como mencionado anteriormente , ServiceManager
também é um binder
, Server
seja adicionando Server
ou obtendo Server
, ele deve passar por isso. Nosso processo ServiceManager
deve corresponder à comunicação com handle
, mas como conseguimos isso handle
? binder
Ainda resta um backdoor aqui , ServcieManager
que handle
é o mesmo para todos os processos, é 0, então não há necessidade de obtê-lo, basta utilizá-lo diretamente.
O segredo do Binder para alta velocidade
Conforme mencionado acima, os métodos e serão chamados quando o processo for iniciado, e binder
o processo é o motivo da alta velocidade. Durante o processo de comunicação, haverá apenas uma cópia dos dados entre o espaço do usuário e o espaço do kernel, enquanto a maioria dos outros métodos de comunicação terá duas ou mais cópias. In irá alocar um pedaço de memória física para o processo, e a memória virtual de e apontará para essa memória, ou seja, essa memória física é compartilhada por eles. Ao enviar uma mensagem para , ele copiará a mensagem enviada por para a memória alocada por, e então notificará para usá-la.Após a conclusão do processamento, a mensagem de resposta também será gravada nesta memória, notificará a resposta e, em seguida, copiará o responder mensagem para o local Processar, responder Concluir chamada. O valor máximo deste espaço de memória é .bind_open
mmap
mmap
mmap
IPC
mmap
binder
binder
Server
Client
Server
Binder
Client
mmap
binder
Server
Server
binder
Client
binder
Client
Client
1MB - 8KB
Processo de comunicação Binder IPC
Alguns protocolos são necessários durante o processo de comunicação. Aqui estão protocolos diferentes. Os protocolos são geralmente divididos em protocolos de controle e protocolos de acionamento.
O protocolo de controle é ioctl(“/dev/binder”)
um método pelo qual outros processos enviam comandos ao driver, incluindo os seguintes:
Ordem | ilustrar | Tipo de parâmetro |
---|---|---|
BINDER_WRITE_READ | Operações de leitura e gravação, os comandos mais comumente usados. O processo IPC consiste em transferir dados por meio deste comando. | fichário_write_read |
BINDER_SET_MAX_THREADS | Defina o número máximo de threads suportados pelo processo | tamanho_t |
BINDER_SET_CONTEXT_MGR | Defina-se como ServiceManager | nenhum |
BINDER_THREAD_EXIT | Saídas de encadeamento do Binder do driver de notificação | nenhum |
BINDER_VERSION | Obtenha o número da versão do driver Binder | versão_do_fichário |
O protocolo do driver inclui os dois protocolos a seguir enviados pelo processo ao driver ( binder_driver_command_protocol
) e o protocolo enviado pelo driver ao processo ( binder_driver_return_protocol
).
binder_driver_command_protocol
:
Ordem | ilustrar | Tipo de parâmetro |
---|---|---|
BC_TRANSACTION | Transação Binder, ou seja: solicitação do cliente ao servidor | binder_transaction_data |
BC_REPLY | Resposta da transação, ou seja: resposta do servidor ao cliente | binder_transaction_data |
BC_FREE_BUFFER | Notifique o driver para liberar o buffer | binder_uintptr_t |
BC_ACQUIRE | Contagem de referência forte +1 | __u32 |
BC_RELEASE | Contagem de referência forte -1 | __u32 |
BC_INCREFS | Contagem de referência fraca +1 | __u32 |
BC_DECREFS | Contagem de referência fraca -1 | __u32 |
BC_ACQUIRE_DONE | Resposta de BR_ACQUIRE | binder_ptr_cookie |
BC_INCREFS_DONE | Resposta de BR_INCREFS | binder_ptr_cookie |
BC_ENTER_LOOPER | Notifique o thread principal do driver que ele está pronto | vazio |
BC_REGISTER_LOOPER | Notifique o driver de que o thread filho está pronto | vazio |
BC_EXIT_LOOPER | Notificar o thread do driver que ele foi encerrado | vazio |
BC_REQUEST_DEATH_NOTIFICATION | Solicitação para receber notificações de óbito | binder_handle_cookie |
BC_CLEAR_DEATH_NOTIFICATION | Remover notificações de morte | binder_handle_cookie |
BC_DEAD_BINDER_DONE | A notificação de óbito foi processada | binder_uintptr_t |
binder_driver_return_protocol
:
Tipo de retorno | ilustrar | Tipo de parâmetro |
---|---|---|
BR_OK | Operação concluída | vazio |
BR_NOOP | Operação concluída | vazio |
BR_ERROR | Um erro ocorreu | __s32 |
BR_TRANSACTION | O processo de notificação recebe uma solicitação do Binder (lado do servidor) | binder_transaction_data |
BR_REPLY | Processo de notificação recebe resposta à solicitação do Binder (Cliente) | binder_transaction_data |
BR_TRANSACTION_COMPLETE | A resposta de confirmação do motorista para aceitar a solicitação | vazio |
BR_FAILED_REPLY | Informar ao remetente que o alvo da comunicação não existe | vazio |
BR_SPAWN_LOOPER | Notificar o processo do Binder para criar um novo thread | vazio |
BR_ACQUIRE | Contagem de referência forte +1 solicitação | binder_ptr_cookie |
BR_RELEASE | Contagem de referências forte – 1 solicitação | binder_ptr_cookie |
BR_INCREFS | Contagem de referência fraca +1 solicitação | binder_ptr_cookie |
BR_DECREFS | Contagem de referências fraca – 1 solicitação | binder_ptr_cookie |
BR_DEAD_BINDER | Enviar notificação de falecimento | binder_uintptr_t |
BR_CLEAR_DEATH_NOTIFICATION_DONE | Limpeza de notificações de óbito concluída | binder_uintptr_t |
BR_DEAD_REPLY | Informe ao remetente que a outra parte está morta | vazio |
在上面介绍了一些命令后,你可能还是不怎么清楚具体怎么通信的,我这里描述一次简单的 binder
IPC 通信:
Client
通过 ServiceManager
获取到目标 Server
的 handle
后,底层调用 ioctl
方法,对应的 ioctl
命令是 BINDER_WRITE_READ
,其中还传递了发送给服务端的包裹的数据,也包含了 binder
驱动命令, 这个命令是 BC_TRANSACTION
,binder
驱动收到后会向 Client
线程回复 BR_TRANSACTION_COMPLETE
表示已经收到请求,binder
驱动会将 Client
传递过来的数据拷贝到对应 Server
的 mmap
内存空间,然后向 Server
发送 BR_TRANSACTION
命令,表示有新的 Client
请求,Server
会读取对应存在 mmap
中的 Client
请求数据,然后解析请求内容,Server
完成请求后,会把返回的数据封装在 reply 中,然后同样通过 ioctl
的 BINDER_WRITE_READ
命令封装回复的数据和驱动指令,驱动指令是 BC_REPLY
,binder
驱动收到后会向 Server
发送 BR_TRANSACTION_COMPLETE
命令,表示已经收到给 Client
的回复,在 binder
驱动中会将 Server
的回复数据拷贝到 Client
所在的进程,然后向 Client
发送 BR_REPLY
表示请求成功,Client
最后解析出 Server
发送来的数据,这样就完成了一次请求。
在 Android 中 Client
和 Server
对象的命名通常有有以下规律:
- | C/C++ | Java | AIDL |
---|---|---|---|
Server | BnXXX | XXXNative | IXXX.Stub |
Client | BpXXX | XXXProxy | IXXX.Stub.Proxy |
从 Service 和 AIDL 来看 binder
Android 中官方提供的唯一使用 binder
的接口就是使用四大组件之一的 Service
了,在 onBind()
回调中返回 Binder
的 Server
,客户端启动 Service
的方式修改成 bindService()
,其中 Service
中的 Binder
的 Server
准备就绪后会传给启动进程的 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
标记到方法参数中,表明这个参数只是当输出发送给Server
,Server
会把返回结果写入到这个对象的参数里,写入后会同步到Client
。 -
inout
标记到方法参数中,也就是同时满足in
和out
的特点。
后续我就通过一个 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
中定义的那些方法,除此之外其中的静态类 Stub
和 Stub.Proxy
他们占据了大部分的篇幅,Stub
其实就是表示 binder
的 Server
,Stub.Proxy
就是 binder
的 Client
,他们也都添加了 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:
}
}
然后我们需要把这个对象在四大组建之一的 Service
的 onBind
回调中返回给系统:
// ...
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);
}
这里很重要他首先会调用 IBinder
的 queryLocalInterface
方法去查询一下这个服务是否在当前进程中,如果不为空就是表示在当前进程中,然后会直接使用,其实这个对象就是 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
会在 ActivityThread
的 handBindService
方法中被调用:
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
传递给 ActivityManagerNative
的 publishService
方法,其实 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