Android13 Framework添加自定义服务

1,121 阅读5分钟

一、定义对外提供服务名称

Context.java文件写入我们对外提供的服务名称,例如Context.WINDOW_SERVICE中的WINDOW_SERVICE。这样其他人就可以通过该名称获取我们的服务。类似下面的Context.WINDOW_SERVICE获取WindowManagerService。需要修改的文件路径:frameworks\base\core\java\android\content\Context.java

  1. 增加静态常量DEVICE_SERVICE。因为我们定义的产量叫DEVICE_SERVICE,所以值需要时device。如果定义的是DEVICE_MANAGER_SERVICE,那么值就得是device_manager

    /**
     * 获取设备服务
     */
    public static final String DEVICE_SERVICE="device";
    
  2. ServiceName注解中添加DEVICE_SERVICE

        DEVICE_SERVICE,//新增
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface ServiceName {}

image.png

二、编写客户端代码

客户端代码指我们提供的服务在用户端的代理,是典型的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回调给客户端应用。

image-20241017173010782

创建下面文件夹,并分别创建DeviceManagerService.javaDeviceManagerServiceInternal.java文件。

frameworks\base\services\core\java\com\android\server\device

DeviceManagerServiceInternal是一个抽象类,定义了onKeyEventDispatched方法。其子类LocalServiceDeviceManagerService中被定义为静态内部类。

package android.os;

import android.view.KeyEvent;

public abstract class DeviceManagerServiceInternal {
    public abstract void onKeyEventDispatched(KeyEvent event);
}

DeviceManagerService通过callbacks持有客户端IDeviceManagerCallback对象,并实现 IDeviceManagerService.Stub的注册和解注册方法,用来往callbacks添加或移除回调对象。LocalService实现DeviceManagerServiceInternalonKeyEventDispatched方法,调用了DeviceManagerServiceonKeyEventDispatched方法。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文件,在SystemServerstartOtherService方法添加下面代码来注册DeviceManagerService,需要在启动WindowManagerService之前添加。这里最好tryCatch一下,避免我们写的服务异常,导致系统无法启动。

t.traceBegin("StartDeviceManagerService");

ServiceManager.addService(Context.DEVICE_SERVICE,new DeviceManagerService(context));

t.traceEnd();

导包:

import com.android.server.device.DeviceManagerService;

image-20241017171544347

五、派发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函数调用DeviceServiceManagerInternalonKeyEventDispatched函数。

mDeviceManagerServiceInternal.onKeyEventDispatched(event);

导包: import com.android.server.device.DeviceManagerServiceInternal;

image-20241017172155181

六、异常:

编译过程会由于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 image-20241028103953509

然后再Android Studio导入frameware.jar,调用相关服务,接收回调事件。

image-20241028105219029

点击虚拟机Home键,查看打印。添加服务成功。

image.png