您的位置:首页 > 移动开发

贯通 Android 底层驱动至应用层APP接口流程

2016-01-27 22:48 513 查看
以下例子均为未经测试的代码,也重点在整个的流程概况。目前仍有些不是太明白的地方。

分以下几点(忽略HAL层):

驱动:lichee/linux-3.4/drivers/

主要是初始化相关芯片以及具体的交互功能,然后创建设备节点来与上层交互。(尽量不做逻辑控制)

调用 class_register() 接口时,会在 /sys/class/ 目录下创建设备节点。

调用 misc_register() 接口时,会在 /dev/ 目录下创建设备节点。

JNI:android/frameworks/base/services/jni/

该层一般是提供JAVA与 C\C++ 之间通信,这一层我主要用来做一些基本的逻辑控制处理,记得之前有

次参加面试,该公司主要是做类似安防的手机,他们就是主要在这层做逻辑控制。该层主要是通过

映射表来描述 JAVA 方法与 C\C++ 函数之间的对应关系。

static JNINativeMethod method_table[] ={

// JAVA 方法 返回值与参数描述 C\C++ 函数

{"Xxx_Init_native", "()I", (void *)HardwareConfig_XxxInit},

{"Xxx_Cmd_native", "(II)I", (void *)HardwareConfig_XxxCmd},

};

Server:android/frameworks/base/services/java/com/android/server/SystemServer.java

这个主要是供其他 APP 通过 aidl 接口调用到 Server 方法,Server 方法通过JNI映射表,

调用JNI的函数。进一步封装接口,实现必要的逻辑处理。

aidl:frameworks/base/core/java/android/os

该文件用来生成 Stub 接口文件,用来声明在 Server 提供的接口。

SystemServer:创建 Server 实例,加入服务表中,供 APP 获取使用。

接口:

声明一些数据结构、获取
Server 根据需要决定是否再进一步封装接口。

其主要的目的是为了APP能够更加方便的使用接口。

APP:

通过接口文件,来调用相关的接口从而间接调用底层驱动功能。

调用流程:APP 通过获取AIDL通信,获取服务,通过服务调用服务的提供的类,调用JNI接口、JNI再去调用驱动。

具体例子:

/////////////////////////////////////////////////////////////////////////////////////////////

驱动:lichee/linux-3.4/drivers/my_drivers/pt22xx.c

会创建一个设备节点:/dev/MicAdjust 用于给上层交互

/////////////////////////////////////////////////////////////////////////////////////////////

long Pt22xx_ioctl(struct file *file, unsigned int cmd, unsigned long args)

{

unsigned char ret = 0;

if (_IOC_TYPE(cmd) != MAGIC)

return -EINVAL;

switch(cmd)

{

case CMD_SETMICVOL: dprintk("CMD_SETMICVOL....");

g_CurrentMicVolume = args;

// 与底层硬件进行交互

break;

case CMD_SETMICECHO: dprintk("CMD_SETMICECHO....");

g_CurrentMicEcho = args;

// 与底层硬件进行交互

break;

case CMD_GETMICVOL: dprintk("CMD_GETMICECHO....");

ret = g_CurrentMicVolume;

break;

case CMD_GETMICECHO: dprintk("CMD_GETMICECHO....");

ret = g_CurrentMicEcho;

break;

default: dprintk("no cmd....");

return -EINVAL;

}

return ret;

}

static struct file_operations Pt22xx_fops = {

.owner = THIS_MODULE,

.unlocked_ioctl = Pt22xx_ioctl,

};

static struct miscdevice Pt22xx_misc =

{

.minor = MISC_DYNAMIC_MINOR,

.name = "MicAdjust",

.fops = &Pt22xx_fops,

};

/*************************** 驱动入口 驱动出口 ***************************/

static int __init Pt22xx_init(void)

{

misc_register(&Pt22xx_misc);

return 0;

}

static void __exit Pt22xx_exit(void)

{

}

/*************************** 驱动入口 驱动出口 ***************************/

module_init(Pt22xx_init);

module_exit(Pt22xx_exit);

MODULE_LICENSE("GPL");

/////////////////////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////////////////////

Jni:android/frameworks/base/services/jni/my_jni/Mic.cpp

会创建一个设备节点:/dev/MicAdjust 用于给上层交互

/////////////////////////////////////////////////////////////////////////////////////////////

//-------------------------------------------------------------------------------------

对应驱动的JNI文件

//-------------------------------------------------------------------------------------

// 功放命令实现

jint Mic_Cmd(JNIEnv *env, jobject thiz, jint cmd, jint arg1)

{

int ret = 0;

// 这里则通过识别命令和参数 通过 ioctl 函数设置驱动

// 这里应用层 ioctl() 实际上回调的是驱动层 -> Pt22xx_ioctl() 函数

return ret;

}

// 初始化函数,需要识别并初始化硬件设备

jint Mic_Init(JNIEnv *env, jobject thiz)

{

// 初始化硬件

// 这里会 open /dev/MicAdjust 设备节点

return 0;

}

//-------------------------------------------------------------------------------------

管理和协调各个JNI程序,实现一些基本的逻辑功能,例如参数保存之类的。。

android/frameworks/base/services/jni/com_android_server_HardwareConfig.cpp

//-------------------------------------------------------------------------------------

namespace android {

/* 一些数据结构 */

///////////////////////////// AMP 逻辑实现 ////////////////////////////////////////

/* 处理获取命令 */

jint HardwareConfig_GetAmp(enum enAmp_CMDTYPE cmd)

{

int ret;

switch(cmd)

{

default:

return eAMP_CMD_ERROR;

}

return ret;

}

// 功放命令实现

jint HardwareConfig_AmpCmd(JNIEnv *env, jobject thiz, jint cmd, jint arg1)

{

int ret = 0;

// 非法参数检查

// 判断是否为获取命令

if( IsAmpGetCmdType(cmd) )

{

return HardwareConfig_GetAmp((enum enAmp_CMDTYPE)cmd);

}

// 参数检查并纠正

// 调用相应的功能函数

ret = Amp_Cmd((enAmp_CMDTYPE)cmd, (enAmp_ARGSTYPE)arg1);

/* 保存相关参数 */

return ret;

}

///////////////////////////// MIC 逻辑实现 ////////////////////////////////////////

jint HardwareConfig_GetMic(enum enMic_CMDTYPE cmd)

{

int ret;

switch((int)cmd)

{

default:

return eMIC_CMD_ERROR;

}

return ret;

}

jint HardwareConfig_MicCmd(JNIEnv *env, jobject thiz, jint cmd, jint arg1)

{

int ret = 0;

// 非法参数检查

// 判断是否为获取命令

if( IsAmpGetCmdType(cmd) )

{

return HardwareConfig_GetAmp((enum enAmp_CMDTYPE)cmd);

}

// 参数检查并纠正

// 调用相应的功能函数

ret = Amp_Cmd((enAmp_CMDTYPE)cmd, (enAmp_ARGSTYPE)arg1);

/* 保存相关参数 */

return ret;

}

///////////////////////////// 以上为逻辑功能实现 ////////////////////////////////////////

// 初始化函数,需要识别并初始化硬件设备
这里对硬件初始化主要是调用各自的JNI接口初始化的

jint HardwareConfig_Init(JNIEnv *env, jobject thiz)

{

// 读取配置文件

/* 功放初始化
*/

Amp_Init();

Amp_Cmd(...);

Amp_Cmd(...);

Amp_Cmd(...);

/* 初始化麦克风 */

Mic_Init();

Mic_Cmd(...);

Mic_Cmd(...);

/* 初始化其他硬件 */

return 0;

}

///////////////////////////// JNI ////////////////////////////////////////

// 构建映射表

static JNINativeMethod method_table[] ={

{"HardwareConfig_Init_native", "()I", (void *)HardwareConfig_Init},

{"Amp_Cmd_native", "(II)I", (void *)HardwareConfig_AmpCmd},

{"Mic_Cmd_native", "(II)I", (void *)HardwareConfig_MicCmd},

//.... 其他硬件

};

int register_android_server_HardwareConfigService(JNIEnv* env)

{

return jniRegisterNativeMethods(env,"com/android/server/HardwareConfigService", method_table, NELEM(method_table));

}

}

//-------------------------------------------------------------------------------------

修改 onload.cpp 文件,该文件是用来集中加载所有Jni。

android\frameworks\base\services\jni\onload.cpp

//-------------------------------------------------------------------------------------

#include "JNIHelp.h"

#include "jni.h"

#include "utils/Log.h"

#include "utils/misc.h"

namespace android {

//... 省略

int register_android_server_HardwareConfigService(JNIEnv* env);

};

using namespace android;

extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)

{

//... 省略

register_android_server_HardwareConfigService(env);

return JNI_VERSION_1_4;

}

//-------------------------------------------------------------------------------------

修改 对应目录下的 Android.mk 文件,该文件是用来编译这些Jni文件的

android\frameworks\base\services\jni\Android.mk

//-------------------------------------------------------------------------------------

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \

// ... 省略

zhc_jni/Mic.cpp \

com_android_server_HardwareConfig.cpp
\

onload.cpp

LOCAL_C_INCLUDES += \

// ... 省略

my_jni

ifeq ($(WITH_MALLOC_LEAK_CHECK),true)

LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK

endif

LOCAL_MODULE:= libandroid_servers

include $(BUILD_SHARED_LIBRARY)

/*************** 完成以上步骤就可以在当前目录下通过 mm 命令编译出 JNI SO库文件了 ***********/

/////////////////////////////////////////////////////////////////////////////////////////////

Server:

在 android\frameworks\base\services\java\com\android\server
建立一个文件 HardwareConfigService.java

/////////////////////////////////////////////////////////////////////////////////////////////

package com.android.server;

import android.content.Context;

import android.util.Slog;

import android.content.Context;

public class HardwareConfigService extends IHardwareConfigService.Stub {

private static final String TAG = "HardwareConfigService";

private static native int HardwareConfig_Init_native();

private static native int Amp_Cmd_native(int cmd, int arg1);

private static native int Mic_Cmd_native(int cmd, int arg1);

private static Context mContext;

///////////////////////////////////// 初始化处理部分 ////////////////////////////////

// 当这个类被创建时,以下代码将会被执行

public HardwareConfigService(Context context)

{

mContext = context;

HardwareConfig_Init_native(); // <---- 这里调用 JNI 部分接口 进行初始化

}

///////////////////////////////////// 接口定义部分 ////////////////////////////////

public int Amp_Cmd(int Cmd, int arg1) // <<---- 对外提供的调用的接口

{

int ret = 0;

// 在这里可以对接口做进一步封装

ret = Amp_Cmd_native(Cmd, arg1); // <---- 这里调用 JNI 部分接口

return ret;

}

public int Mic_Cmd(int Cmd, int arg1) // <<---- 对外提供的调用的接口

{

int ret = 0;

// 在这里可以对接口做进一步封装

ret = Mic_Cmd_native(Cmd, arg1); // <---- 这里调用 JNI 部分接口

return ret;

}

};

//-------------------------------------------------------------------------------------

修改同目录下的SystemServer.java文件,在ServerThread::run方法里加入

//-------------------------------------------------------------------------------------

class ServerThread extends Thread {

private static final String TAG = "SystemServer";

private static final String ENCRYPTING_STATE = "trigger_restart_min_framework";

// ... 省略代码

@Override

public void run() {

try{ // 在这里 new 了一个对象并添加到 ServiceManager 中。

Slog.i(TAG, "add HardwareConfigService");

ServiceManager.addService("HardwareConfigService", new HardwareConfigService(context));

} catch (RuntimeException e) {

Slog.e("System", "******************************************");

Slog.e("System", "************ Failure starting HardwareConfigService", e);

}

// ... 省略代码

}

}

public class SystemServer {

private static final String TAG = "SystemServer";

// ... 省略代码

public static final void init2() {

Slog.i(TAG, "Entered the Android system server!");

Thread thr = new ServerThread();

thr.setName("android.server.ServerThread");

thr.start();

}

}

/*************** 完成以上步骤就可以在 android\frameworks\base\services\java
下通过 mm 命令编译了 ***********/

/////////////////////////////////////////////////////////////////////////////////////////////

AIAL:在 frameworks/base/core/java/android/os/
新建立一个文件 IHardwareConfigService.aidl

/////////////////////////////////////////////////////////////////////////////////////////////

//-------------------------------------------------------------------------------------

加入以下内容,以下内容为 服务里面的public接口,即提供给APP使用的接口

//-------------------------------------------------------------------------------------

package android.os;

interface IHardwareConfigService

{

int Amp_Cmd(int Cmd, int arg1);

int Mic_Cmd(int Cmd, int arg1);

}

//-------------------------------------------------------------------------------------

返回到 frameworks/base 修改
Android.mk 文件

//-------------------------------------------------------------------------------------

LOCAL_SRC_FILES += \

core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl \

## 省略

core/java/android/os/IHardwareConfigService.aidl
\ ## 增加这一行代码

# Include subdirectory makefiles

/////////////////////////////////////////////////////////////////////////////////////////////

接口文件:这个接口文件主要是进一步封装接口,把一些命令标识什么的都放到问个文件里面

在 android\frameworks\base\policy\src\com\android\internal\policy\impl

新建立一个文件 HardwareConfigServiceInterface.java

/////////////////////////////////////////////////////////////////////////////////////////////

package com.android.internal.policy.impl;

import android.os.IHardwareConfigService;

import android.os.RemoteException;

import android.os.ServiceManager;

import android.util.Log;

public class HardwareConfigServiceInterface {

private IHardwareConfigService HardwareConfigService = null;

static final String TAG = "HardwareConfigServiceInterface";

///////////////////////// 功放命令与参数定义
////////////////////////////

public enum enAmp_CMDTYPE

{

// 设置命令

eAMP_CMD_OPEN, // 打开

eAMP_CMD_CLOSE, // 关闭

eAMP_CMD_SETMUTE, // 静音

eAMP_CMD_SETVOLUME, // 设置音量

eAMP_CMD_SETEQ, // 设置音效

eAMP_CMD_SETSIGLEEND, // 设置立体声

eAMP_CMD_SETSURROUND, // 设置环绕

eAMP_CMD_SETTREBLEBASS_CTRL, // 高低音控制

eAMP_CMD_SETTREBLE, // 设置高音

eAMP_CMD_SETBASS, // 设置低音

// .........

eAMP_CMD_ERROR, // 命令执行错误或失败,同时也是命令的个数

};

///////////////////////// 功放接口
////////////////////////////

/* 获取某些命令是已经使能了还是关闭了 设计此接口是为了应用层更加方便的判断 出错返回 eAMP_ARGS_NOT_USER*/

public enAmp_ARGSTYPE Amp_GetCmd(enAmp_CMDTYPE Cmd)

{

int index = 0;

// 省略转换代码

index = Amp_Cmd(Cmd, enAmp_ARGSTYPE.eAMP_ARGS_NOT_USER.ordinal());

// 省略转换代码

return enAmp_ARGSTYPE.eAMP_ARGS_NOT_USER;

}

/* 获取具体的值 例如 高低音的值 出错返回 -1 */

public int Amp_GetData(enAmp_CMDTYPE Cmd)

{

int ret = Amp_Cmd(Cmd, enAmp_ARGSTYPE.eAMP_ARGS_NOT_USER.ordinal());

// 省略转换代码

return ret;

}

public enAmp_CMDTYPE Amp_SetCmd(enAmp_CMDTYPE Cmd, enAmp_ARGSTYPE Args)

{

int index = 0;

// 省略转换代码

index = Amp_Cmd(Cmd, Args.ordinal());

// 省略转换代码

return enAmp_CMDTYPE.eAMP_CMD_ERROR;

}

public int Amp_SetData(enAmp_CMDTYPE Cmd, int Args)

{

Log.d(TAG, "Amp_SetData() Cmd = " + Cmd + "Args = " + Args );

return Amp_Cmd(Cmd, Args);

}

/* 最终的实现是由此命令完成的 设置命令时出错返回 eAMP_CMD_ERROR 的索引*/

private int Amp_Cmd(enAmp_CMDTYPE Cmd, int Args)

{

Log.d(TAG, "Amp_SetCmd() Cmd = " + Cmd + " ordinal = " + Cmd.ordinal());

Log.d(TAG, "Amp_SetCmd() Args = " + Args);

try

{

if(null == HardwareConfigService)

{

HardwareConfigService = IHardwareConfigService.Stub.asInterface(ServiceManager.getService("HardwareConfigService"));

}

return HardwareConfigService.Amp_Cmd(Cmd.ordinal(), Args);

} catch (RemoteException e) {

// TODO Auto-generated catch block

e.printStackTrace();

return (int)(enAmp_CMDTYPE.eAMP_CMD_ERROR.ordinal());

}

}

///////////////////////// 麦克风接口与定义 ////////////////////////////

/* 功放命令集,具体命令需由具体的功放芯片驱动实现
*/

public enum enMic_CMDTYPE

{

// 设置命令

eMIC_CMD_START , // 起始

eMIC_CMD_SETVOLUME, // 设置MIC音量

eMIC_CMD_SETECHO, // 设置MIC回响

eMIC_CMD_SETMUTE, // 麦克风静音

// 获取命令

eMIC_CMD_GETTYPE_START, // 获取命令类型 用于做标识 当大于此值时表示是获取命令类型

eMIC_CMD_GETVOLUME, // 获取MIC音量值

eMIC_CMD_GETECHO, // 获取MIC回响值

eMIC_CMD_GETMUTE,

eMIC_CMD_GETTYPE_STOP, // eMic_CMD_GETTYPE_START 与 eMic_CMD_GETTYPE_STOP 之间是获取命令的类型

eMIC_CMD_ERROR, // 命令执行错误或失败,同时也是命令的个数

};

public enum enMic_ARGSTYPE // 参数

{

eMIC_ARGS_DISABLE ,

eMIC_ARGS_ENABLE,

eMIC_ARGS_NOT_USER, // 不使用

};

///////////////////////// 麦克风接口实现 ////////////////////////////

/* 获取某些命令是已经使能了还是关闭了 设计此接口是为了应用层更加方便的判断 出错返回 eMIC_ARGS_NOT_USER*/

public enMic_ARGSTYPE Mic_GetCmd(enMic_CMDTYPE Cmd)

{

int index = 0;

// 省略转换代码

index = Mic_Cmd(Cmd, enMic_ARGSTYPE.eMIC_ARGS_NOT_USER.ordinal());

// 省略转换代码

return enMic_ARGSTYPE.eMIC_ARGS_NOT_USER;

}

/* 获取具体的值 出错返回 -1 */

public int Mic_GetData(enMic_CMDTYPE Cmd)

{

int ret = Mic_Cmd(Cmd, enMic_ARGSTYPE.eMIC_ARGS_NOT_USER.ordinal());

// 省略转换代码

return ret;

}

public enMic_CMDTYPE Mic_SetCmd(enMic_CMDTYPE Cmd, enMic_ARGSTYPE Args)

{

int index = 0;

// 省略转换代码

index = Mic_Cmd(Cmd, Args.ordinal());

// 省略转换代码

return enMic_CMDTYPE.eMIC_CMD_ERROR;

}

public int Mic_SetData(enMic_CMDTYPE Cmd, int Args)

{

// 省略转换代码

return Mic_Cmd(Cmd, Args);

}

/* 最终的实现是由此命令完成的 设置命令时出错返回 eMIC_CMD_ERROR 的索引*/

private int Mic_Cmd(enMic_CMDTYPE Cmd, int Args)

{

Log.d(TAG, "Mic_SetCmd() Cmd = " + Cmd + " ordinal = " + Cmd.ordinal());

Log.d(TAG, "Mic_SetCmd() Args = " + Args);

try

{

if(null == HardwareConfigService)

{

HardwareConfigService = IHardwareConfigService.Stub.asInterface(ServiceManager.getService("HardwareConfigService"));

}

return HardwareConfigService.Mic_Cmd(Cmd.ordinal(), Args);

} catch (RemoteException e) {

// TODO Auto-generated catch block

e.printStackTrace();

return (int)(enMic_CMDTYPE.eMIC_CMD_ERROR.ordinal());

}

}

}

/*****************************************************************************

昨晚以上的操作之后需要 make updata-api 建议全编一次

*****************************************************************************/

/////////////////////////////////////////////////////////////////////////////////////////////

应用层使用方法:

/////////////////////////////////////////////////////////////////////////////////////////////

1、需要在 Android 工程中加上 android\out\target\common\obj\JAVA_LIBRARIES\android.policy_intermediates\classes.jar

2、导入需要的数据结构

import com.android.internal.policy.impl.HardwareConfigServiceInterface;

import com.android.internal.policy.impl.HardwareConfigServiceInterface.enAmp_CMDTYPE;

import com.android.internal.policy.impl.HardwareConfigServiceInterface.enAmp_ARGSTYPE;

import com.android.internal.policy.impl.HardwareConfigServiceInterface.enMic_CMDTYPE;

import com.android.internal.policy.impl.HardwareConfigServiceInterface.enMic_ARGSTYPE;

import com.android.internal.policy.impl.HardwareConfigServiceInterface.enDevices_Status;

3、定义全局变量

static private HardwareConfigServiceInterface HardwareConfig = null;

4、在初始化函数中new
对象

HardwareConfig = new HardwareConfigServiceInterface();

5、在需要的地方直接调用接口

HardwareConfig.Amp_GetCmd(enAmp_CMDTYPE.eAMP_CMD_GETSDMUTE)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: