android log
21746 ワード
Android logの重要性は言うまでもなく、私たちが問題を分析する根拠であり、コードを理解する良いアシスタントです.本文は以下の2つの方面からlogに対していくつか簡単な総括をします:1.ログ分類2.ログ印刷制御
1.ログ分類
Androidで印刷されたロゴは以下の種類に分けられます:1.main log 2. sytem log 3. radio log 4. event log 5. kernel log 6. crash log 7. security logこれらのlogはsystem/core/liblog/Logger_ですwrite.c印刷を除去する;分類はLog_id.hでは定義されています.
私のAP側の研究開発にとって、よく印刷するロゴは前の4種類です.印刷logで呼び出すクラスはandroidである.util.Log. android.util.Log.JAva内では、よく使われる4中のlogも定義されています.
main logを印刷する場合はandroidを直接呼び出します.util.ログの中の方法でいいです.system logを印刷する場合はandroidを呼び出すことができる.util.Slog. event logを印刷する場合はandroidを呼び出すことができます.utile.Eventlog. radio logを印刷する場合はandroidを呼び出すことができます.telephony.Rlog. 上のいくつかのクラスは印刷するカテゴリを書いただけで、もちろん実際の開発ではカスタマイズされたツールlogクラスを包装し、印刷をよりよく制御することができます.
2.Log印刷制御——adbコマンドでpropertyを設定することでlogの印刷を制御できる
logの印刷はリソースを消費し、一部のlogには機密情報が含まれているため、logの印刷を制御する必要がある.
仕事の中でよく見られるlog印刷制御方式は、DBGがtrueやfalseのような比較的簡単な制御である可能性がある.propertyなどによって制御される可能性もあります.これは一般的に私たちが自分でロゴをコントロールする方法で、何も言うことはありません.
Androidソース生もlogの制御メカニズムを提供しており、このメカニズムを理解した後、adbコマンドを使用してpropertyを設定することでlogの印刷を制御することができます.以下、このメカニズムについて説明します.
androidでもtelephonu.Rlogかandroidかutil.Slogはandroidを通じてutil.logのnative方法Log.println_nativeでlogを印刷します.対応するjniファイルはandroid_util_Log.cpp.android.util.logはまたnativeメソッドisLoggable(String tag,int level)を提供し、このメソッドは現在のlevelのlogが印刷できるかどうかを判断するために使用することができる.isLoggableメソッドandroid_util_Log.cppでの対応方法はandroid_util_Log_isLoggable.
android_util_Log_isLoggableは関数isLoggableを呼び出しました.この関数は簡単です.
__android_log_is_loggableはpropertiesです.cで定義されている(関数__android_log_level(const char*tag,size_t len,int default_prio)は、Android N上で/system/core/liblog/log_に定義されているis_loggable.cではAndroid Oがpropertiesに置かれています.cファイル内).
この関数は呼び出しによって_android_log_レベルはtagが設定したレベルを取得し、デフォルトはANDROID_です.LOG_INFO. 次に見てみましょうandroid_log_levelは、指定したtagに対応するlevelをどのように取得するか.
上の関数が完成した論理は、本当にpropertyを実行して検索したのは関数refresh_です.Cache(struct cache_char*cache,const char*key)、この関数は言わないで、比較的簡単です.
私たちは普段仕事中で、いくつかのロゴを印刷するために、携帯電話/dataディレクトリの下でpush localをよく使います.prop.
local.propファイルの内容は以下の通りです.
携帯電話が再起動するとinitは/data/localをロードします.propでは、ファイルの内容がpropertyとしてロードされます.したがって、log文が実行されると、_android_log_レベルは、対応するpropertyを調べ、設定したレベルを取得できます.実はpushファイルは少し煩雑で、上の分析によると、adbコマンドでproperty制御log出力を設定することができます(有効でなければ、携帯電話を再起動してから試してもいいです).使用できるproperty nameは次のとおりです. log.tag.* (起動時に失われる) persist.log.tag.* persist.log(優先度は前の2つより低いので、前の2つが設定されている場合は、後の2つは有効ではありません) [例1]Telecomをtagとしたすべてのlogを出力するには、以下の方法を用いることができる.adb shell setprop log.tag.Telecom Vまたはadb shell setprop persist.log.tag.Telecom V
[例2]以下のコマンドは、そのためのlogを出力することができますが、使用は推奨されません.logが多すぎると表示に不便をもたらす可能性があります.adb shell setprop persist.log V
1.ログ分類
Androidで印刷されたロゴは以下の種類に分けられます:1.main log 2. sytem log 3. radio log 4. event log 5. kernel log 6. crash log 7. security logこれらのlogはsystem/core/liblog/Logger_ですwrite.c印刷を除去する;分類はLog_id.hでは定義されています.
typedef enum log_id {
LOG_ID_MIN = 0,
LOG_ID_MAIN = 0,
LOG_ID_RADIO = 1,
LOG_ID_EVENTS = 2,
LOG_ID_SYSTEM = 3,
LOG_ID_CRASH = 4,
LOG_ID_SECURITY = 5,
LOG_ID_KERNEL = 6, /* place last, third-parties can not use it */
LOG_ID_MAX
} log_id_t;
#endif
私のAP側の研究開発にとって、よく印刷するロゴは前の4種類です.印刷logで呼び出すクラスはandroidである.util.Log. android.util.Log.JAva内では、よく使われる4中のlogも定義されています.
/** @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 final int LOG_ID_CRASH = 4;
main logを印刷する場合はandroidを直接呼び出します.util.ログの中の方法でいいです.system logを印刷する場合はandroidを呼び出すことができる.util.Slog. event logを印刷する場合はandroidを呼び出すことができます.utile.Eventlog. radio logを印刷する場合はandroidを呼び出すことができます.telephony.Rlog. 上のいくつかのクラスは印刷するカテゴリを書いただけで、もちろん実際の開発ではカスタマイズされたツールlogクラスを包装し、印刷をよりよく制御することができます.
2.Log印刷制御——adbコマンドでpropertyを設定することでlogの印刷を制御できる
logの印刷はリソースを消費し、一部のlogには機密情報が含まれているため、logの印刷を制御する必要がある.
仕事の中でよく見られるlog印刷制御方式は、DBGがtrueやfalseのような比較的簡単な制御である可能性がある.propertyなどによって制御される可能性もあります.これは一般的に私たちが自分でロゴをコントロールする方法で、何も言うことはありません.
......
if (DBG) {
//log
}
......
Androidソース生もlogの制御メカニズムを提供しており、このメカニズムを理解した後、adbコマンドを使用してpropertyを設定することでlogの印刷を制御することができます.以下、このメカニズムについて説明します.
androidでもtelephonu.Rlogかandroidかutil.Slogはandroidを通じてutil.logのnative方法Log.println_nativeでlogを印刷します.対応するjniファイルはandroid_util_Log.cpp.android.util.logはまたnativeメソッドisLoggable(String tag,int level)を提供し、このメソッドは現在のlevelのlogが印刷できるかどうかを判断するために使用することができる.isLoggableメソッドandroid_util_Log.cppでの対応方法はandroid_util_Log_isLoggable.
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 = isLoggable(chars, level);
env->ReleaseStringUTFChars(tag, chars);
return result;
}
android_util_Log_isLoggableは関数isLoggableを呼び出しました.この関数は簡単です.
static jboolean isLoggable(const char* tag, jint level) {
return __android_log_is_loggable(level, tag, ANDROID_LOG_INFO);
}
__android_log_is_loggableはpropertiesです.cで定義されている(関数__android_log_level(const char*tag,size_t len,int default_prio)は、Android N上で/system/core/liblog/log_に定義されているis_loggable.cではAndroid Oがpropertiesに置かれています.cファイル内).
LIBLOG_ABI_PUBLIC int __android_log_is_loggable(int prio, const char* tag,
int default_prio) {
int logLevel =
__android_log_level(tag, (tag && *tag) ? strlen(tag) : 0, default_prio);
return logLevel >= 0 && prio >= logLevel;
}
この関数は呼び出しによって_android_log_レベルはtagが設定したレベルを取得し、デフォルトはANDROID_です.LOG_INFO. 次に見てみましょうandroid_log_levelは、指定したtagに対応するlevelをどのように取得するか.
static int __android_log_level(const char* tag, size_t len, int default_prio) {
/* sizeof() is used on this array below */
static const char log_namespace[] = "persist.log.tag.";//property , property。
static const size_t base_offset = 8; /* skip "persist." */
/* calculate the size of our key temporary buffer */
const size_t taglen = tag ? len : 0;
/* sizeof(log_namespace) = strlen(log_namespace) + 1 */
char key[sizeof(log_namespace) + taglen];// key , property,e.x. persist.log.tag.TelecomFramework
char* kp;
size_t i;
char c = 0;
/*
* Single layer cache of four properties. Priorities are:
* log.tag.
* persist.log.tag.
* log.tag
* persist.log.tag
* Where the missing tag matches all tags and becomes the
* system global default. We do not support ro.log.tag* .
*/
static char* last_tag;// , ; tag。
static size_t last_tag_len;// ; tag 。
static uint32_t global_serial;// ; property 。
/* some compilers erroneously see uninitialized use. !not_locked */
uint32_t current_global_serial = 0;
static struct cache_char tag_cache[2];// ; 。
static struct cache_char global_cache[2];// ; 。
int change_detected;
int global_change_detected;
int not_locked;
strcpy(key, log_namespace);
global_change_detected = change_detected = not_locked = lock();// 0, 0 。
// property 。
if (!not_locked) {// lock
/*
* check all known serial numbers to changes.
*/
for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
if (check_cache(&tag_cache[i].cache)) {
change_detected = 1;
}
}
for (i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) {
if (check_cache(&global_cache[i].cache)) {
global_change_detected = 1;
}
}
current_global_serial = __system_property_area_serial();
if (current_global_serial != global_serial) {
change_detected = 1;
global_change_detected = 1;
}
}
// tag tag , 。
if (taglen) {
int local_change_detected = change_detected;
if (!not_locked) {
if (!last_tag || !last_tag[0] || (last_tag[0] != tag[0]) ||
strncmp(last_tag + 1, tag + 1, last_tag_len - 1)) {//last_tag null,
/* invalidate log.tag. cache */
for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
tag_cache[i].cache.pinfo = NULL;
tag_cache[i].c = '\0';
}
if (last_tag) last_tag[0] = '\0';// , if
local_change_detected = 1;
}
if (!last_tag || !last_tag[0]) {// tag tag
if (!last_tag) {
last_tag = calloc(1, len + 1);
last_tag_len = 0;
if (last_tag) last_tag_len = len + 1;
} else if (len >= last_tag_len) {
last_tag = realloc(last_tag, len + 1);
last_tag_len = 0;
if (last_tag) last_tag_len = len + 1;
}
if (last_tag) {
strncpy(last_tag, tag, len);
last_tag[len] = '\0';
}
}
}
strncpy(key + sizeof(log_namespace) - 1, tag, len);// key "persist.log.tag.*"
key[sizeof(log_namespace) - 1 + len] = '\0';
// tag property:"persist.log.tag.*" "log.tag.*"
kp = key;
for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
struct cache_char* cache = &tag_cache[i];
struct cache_char temp_cache;
if (not_locked) {
temp_cache.cache.pinfo = NULL;
temp_cache.c = '\0';
cache = &temp_cache;
}
if (local_change_detected) {
refresh_cache(cache, kp);
}
if (cache->c) {
c = cache->c;
break;
}
kp = key + base_offset;//
}
}
// "persist.log", 。
switch (toupper(c)) { /* if invalid, resort to global */
case 'V':
case 'D':
case 'I':
case 'W':
case 'E':
case 'F': /* Not officially supported */
case 'A':
case 'S':
case BOOLEAN_FALSE: /* Not officially supported */
break;
default:
/* clear '.' after log.tag */
key[sizeof(log_namespace) - 2] = '\0';// key "persist.log"
kp = key;
for (i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) {
struct cache_char* cache = &global_cache[i];
struct cache_char temp_cache;
if (not_locked) {
temp_cache = *cache;
if (temp_cache.cache.pinfo != cache->cache.pinfo) { /* check atomic */
temp_cache.cache.pinfo = NULL;
temp_cache.c = '\0';
}
cache = &temp_cache;
}
if (global_change_detected) {
refresh_cache(cache, kp);
}
if (cache->c) {
c = cache->c;
break;
}
kp = key + base_offset;
}
break;
}
if (!not_locked) {
global_serial = current_global_serial;
unlock();
}
// property , log level。
switch (toupper(c)) {
/* clang-format off */
case 'V': return ANDROID_LOG_VERBOSE;
case 'D': return ANDROID_LOG_DEBUG;
case 'I': return ANDROID_LOG_INFO;
case 'W': return ANDROID_LOG_WARN;
case 'E': return ANDROID_LOG_ERROR;
case 'F': /* FALLTHRU */ /* Not officially supported */
case 'A': return ANDROID_LOG_FATAL;
case BOOLEAN_FALSE: /* FALLTHRU */ /* Not Officially supported */
case 'S': return -1; /* ANDROID_LOG_SUPPRESS */
/* clang-format on */
}
return default_prio;// property, 。
}
上の関数が完成した論理は、本当にpropertyを実行して検索したのは関数refresh_です.Cache(struct cache_char*cache,const char*key)、この関数は言わないで、比較的簡単です.
私たちは普段仕事中で、いくつかのロゴを印刷するために、携帯電話/dataディレクトリの下でpush localをよく使います.prop.
adb root
adb remount
adb push local.prop /data/local.prop
adb shell chmod 644 /data/local.prop
adb shell chown root.root /data/local.prop
adb reboot
local.propファイルの内容は以下の通りです.
log.tag.Telecom=VERBOSE
log.tag.RIL-SIM=VERBOSE
log.tag.SIMRecords=VERBOSE
log.tag.DCT=VERBOSE
携帯電話が再起動するとinitは/data/localをロードします.propでは、ファイルの内容がpropertyとしてロードされます.したがって、log文が実行されると、_android_log_レベルは、対応するpropertyを調べ、設定したレベルを取得できます.実はpushファイルは少し煩雑で、上の分析によると、adbコマンドでproperty制御log出力を設定することができます(有効でなければ、携帯電話を再起動してから試してもいいです).使用できるproperty nameは次のとおりです.
[例2]以下のコマンドは、そのためのlogを出力することができますが、使用は推奨されません.logが多すぎると表示に不便をもたらす可能性があります.adb shell setprop persist.log V