赞
踩
Java Native Interface (JNI) 是一种编程框架,使得Java代码能够与用其他编程语言(如C和C++)编写的本地代码进行交互。JNI允许Java代码调用本地代码的函数,也允许本地代码调用Java代码的函数。下面是对JNI机制的详细概述,包括其基本原理、工作流程、常见用途和示例代码。
JNI的核心原理是通过一个标准化的接口,使得Java虚拟机(JVM)和本地代码可以互相通信和操作。JNI提供了一套函数,这些函数可以在本地代码中使用,以便与JVM交互,例如创建和操作Java对象,调用Java方法,处理异常等。
使用JNI的工作流程通常包括以下几个步骤:
1、声明本地方法:在Java类中声明native方法。
2、加载本地库:在Java类中加载包含本地方法实现的库。
3、生成头文件:使用javac和javah工具生成包含native方法声明的头文件。
4、实现本地方法:在C/C++中实现native方法。
5、编译本地库:编译C/C++代码生成共享库。
6、调用本地方法:在Java代码中调用native方法。
JNI常用于以下几种场景:
1、性能优化:将性能关键的部分用C/C++实现,以提高执行效率。
2、访问底层系统资源:访问操作系统的底层功能或硬件资源。
3、重用现有库:调用已有的C/C++库或API。
4、实现平台特定功能:在跨平台应用中实现特定平台的功能。
1、性能优化:可以使用高效的本地代码,尤其是在性能关键的部分。
2、硬件访问:能够直接访问Java API不提供的底层硬件功能。
3、代码复用:重用现有的C/C++库,无需重新实现复杂的逻辑。
4、多语言互操作:可以在同一个应用中使用多种编程语言,各取所长。
1、复杂性增加:引入了额外的复杂性,需要了解C/C++和JNI API。
2、平台依赖性:本地代码需要针对不同的平台编译,增加了维护成本。
3、内存管理:需要手动管理内存,容易出现内存泄漏和指针错误。
4、调试困难:调试JNI代码比纯Java代码困难,需要使用特定的工具和方法。
1、性能优化:在需要大量计算或复杂逻辑的地方使用本地代码。
2、硬件功能:访问摄像头、传感器等底层硬件功能。
3、现有库:使用已有的C/C++库,例如图像处理库、加密库等。
4、跨语言调用:在需要与其他编程语言互操作时,例如从Java调用C++代码。
Android日志系统主要由Log类和__android_log_print等C/C++函数组成,提供了记录调试信息的功能。Java层的日志API(如android.util.Log)最终调用的是本地日志函数,这些函数将日志消息写入系统日志缓冲区。
要深入了解Android Log的JNI实现流程,我们需要从JNI机制、Android日志系统、JNI方法实现及其相互配合的细节等方面进行详细分析。
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);
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; }
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)是在哪里加载的呢?
看本地实现文件的mk:frameworks\base\core\jni
LOCAL_SRC_FILES:= \ AndroidRuntime.cpp \ Time.cpp \ com_android_internal_content_NativeLibraryHelper.cpp \ com_google_android_gles_jni_EGLImpl.cpp \ com_google_android_gles_jni_GLImpl.cpp.arm \ android_app_NativeActivity.cpp \ android_opengl_EGL14.cpp \ android_opengl_GLES10.cpp \ android_opengl_GLES10Ext.cpp \ android_opengl_GLES11.cpp \ android_opengl_GLES11Ext.cpp \ android_opengl_GLES20.cpp \ android_database_CursorWindow.cpp \ android_database_SQLiteCommon.cpp \ android_database_SQLiteConnection.cpp \ android_database_SQLiteGlobal.cpp \ android_database_SQLiteDebug.cpp \ android_emoji_EmojiFactory.cpp \ android_view_DisplayEventReceiver.cpp \ android_view_Surface.cpp \ android_view_SurfaceSession.cpp \ android_view_TextureView.cpp \ android_view_InputChannel.cpp \ android_view_InputDevice.cpp \ android_view_InputEventReceiver.cpp \ android_view_KeyEvent.cpp \ android_view_KeyCharacterMap.cpp \ android_view_HardwareRenderer.cpp \ android_view_GLES20DisplayList.cpp \ android_view_GLES20Canvas.cpp \ android_view_MotionEvent.cpp \ android_view_PointerIcon.cpp \ android_view_VelocityTracker.cpp \ android_text_AndroidCharacter.cpp \ android_text_AndroidBidi.cpp \ android_os_Debug.cpp \ android_os_FileUtils.cpp \ android_os_MemoryFile.cpp \ android_os_MessageQueue.cpp \ android_os_ParcelFileDescriptor.cpp \ android_os_Parcel.cpp \ android_os_SELinux.cpp \ android_os_SystemClock.cpp \ android_os_SystemProperties.cpp \ android_os_Trace.cpp \ android_os_UEventObserver.cpp \ android_net_LocalSocketImpl.cpp \ android_net_NetUtils.cpp \ android_net_TrafficStats.cpp \ android_net_wifi_Wifi.cpp \ android_nio_utils.cpp \ android_text_format_Time.cpp \ android_util_AssetManager.cpp \ android_util_Binder.cpp \ android_util_EventLog.cpp \ android_util_Log.cpp \ android_util_FloatMath.cpp \ android_util_Process.cpp \ android_util_StringBlock.cpp \ android_util_XmlBlock.cpp \ android/graphics/AutoDecodeCancel.cpp \ android/graphics/Bitmap.cpp \ android/graphics/BitmapFactory.cpp \ android/graphics/Camera.cpp \ android/graphics/Canvas.cpp \ android/graphics/ColorFilter.cpp \ android/graphics/DrawFilter.cpp \ android/graphics/CreateJavaOutputStreamAdaptor.cpp \ android/graphics/Graphics.cpp \ android/graphics/HarfbuzzSkia.cpp \ android/graphics/Interpolator.cpp \ android/graphics/LayerRasterizer.cpp \ android/graphics/MaskFilter.cpp \ android/graphics/Matrix.cpp \ android/graphics/Movie.cpp \ android/graphics/NinePatch.cpp \ android/graphics/NinePatchImpl.cpp \ android/graphics/NinePatchPeeker.cpp \ android/graphics/Paint.cpp \ android/graphics/Path.cpp \ android/graphics/PathMeasure.cpp \ android/graphics/PathEffect.cpp \ android_graphics_PixelFormat.cpp \ android/graphics/Picture.cpp \ android/graphics/PorterDuff.cpp \ android/graphics/BitmapRegionDecoder.cpp \ android/graphics/Rasterizer.cpp \ android/graphics/Region.cpp \ android/graphics/Shader.cpp \ android/graphics/SurfaceTexture.cpp \ android/graphics/TextLayout.cpp \ android/graphics/TextLayoutCache.cpp \ android/graphics/Typeface.cpp \ android/graphics/Utils.cpp \ android/graphics/Xfermode.cpp \ android/graphics/YuvToJpegEncoder.cpp \ android_media_AudioRecord.cpp \ android_media_AudioSystem.cpp \ android_media_AudioTrack.cpp \ android_media_JetPlayer.cpp \ android_media_RemoteDisplay.cpp \ android_media_ToneGenerator.cpp \ android_hardware_Camera.cpp \ android_hardware_SensorManager.cpp \ android_hardware_SerialPort.cpp \ android_hardware_UsbDevice.cpp \ android_hardware_UsbDeviceConnection.cpp \ android_hardware_UsbRequest.cpp \ android_debug_JNITest.cpp \ android_util_FileObserver.cpp \ android/opengl/poly_clip.cpp.arm \ android/opengl/util.cpp.arm \ android_server_NetworkManagementSocketTagger.cpp \ android_server_Watchdog.cpp \ android_ddm_DdmHandleNativeHeap.cpp \ com_android_internal_os_ZygoteInit.cpp \ android_backup_BackupDataInput.cpp \ android_backup_BackupDataOutput.cpp \ android_backup_FileBackupHelperBase.cpp \ android_backup_BackupHelperDispatcher.cpp \ android_app_backup_FullBackup.cpp \ android_content_res_ObbScanner.cpp \ android_content_res_Configuration.cpp \ android_animation_PropertyValuesHolder.cpp
编译的共享库为: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实现流程了吧?!!!
JNI是Android开发中的一个重要工具,提供了Java代码与本地代码之间的桥梁。通过JNI,开发者可以在Java代码中调用高效的本地代码,访问特定硬件功能,以及重用现有的C/C++库。理解JNI的工作原理和使用方法,对于开发高性能、功能丰富的Android应用至关重要。
JNI(Java Native Interface)是Java平台的重要组成部分,允许Java代码与本地(通常是C/C++)代码进行互操作。在Android开发中,JNI广泛应用于性能优化、硬件访问以及重用现有的本地库。以下是关于JNI使用的总结,包括其优缺点、使用场景、开发步骤、注意事项以及最佳实践。
Android日志系统从应用程序层到JNI层、本地层、Logd守护进程,再到Logcat工具,形成了一个完整的日志记录与查看的流程。通过分析各个层级的代码实现,可以更深入地理解日志系统的设计和工作原理。这些组件紧密协作,提供了一个高效、可靠的日志记录和查看机制,帮助开发者调试和监控应用程序。
欢迎点赞|关注|收藏|评论,您的肯定是我创作的动力 |
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。