前言
在实际开发中,不管是与第三方客户公司还是与自己公司Android应用工程师对接的时候,你可能要把系统里面的一些功能实现通过接口的方式提供给应用层工程师,不过应用访问的方式不止通过接口,后续我们会讲到,现在我们来介绍接口的实现步骤:
步骤一:定义aidl接口
目录:\frameworks\base\core\java\android\app
在目录下新建一个aidl文件ILManager.aidl,代码如下:
package android.app;
interface ILycooManager {
String getProperty(String key, String def);
void setProperty(String key, String value);
boolean checkDevice();
void setStreamMute(int streamType, boolean state);
boolean isStreamMute(int streamType);
}
步骤二:定义接口的唯一标识
目录:\frameworks\base\core\java\android\content\Context.java
在Context.java类里面添加一下标识LYCOO_SERVICE就行了,注意要唯一的,不能重复。
代码如下:
/**
* Use with {@link #getSystemService} to retrieve a
* {@link android.hardware.ConsumerIrManager} for transmitting infrared
* signals from the device.
*
* @see #getSystemService
* @see android.hardware.ConsumerIrManager
*/
public static final String CONSUMER_IR_SERVICE = "consumer_ir";
/* add by keily on 2018/06/05. BEGIN ******************************* */
/**
* BK3254 manager service
*/
public static final String CUSTOM_AUDIO_SERVICE = "custom_audio";
/* add by keily on 2018/06/05. END ******************************* */
/**
* 山景DSP处理服务
*/
public static final String MV_DSP_SERVICE = "mv_dsp";
public static final String L_SERIAL_SERVICE = "LSerial";
/**
* 基础服务
*/
public static final String LYCOO_SERVICE = "lycoo";
/**
* 芯片信息
*/
public static final String CHIPINFO_SERVICE = "chip_info";
/**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
* @param permission The name of the permission being checked.
* @param pid The process ID being checked against. Must be > 0.
* @param uid The user ID being checked against. A uid of 0 is the root
* user, which will pass every permission check.
*
* @return {@link PackageManager#PERMISSION_GRANTED} if the given
* pid/uid is allowed that permission, or
* {@link PackageManager#PERMISSION_DENIED} if it is not.
*
* @see PackageManager#checkPermission(String, String)
* @see #checkCallingPermission
*/
public abstract int checkPermission(String permission, int pid, int uid);
步骤三:定义java接口
目录:\frameworks\base\core\java\android\app
在目录下新建java文件LManager.java,代码如下:
注意:
ILManager类是通过编译ILManager.aidl文件得到的,
java代码是aidl接口的实现封装。
package android.app;
import android.content.Context;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.LogUtils;
/**
* 基础管理服务
*
* Created by lancy on 2019/8/14
*/
public class LManager {
private static final String TAG = LManager.class.getSimpleName();
private Context mContext;
private static ILManager mService;
public LManager(Context context) {
this.mContext = context;
}
public static ILManager getService() {
if (mService == null) {
IBinder b = ServiceManager.getService(Context.LYCOO_SERVICE);
mService = ILManager.Stub.asInterface(b);
}
return mService;
}
/**
* 查询系统属性
*
* @param key 键
* @param def 默认值
* @return 查询结果或者默认值
*
* Created by lancy on 2019/8/14 21:21
*/
public String getProperty(String key, String def) {
ILManager service = getService();
try {
return service.getProperty(key, def);
} catch (RemoteException e) {
LogUtils.error(TAG, "Dead object in getSystemProperty");
e.printStackTrace();
}
return def;
}
/**
* 设置系统属性
*
* @param key 键
* @param value 值
*
* Created by lancy on 2019/8/14 21:21
*/
public void setProperty(String key, String value) {
ILManager service = getService();
try {
service.setProperty(key, value);
} catch (RemoteException e) {
LogUtils.error(TAG, "Dead object in setProperty");
e.printStackTrace();
}
}
/**
* 检查设备合法性
*
* @return 合法返回true, 否则返回false
*
* Created by lancy on 2019/9/2 16:28
*/
public boolean checkDevice() {
ILManager service = getService();
try {
return service.checkDevice();
} catch (RemoteException e) {
LogUtils.error(TAG, "Dead object in checkDevice");
e.printStackTrace();
}
return false;
}
/**
* 静音/取消静音
*
* @param streamType 音源类型
* @param state 静音true, 取消静音false
*
* Created by lancy on 2020/3/3 18:18
*/
public void setStreamMute(int streamType, boolean state){
ILManager service = getService();
try {
service.setStreamMute(streamType, state);
} catch (RemoteException e) {
LogUtils.error(TAG, "Dead object in setStreamMute");
e.printStackTrace();
}
}
/**
* 是否静音
*
* @param streamType 音源类型
* @return 静音返回rue, 否则返回false
*
* Created by lancy on 2020/3/3 18:19
*/
public boolean isStreamMute(int streamType){
ILManager service = getService();
try {
return service.isStreamMute(streamType);
} catch (RemoteException e) {
LogUtils.error(TAG, "Dead object in isStreamMute");
e.printStackTrace();
}
return false;
}
}
步骤四:注册java接口
目录:\frameworks\base\core\java\android\app\ContextImpl.java
直接在该类注册即可,注意里面有个静态方法体,在里面添加即可,可以参照现有的接口注册,代码如下:
registerService(LYCOO_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
return new LManager(ctx);
}});
步骤五:添加接口编译配置
目录:\frameworks\base\Android.mk
在宏LOCAL_SRC_FILES里面添加要编译的aidl接口目录就可以了,具体可以参照系统的,代码如下:
LOCAL_SRC_FILES += \
core/java/android/accounts/IAccountManager.aidl \
core/java/android/accounts/IAccountManagerResponse.aidl \
core/java/android/accounts/IAccountAuthenticator.aidl \
core/java/android/accounts/IAccountAuthenticatorResponse.aidl \
core/java/android/app/IActivityController.aidl \
core/java/android/app/IActivityPendingResult.aidl \
core/java/android/app/IAlarmManager.aidl \
core/java/android/app/IVoiceSerialManager.aidl \
core/java/android/app/ILManager.aidl \此目录就是我们添加的
core/java/android/app/IBackupAgent.aidl \
core/java/android/app/IInstrumentationWatcher.aidl \
core/java/android/app/INotificationManager.aidl \
core/java/android/app/IProcessObserver.aidl \
core/java/android/app/ISearchManager.aidl \
core/java/android/app/ISearchManagerCallback.aidl \
core/java/android/app/IServiceConnection.aidl \
core/java/android/app/IStopUserCallback.aidl \
core/java/android/app/IThumbnailReceiver.aidl \
core/java/android/app/IThumbnailRetriever.aidl \
。。。。。。。。。。。
步骤六:添加具体实现服务
目录:\frameworks\base\services\java\com\android\server
在目录下新建LycooService.java类,具体实现代码如下:
注意:要导包,不然编译不通过。
package com.android.server;
import android.app.ILManager;
import android.content.Context;
import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.LogUtils;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import android.media.AudioManager;
/**
* 基础管理服务
*
* Created by lancy on 2019/8/14
*/
public class LService extends ILManager.Stub {
private static final String TAG = LService.class.getSimpleName();
private static final String DEFAULT_MAC_SEPARATOR = ":";
private static final String MAC_PREFIX = "0A0A";
private static final String SN_KEY = "LYCOO";
private static final int SN_LENGTH = 18;
private static final int[] SN_KEY_INDEXS = {3, 6, 9, 12, 15};
private Context mContext;
private AudioManager mAudioManager;
public LService(Context context) {
this.mContext = context;
init();
}
private void init() {
LogUtils.info(TAG, "LService init........");
}
public String getProperty(String key, String def) {
return SystemProperties.get(key, def);
}
public void setProperty(String key, String value) {
SystemProperties.set(key, value);
}
public boolean checkDevice() {
// check mac
String mac = getEthernetMacBySeparator("");
// LogUtils.debug(TAG, "mac : " + mac);
if (TextUtils.isEmpty(mac)) {
return false;
}
if (!mac.toUpperCase().startsWith(MAC_PREFIX)) {
return false;
}
// check sn
String sn = getSn();
// LogUtils.debug(TAG, "sn : " + sn);
if (TextUtils.isEmpty(sn) || sn.length() != SN_LENGTH) {
return false;
}
String key = String.valueOf(sn.charAt(SN_KEY_INDEXS[0])) +
sn.charAt(SN_KEY_INDEXS[1]) +
sn.charAt(SN_KEY_INDEXS[2]) +
sn.charAt(SN_KEY_INDEXS[3]) +
sn.charAt(SN_KEY_INDEXS[4]);
if (!SN_KEY.equals(key)) {
LogUtils.debug(TAG, "[key] : " + key);
return false;
}
return true;
}
/**
* 查询mac地址
*
* @param separator 分隔符,不需要传""即可。
* @return 以太网mac地址
*
* Created by lancy on 2019/9/2 16:41
*/
private String getEthernetMacBySeparator(String separator) {
String macSerial = null;
String str = "";
try {
//String cmd = "cat /sys/class/net/eth0/address";
String cmd = "cat /sys/ethernet/address";
//if (!new File("/sys/class/net/eth0/address").exists()) {
if (!new File("/sys/ethernet/address").exists()) {
//cmd = "cat /sys/ethernet/address"; // T32
cmd = "cat /sys/class/net/eth0/address";
}
Process pp = Runtime.getRuntime().exec(cmd);
InputStreamReader ir = new InputStreamReader(pp.getInputStream());
LineNumberReader input = new LineNumberReader(ir);
for (; null != str; ) {
str = input.readLine();
if (str != null) {
if (DEFAULT_MAC_SEPARATOR.equals(separator)) {
macSerial = str.trim();
} else {
macSerial = str.replace(":", separator).trim();
}
break;
}
}
} catch (IOException ex) {
// 赋予默认值
ex.printStackTrace();
}
return macSerial;
}
/**
* 查询序列号
* 各平台自己实现
*
* @return 设备序列号
*
* Created by lancy on 2019/9/2 16:42
*/
private String getSn() {
return getProperty("ro.boot.serialno", null);
}
/**
* 静音/取消静音
*
* @param streamType 音源类型
* @param state 静音true, 取消静音false
*
* Created by lancy on 2020/3/3 18:18
*/
public void setStreamMute(int streamType, boolean state){
getAudioManager().setStreamMute(streamType, state);
}
/**
* 是否静音
*
* @param streamType 音源类型
* @return 静音返回rue, 否则返回false
*
* Created by lancy on 2020/3/3 18:19
*/
public boolean isStreamMute(int streamType){
return getAudioManager().isStreamMute(streamType);
}
/**
* 获取 AudioManager
*
* @return AudioManager
* <p>
* Created by keily on 2018/11/23 20:48:55
*/
private AudioManager getAudioManager() {
if (mAudioManager == null) {
synchronized (LService.class) {
if (mAudioManager == null) {
mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
}
}
}
return mAudioManager;
}
}
步骤七:将服务添加到开机启动服务中
目录:\frameworks\base\services\java\com\android\server\SystemServer.java
代码如下:
try {
Slog.i(TAG, ">>>>>>>>> L Service");
LService lService = new LService(context);
ServiceManager.addService(Context.LYCOO_SERVICE, lService );
} catch (Throwable e) {
reportWtf(">>>>>>>>>>> starting L Service", e);
}
步骤八:编译
先按编译文档选好工程,然后直接编译Android就可以了
执行:
make api-update
make -j6
编译好后,在根目录下out文件家里面有对应的class文件
步骤九:将接口打包成jar包
目录:
/out/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/classes/
切换到此目录下,执行打包命令。
cd android4.2/out/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/classes/
jar cvf LManager.jar android/app/LManager.class
步骤十:应用层使用
讲到应用层使用,这里介绍两种办法,一种是通过上面生成的jar包来调用接口,第二种是通过反射来调用接口。如下所示:
第一种:
LManager mLManager=(LManager)getSystemService("lycoo");
mLManager.getSn();
第二种:
try {
Class<?> class1 = null;
class1 = Class.forName("android.app.LManager");
Method method = class1.getMethod("getSn");
String sn =(String)method.invoke(class1.newInstance());
System.out.println("lco::::: "+sn);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
总结:
上面讲了添加接口的步骤与使用方式,其实上面这些步骤都可以参考系统原生的服务接口来添加,不同的也只是我们的接口实现功能而已,上面的方式,我是在RK3128开发板和Android4.4源码上面实现的,不管是Android4.4还是Android7以上的接口添加方式,其实都是大同小异的,都可以在此基础上,另外参照原生的实现方式来添加,好了话有点多了,大家可以去试下,希望对你有帮助。