首页 Android应用程序框架层和系统运行库层日志系统源代码分析

Android应用程序框架层和系统运行库层日志系统源代码分析

举报
开通vip

Android应用程序框架层和系统运行库层日志系统源代码分析Android应用程序框架层和系统运行库层日志系统源代码分析 在开开Android开用程序开~少不了使用Log来开控和开开程序的开行。在上一篇文章 Android 日志系开开开程序 Logger 源代开分析中~我开分析了开开程序Logger的源代开~在前面的文章 浅 开 Android 系开开开中 Log 的使用 一文~我开也开开介开在开用程序中使Log的方法~在开篇文章中~我开开开介开将Android开用程序架开和系开行开存开日志系开框运 的源代开~使得我开可以更好地理解Android的日志系开的开开。 我开在...

Android应用程序框架层和系统运行库层日志系统源代码分析
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接口, view plain 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, view plain 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.** ** 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) ((aGetStringUTFChars(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_ println_native }, 149.}; 150. 151.int register_android_util_Log(JNIEnv* env) 152.{ 153. jclass clazz = env->FindClass("android/util/Log"); 154. 155. if (clazz == NULL) { 156. LOGE("Can't find android/util/Log"); 157. return -1; 158. } 159. 160. levels.verbose = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "VERBOSE ", "I")); 161. levels.debug = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "DEBUG", "I ")); 162. levels.info = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "INFO", "I")); 163. levels.warn = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "WARN", "I")); 164. levels.error = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "ERROR", "I ")); 165. levels.assert = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "ASSERT", "I ")); 166. 167. return AndroidRuntime::registerNativeMethods(env, "android/util/Log", gMethods, NEL EM(gMethods)); 168.} 169. 170.}; // namespace android 在gMethods开量中~定开了println_native本地方法开开的函开用是数android_util_Log_println_native。在android_util_Log_println_native函中~通开数了各开开开正后~就开用行开开函参数确运数__android_log_buf_write来开开Log的入操写作。__android_log_buf_write函开开开在liblog开中~有它4个参数冲区~分开开ID、开先开开ID、Tag字符串和Msg字符串。下面行开开运liblog中的 __android_log_buf_write的开开。 三. 系开行开开日志系开的开开。运 在系开行开开运liblog开的开开中~容比开多~开里~我开只开注日志入操作内写 __android_log_buf_write的相开开开, view plain 1.int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg) 2.{ 3. struct iovec vec[3]; 4. 5. if (!tag) 6. tag = ""; 7. 8. /* XXX: This needs to go! */ 9. if (!strcmp(tag, "HTC_RIL") || 10. !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */ 11. !strcmp(tag, "AT") || 12. !strcmp(tag, "GSM") || 13. !strcmp(tag, "STK") || 14. !strcmp(tag, "CDMA") || 15. !strcmp(tag, "PHONE") || 16. !strcmp(tag, "SMS")) 17. bufID = LOG_ID_RADIO; 18. 19. vec[0].iov_base = (unsigned char *) &prio; 20. vec[0].iov_len = 1; 21. vec[1].iov_base = (void *) tag; 22. vec[1].iov_len = strlen(tag) + 1; 23. vec[2].iov_base = (void *) msg; 24. vec[2].iov_len = strlen(msg) + 1; 25. 26. return write_to_log(bufID, vec, 3); 27.} 函首先是开开开开的数来tag参数是否是开 HTC_RIL、RIL、AT、GSM、STK、CDMA、PHONE和SMS中的一~如果是个~ 就无件地使用条ID开LOG_ID_RADIO的日志开作开入开~接着~把开开的冲区写冲区来 参数prio、tag和msg分开存放在一向量开中~开用个数write_to_log函开入下一数来 步操作。write_to_log是一函指开~定开在文件开始的位置上,个数 view plain 1.static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr); 2.static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init; 且初始化开并__write_to_log_init函,数view plain 1.static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr) 2.{ 3.#ifdef HAVE_PTHREADS 4. pthread_mutex_lock(&log_init_lock); 5.#endif 6. 7. if (write_to_log == __write_to_log_init) { 8. log_fds[LOG_ID_MAIN] = log_open("/dev/"LOGGER_LOG_MAIN, O_WRONLY); 9. log_fds[LOG_ID_RADIO] = log_open("/dev/"LOGGER_LOG_RADIO, O_WRONLY); 10. log_fds[LOG_ID_EVENTS] = log_open("/dev/"LOGGER_LOG_EVENTS, O_WRONLY); 11. log_fds[LOG_ID_SYSTEM] = log_open("/dev/"LOGGER_LOG_SYSTEM, O_WRONLY); 12. 13. write_to_log = __write_to_log_kernel; 14. 15. if (log_fds[LOG_ID_MAIN] < 0 || log_fds[LOG_ID_RADIO] < 0 || 16. log_fds[LOG_ID_EVENTS] < 0) { 17. log_close(log_fds[LOG_ID_MAIN]); 18. log_close(log_fds[LOG_ID_RADIO]); 19. log_close(log_fds[LOG_ID_EVENTS]); 20. log_fds[LOG_ID_MAIN] = -1; 21. log_fds[LOG_ID_RADIO] = -1; 22. log_fds[LOG_ID_EVENTS] = -1; 23. write_to_log = __write_to_log_null; 24. } 25. 26. if (log_fds[LOG_ID_SYSTEM] < 0) { 27. log_fds[LOG_ID_SYSTEM] = log_fds[LOG_ID_MAIN]; 28. } 29. } 30. 31.#ifdef HAVE_PTHREADS 32. pthread_mutex_unlock(&log_init_lock); 33.#endif 34. 35. return write_to_log(log_id, vec, nr); 36.} 开里我开可以看到~如果是第一次开write_to_log函~数write_to_log == __write_to_log_init判开句就断会true~于是开行log_open函打开开开文件~把文数并 件描述符保存在log_fds数开中。如果打开/dev/LOGGER_LOG_SYSTEM文件失开~即log_fds[LOG_ID_SYSTEM] < 0~就把log_fds[LOG_ID_SYSTEM]开置开log_fds[LOG_ID_MAIN]~开就是我开上面描述的如果不存在ID开LOG_ID_SYSTEM的日志开~就把冲区LOG_ID_SYSTEM开置开和LOG_ID_MAIN开开的日志开了冲区。LOGGER_LOG_MAIN、LOGGER_LOG_RADIO、LOGGER_LOG_EVENTS和LOGGER_LOG_SYSTEM四宏定开在个system/core/include/cutils/logger.h文件中,view plain 1.#define LOGGER_LOG_MAIN "log/main" 2.#define LOGGER_LOG_RADIO "log/radio" 3.#define LOGGER_LOG_EVENTS "log/events" 4.#define LOGGER_LOG_SYSTEM "log/system" 接着~把write_to_log函指开指向数__write_to_log_kernel函,数view plain 1.static int __write_to_log_kernel(log_id_t log_id, struct iovec *vec, size_t nr) 2.{ 3. ssize_t ret; 4. int log_fd; 5. 6. if (/*(int)log_id >= 0 &&*/ (int)log_id < (int)LOG_ID_MAX) { 7. log_fd = log_fds[(int)log_id]; 8. } else { 9. return EBADF; 10. } 11. 12. do { 13. ret = log_writev(log_fd, vec, nr); 14. } while (ret < 0 && errno == EINTR); 15. 16. return ret; 17.} 函开用数log_writev来开开Log的入~注意~开里通开一循开入写个来写Log~直到入成功开止。开里写log_writev是一宏~在文件开始的地方定开开,个view plain 1.#if FAKE_LOG_DEVICE 2.// This will be defined when building for the host. 3.#define log_open(pathname, flags) fakeLogOpen(pathname, flags) 4.#define log_writev(filedes, vector, count) fakeLogWritev(filedes, vector, count) 5.#define log_close(filedes) fakeLogClose(filedes) 6.#else 7.#define log_open(pathname, flags) open(pathname, flags) 8.#define log_writev(filedes, vector, count) writev(filedes, vector, count) 9.#define log_close(filedes) close(filedes) 10.#endif 开里~我开看到~一般情下~况log_writev就是writev了~开是常开的批量文个件入函~就不多开了。写数 至些~整开用开程就开束了。开开一下~首先是开用程序开开用开用程序架开的个从框 Java接口~开用程序架开的框Java接口通开开用本开的JNI方法开入到系开行开开的运C接口~系开行开开的运C接口通开开开文件开开开核空开开的来内Logger开开程序。开是一典个型的开用开程~好地开开很Android的系开架~希望开者好好开。构会
本文档为【Android应用程序框架层和系统运行库层日志系统源代码分析】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_751406
暂无简介~
格式:doc
大小:48KB
软件:Word
页数:0
分类:生活休闲
上传时间:2017-12-21
浏览量:50