本文共 5938 字,大约阅读时间需要 19 分钟。
本人并未深入研究过 Android的framework和从事framework的开发,以下内容都是我根据网络上各路大神的博客、知乎和B站视频所讲述的内容,以及我自己的理解整理而成,这其中极可能会有错误,各位看官要小心!!!
apps-->java api frameworks-->android runtime(ART即虚拟机)-->Native C/C++ library -->HAL-->kernel drivers
Java具有“跨平台,可移植性强”,但是问题也来了,不同的平台会拥有一些自己独有的功能,A家有B家没有,你又想在A家平台用,也就说这些功能实际上还是需要平台来提供。所以java程序能够在不同平台上运行,是因为不同平台上的java本地接口不同(JNI)。
Android系统在启动过程中,先启动Kernel创建init进程,紧接着由init进程fork第一个横穿Java和C/C++的进程,即Zygote进程。Zygote启动过程中会在AndroidRuntime.cpp中的startVm创建虚拟机,VM创建完成后,紧接着调用startReg完成虚拟机中的JNI方法注册。
1>创建目录,挂载分区2>解析启动脚本LoadBootScripts() #system/core/rootdir/init.rc3>启动解析的所有服务4>守护所有已启动的服务
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方法
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;}
以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();}
第一种是: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中实现,具体在哪个层里面实现或者两个层一起实现,无所谓。
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.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")
方式一:系统启动过程中一定会调用的C/C++接口,就将接口添加到数组gRegJNI[],系统启动过程中会通过register_jni_procs函数遍历该数组并执行数组中的每一个函数;
方式二:系统启动过程中不一定调用的C/C++接口,采用库文件的方式,应用程序打开库文件进行使用即可。
因此可得出一个结论(不一定正确):系统的基本组件(一定会调用的)使用第一种方式;应用程序(不一定会调用)使用第二种方式。
转载地址:http://deuen.baihongyu.com/