Android 系统日志(Log) JNI实现流程源码分析

news2024/9/23 13:29:09

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_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实现流程了吧?!!!

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工具,形成了一个完整的日志记录与查看的流程。通过分析各个层级的代码实现,可以更深入地理解日志系统的设计和工作原理。这些组件紧密协作,提供了一个高效、可靠的日志记录和查看机制,帮助开发者调试和监控应用程序。

欢迎点赞|关注|收藏|评论,您的肯定是我创作的动力

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1701784.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

无人机助力光伏项目测绘建模

随着全球对可再生能源需求的不断增长&#xff0c;光伏项目作为其中的重要一环&#xff0c;其建设规模和速度都在不断提高。在这一背景下&#xff0c;如何高效、准确地完成光伏项目的测绘与建模工作&#xff0c;成为了行业发展的重要课题。近年来&#xff0c;无人机技术的快速发…

帝国CMS如何修改时间格式,变成几分钟,几小时教程

该插件已经在帝国cms6.6上测试通过&#xff0c;至于其他版本&#xff0c;请自行测试。 目前支持&#xff1a;标签模板&#xff0c;列表模板&#xff0c;内容模板 安装说明&#xff1a; 把以下的内容复制到 /e/class/userfun.php 文件里&#xff08;放在<?php和?>之间…

亚马逊云科技专家分享 | OPENAIGC开发者大赛能量加油站6月5日场预约开启~

由联想拯救者、AIGC开放社区、英特尔联合主办的“AI生成未来第二届拯救者杯OPENAIGC开发者大赛”自上线以来&#xff0c;吸引了广大开发者的热情参与。 为了向技术开发者、业务人员、高校学生、以及个体创业人员等参赛者们提供更充分的帮助与支持&#xff0c;AIGC开放社区特别…

eNSP华为模拟器-DHCP配置

拓扑图 要求 PC1通过DHCP获取192.168.1.1地址PC2和PC3通过DHCP接口地址池方式获取IP地址配置静态路由使其ping通 配置 配置主机名及接口IP地址 # AR1 <Huawei>sys Enter system view, return user view with CtrlZ. [Huawei]sys AR1 [AR1]int g0/0/0 [AR1-Gigabit…

『ZJUBCA Weekly Feed 07』MEV | AO超并行计算机 | Eigen layer AVS生态

一文读懂MEV&#xff1a;区块链的黑暗森林法则 01 &#x1f4a1;TL;DR 这篇文章介绍了区块链中的最大可提取价值&#xff08;MEV&#xff09;概念&#xff0c;MEV 让矿工和验证者通过抢先交易、尾随交易和三明治攻击等手段获利&#xff0c;但也导致网络拥堵和交易费用增加。为了…

微信小程序进阶(1)--自定义组件

自定义组件 1.1 什么是自定义组件 开发文档&#xff1a;https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/ 小程序中常常会有些通用的交互模块&#xff0c;比如&#xff1a;下拉选择列表、搜索框、日期选择器等&#xff1b;这些界面交互模块可…

c语言--结构体

前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 结构体概念简介 c语言数组是一些相同类型的数据的集合。 这个结构体就是一些可以是不同类型的集合。 比如描述班里的一个人&#xff0c;他可能需要名字(字符串),也需要年龄(整数)。 这种情况就需要用结构体。 …

苹果手机备忘录共享到微信,为何显示不支持的类型

作为一名苹果手机用户&#xff0c;我深知其系统的流畅与便捷。然而&#xff0c;在日常使用中&#xff0c;我发现了一个令人不解的问题&#xff1a;为何苹果手机的原生备忘录无法直接分享到微信&#xff1f;每次当我尝试将备忘录里的内容共享给微信好友时&#xff0c;总会遇到“…

六西格玛培训的讲师应该具备哪些能力?

六西格玛培训的讲师作为专业知识的传授者和实践经验的分享者&#xff0c;其能力水平的高低直接决定了培训效果的好坏。那么&#xff0c;一个优秀的六西格玛培训讲师应该具备哪些能力呢&#xff1f;深圳天行健企业管理咨询公司解析如下&#xff1a; 首先&#xff0c;六西格玛培训…

AIGC行业的发展前景与市场需求

简介&#xff1a;探讨当前时机是否适合进入AIGC行业&#xff0c;考虑行业发展阶段和市场需求。 方向一&#xff1a;行业前景 AIGC&#xff08;人工智能生成内容&#xff09;行业是近年来随着人工智能技术的快速发展而兴起的一个新兴领域&#xff0c;它涉及到使用人工智能技术来…

R实验 随机变量及其分布

实验目的&#xff1a; 掌握常见几种离散性随机变量及其分布在R语言中对应的函数用法&#xff1b;掌握常见几种连续性随机变量及其分布在R语言中对应的函数用法&#xff1b;掌握统计量的定义及统计三大抽样分布在R语言中对应的函数用法。 实验内容&#xff1a; &#xff08;习题…

PyTorch的数据处理

&#x1f4a5;今天看一下 PyTorch数据通常的处理方法~ 一般我们会将dataset用来封装自己的数据集&#xff0c;dataloader用于读取数据 Dataset格式说明 &#x1f4ac;dataset定义了这个数据集的总长度&#xff0c;以及会返回哪些参数&#xff0c;模板&#xff1a; from tor…

element ui 的el-input输入一个字后失去焦点,需重新点击输入框才能再次输入!

解决方案&#xff1a; 我是form表单嵌套表格&#xff0c;里面的el-input输入框&#xff0c;输入第一个值的时候会突然失去焦点&#xff0c;需要再次点击输入框才能正常输入&#xff0c;原因是table的key值&#xff0c;需要改成正常的index即可&#xff0c;如果你是循环的&…

进化计算引领深度学习新纪元

《进化深度学习》介绍了进化计算(EC)&#xff0c;并为你提供了一套实用的技术工具&#xff0c;你可以在整个深度学习过程中应用这些技术。本书提供了遗传算法和进化计算方法在网络拓扑、生成模型、强化学习等方面的应用。通过交互式的Colab notebook使你有机会在探索过程中进行…

day15

第一题 1419. 数青蛙 本题主要是采用模拟的解题思路&#xff0c;用一个croak来模拟青蛙的叫声&#xff0c;在一堆字符串中来找到几个croak&#xff0c;并判断这是由几个青蛙叫的&#xff1b; 首先我们使用数组来模拟hash表&#xff0c;其次我们使用hash表来映射青蛙叫的字符中…

smart-link + STP的vlan映射 + monitor-link实现二层链路的负载均衡+主备切换

一、适用场景 1、保护原有投资&#xff0c;不浪费原有网络设备及链路的投资&#xff1b; 2、对高可靠、高可用要求的业务&#xff0c;链路中的设备、接头、线路故障时&#xff0c;毫秒级切换&#xff0c;不影响业务的运行&#xff1b; 3、使用华为、华三智能管理型的交换设备&…

香橙派 AIpro评测

一. 香橙派AIpro开箱 官网外观&#xff1a; ​ ​ 外观实测&#xff1a;做工精致&#xff0c;散热片有精致的金属感 ​ ​ 反面&#xff1a;由于加装了wifi蓝牙模块&#xff0c;如果需要做外壳&#xff0c;需要注意保护天线贴片。在树莓派pi5的前面一版&#xff0c;增加了wifi…

MedSegDiff: Medical Image Segmentation with Diffusion Probabilistic Model 论文总结

题目&#xff1a;MedSegDiff: Medical Image Segmentation&#xff08;图像分割&#xff09;with Diffusion Probabilistic Model&#xff08;扩散概率模型&#xff09; 论文&#xff08;MIDL会议&#xff09;&#xff1a;MedSegDiff: Medical Image Segmentation with Diffusi…

【数组】Leetcode 452. 用最少数量的箭引爆气球【中等】

用最少数量的箭引爆气球 有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points &#xff0c;其中points[i] [xstart, xend] 表示水平直径在 xstart 和 xend之间的气球。你不知道气球的确切 y 坐标。 一支弓箭可以沿着 x 轴从不同点 完全垂直 地…

Linux C++ Socket 套接字、select、poll、epoll 实例

文章目录 1. 概述2. TCP 网络编程实例2.1 服务器端2.2 客户端2.3 运行截图 3. I/O 模型3.1 阻塞式I/O模型3.2 非阻塞I/O模型3.3 I/O 复用模型3.4 信号驱动式I/O3.5 异步I/O模型 4. I/O复用之 select4.1 select 函数描述4.2 服务端代码4.3 客户端代码4.4 运行截图 5. I/O复用之 …