Android应用程序框架层和系统运行库层日志系统源代码分析.docx
《Android应用程序框架层和系统运行库层日志系统源代码分析.docx》由会员分享,可在线阅读,更多相关《Android应用程序框架层和系统运行库层日志系统源代码分析.docx(15页珍藏版)》请在冰豆网上搜索。
Android应用程序框架层和系统运行库层日志系统源代码分析
在开发Android应用程序时,少不了使用Log来监控和调试程序的执行。
在上一篇文章Android日志系统驱动程序Logger源代码分析中,我们分析了驱动程序Logger的源代码,在前面的文章浅谈Android系统开发中Log的使用一文,我们也简单介绍在应用程序中使Log的方法,在这篇文章中,我们将详细介绍Android应用程序框架层和系统运行库存层日志系统的源代码,使得我们可以更好地理解Android的日志系统的实现。
我们在Android应用程序,一般是调用应用程序框架层的Java接口(android.util.Log)来使用日志系统,这个Java接口通过JNI方法和系统运行库最终调用内核驱动程序Logger把Log写到内核空间中。
按照这个调用过程,我们一步步介绍Android应用程序框架层日志系统的源代码。
学习完这个过程之后,我们可以很好地理解Android系统的架构,即应用程序层(Application)的接口是如何一步一步地调用到内核空间的。
一.应用程序框架层日志系统Java接口的实现。
在浅谈Android系统开发中Log的使用一文中,我们曾经介绍过Android应用程序框架层日志系统的源代码接口。
这里,为了描述方便和文章的完整性,我们重新贴一下这部份的代码,在frameworks/base/core/java/android/util/Log.java文件中,实现日志系统的Java接口:
viewplain
1.................................................
2.
3.public final class Log {
4.
5.................................................
6.
7. /**
8. * Priority constant for the println method; use Log.v.
9. */
10. public static final int VERBOSE = 2;
11.
12. /**
13. * Priority constant for the println method; use Log.d.
14. */
15. public static final int DEBUG = 3;
16.
17. /**
18. * Priority constant for the println method; use Log.i.
19. */
20. public static final int INFO = 4;
21.
22. /**
23. * Priority constant for the println method; use Log.w.
24. */
25. public static final int WARN = 5;
26.
27. /**
28. * Priority constant for the println method; use Log.e.
29. */
30. public static final int ERROR = 6;
31.
32. /**
33. * Priority constant for the println method.
34. */
35. public static final int ASSERT = 7;
36.
37......................................................
38.
39. public static int v(String tag, String msg) {
40. return println_native(LOG_ID_MAIN, VERBOSE, tag, msg);
41. }
42.
43. public static int v(String tag, String msg, Throwable tr) {
44. return println_native(LOG_ID_MAIN, VERBOSE, tag, msg + '\n' + getStackTraceString(tr));
45. }
46.
47. public static int d(String tag, String msg) {
48. return println_native(LOG_ID_MAIN, DEBUG, tag, msg);
49. }
50.
51. public static int d(String tag, String msg, Throwable tr) {
52. return println_native(LOG_ID_MAIN, DEBUG, tag, msg + '\n' + getStackTraceString(tr));
53. }
54.
55. public static int i(String tag, String msg) {
56. return println_native(LOG_ID_MAIN, INFO, tag, msg);
57. }
58.
59. public static int i(String tag, String msg, Throwable tr) {
60. return println_native(LOG_ID_MAIN, INFO, tag, msg + '\n' + getStackTraceString(tr));
61. }
62.
63. public static int w(String tag, String msg) {
64. return println_native(LOG_ID_MAIN, WARN, tag, msg);
65. }
66.
67. public static int w(String tag, String msg, Throwable tr) {
68. return println_native(LOG_ID_MAIN, WARN, tag, msg + '\n' + getStackTraceString(tr));
69. }
70.
71. public static int w(String tag, Throwable tr) {
72. return println_native(LOG_ID_MAIN, WARN, tag, getStackTraceString(tr));
73. }
74.
75. public static int e(String tag, String msg) {
76. return println_native(LOG_ID_MAIN, ERROR, tag, msg);
77. }
78.
79. public static int e(String tag, String msg, Throwable tr) {
80. return println_native(LOG_ID_MAIN, ERROR, tag, msg + '\n' + getStackTraceString(tr));
81. }
82.
83...................................................................
84. /** @hide */ public static native int LOG_ID_MAIN = 0;
85. /** @hide */ public static native int LOG_ID_RADIO = 1;
86. /** @hide */ public static native int LOG_ID_EVENTS = 2;
87. /** @hide */ public static native int LOG_ID_SYSTEM = 3;
88.
89. /** @hide */ public static native int println_native(int bufID,
90. int priority, String tag, String msg);
91.}
定义了2~7一共6个日志优先级别ID和4个日志缓冲区ID。
回忆一下Android日志系统驱动程序Logger源代码分析一文,在Logger驱动程序模块中,定义了log_main、log_events和log_radio三个日志缓冲区,分别对应三个设备文件/dev/log/main、/dev/log/events和/dev/log/radio。
这里的4个日志缓冲区的前面3个ID就是对应这三个设备文件的文件描述符了,在下面的章节中,我们将看到这三个文件描述符是如何创建的。
在下载下来的Android内核源代码中,第4个日志缓冲区LOG_ID_SYSTEM并没有对应的设备文件,在这种情况下,它和LOG_ID_MAIN对应同一个缓冲区ID,在下面的章节中,我们同样可以看到这两个ID是如何对应到同一个设备文件的。
在整个Log接口中,最关键的地方声明了println_native本地方法,所有的Log接口都是通过调用这个本地方法来实现Log的定入。
下面我们就继续分析这个本地方法println_native。
二. 应用程序框架层日志系统JNI方法的实现。
在frameworks/base/core/jni/android_util_Log.cpp文件中,实现JNI方法println_native:
viewplain
1./* //device/libs/android_runtime/android_util_Log.cpp
2.**
3.** Copyright 2006, The Android Open Source Project
4.**
5.** Licensed under the Apache License, Version 2.0 (the "License");
6.** you may not use this file except in compliance with the License.
7.** You may obtain a copy of the License at
8.**
9.** http:
//www.apache.org/licenses/LICENSE-2.0
10.**
11.** Unless required by applicable law or agreed to in writing, software
12.** distributed under the License is distributed on an "AS IS" BASIS,
13.** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14.** See the License for the specific language governing permissions and
15.** limitations under the License.
16.*/
17.
18.#define LOG_NAMESPACE "log.tag."
19.#define LOG_TAG "Log_println"
20.
21.#include
22.#include
23.#include
24.#include
25.
26.#include "jni.h"
27.#include "utils/misc.h"
28.#include "android_runtime/AndroidRuntime.h"
29.
30.#define MIN(a,b) ((a
a:
b)
31.
32.namespace android {
33.
34.struct levels_t {
35. jint verbose;
36. jint debug;
37. jint info;
38. jint warn;
39. jint error;
40. jint assert;
41.};
42.static levels_t levels;
43.
44.static int toLevel(const char* value)
45.{
46. switch (value[0]) {
47. case 'V':
return levels.verbose;
48. case 'D':
return levels.debug;
49. case 'I':
return levels.info;
50. case 'W':
return levels.warn;
51. case 'E':
return levels.error;
52. case 'A':
return levels.assert;
53. case 'S':
return -1; // SUPPRESS
54. }
55. return levels.info;
56.}
57.
58.static jboolean android_util_Log_isLoggable(JNIEnv* env, jobject clazz, jstring tag, jint level)
59.{
60.#ifndef HAVE_ANDROID_OS
61. return false;
62.#else /* HAVE_ANDROID_OS */
63. int len;
64. char key[PROPERTY_KEY_MAX];
65. char buf[PROPERTY_VALUE_MAX];
66.
67. if (tag == NULL) {
68. return false;
69. }
70.
71. jboolean result = false;
72.
73. const char* chars = env->GetStringUTFChars(tag, NULL);
74.
75. if ((strlen(chars)+sizeof(LOG_NAMESPACE)) > PROPERTY_KEY_MAX) {
76. jclass clazz = env->FindClass("java/lang/IllegalArgumentException");
77. char buf2[200];
78. snprintf(buf2, sizeof(buf2), "Log tag \"%s\" exceeds limit of %d characters\n",
79. chars, PROPERTY_KEY_MAX - sizeof(LOG_NAMESPACE));
80.
81. // release the chars!
82. env->ReleaseStringUTFChars(tag, chars);
83.
84. env->ThrowNew(clazz, buf2);
85. return false;
86. } else {
87. strncpy(key, LOG_NAMESPACE, sizeof(LOG_NAMESPACE)-1);
88. strcpy(key + sizeof(LOG_NAMESPACE) - 1, chars);
89. }
90.
91. env->ReleaseStringUTFChars(tag, chars);
92.
93. len = property_get(key, buf, "");
94. int logLevel = toLevel(buf);
95. return (logLevel >= 0 && level >= logLevel) ?
true :
false;
96.#endif /* HAVE_ANDROID_OS */
97.}
98.
99./*
100. * In class android.util.Log:
101. * public static native int println_native(int buffer, int priority, String tag, String msg)
102. */
103.static jint android_util_Log_println_native(JNIEnv* env, jobject clazz,
104. jint bufID, jint priority, jstring tagObj, jstring msgObj)
105.{
106. const char* tag = NULL;
107. const char* msg = NULL;
108.
109. if (msgObj == NULL) {
110. jclass npeClazz;
111.
112. npeClazz = env->FindClass("java/lang/NullPointerException");
113. assert(npeClazz !
= NULL);
114.
115. env->ThrowNew(npeClazz, "println needs a message");
116. return -1;
117. }
118.
119. if (bufID < 0 || bufID >= LOG_ID_MAX) {
120. jclass npeClazz;
121.
122. npeClazz = env->FindClass("java/lang/NullPointerException");
123. assert(npeClazz !
= NULL);
124.
125. env->ThrowNew(npeClazz, "bad bufID");
126. return -1;
127. }
128.
129. if (tagObj !
= NULL)
130. tag = env->GetStringUTFChars(tagObj, NULL);
131. msg = env->GetStringUTFChars(msgObj, NULL);
132.
133. int res = __android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg);
134.
135. if (tag !
= NULL)
136. env->ReleaseStringUTFChars(tagObj, tag);
137. env->ReleaseStringUTFChars(msgObj, msg);
138.
139. return res;
140.}
141.
142./*
143. * JNI registration.
144. */
145.static JNINativeMethod gMethods[] = {
146. /* name, signature, funcPtr */
147. { "isLoggable", "(Ljava/lang/String;I)Z", (void*) android_util_Log_isLoggable },
148. { "println_native", "(IILjava/lang/String;Ljava/lang/String;)I", (void*) android_util_Log