新增系统服务
在Framework下面新增系统服务就可以和系统默认服务一样用getSystemService()方法去调用,这样做可以方便的对外提供第三方应用没有权限去做的接口。具体步骤如下:
1. 编写***.aidl文件:在Eclipse插件下新建文件,文件后缀名为.aidl,然后再aidl文件中编写接口与方法。比如ITestService.aidl。
我的示例如下:
packageandroid.os;
/**{@hide} */
interfaceITestService
{
boolean getState();
void setState(boolean name);
}
如果在方法上面加/**{@hide}*/修饰的话表示api不提供对外接口,在执行make update-api 后不会出现在frameworks\ base\core\java
\android\content\Context.java中。上面的ITestService.aidl位于frameworks\base\core\java\android\os\ITestService.aidl
2. 在mk文件中增加:在 frameworks\base\Android.mk中添加刚才编写的aidl文件。
LOCAL_SRC_FILES+= \
core/java/android/os/ITestService.aidl
3. 真正的实现:在frameworks\base\services\java\com\android\server下面新增TestService.java,这个类继承ITestService.Stub,然后实现上述aidl文件中的接口中的方法。我的示例如下:
packagecom.android.server;
importandroid.os.ITestService;
importandroid.os.RemoteException;
importandroid.content.Context;
publicclass TestService extends ITestService.Stub
{
private Context mContext;
public TestService(Context context) {
mContext = context;
}
@Override
public boolean getState() throwsRemoteException {
// TODO Auto-generated method stub
System.out.println("啦啦啦德玛西亚");
return false;
}
@Override
public void setGuardState(boolean name)
throws RemoteException {}
}
}
4. 将TestService添加到ServiceManager中:找到frameworks/base/
services/java/com/android/server/SystemServer.java,在一堆的ServiceManager.addService代码块中添加如下代码:
try {
test = new TestService(context);
ServiceManager.addService(Context.TEST_SERVICE,test);
} catch (Throwable e) {
reportWtf("Failurecreating TestService", e);
}
这段代码表示在SystemServer中启动服务,这样在启动ServiceManager中,上面代码中Context. TEST_SERVICE是自己在Context类中定义的常量,也就是给服务定义的名字,使用常量 方便获取服务,而不需要记住注册服务时用的名字,且想换名字 时只需改一个常量的值。
5. 新增对外接口:编写接口类用于其他地方的调用,就是getSystemService()方法得到的真正的类。类文件和上述aidl文件同一目录。我的示例如下:
package android.os;
import android.os.RemoteException;
import android.util.Log;
/**
*Class that get and set state. To obtain an instance of the
*system vibrator, call {@link Context#getSystemService} with
*{@link Context#TEST_SERVICE} as argument.
*/
public class TestService {
private static final String LOG_TAG = "TestService";
ITestServicemService;
public TestService(ITestService service) {
mService = service;
}
public boolean getState() {
try {
Log.i(LOG_TAG,"......................");
return mService.getState();
} catch (RemoteException e) {
Log.e(LOG_TAG, "[getState]RemoteException");
}
return false;
}
public void setState(boolean name) {
try {
mService.setState(name);
} catch (RemoteException e) {
Log.e(LOG_TAG, "[State]RemoteException");
}
}
}
这个类用于第三方调用,您可以随意扩展,我这里是调用了aidl的实现类的一些方法。
6. 增加新服务的注册:通过跟踪(frameworks\base\core\java\android\app\ContextImpl.java)getSystemService(),
@Override
publicObject getSystemService(String name) {
ServiceFetcherfetcher =SYSTEM_SERVICE_MAP.get(name);
return fetcher ==null ?null :fetcher.getService(this);
}
继续跟踪SYSTEM_SERVICE_MAP
privatestaticvoidregisterService(StringserviceName, ServiceFetcher fetcher) {
if (!(fetcherinstanceof StaticServiceFetcher)) {
fetcher.mContextCacheIndex =
sNextPerContextServiceCacheIndex++;
}
SYSTEM_SERVICE_MAP.put(serviceName,fetcher);
}
}
在registerService()中会去put。继续跟踪会发现系统默认服务也会调用registerService()去注册。我们的示例如下:
registerService(Context.TEST_SERVICE,newServiceFetcher() {
public Object createService(ContextImplctx) {
IBinder b = ServiceManager.getService(Context.TEST_SERVICE);
ITestService service = ITestService.Stub.asInterface(b);
returnnew TestService(service);
}});
7.在Context.java增加上述Contex.TEST_SERVICE:
frameworks/base/core/java/android/content/Context.java的末尾加入public static final String TEST_SERVICE = "test";这样就可以通过Context. TEST_SERVICE引用了。
8.update-api:因为更改了api,所以调用make update-api去更新,如果你的方法没有加hide标记,就会在current.txt中找到你的新加服务方法。然后就进行编译后去调用吧。执行adbshell ps可以去查看服务在不在运行。
9.调用:import android.os.TestService;
TestService test= (TestService)this.getSystemService(Context.TEST_SERVICE);
test.getState();
完结。谢谢。