博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Framework
阅读量:3897 次
发布时间:2019-05-23

本文共 5938 字,大约阅读时间需要 19 分钟。

0. 声明

        本人并未深入研究过 Android的framework和从事framework的开发,以下内容都是我根据网络上各路大神的博客、知乎和B站视频所讲述的内容,以及我自己的理解整理而成,这其中极可能会有错误,各位看官要小心!!!

1. android应用程序到底层驱动的流程

        apps-->java api frameworks-->android runtime(ART即虚拟机)-->Native C/C++ library -->HAL-->kernel drivers

2. JNI的意义

        Java具有“跨平台,可移植性强”,但是问题也来了,不同的平台会拥有一些自己独有的功能,A家有B家没有,你又想在A家平台用,也就说这些功能实际上还是需要平台来提供。所以java程序能够在不同平台上运行,是因为不同平台上的java本地接口不同(JNI)。

3. JNI方法的注册

        Android系统在启动过程中,先启动Kernel创建init进程,紧接着由init进程fork第一个横穿Java和C/C++的进程,即Zygote进程。Zygote启动过程中会在AndroidRuntime.cpp中的startVm创建虚拟机,VM创建完成后,紧接着调用startReg完成虚拟机中的JNI方法注册。

3.1 system/core/init.cpp下有一个mian()方法,改方法重点实现了四个功能:

1>创建目录,挂载分区2>解析启动脚本LoadBootScripts()		#system/core/rootdir/init.rc3>启动解析的所有服务4>守护所有已启动的服务

3.2 Zygote 进程是由init进程通过解析init.rc文件而创建的

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server    class main    socket zygote stream 660 root system    onrestart write /sys/android_power/request_state wake    onrestart write /sys/power/state on    onrestart restart media    onrestart restart netd

        对应找到 /frameworks/base/cmds/app_process/app_main.cpp源码文件中的main方法

if (zygote) {        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);    } else if (className) {        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);    }

        然后来到 /frameworks/base/core/jni/AndroidRuntime.cpp中的start方法

3.3 frameworks/base/core/jni/AndroidRuntime.cpp

void AndroidRuntime::start(const char* className, const Vector
& options, bool zygote){ startVm(&mJavaVM, &env, zygote);//创建虚拟机 startReg(env); //注册虚拟机中的JNI方法}int AndroidRuntime::startReg(JNIEnv* env) { ALOGV("--- registering native functions ---\n"); env->PushLocalFrame(200); if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) { //gRegJNI就是一个函数名数组 env->PopLocalFrame(NULL); return -1; } env->PopLocalFrame(NULL);}static const RegJNIRec gRegJNI[] = { REG_JNI(register_com_android_internal_os_ZygoteInit), REG_JNI(register_android_hardware_Camera), REG_JNI(register_android_hardware_camera2_CameraMetadata), //... };//register_jni_procs函数遍历JNI方法注册函数表,逐个调用,逐个注册。static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env){ for (size_t i = 0; i < count; i++) if (array[i].mProc(env) < 0) return -1; return 0;}

3.4 frameworks/base/core/jni/android_hardware_Camera.cpp

        以Camera JNI方法的注册为例进行解析

//register_android_hardware_Camera这个函数就是将C++类和JAVA类的变量,方法,类对//应起来。return之前的代码是将java的域映射到c++,被后面c++调用java的方法所用。//registerNativeMethods是将camMethods里的c++方法映射到java域中,被后面的java调//用c++的native方法所用。// Get all the required offsets in java class and register native functionsint register_android_hardware_Camera(JNIEnv *env){    field fields_to_find[] = {        { "android/hardware/Camera", "mNativeContext",   "J", &fields.context },        { "android/hardware/Camera$CameraInfo", "facing",   "I", &fields.facing },        { "android/hardware/Camera$CameraInfo", "orientation",   "I", &fields.orientation },        //······    };    find_fields(env, fields_to_find, NELEM(fields_to_find));    jclass clazz = FindClassOrDie(env, "android/hardware/Camera");    fields.post_event = GetStaticMethodIDOrDie(env, clazz, "postEventFromNative",                                               "(Ljava/lang/Object;IIILjava/lang/Object;)V");    //······    // Register native functions    return RegisterMethodsOrDie(env, "android/hardware/Camera", camMethods, NELEM(camMethods));}// "()I"代表方法没有参数,返回值为int型// "()V"代表方法没有参数,也没有返回值// "(II)I"代表方法有两个int型参数和一个int型的返回值static const JNINativeMethod camMethods[] = {  { "getNumberOfCameras",    "()I",    (void *)android_hardware_Camera_getNumberOfCameras },  { "_getCameraInfo",    "(ILandroid/hardware/Camera$CameraInfo;)V",    (void*)android_hardware_Camera_getCameraInfo },  { "previewEnabled",    "()Z",    (void *)android_hardware_Camera_previewEnabled },  { "startSmoothZoom",    "(I)V",    (void *)android_hardware_Camera_startSmoothZoom },   { "_enableShutterSound",    "(Z)Z",    (void *)android_hardware_Camera_enableShutterSound },    //······ }; //这里的Camera指的是native中的class Camera类,getNumberOfCameras是其中的静态方法。 static jint android_hardware_Camera_getNumberOfCameras(JNIEnv *env, jobject thiz){    return Camera::getNumberOfCameras();}

4. 操控硬件的方法

        第一种是:framework层直接使用kernel的生成的设备节点/属性;

        第二种是:framework层通过JNI调用C/C++编写的接口,这个C/C++接口的实现是在(native library或者HAL层单独实现)或(native library实现,然后再调用HAL层接口)。

        说到底,第二种方法的关键就在于通过register_jni_procs函数将自定义的JNI接口进行注册,使Java程序可以调用到C/C++的接口,需要注意的是:C/C++的接口是在kernel之上的,所以这个C/C++接口只可能是在Native和HAL中实现,具体在哪个层里面实现或者两个层一起实现,无所谓。

5. 添加JNI参考步骤

1.编写带有native声明的方法的java类,生成.java文件2.使用javac命令编译所编写的java类,生成.class文件3.使用javah -jni java类名生成扩展名为h的头文件,也即生成.h文件4.使用C/C++(或者其他编程想语言)实现本地方法,创建.h文件的实现,也就是创建.cpp文件实现.h文件中的方法5.将C/C++编写的文件生成动态连接库,生成dll文件

6. Android控制gpio实现对小灯读写

        6.1 kernel下添加led.c驱动文件,提供led_open、led_close和led_ioctl三个接口,生成设备节点dev/led_dev。

        6.2 在system/core/rootdir/init.rc中修改/dev/led_dev节点的系统所有者和权限

chown system system /dev/led_devchmod 0766 /dev/led_dev

        6.3 生成头文件

//1.新建一个安卓工程,然后新建类public class GpioLED {		    //控制LED上电	    public native static void ledPowerOn();	    // 控制LED下电	    public native static void ledPowerOff();	} //2.进入bin/classes,使用命令“javah -jni 包名.类名”生成头文件,比如javah -jni com.coban.ledsimple.LEDGpio

        6.4 jni实现,新建ledcontrol.c和Android.mk文件,最后生成ledcontrol.so库文件,以下为ledcontrol.c简略版:

//include
<第三步生成的头文件>
//定义驱动里面的IOCTL命令码JNIEXPORT void JNICALL Java_com_coban_ledsimple_LEDGpio_ledPowerOn(JNIEnv* env, jclass mc){ fd=open(DEVICE_NAME,O_RDWR); if(fd>0) ioctl(fd,LED_ON,NULL) ; LOGI("open success");}JNIEXPORT void JNICALL Java_com_coban_ledsimple_LEDGpio_ledPowerOff(JNIEnv* env, jclass mc){ ioctl(fd,LED_OFF,NULL) ; close(fd);}

        6.5 app调用

System.loadLibrary("ledcontrol")

7. 小总结:

        方式一:系统启动过程中一定会调用的C/C++接口,就将接口添加到数组gRegJNI[],系统启动过程中会通过register_jni_procs函数遍历该数组并执行数组中的每一个函数;

        方式二:系统启动过程中不一定调用的C/C++接口,采用库文件的方式,应用程序打开库文件进行使用即可。

        因此可得出一个结论(不一定正确):系统的基本组件(一定会调用的)使用第一种方式;应用程序(不一定会调用)使用第二种方式。

转载地址:http://deuen.baihongyu.com/

你可能感兴趣的文章
皮克斯宣布开源Universal Scene Description
查看>>
复盘:一个创业项目的失败之路
查看>>
阿里巴巴宣布加入Linux基金会
查看>>
为什么你应该尝试 “全栈”
查看>>
程序员什么时候该考虑辞职
查看>>
如何写一本书?
查看>>
加班能体现编程的热情吗?
查看>>
Hadley Wickham:一个改变了R的人
查看>>
glibc 指导委员会解散声明
查看>>
Linux创始者托瓦兹谈及IoT --「安全在其次」
查看>>
传感器数据分析(Sensor Data Analytics)是什么?
查看>>
智能硬件开发如何选择低功耗MCU?
查看>>
阿里感悟(十)如何写好简历
查看>>
阿里感悟(十一)如何准备面试
查看>>
软件架构入门
查看>>
80 多个 Linux 系统管理员必备的监控工具
查看>>
OOD的原则
查看>>
Tool to trace local function calls in Linux
查看>>
Linux 下查询 DNS 服务器信息
查看>>
ulimit 里的 file size 的 block 单位是多少?
查看>>