定制Android系统开发之三——跟着我实现系统服务

时间:2022-12-02 16:05:53

在这篇博文中,我将一步一步建立一个SystemService。

这个系统服务是用于控制收音机的,名字就叫做RadioManagerService。

新建IRadioManager.aidl;

framework/base/core/java/amdroid/os/中新建IRadioManager.aidl文件。文件的内容如下:

package android.os;

interface IRadioManager{
void test();
}

aidl文件的语法规则可以网上查一下,这里就不做解释了。

将.adil文件名添加到Android.mk脚本中;

上面虽然新建了aidl文件,但是在编译的过程中并不会编译,只有在Android.mk中添加相关说明之后才会编译。

这个Android.mk文件的位置是:frameworks/base/Android.mk

LOCAL_SRC_FILES += \ 
core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl \
core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl \
#…… 此处省略很多行
com/java/android/os/IRadioManager.aidl

编写Service,实现xxx.stub;

frameworks/base/services/java/com/android/server/目录下新建RadioManagerService.java。其内容如下:

public class RadioManagerService extends IRadioManager.Stub implements IOnUartMsgListener {
private static final String TAG = "TimothyRadioManagerService";
private Context mContext;

public RadioManagerService(Context context) {
this.mContext = context;
}

@Override
public void test() throws RemoteException {
Log.d(TAG, "test() is called");
}
}

实现Manager,调用Service;

framework/base/core/java/android/os/目录下新建RadioManager.java,内容如下:

public class RadioManager {
private static final String TAG = "TimothyRadioManager";
private Context mContext;
private IRadioManager mService; // 要调用服务器的接口,首先就要保存服务器的对象。就好比只有知道了找人办事,首先得知道要找的人叫什么。

public RadioManager(Context context, IRadioManager service) {
mContext = context;
mService = service;
}
public void test() {
Log.d(TAG, "test() is called");
mService.test(); // 调用客户端的test()函数,实际上调用的是服务器的test()函数。
}
}

将自定义的服务注册到SystemServer;

framework/base/services/java/com/android/server/SystemServer.java的initAndLoop()函数里增加声明,并注册Service。

public void initAndLoop() {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN,
SystemClock.uptimeMillis());

Looper.prepareMainLooper();

// 此处省略很多行

Installer installer = null;
AccountManagerService accountManager = null;
ContentService contentService = null;
LightsService lights = null;
PowerManagerService power = null;

// 此处省略很多行

com.android.server.RadioManagerService audioManagerService = null;

// 此处省略很多行

// 找个系统添加其他Service的地方加上下面这些
try {
Slog.i(TAG, "radio service");
radioManagerService = new com.android.server.RadioManagerService(context);
ServiceManager.addService(Context.RADIO_MANAGER_SERVICE, radioManagerService);
} catch (Throwable e) {
reportWtf("starting iflytek radio service", e);
}
}

千万别忘了,在Context中增加RADIO_MANAGER_SERVICE这个常量的定义。

在ContextImpl.java中注册服务;

framework/base/core/java/android/app/ContextImpl.java中注册其他服务的地方加上下面的代码:

registerService(RADIO_MANAGER_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(RADIO_MANAGER_SERVICE);
return new android.os.iflytek.RadioManager(ctx, IRadioManager.Stub.asInterface(b));
}});

当你在使用Context.getSystemService()的时候,代码会走到这里。

结论

到这里,在Android APP中就能通过使用下面的代码调用系统服务:

RadioManager mRadioManager = (RadioManager)getSystemService(Context.RADIO_MANAGER_SERVICE);
mRadioManager.test();

因为改了framework中的代码,增加了接口,在编译的时候,需要先执行

make update-api

之后再make。