ServiceManagerProxy对象的获取过程
各个类之间的关系图如下所示:
+----------+
|IInterface|
+-----+----+
^
|
+-------+-------+
|IServiceManager|
+-+-----------+-+
^ ^
| |
+----------------+--+ +-+------------------+ +--------------+
|ServiceManagerProxy| |ServiceManagerNative| <-has-+ServiceManager|
++------------------+ +-----------------+--+ +--------------+
| |
(mRemote) |
| |
| +-------------+ +----------+ |
+> | BinderProxy | | Binder | <-+
++-----+------+ +--+-----+-+
| | | |
| | | |
(mObject) | +-------+ | (mObject)
| +-----> |IBinder| <---+ |
Java | +-------+ |
+------------------------------------------------------+
C++ v v
BpBinder BBinder
- 通常来说我们只跟ServiceManager打交道。对ServiceManager的调用都会转发给其内部成员sServiceManager(ServiceManagerNative对象)。
- Binder类提供了使用Binder机制的能力,IServiceManager接口定义了ServiceManager的API。
一次获取ServiceManager Proxy对象的调用过程如下图所示:
+-------------+ +-------------------+ +--------------+
|ServerManager| |ServerManagerNative| |BinderInternal|
+------+------+ +---------+---------+ +-------+------+
| | |
| | |
| | | +
getIServiceManager() | | | |
+-----------------> | | getContextObject() | JNI
+----------------------------------------------> | |
| | +------------>
| | | |
| | | |
| | <------------+
| | asInterface() | IBinder |
| | <----------------------+ |
| | | |
new ServiceManagerProxy()| | |
| <----------------------+ | |
| | | |
| | | |
| | | |
| | |
+ + +
Java Service接口的定义和解析
Java Service牵涉到的类之间的关系和调用流程大致如下图所示:
+----------------------------------------------------+
| |
| [Context Manager] |
| ^ |
+servicemanager-----------|--------------------------+
|
+-----------------------+ | +----------------------------+
| +-----------------+ | | | |
| | [Binder Client] | | | | +------------------------+ |
| +-----------^-----+ | | | |IBinder | |
| +------------|------+ | | | | +--------------------+ | |
| |AIDL | | | | | | |Binder | | |
| | +----------|----+ | | | | | | +----------------+ | | |
| | |Proxy | | | | | | | | |AIDL | | | |
| | | | | | | | | | | | +------------+ | | | |
| | | +--------|--+ | | | | | | | | |Stub | | | | |
| | | |IBinder | | | | | | | | | | | +--------+ | | | | |
| | | | | | | | | | | | | | | | Binder | | | | | |
| | | | +------v+ | | | | | | | | | | |Service | | | | | |
| | | | | Token | | | | | | | | | | | +----^---+ | | | | |
| | | | +----^--+ | | | | | | | | | +------|-----+ | | | |
| | | +------|----+ | | | | | | | +--------|-------+ | | |
| | +--------|------+ | | | | | +----------|---------+ | |
| +----------|--------+ | | | +------------|-----------+ |
+Process A---|----------+ | +Process B+----|-------------+
| | |
+------------|------------v-----------------|--------+
| +---->[Binder Driver]<---------+ |
| |
+kernel----------------------------------------------+
通常来说,我们通过AIDL来定义service接口,系统会自动根据AIDL文件生成一个对应的java接口。
以IMyService为例,系统根据IMyService.aidl生成IMyService.java:
// IMyService.aidl
interface IMyService {
void hello(String val);
}
// IMyService.java
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: C:\\Users\\xinyu.he\\workspace\\LayoutTest\\src\\com\\example\\layouttest\\IMyService.aidl
*/
package com.example.layouttest;
public interface IMyService extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.example.layouttest.IMyService
{
private static final java.lang.String DESCRIPTOR = "com.example.layouttest.IMyService";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.example.layouttest.IMyService interface,
* generating a proxy if needed.
*/
public static com.example.layouttest.IMyService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.layouttest.IMyService))) {
return ((com.example.layouttest.IMyService)iin);
}
return new com.example.layouttest.IMyService.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
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_hello:
{
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
this.hello(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.example.layouttest.IMyService
{
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 void hello(java.lang.String val) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(val);
mRemote.transact(Stub.TRANSACTION_hello, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_hello = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public void hello(java.lang.String val) throws android.os.RemoteException;
}
可以看到系统自动生成了两个内部类IMyService.Stub和IMyService.Proxy。这两个类都实现了IMyService接口,其作用是对调用者屏蔽了Binder机制。
* IMyService.Stub用来描述一个自定义的Java服务。MyService继承于IMyService.Stub,并实现了hello()方法。
* IMyService.Stub.asInterface方法用来生成一个Proxy对象,Client获取到Proxy对象后,调用其hello()方法,Proxy对象向Service发送TRANSACTION_hello,触发Stub对象的onTransact方法。onTransact方法调用子类实现的hello()方法。
Java服务的启动过程
Java服务一般运行在Android系统进程或者应用程序进程中,需要在启动之前注册到Service Manager。由于android进程自带Binder线程池,所以只需将service注册到servicemanager中即可(不用初始化Binder等)。
注册service的代码一般如下所示:
ServiceManager.addService("MyService", new MyService());
- 首先分析一下MyService类的创建过程:MyService继承于IMyService,简介继承于Binder类,因此Binder的初始化方法会被调用。Binder对象初始化时会调用JNI方法init()。init方法会创建一个JavaBBinderHolder对象,然后将其地址保存在Binder对象的mBinder成员变量中。同时也将MyService保存在自身的mObject成员变量中。
JavaBBinderHolder对象有成员变量mBinder,指向一个JavaBBinder对象。JavaBBinder继承于BBinder。 - MyService创建完毕后,通过addService方法注册到servermanager中。addService方法发起一个ADD_SERVICE_TRANSACTION,参数为MyService对象和注册名称name。
- servermanager收到ADD_SERVICE_TRANSACTION请求以后,将Parcel中的BBinder取出,并注册到内部。
Java服务代理对象的获取过程
service注册到ServerManager后,Android App便可以通过ServiceManager来获得service的一个proxy对象了。一般来说,获取一个service proxy对象的代码片段如下所示:
...
myService = IMyService.Stub.asInterface(ServiceManager.getService("myService"));
...
该代码片段的内部逻辑如下所示:
+--------+ +----------+ +--------------+ +-------------------+
|Activity| |IMyService| |ServiceManager| |ServiceManagerProxy|
+--------+ +-----+----+ +--------+-----+ +---------+---------+
| | | |
| | getService(name)| |
+----------------------------------------> |
| | | getService(name) |
| | +---------------------->
| | | | GET_SERVICE_TRANSACTION
| | | +------------------------>
| | | | BinderProxy
<----------------------------------------------------------------------------------------+
| | | |
| | | |
|Stub.asInterface(obj) | |
+--------------------> | |
| | | |
| | | |
| Stub.Proxy | | |
<--------------------+ | |
| | | |
| | | |
| | | |
| | | |
Java服务的调用过程
使用service提供的服务时,直接在Proxy对象上调用AIDL定义好的接口方法即可。其内部逻辑如下所示:
+--------+ +----------------------+ +--------------------+ +-------------+ +----------------------+
|Activity| |IMySer|ice(Stub.Proxy)| |mRemote(BinderProxy)| |Binder Driver| |MyService(Stub:Binder)|
+---+----+ +---------+------------+ +-----------+--------+ +-----+-------+ +--------+-------------+
| | | | |
| | | | |
| mySer^ice.hello()| | | |
+-----------------> | | | |
| |transact(Stub.TRANSACTION_hello) | |
| +--------------------------> | | |
| | | | |
| | | onTransact()...| |
| | +----------------> | |
| | | | execTransact() |
| | | +------------------> |
| | | | |
| | | | onTransact() |
| | | | +-------------+
| | | | | |
| | | | +-----------> |
| | | | |
| | | | hello() |
| | | | +-------------+
| | | | | |
| | | | +-----------> |
| | | | |
| | | | |
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。