Android 理解frameworks services jni hardware kernel 整个控制过程实例包括回调
一、这个例子的实现的功能是,app控制power pin和control pin,可以read feedback pin的电平,如果feedback pin的电平有变化,会触发中断,底层把这个中断信息通过一系列回调和侦听发送到app。
通过这个简单的实例可以了解frameworks services jni hardware kernel整个流程,里面涉及到回调和侦听还是需要花费很多精力去理解和调试。
二、kernel 驱动\kernel\drivers\char\moneybox.c,获取中断,控制gpio,提供杂项设备节点 /dev/moneybox以及下面3个控制节点
/sys/devices/platform/moneybox/enpower
/sys/devices/platform/moneybox/control
/sys/devices/platform/moneybox/feedback
三、hardware 主要代码下面的代码
hardware/libhardware/include/hardware/moneybox.h
hardware/libhardware/modules/Android.mk
hardware/libhardware/modules/moneybox/Android.mk
hardware/libhardware/modules/moneybox/moneybox.cpp
3.1 moneybox.cpp代码
3.2 moneybox.h代码
#ifndef ANDROID_FREG_INTERFACE_H
#define ANDROID_FREG_INTERFACE_H
#include <hardware/hardware.h>
__BEGIN_DECLS
/**
* The id of this module
*/
#define MONEYBOX_HARDWARE_MODULE_ID "moneybox"
/**
* The id of this device
*/
#define MONEYBOX_HARDWARE_DEVICE_ID "moneybox"
struct moneybox_module_t {
struct hw_module_t common;
};
/* Callback function type */
typedef void (*moneybox_notify_t)(int m,int n);
struct moneybox_device_t {
struct hw_device_t common;
int fd;
moneybox_notify_t notify;
int (*set_val)(struct moneybox_device_t* dev, int val);
int (*set_enable_power)(struct moneybox_device_t* dev, int val);
int (*set_control_val)(struct moneybox_device_t* dev, int val);
int (*get_feedback_val)(struct moneybox_device_t* dev, int* val);
int (*set_notify)(struct moneybox_device_t *dev, moneybox_notify_t notify);
};
__END_DECLS
#endif
四、JNI代码frameworks/base/services/core/jni/com_android_server_MoneyboxService.cpp
#define LOG_TAG "MoneyboxServiceJNI"
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
#include <utils/misc.h>
#include <utils/Log.h>
#include <hardware/hardware.h>
#include <hardware/moneybox.h>
#include <utils/Looper.h>
#include <android_os_MessageQueue.h>
#include <stdio.h>
static jobject mCallbacksObj = NULL;
static jmethodID javaCallback;
JNIEnv* m_env;
jobject mobj;
jclass jSdkClass;
jobject g_jobj; //全局对象
namespace android
{
static void moneybox_setVal(JNIEnv* env, jobject clazz, jint ptr, jint value) {
moneybox_device_t* device = (moneybox_device_t*)ptr;
if(!device) {
ALOGE("Device moneybox is not open.");
return;
}
int val = value;
ALOGI("Set value %d to device moneybox.", val);
device->set_val(device, val);
}
static void moneybox_set_enable_power(JNIEnv* env, jobject clazz, jint ptr, jint value) {
moneybox_device_t* device = (moneybox_device_t*)ptr;
if(!device) {
ALOGE("Device moneybox is not open.");
return;
}
int val = value;
device->set_enable_power(device, val);
ALOGI("Set value %d to device moneybox.", val);
}
static void moneybox_set_control_val(JNIEnv* env, jobject clazz, jint ptr, jint value) {
int val = value;
moneybox_device_t* device = (moneybox_device_t*)ptr;
if(!device) {
ALOGE("Device moneybox is not open.");
return;
}
device->set_control_val(device, val);
ALOGI("Set value %d to device moneybox.", val);
}
static inline int moneybox_device_open(const hw_module_t* module, struct moneybox_device_t** device) {
return module->methods->open(module, MONEYBOX_HARDWARE_DEVICE_ID, (struct hw_device_t**)device);
}
// Called by the HAL to notify us of moneybox events
static void hal_notify_callback(int m,int n) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
if (!mCallbacksObj)
return;
jclass clz = env->GetObjectClass(mCallbacksObj);
jint ret = env->CallStaticIntMethod(clz, javaCallback,(jint)m,(jint)n);
ALOGI("hal_notify_callback ,m=%d,n=%d,ret=%d.",m,n,ret);
}
static jint moneybox_get_feedback_val(JNIEnv* env, jobject clazz, jint ptr) {
int val = 0;
moneybox_device_t* device = (moneybox_device_t*)ptr;
if(!device) {
ALOGE("Device moneybox is not open.");
return 0;
}
device->get_feedback_val(device, &val);
ALOGI("Get Value %d from device moneybox....", val);
#if 0
if (!mCallbacksObj)
mCallbacksObj = env->NewGlobalRef(clazz);
jclass clz = env->GetObjectClass(mCallbacksObj);
//jint ret = env->CallIntMethod(mCallbacksObj, javaCallback,(jint)val,(jint)val);
jint ret = env->CallStaticIntMethod(clz, javaCallback,(jint)val,(jint)val);
if (env->ExceptionCheck()) {
ALOGE("An exception was thrown by callback");
env->ExceptionClear();
}
ALOGI(" CallIntMethod mCallbacksObj env ret=%d",ret);
#endif
return val;
}
static jint moneybox_init(JNIEnv* env, jobject clazz) {
int err;
moneybox_module_t* module;
moneybox_device_t* device;
ALOGI("Initializing HAL stub moneybox......");
if(hw_get_module(MONEYBOX_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == 0) {
ALOGI("Device moneybox found.");
if(moneybox_device_open(&(module->common), &device) == 0) {
ALOGI("Device moneybox is Opened.");
err=device->set_notify(device, hal_notify_callback);
if (err < 0) {
ALOGE("Failed in call to set_notify(), err=%d", err);
}else
ALOGI("Call to set_notify successfully!");
if (!mCallbacksObj)
mCallbacksObj = env->NewGlobalRef(clazz);
ALOGI("moneybox_device_open successfully!");
return (jint)device;
}
ALOGE("Failed to open device moneybox.");
return 0;
}
ALOGE("Failed to get HAL stub moneybox.");
return 0;
}
static void moneybox_class_init_native(JNIEnv* env, jclass clazz) {
ALOGE("moneybox_class_init_native GetMethodID moneybox_callback");
//javaCallback = env->GetMethodID(clazz, "moneybox_callback", "(II)I");
javaCallback = env->GetStaticMethodID(clazz, "moneybox_callback", "(II)I");
}
static const JNINativeMethod method_table[] = {
{"class_init_native", "()V", (void *)moneybox_class_init_native},
{"init_native", "()I", (void*)moneybox_init},
{"setVal_native", "(II)V", (void*)moneybox_setVal},
{"set_enable_power_native", "(II)V", (void*)moneybox_set_enable_power},
{"set_control_val_native", "(II)V", (void*)moneybox_set_control_val},
{"get_feedback_val_native", "(I)I", (void*)moneybox_get_feedback_val},
};
int register_android_server_MoneyboxService(JNIEnv *env) {
int res = jniRegisterNativeMethods(env, "com/android/server/MoneyboxService", method_table, NELEM(method_table));
/*
jclass clazz;
clazz=env->FindClass("com/android/server/MoneyboxService");
javaCallback = env->GetMethodID(clazz, "moneybox_callback", "(II)I");
*/
ALOGI("register_android_server_MoneyboxService");
return res;
}
};
五、frameworks/base/services/core/jni/onload.cpp注册jni
int register_android_server_MoneyboxService(JNIEnv* env);
六、添加服务文件frameworks/base/services/core/java/com/android/server/MoneyboxService.java
七,添加manager文件, frameworks/base/core/java/android/os/SystemMoneybox.java ,提供api个app
八、添加服务frameworks/base/services/java/com/android/server/SystemServer.java
try {
traceBeginAndSlog("Moneybox Service");
ServiceManager.addService("moneybox", new MoneyboxService(context));
} catch (Throwable e) {
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
九、注册服务 frameworks/base/core/java/android/app/SystemServiceRegistry.java
registerService(Context.MONEYBOX_SERVICE, SystemMoneybox.class,
new CachedServiceFetcher<SystemMoneybox>() {
@Override
public SystemMoneybox createService(ContextImpl ctx) {
//return new SystemMoneybox(ctx);//ctx.mMainThread.getHandler().getLooper()
return new SystemMoneybox(ctx,ctx.mMainThread.getHandler().getLooper());
}});
十、添加frameworks/base/core/java/android/os/IMoneyboxService.aidl进行跨进行binder通信
package android.os;
import android.os.IMoneyboxTListener;
interface IMoneyboxService {
void setVal(int val);
void set_enable_power(int val);
void set_control_val(int val);
int get_feedback_val();
void registerListener(IMoneyboxTListener listener);
}
十一、添加frameworks/base/core/java/android/os/IMoneyboxTListener.aidl用于回调binder通信
package android.os;
import android.os.Bundle;
oneway interface IMoneyboxTListener
{
void onMoneyboxChanged(int i);
}
十二、添加frameworks/base/location/java/android/location/MoneyboxListener.java 用于侦听
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.location;
import android.os.Bundle;
/**
* Used for receiving notifications from the LocationManager when
* the location has changed. These methods are called if the
* LocationListener has been registered with the location manager service
* using the {@link LocationManager#requestLocationUpdates(String, long, float, LocationListener)}
* method.
*
* <div class="special reference">
* <h3>Developer Guides</h3>
* <p>For more information about identifying user location, read the
* <a href="{@docRoot}guide/topics/location/obtaining-user-location.html">Obtaining User
* Location</a> developer guide.</p>
* </div>
*/
public interface MoneyboxListener {
void onMoneyboxChanged(int i);
}
十三、frameworks/base/Android.mk添加下面内容
core/java/android/os/IMoneyboxService.aidl \
core/java/android/os/IMoneyboxTListener.aidl \
十四、APP demo,app通过下面两种方法调用系统服务。
IMoneyboxService.Stub.asInterface( ServiceManager.getService("moneybox"));
或者
(SystemMoneybox) getSystemService("moneybox");
十五、make update-api更新api,mmm frameworks/base/services/、mmm frameworks/base/编译出framework.jar、services.jar和libandroid_servers.so(jni),push到机器运行测试
15.1、执行service list查看该服务是否已经start。
15.2、确认是否已经生成杂项设备节点和平台总线控制node。
xxx:/ # ls -l /dev/moneybox
crwxrwxrwx 1 root root 10, 60 2021-04-27 00:26 /dev/moneybox
xxx:/ # ls /sys/devices/platform/moneybox/
control driver driver_override enpower feedback modalias of_node power subsystem uevent
xxx:/ #
15.3、运行demo app
15.3、点击demo里面的button调用framework接口,然后通过servies,jni、hardware、kernel控制gpio,然后feedback gpio电平有变化的时候会通过一系列回调传数据到app,看下面的log,
所有的通路都是测试ok。
十六、整个过程涉及到下面的文件。
DEMO APP代码在Moneyboxapp目录下,用mmm进行编译
A packages/apps/Moneyboxapp/Android.mk
A packages/apps/Moneyboxapp/AndroidManifest.xml
A packages/apps/Moneyboxapp/res/drawable/icon.png
A packages/apps/Moneyboxapp/res/layout/main.xml
A packages/apps/Moneyboxapp/res/values/strings.xml
A packages/apps/Moneyboxapp/src/giada/ibc/moneybox/Moneybox.java
Framework涉及到的代码:
M device/rockchip/rk3288/device.mk
M frameworks/base/Android.mk
M frameworks/base/core/java/android/app/SystemServiceRegistry.java
M frameworks/base/core/java/android/content/Context.java
A frameworks/base/core/java/android/os/IMoneyboxService.aidl
A frameworks/base/core/java/android/os/IMoneyboxTListener.aidl
A frameworks/base/core/java/android/os/SystemMoneybox.java
A frameworks/base/location/java/android/location/MoneyboxListener.java
A frameworks/base/services/core/java/com/android/server/MoneyboxService.java
M frameworks/base/services/core/jni/Android.mk
A frameworks/base/services/core/jni/com_android_server_MoneyboxService.cpp
M frameworks/base/services/core/jni/onload.cpp
M frameworks/base/services/java/com/android/server/SystemServer.java
hardware的代码:
A hardware/libhardware/include/hardware/moneybox.h
M hardware/libhardware/modules/Android.mk
A hardware/libhardware/modules/moneybox/Android.mk
A hardware/libhardware/modules/moneybox/moneybox.cpp
底层驱动涉及到的代码:
M device/rockchip/common/init.connectivity.rc
M kernel/arch/arm/boot/dts/rk3288-giada-jhs66l-act8846.dts
M kernel/drivers/char/Makefile
A kernel/drivers/char/moneybox.c
十七、源码下载路径 frameworks_services_jni_hardware_kernel.zip-Linux文档类资源-CSDN下载 包含所有的文件。
十八、饮水思源,参考文章:
1、android 创建一个实时监听的系统Service
android 创建一个实时监听的系统Service_lz强的博客-CSDN博客_android 监听service
2、安卓硬件服务实例:手把手教你如何从驱动到应用添加硬件服务
安卓硬件服务实例:手把手教你如何从驱动到应用添加硬件服务_kavin.zhu的博客-CSDN博客_安卓硬件驱动
3、Android Hal层回调APP应用接口
Android Hal层回调APP应用接口_yujd的博客-CSDN博客
4、Android硬件服务框架实例之Vibrator(驱动到应用)
Android硬件服务框架实例之Vibrator(驱动到应用)_kavin.zhu的博客-CSDN博客_android振动代码
5、https://www.jianshu.com/p/0f46a95d576f (Android 添加一个系统服务的完整流程(SystemService))