1、JNI概述
Java Native Interface (JNI) 是一种编程框架,使得Java代码可以或许与用其他编程语言(如C和C++)编写的当地代码进行交互。JNI允许Java代码调用当地代码的函数,也允许当地代码调用Java代码的函数。下面是对JNI机制的具体概述,包括其基本原理、工作流程、常见用途和示例代码。
1.1. JNI的基本原理
JNI的核心原理是通过一个标准化的接口,使得Java虚拟机(JVM)和当地代码可以互相通讯和操纵。JNI提供了一套函数,这些函数可以在当地代码中使用,以便与JVM交互,例如创建和操纵Java对象,调用Java方法,处理异常等。
1.2. JNI的工作流程
使用JNI的工作流程通常包括以下几个步调:
1、声明当地方法:在Java类中声明native方法。
2、加载当地库:在Java类中加载包含当地方法实现的库。
3、生成头文件:使用javac和javah工具生成包含native方法声明的头文件。
4、实现当地方法:在C/C++中实现native方法。
5、编译当地库:编译C/C++代码生成共享库。
6、调用当地方法:在Java代码中调用native方法。
1.3. JNI的常见用途
JNI常用于以下几种场景:
1、性能优化:将性能关键的部分用C/C++实现,以提高实验效率。
2、访问底层体系资源:访问操纵体系的底层功能或硬件资源。
3、重用现有库:调用已有的C/C++库或API。
4、实现平台特定功能:在跨平台应用中实现特定平台的功能。
2、JNI的优缺点
2.1、长处
1、性能优化:可以使用高效的当地代码,尤其是在性能关键的部分。
2、硬件访问:可以或许直接访问Java API不提供的底层硬件功能。
3、代码复用:重用现有的C/C++库,无需重新实现复杂的逻辑。
4、多语言互操纵:可以在同一个应用中使用多种编程语言,各取所长。
2.2、缺点
1、复杂性增长:引入了额外的复杂性,必要相识C/C++和JNI API。
2、平台依赖性:当地代码必要针对差别的平台编译,增长了维护成本。
3、内存管理:必要手动管理内存,轻易出现内存泄漏和指针错误。
4、调试困难:调试JNI代码比纯Java代码困难,必要使用特定的工具和方法。
3、JNI的使用场景
1、性能优化:在必要大量盘算或复杂逻辑的地方使用当地代码。
2、硬件功能:访问摄像头、传感器等底层硬件功能。
3、现有库:使用已有的C/C++库,例如图像处理库、加密库等。
4、跨语言调用:在必要与其他编程语言互操纵时,例如从Java调用C++代码。
4、Android日志体系概述
Android日志体系重要由Log类和__android_log_print等C/C++函数构成,提供了记载调试信息的功能。Java层的日志API(如android.util.Log)终极调用的是当地日志函数,这些函数将日志消息写入体系日志缓冲区。
要深入相识Android Log的JNI实现流程,我们必要从JNI机制、Android日志体系、JNI方法实现及其相互配合的细节等方面进行具体分析。
5、当地方法声明(关键字native)
frameworks\base\core\java\android\util\Log.java
- /**
- * Checks to see whether or not a log for the specified tag is loggable at the specified level.
- *
- * The default level of any tag is set to INFO. This means that any level above and including
- * INFO will be logged. Before you make any calls to a logging method you should check to see
- * if your tag should be logged. You can change the default level by setting a system property:
- * 'setprop log.tag.<YOUR_LOG_TAG> <LEVEL>'
- * Where level is either VERBOSE, DEBUG, INFO, WARN, ERROR, ASSERT, or SUPPRESS. SUPPRESS will
- * turn off all logging for your tag. You can also create a local.prop file that with the
- * following in it:
- * 'log.tag.<YOUR_LOG_TAG>=<LEVEL>'
- * and place that in /data/local.prop.
- *
- * @param tag The tag to check.
- * @param level The level to check.
- * @return Whether or not that this is allowed to be logged.
- * @throws IllegalArgumentException is thrown if the tag.length() > 23.
- */
- public static native boolean isLoggable(String tag, int level);
复制代码
- /**
- * Low-level logging call.
- * @param priority The priority/type of this log message
- * @param tag Used to identify the source of a log message. It usually identifies
- * the class or activity where the log call occurs.
- * @param msg The message you would like logged.
- * @return The number of bytes written.
- */
- public static int println(int priority, String tag, String msg) {
- return println_native(LOG_ID_MAIN, priority, tag, msg);
- }
- /** @hide */ public static final int LOG_ID_MAIN = 0;
- /** @hide */ public static final int LOG_ID_RADIO = 1;
- /** @hide */ public static final int LOG_ID_EVENTS = 2;
- /** @hide */ public static final int LOG_ID_SYSTEM = 3;
- /** @hide */ public static native int println_native(int bufID,
- int priority, String tag, String msg);
复制代码
6、当地方法实现
frameworks\base\core\jni\android_util_Log.cpp
- static jboolean android_util_Log_isLoggable(JNIEnv* env, jobject clazz, jstring tag, jint level)
- {
- if (tag == NULL) {
- return false;
- }
- const char* chars = env->GetStringUTFChars(tag, NULL);
- if (!chars) {
- return false;
- }
- jboolean result = false;
- if ((strlen(chars)+sizeof(LOG_NAMESPACE)) > PROPERTY_KEY_MAX) {
- char buf2[200];
- snprintf(buf2, sizeof(buf2), "Log tag "%s" exceeds limit of %d characters\n",
- chars, PROPERTY_KEY_MAX - sizeof(LOG_NAMESPACE));
- jniThrowException(env, "java/lang/IllegalArgumentException", buf2);
- } else {
- result = isLoggable(chars, level);
- }
- env->ReleaseStringUTFChars(tag, chars);
- return result;
- }
复制代码
- /*
- * In class android.util.Log:
- * public static native int println_native(int buffer, int priority, String tag, String msg)
- */
- static jint android_util_Log_println_native(JNIEnv* env, jobject clazz,
- jint bufID, jint priority, jstring tagObj, jstring msgObj)
- {
- const char* tag = NULL;
- const char* msg = NULL;
- if (msgObj == NULL) {
- jniThrowNullPointerException(env, "println needs a message");
- return -1;
- }
- if (bufID < 0 || bufID >= LOG_ID_MAX) {
- jniThrowNullPointerException(env, "bad bufID");
- return -1;
- }
- if (tagObj != NULL)
- tag = env->GetStringUTFChars(tagObj, NULL);
- msg = env->GetStringUTFChars(msgObj, NULL);
- int res = __android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg);
- if (tag != NULL)
- env->ReleaseStringUTFChars(tagObj, tag);
- env->ReleaseStringUTFChars(msgObj, msg);
- return res;
- }
复制代码
7、虚拟机里面动态注册
frameworks\base\core\jni\AndroidRuntime.cpp
- /*
- * Register android native functions with the VM.
- */
- /*static*/ int AndroidRuntime::startReg(JNIEnv* env)
- {
- /*
- * This hook causes all future threads created in this process to be
- * attached to the JavaVM. (This needs to go away in favor of JNI
- * Attach calls.)
- */
- androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
- ALOGV("--- registering native functions ---\n");
- /*
- * Every "register" function calls one or more things that return
- * a local reference (e.g. FindClass). Because we haven't really
- * started the VM yet, they're all getting stored in the base frame
- * and never released. Use Push/Pop to manage the storage.
- */
- env->PushLocalFrame(200);
- if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
- env->PopLocalFrame(NULL);
- return -1;
- }
- env->PopLocalFrame(NULL);
- //createJavaThread("fubar", quickTest, (void*) "hello");
- return 0;
- }
复制代码
- 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) {
- #ifndef NDEBUG
- ALOGD("----------!!! %s failed to load\n", array[i].mName);
- #endif
- return -1;
- }
- }
- return 0;
- }
复制代码
注意传入进来的参数
- static const RegJNIRec gRegJNI[] = {
- REG_JNI(register_android_debug_JNITest),
- REG_JNI(register_com_android_internal_os_RuntimeInit),
- REG_JNI(register_android_os_SystemClock),
- REG_JNI(register_android_util_EventLog),
- REG_JNI(register_android_util_Log),
- REG_JNI(register_android_util_FloatMath),
- REG_JNI(register_android_text_format_Time),
- REG_JNI(register_android_content_AssetManager),
- REG_JNI(register_android_content_StringBlock),
- REG_JNI(register_android_content_XmlBlock),
- REG_JNI(register_android_emoji_EmojiFactory),
- REG_JNI(register_android_text_AndroidCharacter),
- REG_JNI(register_android_text_AndroidBidi),
- REG_JNI(register_android_view_InputDevice),
- REG_JNI(register_android_view_KeyCharacterMap),
- REG_JNI(register_android_os_Process),
- REG_JNI(register_android_os_SystemProperties),
- REG_JNI(register_android_os_Binder),
- REG_JNI(register_android_os_Parcel),
- REG_JNI(register_android_view_DisplayEventReceiver),
- REG_JNI(register_android_nio_utils),
- REG_JNI(register_android_graphics_PixelFormat),
- REG_JNI(register_android_graphics_Graphics),
- REG_JNI(register_android_view_GLES20DisplayList),
- REG_JNI(register_android_view_GLES20Canvas),
- REG_JNI(register_android_view_HardwareRenderer),
- REG_JNI(register_android_view_Surface),
- REG_JNI(register_android_view_SurfaceSession),
- REG_JNI(register_android_view_TextureView),
- REG_JNI(register_com_google_android_gles_jni_EGLImpl),
- REG_JNI(register_com_google_android_gles_jni_GLImpl),
- REG_JNI(register_android_opengl_jni_EGL14),
- REG_JNI(register_android_opengl_jni_GLES10),
- REG_JNI(register_android_opengl_jni_GLES10Ext),
- REG_JNI(register_android_opengl_jni_GLES11),
- REG_JNI(register_android_opengl_jni_GLES11Ext),
- REG_JNI(register_android_opengl_jni_GLES20),
- REG_JNI(register_android_graphics_Bitmap),
- REG_JNI(register_android_graphics_BitmapFactory),
- REG_JNI(register_android_graphics_BitmapRegionDecoder),
- REG_JNI(register_android_graphics_Camera),
- REG_JNI(register_android_graphics_Canvas),
- REG_JNI(register_android_graphics_ColorFilter),
- REG_JNI(register_android_graphics_DrawFilter),
- REG_JNI(register_android_graphics_Interpolator),
- REG_JNI(register_android_graphics_LayerRasterizer),
- REG_JNI(register_android_graphics_MaskFilter),
- REG_JNI(register_android_graphics_Matrix),
- REG_JNI(register_android_graphics_Movie),
- REG_JNI(register_android_graphics_NinePatch),
- REG_JNI(register_android_graphics_Paint),
- REG_JNI(register_android_graphics_Path),
- REG_JNI(register_android_graphics_PathMeasure),
- REG_JNI(register_android_graphics_PathEffect),
- REG_JNI(register_android_graphics_Picture),
- REG_JNI(register_android_graphics_PorterDuff),
- REG_JNI(register_android_graphics_Rasterizer),
- REG_JNI(register_android_graphics_Region),
- REG_JNI(register_android_graphics_Shader),
- REG_JNI(register_android_graphics_SurfaceTexture),
- REG_JNI(register_android_graphics_Typeface),
- REG_JNI(register_android_graphics_Xfermode),
- REG_JNI(register_android_graphics_YuvImage),
- REG_JNI(register_android_database_CursorWindow),
- REG_JNI(register_android_database_SQLiteConnection),
- REG_JNI(register_android_database_SQLiteGlobal),
- REG_JNI(register_android_database_SQLiteDebug),
- REG_JNI(register_android_os_Debug),
- REG_JNI(register_android_os_FileObserver),
- REG_JNI(register_android_os_FileUtils),
- REG_JNI(register_android_os_MessageQueue),
- REG_JNI(register_android_os_ParcelFileDescriptor),
- REG_JNI(register_android_os_SELinux),
- REG_JNI(register_android_os_Trace),
- REG_JNI(register_android_os_UEventObserver),
- REG_JNI(register_android_net_LocalSocketImpl),
- REG_JNI(register_android_net_NetworkUtils),
- REG_JNI(register_android_net_TrafficStats),
- REG_JNI(register_android_net_wifi_WifiManager),
- REG_JNI(register_android_os_MemoryFile),
- REG_JNI(register_com_android_internal_os_ZygoteInit),
- REG_JNI(register_android_hardware_Camera),
- REG_JNI(register_android_hardware_SensorManager),
- REG_JNI(register_android_hardware_SerialPort),
- REG_JNI(register_android_hardware_UsbDevice),
- REG_JNI(register_android_hardware_UsbDeviceConnection),
- REG_JNI(register_android_hardware_UsbRequest),
- REG_JNI(register_android_media_AudioRecord),
- REG_JNI(register_android_media_AudioSystem),
- REG_JNI(register_android_media_AudioTrack),
- REG_JNI(register_android_media_JetPlayer),
- REG_JNI(register_android_media_RemoteDisplay),
- REG_JNI(register_android_media_ToneGenerator),
- REG_JNI(register_android_opengl_classes),
- REG_JNI(register_android_server_NetworkManagementSocketTagger),
- REG_JNI(register_android_server_Watchdog),
- REG_JNI(register_android_ddm_DdmHandleNativeHeap),
- REG_JNI(register_android_backup_BackupDataInput),
- REG_JNI(register_android_backup_BackupDataOutput),
- REG_JNI(register_android_backup_FileBackupHelperBase),
- REG_JNI(register_android_backup_BackupHelperDispatcher),
- REG_JNI(register_android_app_backup_FullBackup),
- REG_JNI(register_android_app_ActivityThread),
- REG_JNI(register_android_app_NativeActivity),
- REG_JNI(register_android_view_InputChannel),
- REG_JNI(register_android_view_InputEventReceiver),
- REG_JNI(register_android_view_KeyEvent),
- REG_JNI(register_android_view_MotionEvent),
- REG_JNI(register_android_view_PointerIcon),
- REG_JNI(register_android_view_VelocityTracker),
- REG_JNI(register_android_content_res_ObbScanner),
- REG_JNI(register_android_content_res_Configuration),
- REG_JNI(register_android_animation_PropertyValuesHolder),
- REG_JNI(register_com_android_internal_content_NativeLibraryHelper),
- };
复制代码
看到register_android_util_Log了吧
- int register_android_util_Log(JNIEnv* env)
- {
- jclass clazz = env->FindClass("android/util/Log");
- if (clazz == NULL) {
- ALOGE("Can't find android/util/Log");
- return -1;
- }
- levels.verbose = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "VERBOSE", "I"));
- levels.debug = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "DEBUG", "I"));
- levels.info = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "INFO", "I"));
- levels.warn = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "WARN", "I"));
- levels.error = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "ERROR", "I"));
- levels.assert = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "ASSERT", "I"));
- return AndroidRuntime::registerNativeMethods(env, "android/util/Log", gMethods, NELEM(gMethods));
- }
复制代码
动态注册完成,那共享库(.so)是在哪里加载的呢?
8、共享库加载
看当地实现文件的mk:frameworks\base\core\jni

编译的共享库为:LOCAL_MODULE:= libandroid_runtime
- ifeq ($(HAVE_SELINUX),true)
- LOCAL_C_INCLUDES += external/libselinux/include
- LOCAL_SHARED_LIBRARIES += libselinux
- LOCAL_CFLAGS += -DHAVE_SELINUX
- endif # HAVE_SELINUX
- ifeq ($(USE_OPENGL_RENDERER),true)
- LOCAL_SHARED_LIBRARIES += libhwui
- endif
- LOCAL_SHARED_LIBRARIES += \
- libdl
- # we need to access the private Bionic header
- # <bionic_tls.h> in com_google_android_gles_jni_GLImpl.cpp
- LOCAL_CFLAGS += -I$(LOCAL_PATH)/../../../../bionic/libc/private
- LOCAL_LDLIBS += -lpthread -ldl
- ifeq ($(WITH_MALLOC_LEAK_CHECK),true)
- LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK
- endif
- LOCAL_MODULE:= libandroid_runtime
- include $(BUILD_SHARED_LIBRARY)
- include $(call all-makefiles-under,$(LOCAL_PATH))
复制代码
而共享库LOCAL_MODULE:= libandroid_runtime又被编译到另一个共享库:LOCAL_MODULE:= libandroid_servers
frameworks\base\services\jni:
- LOCAL_PATH:= $(call my-dir)
- include $(CLEAR_VARS)
- LOCAL_SRC_FILES:= \
- com_android_server_AlarmManagerService.cpp \
- com_android_server_BatteryService.cpp \
- com_android_server_input_InputApplicationHandle.cpp \
- com_android_server_input_InputManagerService.cpp \
- com_android_server_input_InputWindowHandle.cpp \
- com_android_server_LightsService.cpp \
- com_android_server_power_PowerManagerService.cpp \
- com_android_server_SerialService.cpp \
- com_android_server_SystemServer.cpp \
- com_android_server_UsbDeviceManager.cpp \
- com_android_server_UsbHostManager.cpp \
- com_android_server_VibratorService.cpp \
- com_android_server_location_GpsLocationProvider.cpp \
- com_android_server_connectivity_Vpn.cpp \
- onload.cpp
- LOCAL_C_INCLUDES += \
- $(JNI_H_INCLUDE) \
- frameworks/base/services \
- frameworks/base/core/jni \
- external/skia/include/core \
- libcore/include \
- libcore/include/libsuspend \
- $(call include-path-for, libhardware)/hardware \
- $(call include-path-for, libhardware_legacy)/hardware_legacy \
- LOCAL_SHARED_LIBRARIES := \
- libandroid_runtime \
- libandroidfw \
- libcutils \
- libhardware \
- libhardware_legacy \
- libnativehelper \
- libsystem_server \
- libutils \
- libui \
- libinput \
- libskia \
- libgui \
- libusbhost \
- libsuspend
- ifeq ($(WITH_MALLOC_LEAK_CHECK),true)
- LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK
- endif
- LOCAL_MODULE:= libandroid_servers
- include $(BUILD_SHARED_LIBRARY)
复制代码
那就看共享库libandroid_servers是在那边加载的吧!
frameworks\base\services\java\com\android\server
- public static void main(String[] args) {
- if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
- // If a device's clock is before 1970 (before 0), a lot of
- // APIs crash dealing with negative numbers, notably
- // java.io.File#setLastModified, so instead we fake it and
- // hope that time from cell towers or NTP fixes it
- // shortly.
- Slog.w(TAG, "System clock is before 1970; setting to 1970.");
- SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
- }
- if (SamplingProfilerIntegration.isEnabled()) {
- SamplingProfilerIntegration.start();
- timer = new Timer();
- timer.schedule(new TimerTask() {
- @Override
- public void run() {
- SamplingProfilerIntegration.writeSnapshot("system_server", null);
- }
- }, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
- }
- // Mmmmmm... more memory!
- dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();
- // The system server has to run all of the time, so it needs to be
- // as efficient as possible with its memory usage.
- VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
- System.loadLibrary("android_servers");
- init1(args);
- }
复制代码
现在知道Log的JNI实现流程了吧?!!!
9、总结
JNI是Android开发中的一个重要工具,提供了Java代码与当地代码之间的桥梁。通过JNI,开发者可以在Java代码中调用高效的当地代码,访问特定硬件功能,以及重用现有的C/C++库。理解JNI的工作原理和使用方法,对于开发高性能、功能丰富的Android应用至关重要。
JNI(Java Native Interface)是Java平台的重要构成部分,允许Java代码与当地(通常是C/C++)代码进行互操纵。在Android开发中,JNI广泛应用于性能优化、硬件访问以及重用现有的当地库。以下是关于JNI使用的总结,包括其优缺点、使用场景、开发步调、注意事项以及最佳实践。
Android日志体系从应用步调层到JNI层、当地层、Logd保卫历程,再到Logcat工具,形成了一个完整的日志记载与查看的流程。通过分析各个层级的代码实现,可以更深入地理解日志体系的设计和工作原理。这些组件精密协作,提供了一个高效、可靠的日志记载和查看机制,资助开发者调试和监控应用步调。
欢迎点赞|关注|收藏|评论,您的肯定是我创作的动力 |
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |