一、定义对外提供服务名称
往Context.java文件写入我们对外提供的服务名称,例如Context.WINDOW_SERVICE中的WINDOW_SERVICE。这样其他人就可以通过该名称获取我们的服务。类似下面的Context.WINDOW_SERVICE获取WindowManagerService。需要修改的文件路径:frameworks\base\core\java\android\content\Context.java。
-
增加静态常量
DEVICE_SERVICE。因为我们定义的产量叫DEVICE_SERVICE,所以值需要时device。如果定义的是DEVICE_MANAGER_SERVICE,那么值就得是device_manager。/** * 获取设备服务 */ public static final String DEVICE_SERVICE="device"; -
在
ServiceName注解中添加DEVICE_SERVICE。
DEVICE_SERVICE,//新增
})
@Retention(RetentionPolicy.SOURCE)
public @interface ServiceName {}
二、编写客户端代码
客户端代码指我们提供的服务在用户端的代理,是典型的Binder通信机制中的客户端。涉及IPC,需要通过AIDL来实现,这里建议在Android Studio建项目,创立同样的包名和类。避免在AOSP中直接编写异常。添加文件路径:
-
frameworks\base\core\java\android\os\device\IDeviceManagerCallback.aid -
frameworks\base\core\java\android\os\device\IDeviceManagerService.aidl
文件内容:
// IDeviceManagerCallback.aidl
package android.os.device;
import android.view.KeyEvent;
// Declare any non-default types here with import statements
interface IDeviceManagerCallback {
void onKeyEventDispatched(in KeyEvent event);
}
// IDeviceManagerService.aidl
package android.os.device;
import android.os.device.IDeviceManagerCallback;
interface IDeviceManagerService {
void registerCallback(IDeviceManagerCallback callback);
void unregisterCallback(IDeviceManagerCallback callback);
}
这两个AIDL文件定义了客户端与服务端通信接口,其中IDeviceManagerCallback定义了当KeyEvent发生时服务端回调客户端接口,IDeviceManagerService定义了客户端向服务端注册与解注册Callback的接口。
为了实现类似getSystemService(Context.WINDOW_SERVICE)后可以转化成WindowManager类型,我们需要实现DeviceManager类。
添加文件路径:
frameworks\base\core\java\android\app\device\DeviceManager.java
文件内容:
package android.app.device;
import android.os.RemoteException;
import android.os.device.IDeviceManagerService;
import android.util.Log;
public class DeviceManager {
private static final String TAG = "DeviceManager";
private IDeviceManagerService mService;
public DeviceManager(IDeviceManagerService service){
mService=service;
}
public void registerCallback(DeviceManagerCallback callback){
try {
mService.registerCallback(callback);
} catch (RemoteException e) {
Log.e(TAG,"Failure to register callback:"+callback);
e.printStackTrace();
throw e.rethrowFromSystemServer();
}
}
public void unregisterCallback(DeviceManagerCallback callback){
try {
mService.unregisterCallback(callback);
} catch (RemoteException e) {
Log.e(TAG,"Failure to unregister callback:"+callback);
e.printStackTrace();
throw e.rethrowFromSystemServer();
}
}
}
从代码可以看出,我们还需要实现DeviceManagerCallback类。
文件路径:
frameworks\base\core\java\android\app\device\DeviceManagerCallback.java
文件内容:
package android.app.device;
import android.os.RemoteException;
import android.os.device.IDeviceManagerCallback;
import android.view.KeyEvent;
public abstract class DeviceManagerCallback extends IDeviceManagerCallback.Stub {
@Override
public void onKeyEventDispatched(KeyEvent event) throws RemoteException {
onKeyEventArrive(event);
}
public abstract void onKeyEventArrive(KeyEvent event);
}
也就是说,其他人可以通过getSystemService(Context.DEVICE_SERVICE)转换成DeviceManager后注册DeviceManagerCallback来监听按键的分发。
注意:其中了避免lint检查问题,我们在现有的AOSP路径添加了device路径,为后续做铺垫。同时所有Java文件都要注意导包。
接下来往SystemServiceRegistry注册我们提供的服务。路径:frameworks\base\core\java\android\app\SystemServiceRegistry.java
在static{}静态代码块增加下面代码:
registerService(Context.DEVICE_SERVICE,DeviceManager.class,
new CachedServiceFetcher<DeviceManager>(){
@java.lang.Override
public DeviceManager createService(ContextImpl ctx) throws ServiceNotFoundException {
IBinder b=ServiceManager.getServiceOrThrow(Context.DEVICE_SERVICE);
return new DeviceManager(IDeviceManagerService.Stub.asInterface(b));
}
});
导包:
import android.app.device.DeviceManager;
import android.os.device.IDeviceManagerService;
三、编写服务端
服务端实现的功能是在KeyEvent发生时,通过DeviceManagerService回调给客户端应用。
创建下面文件夹,并分别创建DeviceManagerService.java和DeviceManagerServiceInternal.java文件。
frameworks\base\services\core\java\com\android\server\device
DeviceManagerServiceInternal是一个抽象类,定义了onKeyEventDispatched方法。其子类LocalService在DeviceManagerService中被定义为静态内部类。
package android.os;
import android.view.KeyEvent;
public abstract class DeviceManagerServiceInternal {
public abstract void onKeyEventDispatched(KeyEvent event);
}
DeviceManagerService通过callbacks持有客户端IDeviceManagerCallback对象,并实现 IDeviceManagerService.Stub的注册和解注册方法,用来往callbacks添加或移除回调对象。LocalService实现DeviceManagerServiceInternal的onKeyEventDispatched方法,调用了DeviceManagerService的onKeyEventDispatched方法。DeviceManagerService对象创建时会创建LocalService单例并添加到LocalServices中。这样PhoneWindowManager可以通过DeviceManagerServiceInternal来通知KeyEvent的触发。
package android.os;
package android.os;
import android.content.Context;
import android.util.Log;
import android.view.KeyEvent;
import com.android.server.LocalServices;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class DeviceManagerService extends IDeviceManagerService.Stub{
private static final String TAG = "DeviceService";
private List<IDeviceManagerCallback> callbacks=new ArrayList<>();
public DeviceManagerService(Context context){
LocalServices.addService(DeviceManagerServiceInternal.class,new LocalService());
}
@Override
public void registerCallback(IDeviceManagerCallback callback) throws RemoteException {
if (callbacks.contains(callback)){
callbacks.remove(callback);
}
callbacks.add(callback);
}
@Override
public void unregisterCallback(IDeviceManagerCallback callback) throws RemoteException {
if (callbacks.contains(callback)){
callbacks.remove(callback);
}
}
public void onKeyEventDispatched(KeyEvent event){
List<IDeviceManagerCallback> diedCallbacks=new ArrayList<>();
callbacks.forEach(new Consumer<IDeviceManagerCallback>() {
@Override
public void accept(IDeviceManagerCallback iDeviceServiceCallback) {
if (iDeviceServiceCallback.asBinder().isBinderAlive()){
try {
iDeviceServiceCallback.onKeyEventDispatched(event);
} catch (RemoteException e) {
Log.e(TAG,"The callback client has error:"+e.getMessage());
e.printStackTrace();
}
}else{
diedCallbacks.add(iDeviceServiceCallback);
}
}
});
if (!diedCallbacks.isEmpty()){
callbacks.removeAll(diedCallbacks);
}
}
//用户SystemServer内部通信,即PhoneWidnowManager调用
final class LocalService extends DeviceManagerServiceInternal{
@Override
public void onKeyEventDispatched(KeyEvent event) {
DeviceManagerService.this.onKeyEventDispatched(event);
}
}
}
四、注册服务
我们需要往ServiceManager注册DeviceManagerService,这样getSystemService才能查询到。
修改frameworks\base\services\java\com\android\server\SystemServer.java文件,在SystemServer的startOtherService方法添加下面代码来注册DeviceManagerService,需要在启动WindowManagerService之前添加。这里最好tryCatch一下,避免我们写的服务异常,导致系统无法启动。
t.traceBegin("StartDeviceManagerService");
ServiceManager.addService(Context.DEVICE_SERVICE,new DeviceManagerService(context));
t.traceEnd();
导包:
import com.android.server.device.DeviceManagerService;
五、派发KeyEvent,实现业务
这样客户端和服务端的交互逻辑就写好,接下来需要实现业务逻辑,在PhoneWindowManager就可以开始派发KeyEvent。
frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java
修改PhoneWindowManager,获取DeviceServiceManagerInternal单例:
//定义变量
DeviceManagerServiceInternal mDeviceManagerServiceInternal;
//获取实例
public void init(){
....
mDeviceManagerServiceInternal=LocalServices.getService(DeviceManagerServiceInternal.class);
...
}
在interceptKeyBeforeDispatching函数调用DeviceServiceManagerInternal的onKeyEventDispatched函数。
mDeviceManagerServiceInternal.onKeyEventDispatched(event);
导包:
import com.android.server.device.DeviceManagerServiceInternal;
六、异常:
编译过程会由于lint检查出现错误,我们将新建的文件的类不进行lint检查。
在文件frameworks\base\Android.bp找到metalava_framework_docs_args添加下面代码:
"--api-lint-ignore-prefix android.os.device. " +
"--api-lint-ignore-prefix android.app.device. " +
"--api-lint-ignore-prefix com.android.server.device. " +
七、Linux SELinux
到这里基本就完成了,但发现系统启动之后,我们的服务没有启动,看日志是因为SElinux安全问题,所以我们需要修改相关内容。但为了简单,我们直接关闭SELinux。
修改文件:system\core\init\selinux.cpp文件的IsEnforcing函数。同时把StatusFromProperty函数整个注释掉,不存在该函数。
bool IsEnforcing() {
//注释掉这部分
// if (ALLOW_PERMISSIVE_SELINUX) {
// return StatusFromProperty() == SELINUX_ENFORCING;
// }
return false;
}
手动关闭selinx参数,可以参考[在Android10版本的Framework中添加系统服务]
八、验证
-
编译make installclean、make update-api、make
-
启动虚拟机,或者刷机之后,可以通过下面adb命令查看是否存在服务:
service list | grep device
然后再Android Studio导入frameware.jar,调用相关服务,接收回调事件。
点击虚拟机Home键,查看打印。添加服务成功。