我们平时打印log信息,一般情况下是可以打印指定tag信息,首先是你知道这个程序或则个服务的tag,对于第三方的apk我们一般情况下不知道他们的tag,所有在这种情况下想知道他们的log信息特别麻烦,
所以我们改进了原来的logcat工具。使它可以打印指定指定进程的log日志信息!
按照我们平时习惯!加入我们想打印TAG=Gank的log信息。我们在终端在adb shell 连上情况下,
可以输入logcat -s Gank ,如果设备有这个Gank的log信息就会不断输出,在我们中断如下:
V/Gank ( 826): Action: android.intent.action.TIME_TICK
V/Gank ( 826): ActivityController -- activityStarting PKG: com.pptv.setting---LastPkg: null Int
nt: Intent { cmp=com.pptv.setting/.root.SettingsActivity }
V/Gank ( 826): == App Login!
I/Gank ( 854): log=t:34409714810,p:launcher.pptv.com%2Fv3%2Fnavigation,e:mv,tp:launcher.pptv.co
%2Fv3%2F%E8%AE%BE%E7%BD%AE,a:clk,ch:100030;
V/Gank ( 826): ActivityController -- activityStarting PKG: com.pptv.setting---LastPkg: com.pptv
setting Intent: Intent { cmp=com.pptv.setting/.SystemInfoSetting }
V/Gank ( 826): == At Some app -- com.pptv.setting
I/Gank ( 990): log=t:3790,p:launcher.pptv.com%2Fv3%2F%E8%AE%BE%E7%BD%AE,e:mv,pr:launcher.pptv.c
m%2Fv3%2Fnavigation,a:clk,op:setting_SystemInfo;
V/Gank ( 826): Action: android.intent.action.TIME_TICK
I/Gank ( 826): BootLog Init and Upload
我们改进的可以打印的logcat工具也是按照 -s 指定进程,用同一个标识,例如: logcat -s 625 ,625是进程Id。
改动总共是四个文件分别是
system/core/include/cutils/logprint.h
system/core/include/log/logprint.h
system/core/liblog/logprint.c
system/core/logcat/logcat.cpp
在文件 logcat.cpp代码中
switch(ret) {
case 's':
// default to all silent
android_log_addFilterRule(g_logformat, "*:s");
break;
android_log_addFilterRule添加过滤规则的,所以我们在这个函数里面添加过滤pid进程。
在头文件logprint.h中我们先修改上面函数需要用到的结构体
typedef struct FilterInfo_t {
char *mTag;
int32_t mPid;
android_LogPriority mPri;
struct FilterInfo_t *p_next;
} FilterInfo;
我们添加了 int32_t mPid用于存贮pid进程号。
原函数是:
int android_log_addFilterRule(AndroidLogFormat *p_format,
const char *filterExpression)
{
size_t i=0;
size_t tagNameLength;
android_LogPriority pri = ANDROID_LOG_DEFAULT;
tagNameLength = strcspn(filterExpression, ":");
if (tagNameLength == 0) {
goto error;
}
if(filterExpression[tagNameLength] == ':') {
pri = filterCharToPri(filterExpression[tagNameLength+1]);
if (pri == ANDROID_LOG_UNKNOWN) {
goto error;
}
}
if(0 == strncmp("*", filterExpression, tagNameLength)) {
// This filter expression refers to the global filter
// The default level for this is DEBUG if the priority
// is unspecified
if (pri == ANDROID_LOG_DEFAULT) {
pri = ANDROID_LOG_DEBUG;
}
p_format->global_pri = pri;
} else {
// for filter expressions that don't refer to the global
// filter, the default is verbose if the priority is unspecified
if (pri == ANDROID_LOG_DEFAULT) {
pri = ANDROID_LOG_VERBOSE;
}
char *tagName;
// Presently HAVE_STRNDUP is never defined, so the second case is always taken
// Darwin doesn't have strnup, everything else does
#ifdef HAVE_STRNDUP
tagName = strndup(filterExpression, tagNameLength);
#else
//a few extra bytes copied...
tagName = strdup(filterExpression);
tagName[tagNameLength] = '\0';
#endif /*HAVE_STRNDUP*/
FilterInfo *p_fi = filterinfo_new(tagName, pri);
free(tagName);
p_fi->p_next = p_format->filters;
p_format->filters = p_fi;
}
return 0;
error:
return -1;
}
修改后函数是:
int android_log_addFilterRule(AndroidLogFormat *p_format,
const char *filterExpression)
{
size_t i=0;
size_t tagNameLength;
android_LogPriority pri = ANDROID_LOG_DEFAULT;
tagNameLength = strcspn(filterExpression, ":");
if (tagNameLength == 0) {
goto error;
}
if(filterExpression[tagNameLength] == ':') {
pri = filterCharToPri(filterExpression[tagNameLength+1]);
if (pri == ANDROID_LOG_UNKNOWN) {
goto error;
}
}
if(0 == strncmp("*", filterExpression, tagNameLength)) {
// This filter expression refers to the global filter
// The default level for this is DEBUG if the priority
// is unspecified
if (pri == ANDROID_LOG_DEFAULT) {
pri = ANDROID_LOG_DEBUG;
}
p_format->global_pri = pri;
} else {
// for filter expressions that don't refer to the global
// filter, the default is verbose if the priority is unspecified
if (pri == ANDROID_LOG_DEFAULT) {
pri = ANDROID_LOG_VERBOSE;
}
char *tagName;
// Presently HAVE_STRNDUP is never defined, so the second case is always taken
// Darwin doesn't have strnup, everything else does
#ifdef HAVE_STRNDUP
tagName = strndup(filterExpression, tagNameLength);
#else
//a few extra bytes copied...
tagName = strdup(filterExpression);
tagName[tagNameLength] = '\0';
#endif /*HAVE_STRNDUP*/
int n=strlen(tagName);
int i,mpid=1,flag=1;
FilterInfo *p_fi;
for(i=0;i<n;i++)
{
if(!isdigit(tagName[i]))
{
flag=0;
break;
}
}
if(flag)
{
mpid=atoi(tagName);
p_fi =filterinfo_new("",mpid,pri);
}
else
{
p_fi = filterinfo_new(tagName,0, pri);
}
free(tagName);
p_fi->p_next = p_format->filters;
p_format->filters = p_fi;
}
return 0;
error:
return -1;
}
首先获得tagname大小 ,tagname就是 我们的tag(Gank或者625
),在 c
语言中 通过main函数传递参数一律都是按照字符串对待,
int main(int argc, char **argv),所以logcat 获得 argv参数都是字符串,然后判断tagname每一个字符是否都是小于9大于0,若都是我们就认为传递的是进程id,我们就用构造函数
filterinfo_new
构造 FilterInfo *p_fi结构体,
static FilterInfo * filterinfo_new(const char*tag,int32_t pid, android_LogPriority pri)
{
FilterInfo *p_ret;
<pre code_snippet_id="598655" snippet_file_name="blog_20150205_8_9575285" name="code" class="html">
p_ret = (FilterInfo *)calloc(1, sizeof(FilterInfo));
p_ret->mTag = strdup(tag);
p_ret->mPid = pid;
return p_ret;
}
</pre><pre code_snippet_id="598655" snippet_file_name="blog_20150205_9_3771230" name="code" class="html"> p_fi->p_next = p_format->filters;
p_format->filters = p_fi;
上面两行复制过后全局p_format就保存了我们的p_fi。
下面函数处理我们写到buf的log信息
static void processBuffer(log_device_t* dev, struct logger_entry *buf)
{
int bytesWritten = 0;
int err;
AndroidLogEntry entry;
char binaryMsgBuf[1024];
if (dev->binary) {
err = android_log_processBinaryLogBuffer(buf, &entry, g_eventTagMap,
binaryMsgBuf, sizeof(binaryMsgBuf));
//printf(">>> pri=%d len=%d msg='%s'\n",
// entry.priority, entry.messageLen, entry.message);
} else {
err = android_log_processLogBuffer(buf, &entry);
}
if (err < 0) {
goto error;
}
if (android_log_shouldPrintLine(g_logformat, entry.tag, entry.pid,entry.priority)) {
if (false && g_devCount > 1) {
binaryMsgBuf[0] = dev->label;
binaryMsgBuf[1] = ' ';
bytesWritten = write(g_outFD, binaryMsgBuf, 2);
if (bytesWritten < 0) {
perror("output error");
exit(-1);
}
}
函数android_log_shouldPrintLine
用于确定打印指定log日志信息,
原函数是
int android_log_shouldPrintLine (
AndroidLogFormat *p_format, const char *tag, android_LogPriority pri)
{
return pri >= filterPriForTag(p_format, tag);
}
修改后函数
int android_log_shouldPrintLine (
AndroidLogFormat *p_format, const char *tag,int32_t pid, android_LogPriority pri)
{
return pri >= filterPriForTag(p_format, tag,pid);
}
多了一个pid参数,
原函数:
static android_LogPriority filterPriForTag(
AndroidLogFormat *p_format, const char *tag)
{
FilterInfo *p_curFilter;
for (p_curFilter = p_format->filters
; p_curFilter != NULL
; p_curFilter = p_curFilter->p_next
) {
if (p_curFilter->mPri == ANDROID_LOG_DEFAULT) {
return p_format->global_pri;
} else {
return p_curFilter->mPri;
}
}
return p_format->global_pri;
}
修改后函数:
static android_LogPriority filterPriForTag(
AndroidLogFormat *p_format, const char *tag,int32_t pid)
{
FilterInfo *p_curFilter;
for (p_curFilter = p_format->filters
; p_curFilter != NULL
; p_curFilter = p_curFilter->p_next) {
if(p_curFilter->mPid != 0)
{
if (pid==p_curFilter->mPid) {
if (p_curFilter->mPri == ANDROID_LOG_DEFAULT) {
return p_format->global_pri;
} else {
return p_curFilter->mPri;
}
}
}
else
{
if(0 == strcmp(tag, p_curFilter->mTag))
{
if (pid==p_curFilter->mPid) {
if (p_curFilter->mPri == ANDROID_LOG_DEFAULT) {
return p_format->global_pri;
} else {
return p_curFilter->mPri;
}
}
}
}
}
return p_format->global_pri;
}
先是判断判断entry.pid大于0就是传递pid,等于0就是传递tag, 接着我们entry结构体中的pid,entry.pid是否和p_format 结构体中相等, 就打印entry的log信息进程pid的日志信息。
--------- beginning of /dev/log/system
D/PowerManagerNotifier( 625): onWakeLockReleased: flags=1, tag="AlarmManager", packageName=android,
ownerUid=1000, ownerPid=625, workSource=WorkSource{10016}
D/PowerManagerService( 625): updateWakeLockSummaryLocked: mWakefulness=Awake, mWakeLockSummary=0x0
D/PowerManagerService( 625): newScreenState = 2
D/PowerManagerService( 625): updateScreenStateLocked: mScreenBrightnessModeSetting=2, autoBrightness=false,
ecoBrightness=true, screenAutoBrightnessAdjustment=0.0, screenBrightness=102
D/PowerManagerDisplayController( 625): requestPowerState: screenState=2, useProximitySensor=false,
forceProximitySensorEnable=false, forceWakeUpEnable=false, screenBrightness=102,
screenAutoBrightnessAdjustment=0.0, useAutoBrightness=false, useEcoBrightness=true, blockScreenOn=false,
waitForNegativeProximity=false
I/PowerManagerService( 625): setBrightness mButtonLight 0.
D/PowerManagerService( 625): updateScreenStateLocked: mDisplayReady=true, newScreenState=2, mWakefulness=1,
mWakeLockSummary=0x0, mUserActivitySummary=0x1, mBootCompleted=true
D/PowerManagerService( 625): Releasing suspend blocker "PowerManagerService.WakeLocks".
D/PowerManagerService( 625): handleSandman: canDream=true, mWakefulness=Awake
V/ActivityManager( 625): Broadcast: Intent { act=android.intent.action.TIME_TICK flg=0x50000014 (has extras) }
ordered=true userid=-1 callerApp=null
D/PowerManagerService( 625): acquireWakeLockInternal: lock=1106590840, flags=0x1, tag="AlarmManager",
ws=WorkSource{1000}, uid=1000, pid=625
D/PowerManagerNotifier( 625): onWakeLockAcquired: flags=1, tag="AlarmManager", packageName=android,
ownerUid=1000, ownerPid=625, workSource=WorkSource{1000}
@
结果先是正确