在Android framework中添加系统aidl服务供app调用
1.添加aidl服务,首先需要写一个.aidl文件,这里添加在framework/base/core/java/android/hardware下,新建一个ICopyCameraData.aidl文件,文件内容如下:
// ICopyCameraData.aidl
package android.hardware;
// Declare any non-default types here with import statements
import android.hardware.ICameraDataCallBack;
interface ICopyCameraData {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
byte[] onPreviewFrame();
void setPreviewFrame(in byte[] data);
void registerCallBack(ICameraDataCallBack callback);
void unRegisterCallBack(ICameraDataCallBack callback);
}
因为在aidl中需要用到接口回调,所以还需要在同目录下新建一个ICameraDataCallBack.aidl文件,内容如下:
// ICopyCameraData.aidl
package android.hardware;
// Declare any non-default types here with import statements
interface ICameraDataCallBack {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void setPreviewFrame(in byte[] data);
}
因为aidl用于进程间通信,所以在ICopyCameraData.aidl文件中的方法供服务器端使用,在ICameraDataCallBack.aidl文件中的方法供客户端调用。
2.在添加完文件之后,要在framework/base下的Android.mk中将新加的两个文件加入编译,这样才能自动编译出后边要用的java文件,按照之前在文件中已有的aidl样式添加即可(注意:在Android O以上,已经移到Android.bp中):
"core/java/android/hardware/ICopyCameraData.aidl",
"core/java/android/hardware/ICameraDataCallBack.aidl",
3.接下来就要编写需要添加的服务了,在framework/base/services/core/java/com/android/server下新加CameraDataService.java去实现刚写的.aidl文件中的方法:
package com.android.server;
import android.hardware.Camera;
import android.os.RemoteException;
import android.content.Context;
import android.hardware.ICopyCameraData;
import android.hardware.ICameraDataCallBack;
import android.util.Log;
import android.os.RemoteCallbackList;
public class CameraDataService extends ICopyCameraData.Stub {
private byte[] mData;
private RemoteCallbackList<ICameraDataCallBack> mRemoteCallbackList = new RemoteCallbackList<ICameraDataCallBack>();
@Override
public byte[] onPreviewFrame() throws RemoteException {
return mData;
}
@Override
public void setPreviewFrame(byte[] data) throws RemoteException {
mData = data;
final int len = mRemoteCallbackList.beginBroadcast();
for(int i = 0; i < len; i++) {
ICameraDataCallBack mCallback = mRemoteCallbackList.getBroadcastItem(i);
if(mCallback!=null){
mCallback.setPreviewFrame(data);
}
}
mRemoteCallbackList.finishBroadcast();
}
@Override
public void registerCallBack(ICameraDataCallBack callback) throws RemoteException {
mRemoteCallbackList.register(callback);
final int N=mRemoteCallbackList.beginBroadcast();
Log.e("registerListener", "size:"+N);
mRemoteCallbackList.finishBroadcast();
}
@Override
public void unRegisterCallBack(ICameraDataCallBack callback) throws RemoteException {
mRemoteCallbackList.unregister(callback);
final int N=mRemoteCallbackList.beginBroadcast();
Log.e("unregisterListener", "size:"+N);
mRemoteCallbackList.finishBroadcast();
}
public CameraDataService(Context context){
}
}
首先这里的构造函数不能少,registerCallBack和unRegisterCallBack方法其实是固定的写法,就是将ICameraDataCallBack接口注册到服务中。setPreviewFrame()中的方法是可以自定义的,这里传递的是byte[]数组类型。
4.由于添加的是系统级别的服务,所以需要在系统启动的时候将这个服务启动起来,在framework/base/services/java/com/android/server中的SystemServer.java中的startOtherServices()方法中,添加刚才写服务:
CameraDataService cameraDataService = null;
try {
cameraDataService = new CameraDataService(context);
ServiceManager.addService("cameraDataService", cameraDataService);
} catch (Throwable e) {
reportWtf("starting cameraDataService", e);
}
这样就将可以在开机的时候将自定义服务启动起来,但要注意,这个服务不要启动的太早。addService参数里的名称是可以随便起的,后边要用到。
5.添加系统服务是需要权限的,在system/sepolicy/service/下的service_contexts.te中按照文件的格式,在文件的末尾添加
cameraDataService u:object_r:cameradata_service:s0
这里的cameraDataService就是我们之前在SystemServer中起的服务名称,需要一致。
在system/sepolicy/service/下的service.te中按照文件的格式,在文件的末尾添加
type cameradata_service, system_api_service, system_server_service, service_manager_type;
6.在添加完上边的权限之后,这时候服务已经可以注册到系统中了,但是在使用中还是需要一些SELinux权限,这里我还没有添加,先用adb shell setenforce 0调试。
7.这时的服务已经是一个正常的系统服务了,可以使用了。接下来是使用方法。在服务端我是在framework的camera.java中去传递一个应用获取到的camera数据给另外一个应用使用:
(1)首先获取服务:
//bindRemoteService();
copyCameraData = ICopyCameraData.Stub.asInterface(ServiceManager.getService("cameraDataService"));
try{
// copyCameraData.registerCallBack(mCameraDataCallBack);
copyCameraData.asBinder().linkToDeath(mDeathRecipient, 0);
}catch(Exception e){
}
(2)在获取数据的地方,将数据传给服务:
if(mPreviewCallback != null){
mPreviewCallback.onPreviewFrame(yuv,Camera.this);
try{
copyCameraData.setPreviewFrame(yuv);
}catch(Exception e){
e.printStackTrace();
}
}
8.接着就是客户端,也就是app去调用服务获取数据了:
(1)获取服务,并注册回调
copyCameraData = ICopyCameraData.Stub.asInterface(ServiceManager.getService("cameraDataService"));
try{
copyCameraData.registerCallBack(mCameraDataCallBack);
}catch(Exception e){}
(2)获取回调实例
private ICameraDataCallBack mCameraDataCallBack=new ICameraDataCallBack.Stub() {
@Override
public void setPreviewFrame(byte[] data) throws RemoteException {
try{
Log.e("callback","setPreviewFrame"+data.length);
} catch (Exception e) {
e.printStackTrace();
}
}
};
(3)在应用销毁时取消注册服务:
try{
copyCameraData.unRegisterCallBack(mCameraDataCallBack);
}catch(Exception e){
}
至此服务添加完成。