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

以下例子均为未经测试的代码,也 重点在整个的流程概况。目前仍有些不是太明白的地方。

分以下几点(忽略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)
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在隧道工程中,贯通误差是指隧道两侧钻探工作面在地下相遇时,由于复杂的地质情况导致实际贯通位置与设计位置之间存在的偏差。为了准确预测和控制贯通误差,excel表格可以应用于隧道贯通误差的预计。 首先,使用excel可以对隧道的地质勘探数据进行整理和分析。将不同地层、岩石结构等数据输入表格中,并利用excel的数据处理功能进行统计和计算。通过分析地质数据,可以了解隧道施工过程中可能遇到的地质情况,为贯通误差的预测提供基础。 其次,excel可以利用历史工程数据进行模拟和预测。通过录入历史隧道工程的贯通误差数据,利用excel的数据分析和图表生成功能,可以得出贯通误差的趋势和规律。通过对历史数据的分析,可以建立合适的数学模型,并在模型的基础上进行预测,从而辅助设计师和施工人员合理预判贯通误差。 此外,excel还可以结合地理信息系统(GIS)进行预测。通过将隧道设计图纸和地质数据导入excel表格中,利用excel的地理信息处理功能,可以在地图上实现隧道贯通误差的可视化预测。通过图表和地图的展示,可以直观地了解不同地段的贯通误差情况,为隧道施工过程中的调整和控制提供参考。 综上所述,excel在隧道贯通误差预计中具有重要的应用价值。通过整理和分析地质数据,模拟历史工程数据,以及与GIS结合进行预测,可以帮助预测隧道贯通误差,提供科学依据和决策支持,从而确保隧道工程的安全和顺利进行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值