Android Framework添加自定义服务和接口

1、概述

本博文配套的硬件是瑞芯微RK3288芯片,跑的是Android5.1的SDK。作为设备开发商,经常有release接口给第三方调用的需求,本文基于实际案例撰写,不同版本的Android Framework架构可能略有不同,但是大同小异,均可作为参考。

2、扩展Framework接口

第三方APP如果要操作硬件,比如通过ioctl操作某个GPIO,大体上来说,应该有以下两种方法:

1、我们封装操作硬件的API,形成一个so库给到第三方,并写好JNI接口打通到Java层,第三方直接调用Java层接口就好。这种方法理论上可行,但是实际操作中一般会有API调用权限问题。操作硬件接口,一般都需要调用者进程需要system权限甚至是root权限,通过release JNI接口的方式给第三方调用,所有的代码都是跑在第三方APP的进程,一般而言,我们是不会随便给第三方APP系统权限,这样既会有安全问题,也会引入第三方APP升级麻烦等问题,不推荐使用。

2、扩展Framework接口:第三方APP调用标准接口,然后通过aidl的方式,跨进程调用到system_server进程中对应的远程接口,由于system_server是系统进程,所以不存在权限问题。本文就是使用该种方式。

2.1、定义Java接口

在 frameworks/base/core/java目录下,根据包名创建一个子目录,比如我创建的是com/wrtsz/api/,在该目录下,新建一个java文件,比如WrtdevManager.java ,对应的代码如下:

package com.wrtsz.api;

import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;

public class WrtdevManager {
	
	private final IWrtdevManager mService;

    private Handler mHandler;
    private static final String TAG = "WrtdevManager";
	
    public WrtdevManager(IWrtdevManager service, Handler handler) 
	{
        mHandler = handler;
        mService = service;
    }   

	public int getMicroWaveState()
	{
		try{
	        return mService.getMicroWaveState();
	    }catch (RemoteException e){
	        Log.e(TAG, "getMicroWaveState failed");
	        return -1;
	    }
	}
	
	public byte[] getIcCardNo()
	{
		try{
	        return mService.getIcCardNo();
	    }catch (RemoteException e){
	        Log.e(TAG, "getIcCardNo failed");
	        return null;
	    }
	}

	public int openLed(int opIndex)
	{
		try{
	        return mService.openLed(opIndex);
	    }catch (RemoteException e){
	        Log.e(TAG, "openWhiteLed failed");
	        return -1;
	    }
	}

	public int openDoor()
	{
		try{
	        return mService.openDoor();
	    }catch (RemoteException e){
	        Log.e(TAG, "openDoor failed");
	        return -1;
	    }
	}

}

以上代码,注意两点:

1、每个接口中,都必须catch RemoteException异常,这个不加上应该编译不过,主要是防止对应的远程接口没有定义,导致APP调用出错;

2、构造函数有两个参数,一个是Handler,一个是IWrtdevManager (继承于android.os.IInterface)

2.2、定义aidl接口

在WrtdevManager.java文件中有用到IWrtdevManager,这是通过编译aidl文件生成,定义的.aidl文件如下:

package com.wrtsz.api;

interface IWrtdevManager
{
    int getMicroWaveState();
	byte[] getIcCardNo();
	int openLed(int opIndex);
	int openDoor();	
}

需要注意的是:.aidl中的接口必须跟.java中的接口保持一致,否则会编译不过。另外就是aidl语言的语法跟Java语言略有不同,且传递的参数必须是Java基本类型或者是其他实现Parcelable 接口的类,这里不再详述,可以参考官方文档:https://developer.android.com/guide/components/aidl?hl=zh-cn

2.3、编译接口

上面虽然定义了两个文件,但是默认情况下,编译Android的时候是不会编译到这两个文件的,如果要用编译到对应的文件,需要修改frameworks/base/Android.mk文件,在对应的LOCAL_SRC_FILES宏中添加对应的文件即可,相应的patch文件如下:

 	packages/services/Proxy/com/android/net/IProxyCallback.aidl \
 	packages/services/Proxy/com/android/net/IProxyPortListener.aidl \
 	core/java/android/os/IDisplayDeviceManagementService.aidl \
+ 	core/java/com/wrtsz/api/IWrtdevManager.aidl \
+ 	core/java/com/wrtsz/api/WrtdevManager.java
 	
 
 # FRAMEWORKS_BASE_JAVA_SRC_DIRS comes from build/core/pathmap.mk
 LOCAL_AIDL_INCLUDES += $(FRAMEWORKS_BASE_JAVA_SRC_DIRS)

清空之后在Android根目录编译,发现会报错:

see build/core/apicheck_msg_current.txt
******************************
You have tried to change the API from what has been previously approved.

To make these errors go away, you have two choices:
   1) You can add "@hide" javadoc comments to the methods, etc. listed in the
      errors above.

   2) You can update current.txt by executing the following command:
         make update-api

      To submit the revised current.txt to the main Android repository,
      you will need approval.
******************************

熟悉Android SDK开发的就比较清楚原因,因为我们添加了系统接口,需要先make update-api,执行完该命令后,发现frameworks/base/api/current.txt文件有更新,可以看到,文件中增加了一个WRTSZ_SERVICE 的常量和一个com.wrtsz.api的package,该package中就有对应的接口声明。

     field public static final java.lang.String WIFI_P2P_SERVICE = "wifip2p";
     field public static final java.lang.String WIFI_SERVICE = "wifi";
     field public static final java.lang.String WINDOW_SERVICE = "window";
     field public static final java.lang.String WRTSZ_SERVICE = "wrtsz";
   }
 
   public class ContextWrapper extends android.content.Context {
@@ -39532,6 +39533,24 @@ package com.android.internal.util {
 
 }
 
 package com.wrtsz.api {
 
   public abstract interface IWrtdevManager implements android.os.IInterface {
     method public abstract byte[] getIcCardNo() throws android.os.RemoteException;
     method public abstract int getMicroWaveState() throws android.os.RemoteException;
     method public abstract int openDoor() throws android.os.RemoteException;
     method public abstract int openLed(int) throws android.os.RemoteException;
   }
 
   public static abstract class IWrtdevManager.Stub extends android.os.Binder implements com.wrtsz.api.IWrtdevManager {
     ctor public IWrtdevManager.Stub();
     method public android.os.IBinder asBinder();
     method public static com.wrtsz.api.IWrtdevManager asInterface(android.os.IBinder);
     method public boolean onTransact(int, android.os.Parcel, android.os.Parcel, int) throws android.os.RemoteException;
   }
 
 }
 

接着就可以敲make -j16命令直接编译了,编译完成之后,在./out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/com/wrtsz/api目录下会生成一个IWrtdevManager.java文件,对应的内容如下:

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: frameworks/base/core/java/com/wrtsz/api/IWrtdevManager.aidl
 */
package com.wrtsz.api;
public interface IWrtdevManager extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.wrtsz.api.IWrtdevManager
{
private static final java.lang.String DESCRIPTOR = "com.wrtsz.api.IWrtdevManager";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
 * Cast an IBinder object into an com.wrtsz.api.IWrtdevManager interface,
 * generating a proxy if needed.
 */
public static com.wrtsz.api.IWrtdevManager asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.wrtsz.api.IWrtdevManager))) {
return ((com.wrtsz.api.IWrtdevManager)iin);
}
return new com.wrtsz.api.IWrtdevManager.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getMicroWaveState:
{
data.enforceInterface(DESCRIPTOR);
int _result = this.getMicroWaveState();
reply.writeNoException();
reply.writeInt(_result);
return true;
}
case TRANSACTION_getIcCardNo:
{
data.enforceInterface(DESCRIPTOR);
byte[] _result = this.getIcCardNo();
reply.writeNoException();
reply.writeByteArray(_result);
return true;
}
case TRANSACTION_openLed:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
int _result = this.openLed(_arg0);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
case TRANSACTION_openDoor:
{
data.enforceInterface(DESCRIPTOR);
int _result = this.openDoor();
reply.writeNoException();
reply.writeInt(_result);
return true;
}
case TRANSACTION_getFireAlarmStatus:
{
data.enforceInterface(DESCRIPTOR);
int _result = this.getFireAlarmStatus();
reply.writeNoException();
reply.writeInt(_result);
return true;
}
case TRANSACTION_getMagnetometerStatus:
{
data.enforceInterface(DESCRIPTOR);
int _result = this.getMagnetometerStatus();
reply.writeNoException();
reply.writeInt(_result);
return true;
}
case TRANSACTION_getTamperStatus:
{
data.enforceInterface(DESCRIPTOR);
int _result = this.getTamperStatus();
reply.writeNoException();
reply.writeInt(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.wrtsz.api.IWrtdevManager
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
@Override public int getMicroWaveState() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getMicroWaveState, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public byte[] getIcCardNo() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
byte[] _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getIcCardNo, _data, _reply, 0);
_reply.readException();
_result = _reply.createByteArray();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public int openLed(int opIndex) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(opIndex);
mRemote.transact(Stub.TRANSACTION_openLed, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public int openDoor() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_openDoor, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public int getFireAlarmStatus() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getFireAlarmStatus, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public int getMagnetometerStatus() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getMagnetometerStatus, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public int getTamperStatus() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getTamperStatus, _data, _reply, 0);
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_getMicroWaveState = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_getIcCardNo = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
static final int TRANSACTION_openLed = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
static final int TRANSACTION_openDoor = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
static final int TRANSACTION_getFireAlarmStatus = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4);
static final int TRANSACTION_getMagnetometerStatus = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5);
static final int TRANSACTION_getTamperStatus = (android.os.IBinder.FIRST_CALL_TRANSACTION + 6);
}
public int getMicroWaveState() throws android.os.RemoteException;
public byte[] getIcCardNo() throws android.os.RemoteException;
public int openLed(int opIndex) throws android.os.RemoteException;
public int openDoor() throws android.os.RemoteException;
public int getFireAlarmStatus() throws android.os.RemoteException;
public int getMagnetometerStatus() throws android.os.RemoteException;
public int getTamperStatus() throws android.os.RemoteException;
}

文件的头两行注释就写清楚了:1、这个文件是自动生成的,不要自行修改;2、其对应的原始文件为frameworks/base/core/java/com/wrtsz/api/IWrtdevManager.aidl

 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: frameworks/base/core/java/com/wrtsz/api/IWrtdevManager.aidl
 

2.4、输出jar包

以上完成之后,我们最终要输出给第三方一个jar包,该文件最终生成在out/target/common/obj/JAVA_LIBRARIES/framework_intermediates目录下,我们可以ls -l看一下,目录下的classes.jar文件就是我们要找的文件。

Android Framework添加自定义服务和接口_第1张图片

当然,细心的童鞋可能会发现classes.jar、class-full-debug.jar、classes-jarjar.jar其实是三个同样的文件,校验md5值就可以证明。

然后把对应的 classes.jar文件release给第三方,替换原生的android.jar,就可以愉快地调用我们的WrtdevManager接口了。

3、添加自定义service

以上部分完成后,第三方APP调用接口的时候,会发现编译不会报错,但是运行时会报RemoteException的异常,因为我们还没有定义对应的service。

3.1、service定义

可以在frameworks/opt目录下创建一个vendor/wrtsz/java/com/wrtsz/server目录,在该目录下首先新建一个WrtdevService类,该类继承自SystemService类,对应的代码如下:

package com.wrtsz.server;

import android.content.Context;
import android.util.Log;
import com.android.server.SystemService;

public final class WrtdevService extends SystemService {

    private static final String TAG = "csh_debug_wrtsz";
    final WrtdevServiceImpl mImpl;

    public WrtdevService(Context context) {
        super(context);
        mImpl = new WrtdevServiceImpl(context);
    }

    @Override
    public void onStart() {
        Log.i(TAG, "Registering service " + Context.WRTSZ_SERVICE);
        publishBinderService(Context.WRTSZ_SERVICE, mImpl);
    }

    @Override
    public void onBootPhase(int phase) {
        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
            mImpl.start();
        }
    }
}

可以看到,在WrtdevService中,我们调用了WrtdevServiceImpl 类,这个类才是真正干活儿的,说白了WrtdevService类不过是个马甲,方便SystemServer统一管理。Android5.1是这种架构,之前Android4.4中可以不需要定义WrtdevService,直接定义WrtdevServiceImpl类,其代码如下:

package com.wrtsz.server;

import android.util.Log;
import android.content.Context;
import com.wrtsz.api.IWrtdevManager;

public class WrtdevServiceImpl extends IWrtdevManager.Stub {
    private static final String TAG = "WrtdevServiceImpl";
    public Context mContext;
    private final WrtdevNative mNative;

    public WrtdevServiceImpl(Context context) {
         Log.i(TAG, "Creating WrtdevServiceImpl");
         mContext=context;
		 mNative=new WrtdevNative();
    }

    public void start() 
    {
        Log.i(TAG, "Starting Wrtdev  service");       
    }

	public int getMicroWaveState()
	{
		return mNative.getMicroWaveState();
	}

	public byte[] getIcCardNo()
	{
		
		return mNative.getIcCardNo();
	}

	public int openLed(int opIndex)
	{		
		return mNative.openLed(opIndex);
	}

	public int openDoor()
	{
		return mNative.openDoor();

	}
}

WrtdevServiceImpl类中实现了所有WrtdevManager中定义的接口,它通过一个native类,最终调用C层接口,由于跟业务有关,这里不再赘述。

然后就是在同目录下新建一个Android.mk,对应的内容如下:

LOCAL_CFLAGS += -Wno-unused-parameter -Wno-int-to-pointer-cast
LOCAL_CFLAGS += -Wno-maybe-uninitialized -Wno-parentheses
LOCAL_CPPFLAGS += -Wno-conversion-null

include $(CLEAR_VARS)

LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/java
LOCAL_SRC_FILES := $(call all-java-files-under, java) \
	$(call all-Iaidl-files-under, java) \
	$(call all-logtags-files-under, java)

LOCAL_JAVA_LIBRARIES := services
LOCAL_MODULE := wrtsz-service

include $(BUILD_JAVA_LIBRARY)

 编译之后会在./out/target/product/rk3288/system/framework/目录下生成一个wrtsz-service.jar文件。

3.2、注册与启动service

系统service的注册统一在frameworks/base/core/java/android/app/ContextImpl.java 中,调用registerService方法。

import java.util.ArrayList;
 import java.util.HashMap;
 
 import com.wrtsz.api.WrtdevManager;
 import com.wrtsz.api.IWrtdevManager;
 
 class ReceiverRestrictedContext extends ContextWrapper {
     ReceiverRestrictedContext(Context base) {
         super(base);
@@ -648,6 +651,16 @@ class ContextImpl extends Context {
                  }});


         registerService(WRTSZ_SERVICE, new ServiceFetcher() {
                  public Object createService(ContextImpl ctx) {
                     IBinder b = ServiceManager.getService(WRTSZ_SERVICE);
                     IWrtdevManager service = IWrtdevManager.Stub.asInterface(b);
                     return new WrtdevManager(service, ctx.mMainThread.getHandler());
                  }});

 
         registerService(WINDOW_SERVICE, new ServiceFetcher() {
                 Display mDefaultDisplay;
                 public Object getService(ContextImpl ctx) {

这里的WRTSZ_SERVICE常量定义在 frameworks/base/core/java/android/content/Context.java 中,方便上层APP通过addService方法调用时,直接传这个常量。

注册完服务之后,需要启动服务,需要在 frameworks/base/services/java/com/android/server/SystemServer.java中添加,调用startService启动,直接传对应的类全名即可。

try {
    Slog.i("csh_debug_wrtsz", "WrtszService");
    mSystemServiceManager.startService("com.wrtsz.server.WrtdevService");
}catch (Throwable e) {
    reportWtf("start WrtszService error ", e);
}

以上添加完之后,如果要正常编译运行,还需要在device/rockchip/common/device.mk中添加几行代码:

 PRODUCT_PACKAGES += \
     wrtsz-service
 
 PRODUCT_SYSTEM_SERVER_JARS += \
     wrtsz-service

注意一定要在PRODUCT_SYSTEM_SERVER_JARS宏中添加自定义的service,否则系统跑起来之后,自定义的service代码其实没有执行。

4、总结

 以上就是自定义Android服务和接口的全部内容,不同的芯片商和不同的Android版本,可能略有不同,但是整体架构差不多。

你可能感兴趣的:(Android调试)