添加android service并通过getSystemService调用

大概实现类似TelephoneManager这样的远程服务,但是由于TelephoneManager是已经封装过的代理类,所以我们不需要去获取binder,但是对于调用另一个应用的service,需要通过aidl来通信。请注意:这两种实现方式会有区别,后面会附上代码。

这里主要讲前者,对于aidl实现跨进程调用大概介绍一下。

1.添加service到SystemService

测试的service类是InnerToolService,表示内置到framework的自定义服务,使用的aidl包括:
IInnerToolService  定义接口,InnerToolService实现该接口
IInnerToolCB.aidl  定义回调  不熟悉aidl的话可以先不加

1).添加需要的Service的java文件。

注意:包名也要一样。package com.android.server;然后找到SystemServer,修改如下在ServerThread的run方法里添加:

//add innertool
try {              
    ServiceManager.addService("innertool", new InnerToolService(context));            
} catch (Throwable e) {     
}
//End

注意"innertool"相当于service的标记,在使用getSystemService来获取时需要提供该标记。

2).frameworks\base\core\java\android\app\ContextImpl.java
这里主要是响应getSystemService,如果service未启动,则启动service。

首先添加import语句
			//inner tool
			import com.android.innertool.IInnerToolService;
			//End

然后在内部类ServiceFetcher的static语句块里添加以下代码:
			
			//add innertool 
			registerService("innertool", new ServiceFetcher() {
                public Object getService(ContextImpl ctx) {
			IBinder b = ServiceManager.getService("innertool");
			IInnerToolService service = IInnerToolService.Stub.asInterface(b);
			Log.e("tool", "fetch innertool service = " + service);
			return  service;
                }});
			//End

3).aidl相关文件的编译

framework/base/Android.mk文件,在LOCAL_SRC_FILES下添加相关的aidl文件
		
		LOCAL_SRC_FILES += \
				innertool/java/com/android/innertool/IInnerToolService.aidl \
				innertool/java/com/android/innertool/IInnerToolCB.aidl

到这里基本就添加完成了,可能部分不同的平台或者项目会存在差异,大家需要细心。然后是对于远程service的调用

假设aidl定义的接口如下

interface IInnerToolService{
	void exec(String arg0,String arg1,IInnerToolCB arg2);
}

2.通过aidl调用远程service

上面定义了aidl文件,使用的包名是com.android.innertool,那我们本地应用也需要有这个包名下的aidl文件

即测试应用需要创建com.android.innertool这个包,并将IInnerToolService.aidl和IInnerToolCB.aidl文件放进去,这样会在gen/生成对应的java文件。

然后就可以使用该SystemService的接口了。

private IInnerToolService toolService2;
toolService2 = (IInnerToolService) getSystemService("innertool");
try {
    toolService2.exec("aaa", "bbb", new InnerToolCB());
} catch (RemoteException e1) {
    // TODO Auto-generated catch block
    e1.printStackTrace();
}

这样基本就走通了简单的调用流程。

附上相应的代码

package com.android.server;

import android.content.Context;
import android.os.RemoteException;
import android.util.Log;

import com.android.innertool.IInnerToolCB;
import com.android.innertool.IInnerToolService;

public class InnerToolService extends IInnerToolService.Stub{

	private Context mContext;

	public InnerToolService(Context context) {	
		mContext = context; 
	}

	@Override
	public void exec(String arg0, String arg1, IInnerToolCB arg2)
			throws RemoteException {
		// TODO Auto-generated method stub
		Log.v("InnerToolService", "exec,"+arg0+","+arg1+","+arg2);
	}
}


3.下面简单的介绍调用其他应用的service

假设仍然以上面的接口作为测试,这样被调用的应用需要有一个Serivce来实现IInnerToolService.Stub并返回该binder

代码如下:

package com.android.test;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

public class MyService extends Service{

	private IInnerToolService.Stub binder = new IInnerToolService.Stub(){

		@Override
		public void exec(String arg0, String arg1, IInnerToolCB arg2)
				throws RemoteException {
			// TODO Auto-generated method stub
			Log.v("InnerToolService", "exec,"+arg0+","+arg1+","+arg2);
		}
	};

	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		Log.v("InnerToolService", "onBind");
		return binder;
	}
}

这样调用的地方就可以通过bindService来获取该binder从而能跨进程通信

调用代码

private IInnerToolService toolService; 
private ServiceConnection mSerConn;
mSerConn = new ServiceConnection() {


@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub

toolService = IInnerToolService.Stub.asInterface(service);
}


@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub

}

};
try {
toolService.exec("aaa", "bbbb", new InnerToolCB());
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

通过两者对比,可以看到都是通过binder来通信的,不过由于获取binder的方式不同,所以代码有些区别。

4.aidl编译相关

如果是简单的接口文件,在mk文件里附上路径就可以,如果是Parcel类型,则需要实现java文件。因为aidl文件里只有一句声明
package com.android.innertool;

parcelable Entity;
对于这个例子,则需要在com.android.innertool下创建Entity.java,并implements Parcelable,然后按需求设计相应的数据结构等。
另外注意,必须实现以下方法
public void writeToParcel(Parcel dest, int arg1) 
public void readFromParcel(Parcel _reply)  // 这是系统解析aidl并生成java文件时在接口里要调用的
对于第二个方法,大家也许会发现,平时使用intent传递的类型不需要重写啊,只需要实现Parcelable.Creator<AppAction> CREATOR
但是这里必须要实现,因为在onTransact方法里会通过这个方法来获取参数
_arg0 = com.android.innertool.Entity.CREATOR.createFromParcel(data);

然后在接口里使用这个类时,需要添加限定符in,out,或者inout,否则编译不过。
例如在上面的aidl文件IInnerToolService里添加接口send(inout Entity entity),这里的in,out不明确的话,使用inout。



阅读更多
换一批

没有更多推荐了,返回首页