学习参考:http://blog.csdn.net/luoshengyang/article/details/6642463
本博文将基于Binder扩展android的系统服务,在编写实例的同时,将会对Binder机制在framework层的接口源码进行分析。
扩展的系统服务描述如下:霍金不会说话,希望Android手机帮助他说话,那么需要将说话的服务当作系统服务放到到Android系统中。实例会编写或分析如下内容:
- 获取Service Manager的Java远程接口的过程;
- 系统服务HawkingService接口的定义;
- HawkingService的启动过程;
- Client获取HawkingService的Java远程接口的过程;
1. 获取ServiceManager的Java远程接口的过程
因为系统服务全部被ServiceManager管理,所以这里将分析一下如何获取ServiceManager的Java远程接口。下面是ServiceManager相关的类图。
如图所示,ServiceManager中有个getIServiceManager方法可以返回ServiceManager的Java运程接口,利用返回的对象就可以获得ServiceManager对系统服务管理的服务了。
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager
sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
return sServiceManager;
}
跟踪代码可以看到最终要返回IServiceManager,需要往ServiceManagerProxy的构造函数中传入一个IBinder对象,这个对象是由BinderInternal.getContextObject()返回的。
public static final native IBinder getContextObject();
而getContextObject是个native方法,通过JNI返回了一个IBinder对象。具体的C++层的代码这里暂时不做分析。这样获取ServiceManager的Java远程接口就结束了。
2. 系统服务HawkingService接口的定义
HawkingService提供的服务就是say,如下:
interface IHawkingService{
void say(String sth);
}
我利用AIDL生成了HawkingService相关的proxy,stub代码,如下:
public interface IHawkingService extends IInterface {
//Hawking Server
public static abstract class Stub extends Binder implements IHawkingService {
private static final java.lang.String DESCRIPTOR = "com.test.IHawkingService";
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* 如果是本地服务接口,将IBinder对象cast为IHawkingService并返回
* 如果不是本地服务(可能是远程服务)接口,返回IHawkingService的代理对象
*/
public static IHawkingService asInterface(IBinder obj) {
if ((obj == null)) {
return null;
}
IInterface iin = (IInterface) obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof IHawkingService))) {
return ((IHawkingService) iin);
}
return new IHawkingService.Stub.Proxy(obj);
}
public IBinder asBinder() {
return this;
}
@Override
public boolean onTransact(int code, Parcel data,Parcel reply, int flags)
throws RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_say: {
data.enforceInterface(DESCRIPTOR);
String _arg0 = data.readString();
this.say(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
//Hawking Proxy
private static class Proxy implements IHawkingService {
private IBinder mRemote;
Proxy(IBinder remote) {
mRemote = remote;
}
public IBinder asBinder() {
return mRemote;
}
public void say(String sth) throws RemoteException {
Parcel _data = Parcel.obtain();
Parcel _reply = Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(sth);
mRemote.transact(Stub.TRANSACTION_say, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_say = (IBinder.FIRST_CALL_TRANSACTION + 0);
}
public void say(String sth) throws RemoteException;
}
IHawkingService的服务端实现类时HawkingService,代码如下
public class HawkingService extends IHawkingService.Stub{
@Override
public void say(String sth) throws RemoteException {
System.out.println("hawking say: "+sth);
}
}
3. HawkingService服务的启动过程
开机时,系统服务的启动都是交给SystemServer进行处理的,SystemServer会启动一个ServerThread的线程用于启动系统服务并把启动的服务添加到ServiceManager中。
public class SystemServer
{
native public static void init1(String[] args);
public static void main(String[] args) {
.......
}
public static final void init2() {
Slog.i(TAG, "Entered the Android system server!");
Thread thr = new ServerThread();
thr.setName("android.server.ServerThread");
thr.start();
}
}
class ServerThread extends Thread {
......
@Override
public void run() {
.....
Looper.prepare();
......
try {
Slog.i(TAG, "HawkingService");
ServiceManager.addService("hawking", new HawkingService());
} catch (Throwable e) {
Slog.e(TAG, "Failure starting Hawking Service", e);
}
......
Looper.loop();
......
}
}
如上述代码ServiceManager.addService("hawking", new HawkingService());,new HawkingService()是创建了一个Binder对象,下面我们就来看一下,如何创建一个Binder对象以及如何将这个进行add Service。
创建Binder对象过程:
public class Binder implements IBinder {
......
private int mObject;
......
public Binder() {
init();
......
}
private native final void init();
......
}
new HawkingService()会调用Binder的构造函数,如上述代码,Binder的构造函数会调用一个native方法init,这个方法定义在frameworks/base/core/jni/android_util_Binder.cpp中。
static void android_os_Binder_init(JNIEnv* env, jobject clazz)
{
JavaBBinderHolder* jbh = new JavaBBinderHolder(env, clazz);
if (jbh == NULL) {
jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
return;
}
LOGV("Java Binder %p: acquiring first ref on holder %p", clazz, jbh);
jbh->incStrong(clazz);
env->SetIntField(clazz, gBinderOffsets.mObject, (int)jbh);
}
可以看出init做的事情就是创建一个JavaBBinderHolder对象,并将对象地址返回给
mObject。
ServiceManager.addService过程
class ServiceManagerProxy implements IServiceManager {
public ServiceManagerProxy(IBinder remote) {
mRemote = remote;
}
......
public void addService(String name, IBinder service)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
data.writeStrongBinder(service);
mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
reply.recycle();
data.recycle();
}
......
private IBinder mRemote;
}
addService最终的实现在ServiceManagerProxy中。上述代码 data.writeStrongBinder(service) 是将Binder对象写入到Parcel包裹中,这个写入的对象service就是刚才生成的mObject地址转化过来的。具体的实现在writeStrongBinder的JNI实现中。
4.Client获取HawkingService的Java远程接口的过程
下面编写一个客户端通过ServiceManager的getService方法去获取系统服务HawkingService。
public class HawkingActivity extends Activity{
private IHawkingService hawkingService;
@Override
public void onCreate(Bundle savedInstanceState) {
hawkingService= IHawkingService.Stub.asInterface(
ServiceManager.getService("hawking"));
hawkingService.say("Hello everyone");
}
}
ServiceManager.getService实际上是调用了ServiceManagerProxy.getService函数。
class ServiceManagerProxy implements IServiceManager {
public ServiceManagerProxy(IBinder remote) {
mRemote = remote;
}
public IBinder getService(String name) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
IBinder binder = reply.readStrongBinder();
reply.recycle();
data.recycle();
return binder;
}
.......
}