需求:客户自己的第三方apk要求能够控制上层读写控制亮度等级/以及控制指纹开关,对于上层app控制硬件设备模块,一般做法都是通过对设备模块生成的设备节点文件进行读写实现,经过查询,指纹模块相关的设备节点是 “/dev/switch_gpio”,接下来就是想办法通过JNI进行读写了
Android 版本:10.0
前言:为了第三方apk直接使用访问设备节点,这里采用aidl +JNI的形式开发,采用aidl是为了自定义一个service manger,生成相应的jar包提供给apk,JNI的目的是为了JAVA层与C通信,在C中可以以C语言进行IO流读写
修改部分:
modified: device/mediatek/sepolicy/bsp/non_plat/device.te
modified: device/mediatek/sepolicy/bsp/non_plat/file_contexts
modified: device/mediatek/sepolicy/bsp/plat_private/service.te
modified: device/mediatek/sepolicy/bsp/plat_private/service_contexts
modified: device/mediatek/sepolicy/bsp/plat_private/system_server.te
modified: frameworks/base/Android.bp
modified: frameworks/base/core/java/android/app/SystemServiceRegistry.java
modified: frameworks/base/services/core/jni/Android.bp
modified: frameworks/base/services/core/jni/onload.cpp
modified: frameworks/base/services/java/com/android/server/SystemServer.java
modified: vendor/mediatek/proprietary/packages/apps/MtkSettings/src/com/android/settings/display/ScreenshotButtonPreferenceController.java
+frameworks/base/core/java/android/app/SelfManager.java
+frameworks/base/core/java/android/os/ISelfManager.aidl
+frameworks/base/services/core/java/com/android/server/SelfManagerService.java
+frameworks/base/services/core/jni/com_android_server_SelfManagerService.cpp
一:aidl部分相应修改
1.自定义一个aidl文件
frameworks/base/core/java/android/os/ISelfManager.aidl
package android.os;
interface ISelfManager {
int readBrightness();
void writeBrightness(int level);
}
frameworks/base/services/core/java/com/android/server/SelfManagerService.java
//继承ISelfManager.Stub并重写其中的方法
package com.android.server;
import android.util.Log;
import android.os.ISelfManager;
public class SelfManagerService extends ISelfManager.Stub {
@Override
public int readBrightness() {
int result = tngpio_read();
Log.e(“zhy”, “read=” + result);
return result;
}
@Override
public void writeBrightness(int level) {
Log.e(“zhy”, “write:” + level);
tngpio_write(level);
}
private static native int tngpio_read();//本地接口
private static native void tngpio_write(int level);//本地接口
}
frameworks/base/core/java/android/app/SelfManager.java
//创建服务管理类,用于管理相应的接口方法可通过Context.getServcie()获取, 类似系统中的ActivityManager,MessageManager…
package android.app;
import android.util.Log;
import android.os.ISelfManager;
import android.content.Context;
import android.os.RemoteException;
/**
Interact with the overall activities running in the system.
*/
public class SelfManager {
private static String TAG = “SelfManager”;
ISelfManager mSelfManager;
public SelfManager(Context ctx,ISelfManager selfManager) {
mSelfManager = selfManager;
}
public int readBrightness() throws RemoteException {
return mSelfManager.readBrightness();
}
public void writeBrightness(int level) throws RemoteException {
mSelfManager.writeBrightness(level);
}
}
4.将aidl文件添加到makefile中
— a/frameworks/base/Android.bp
+++ b/frameworks/base/Android.bp
@@ -263,6 +263,7 @@ java_defaults {
“core/java/android/os/IRecoverySystem.aidl”,
“core/java/android/os/IRecoverySystemProgressListener.aidl”,
“core/java/android/os/IRemoteCallback.aidl”,
5.注册系统服务,后面framework层可通过Context.getService()形式获取
— a/frameworks/base/core/java/android/app/SystemServiceRegistry.java
+++ b/frameworks/base/core/java/android/app/SystemServiceRegistry.java
@@ -204,6 +204,8 @@ import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicInteger;
+import android.os.ISelfManager;
+
/**
registerService(Context.TELEPHONY_SERVICE, TelephonyManager.class,
new CachedServiceFetcher() {
@Override
6.将自定义系统服务SelfManagerService 无法加入加ServiceManager,加入到SystemServer开机将会启动
— a/frameworks/base/services/java/com/android/server/SystemServer.java
+++ b/frameworks/base/services/java/com/android/server/SystemServer.java
@@ -990,6 +990,12 @@ public final class SystemServer {
mSystemServiceManager.startService(KeyChainSystemService.class);
traceEnd();
//kzh add start
ServiceManager.addService(“selfservice”, new SelfManagerService());
//end
traceBeginAndSlog("StartSchedulingPolicyService");
ServiceManager.addService("scheduling_policy", new SchedulingPolicyService());
traceEnd();
7.android具有selinux机制,不允许自定义的SystemServer被访问。所以得先添加自定义的SystemServer
(1)添加service
— a/device/mediatek/sepolicy/bsp/plat_private/service_contexts
+++ b/device/mediatek/sepolicy/bsp/plat_private/service_contexts
@@ -59,3 +59,5 @@ vendor.trustonic.teeregistryservice.ITeeRegistryService u:object_r:teeregist
#camerapostalgo
mediatek.campostalgo u:object_r:camerapostalgo_service:s0
+
+selfservice u:object_r:self_service:s0
(2)指定服务类型
— a/device/mediatek/sepolicy/bsp/plat_private/service.te
+++ b/device/mediatek/sepolicy/bsp/plat_private/service.te
@@ -7,3 +7,4 @@ type aal_service, service_manager_type;
type mtk_connmetrics_service, service_manager_type;
type terservice_service, service_manager_type;
type camerapostalgo_service, service_manager_type;
+type self_service, app_api_service, system_api_service, system_server_service, service_manager_type;
至此aidl部分已经添加完成,第三方apk可以调用和使用自定义的SelfManager 了。
二 :JNI部分修改
1.添加c文件,com_android_server_SelfManagerService.cpp,文件命名是有原因的,是因为我们的本地接口在com/android/server/SelfManagerService.java中,所以我们这样命名
frameworks/base/services/core/jni/com_android_server_SelfManagerService.cpp:
#define LOG_TAG “zhy”
#include “jni.h”
#include
#include “android_runtime/AndroidRuntime.h”
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//方法在驱动中生成的节点
#define DEV_NAME “/dev/switch_gpio”
namespace android
{
static jint com_android_server_SelfManagerService_tngpio_read (JNIEnv* env, jobject clazz)
{
FILE *fp = NULL;
fp = fopen(DEV_NAME, “w+”);
char buff[255];
fgets(buff, 255, fp);
fclose(fp);
return atoi(buff);
}
static void com_android_server_SelfManagerService_tngpio_write (JNIEnv* env, jobject clazz, int level)
{
ALOGE("tngpio_write level= %d", level);
FILE *fp = NULL;
fp = fopen(DEV_NAME, "w+");
char str[255];
sprintf(str,"%d",level);
fputs(str,fp);
fclose(fp);
}
/Java本地接口方法表/
static JNINativeMethod method_table[] = {
{ “tngpio_read”, “()I”, (void*)com_android_server_SelfManagerService_tngpio_read },
{ “tngpio_write”, “(I)V”, (void*)com_android_server_SelfManagerService_tngpio_write }
};
/注册Java本地接口方法/
int register_android_server_SelfManagerService(JNIEnv *env)
{
return jniRegisterNativeMethods(env, “com/android/server/SelfManagerService”,
method_table, NELEM(method_table));
}
};
2.将.cpp文件添加到makefile中
— a/frameworks/base/services/core/jni/Android.bp
+++ b/frameworks/base/services/core/jni/Android.bp
@@ -52,6 +52,7 @@ cc_library_static {
“com_android_server_GraphicsStatsService.cpp”,
“com_android_server_am_AppCompactor.cpp”,
“com_android_server_am_LowMemDetector.cpp”,
using namespace android;
@@ -107,5 +108,6 @@ extern “C” jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
register_android_server_security_VerityUtils(env);
register_android_server_am_AppCompactor(env);
register_android_server_am_LowMemDetector(env);
三:编译验证结果
make之前需要make update-api,
在settings中通过一个switch开关切换操作
发现设备卡死然后自动重启,通过查询log得知
报selinux错误:
05-20 12:53:31.612 915 915 W Binder:915_D: type=1400 audit(0.0:126): avc: denied { read write } for name=“switch_gpio” dev=“tmpfs” ino=10853 scontext=u:r:system_server:s0 tcontext=u:object_r:device:s0 tclass=chr_file permissive=0
Android app对/dev下的设备是不具有读写权限的,应用程序怎样才能读写/dev下设备呢?
— a/device/mediateksample/tb8766p1_64_bsp/init.project.rc
+++ b/device/mediateksample/tb8766p1_64_bsp/init.project.rc
@@ -9,6 +9,10 @@ on init
on post-fs-data
chmod 0666 sys/devices/platform/1000b000.pinctrl/mt_gpio
chmod 0666 /dev/switch_gpio
chown root system /dev/switch_gpio
#Camera
chmod 0660 /dev/MAINAF
2.添加设备
— a/device/mediatek/sepolicy/bsp/non_plat/file_contexts
+++ b/device/mediatek/sepolicy/bsp/non_plat/file_contexts
@@ -74,6 +74,8 @@
/dev/socket/wo_epdg_ipsec(/.*)? u:object_r:wo_epdg_ipsec_socket:s0
/dev/ttyC5 u:object_r:nwkopt_device:s0
/dev/mix_event u:object_r:tx_device:s0
+/dev/switch_gpio u:object_r:switch_gpio_device:s0
3.指定设备类型
— a/device/mediatek/sepolicy/bsp/non_plat/device.te
+++ b/device/mediatek/sepolicy/bsp/non_plat/device.te
@@ -24,8 +24,7 @@ allow system_server teei_client_device:chr_file r_file_perms;
type nwkopt_device, dev_type;
type tx_device, dev_type;
-# add for usb switch
+type switch_gpio_device, dev_type;
4.添加权限,允许system_server 对该switch_gpio_device设备进行读写权限
— a/device/mediatek/sepolicy/bsp/non_plat/device.te
+++ b/device/mediatek/sepolicy/bsp/non_plat/device.te
@@ -24,8 +24,7 @@ allow system_server teei_client_device:chr_file r_file_perms;
type nwkopt_device, dev_type;
type tx_device, dev_type;
type switch_gpio_device, dev_type;
+allow system_server switch_gpio_device:chr_file rw_file_perms;
最后验证ok