ChkBugReport 中 bugreport 全部解析
Main 中 run 函数 -> 调用 mMod.addFile(arg, null, false); -> BugReportModule 中最终调用 private boolean load(InputStream is, boolean partial, String secName) 函数:
<span style="color:#333333">private boolean load(InputStream is, boolean partial, String secName) throws IOException {
long t0 = System.currentTimeMillis();
printOut(1, "Loading input...");
LineReader br = new LineReader(is);
String buff;
Section curSection = null;
mTimestamp = null;
int lineNr = 0;
int skipCount = 5;
boolean formatOk = partial;
while (null != (buff = br.readLine())) {
if (!formatOk) {
// Sill need file format validation
// Check if this is a dropbox file
if (0 == lineNr && buff.startsWith("Process: ")) {
return loadFromDopBox(br, buff);
}
if (0 == lineNr) {
// Not detected yet
if (buff.startsWith("==============")) {
// Ok, pass through and start processing
} else {
if (0 == --skipCount) {
// give up (simply pass through and let if fail later)
} else {
// Give another chance
continue;
}
}
}
// Verify file format (just a simple sanity check)
lineNr++;
if (1 == lineNr && !buff.startsWith("==============")) break;
if (2 == lineNr && !buff.startsWith("== dumpstate")) break;
if (3 == lineNr && !buff.startsWith("==============")) break;
if (4 == lineNr) {
formatOk = true;
}
// Extract timestamp of crash
Calendar ts = Util.parseTimestamp(this, buff);
if (ts != null) {
mTimestamp = ts;
}
}
// Parse sections and sub-sections
if (buff.startsWith("------ ")) {
// build up file name
int e = buff.indexOf(" ------");
if (e >= 0) {
String sectionName = buff.substring(7, e);
// Workaround for SMAP spamming
boolean newSection = true;
if (curSection != null && curSection.getName().equals("SMAPS OF ALL PROCESSES")) {
if (sectionName.startsWith("SHOW MAP ")) {
newSection = false;
}
}
if (newSection) {
Section section = new Section(this, sectionName);
addSection(section);
curSection = section;
continue;
}
}
}
// Workaround for buggy wallpaper service dump
int idx = buff.indexOf(SECTION_DIVIDER);
if (idx > 0) {
if (curSection != null) {
curSection.addLine(buff.substring(0, idx));
}
buff = buff.substring(idx);
}
if (buff.equals(SECTION_DIVIDER)) {
// Another kind of marker
// Need to read the next line
String sectionName = br.readLine();
if (sectionName != null) {
if ("DUMP OF SERVICE activity:".equals(sectionName)) {
// skip over this name, and use the next line as title, the provider thingy
sectionName = br.readLine();
}
}
if (sectionName != null) {
Section section = new Section(this, sectionName);
addSection(section);
curSection = section;
}
continue;
}
// Add the current line to the current section
if (curSection == null && partial) {
// We better not spam the header section, so let's create a fake section
curSection = new Section(this, secName);
addSection(curSection);
}
if (curSection != null) {
curSection.addLine(buff);
} else {
addHeaderLine(buff);
mBugReportHeader.add(buff);
}
}
br.close();
long t1 = System.currentTimeMillis();
printOut(1, String.format("Loaded in %.2f seconds.", (t1 - t0) / 1000.0f));
if (!formatOk) {
throw new IOException("Does not look like a bugreport file!");
}
return true;
}</span>
使用 Section 对象保存。保存对应文件操作:
<span style="color:#333333">private void saveSections() throws IOException {
Chapter ch = new Chapter(getContext(), "Raw data");
List list = new List();
ch.add(list);
for (Section s : mSections) {
String fn = mDoc.getRelRawDir() + s.getFileName();
list.add(new Link(mDoc.getRelRawDir() + s.getFileName(), s.getName()));
FileOutputStream fos = new FileOutputStream(getBaseDir() + fn);
PrintStream ps = new PrintStream(fos);
int cnt = s.getLineCount();
for (int i = 0; i < cnt; i++) {
ps.println(s.getLine(i));
}
ps.close();
fos.close();
}
addChapter(ch);
}</span>
从HTML报告中Raw data查看:
xml 插件扩展 Load 子标签支持
Load 扩展标签
<span style="color:#333333"> <load>
<filter section="DUMP OF SERVICE dropbox" chapterName="DUMP/DUMP OF SERVICE dropbox" infoId="dumpdropboxlog" />
</load></span>
load 标签 filter 子标签中:
- section 是生成Log对象;
- chapterName 报告中左侧目录;
- infoId 筛选Log时从 BugReportModule.java 中获取 Log 的 key。
Section key有哪些
查看 Section 对象,添加 Log 输出,在 HTML 报告查看 Header 中ChkBugReport's log: chkbugreport_log.txt:
从代码中是使用mShortName:
<span style="color:#333333">public void addSection(Section section) {
mSections.add(section);
mSectionMap.put(section.getShortName(), section);
}
/**
* Find the Section with the given name,
*
* @param name The name of the section
* @return The Section from the bugreport or null if not found
*/
public Section findSection(String name) {
return mSectionMap.get(name);
}</span>
code 实现
ExtXMLPlugin.java 中扩展load、generate 函数等:
<span style="color:#333333"> private Vector<ExtLogData> mLogs = new Vector<ExtLogData>();
@Override
public void load(Module mod) {
// Execute the "load" tag
XMLNode load = mXml.getChild("load");
if (load == null) {
// <load> tag is missing, do nothing.
return;
}
BugReportModule br = (BugReportModule) mod;
for (XMLNode chTag : load) {
String tag = chTag.getName();
if (tag == null) continue;
if ("filter".equals(tag)) {
String section = chTag.getAttr("section");
String chapterName = chTag.getAttr("chapterName");
String infoId = chTag.getAttr("infoId");
br.printOut(2, TAG + " section [" + section + "] , chapterName [" + chapterName + "] , infoId [" + infoId + "]");
if(section == null) continue;
loadLog(br, section, chapterName, infoId);
}
}
}
private void loadLog(BugReportModule br, String sectionName, String chapterName, String infoId) {
Section section = br.findSection(sectionName);
if (section == null) {
br.printErr(3, TAG + "Cannot find section [" + sectionName + "] (ignoring)");
return;
}
ExtLogData data = new ExtLogData(br, section, chapterName, infoId);
mLogs.add(data);
}
@Override
public void generate(Module mod) {
for (ExtLogData log : mLogs) {
log.generate();
}
// Find the generate tag
XMLNode gen = mXml.getChild("generate");
if (gen != null) {
for (XMLNode chTag : gen) {
String tag = chTag.getName();
if (tag == null) continue;
if ("chapter".equals(tag)) {
Chapter ch = mod.findOrCreateChapter(chTag.getAttr("name"));
// Now execute each child tag
mod.printOut(2,TAG + " Chapter name : " +ch.getName());
for (XMLNode code : chTag) {
exec(mod, ch, code);
}
} else {
mod.printErr(4, "A non-chapter tag is found in <generate>, ignoreing it: " + tag);
}
}
}
}</span>
Log数据处理类ExtLogData.java :
<span style="color:#333333">public class ExtLogData {
public final static String TAG = "[ExtLogData]";
private Chapter mCh;
private LogLines mParsedLog = new LogLines();
private BugReportModule mMod;
public ExtLogData(BugReportModule mod, Section section, String chapterName, String infoId) {
mMod = mod;
// initParsedLog
if (section != null) {
// Load and parse the lines
int cnt = section.getLineCount();
for (int i = 0; i < cnt; i++) {
LogLine log = new LogLine(mMod, section.getLine(i), LogLine.FMT_UNKNOWN, null);
mParsedLog.add(log);
}
mMod.printOut(2, TAG + section.getShortName() + "[" + cnt + "]");
}
if (section != null && chapterName != null && mParsedLog.size() != 0) {
mCh = mod.findOrCreateChapter(chapterName);
}
if (section != null && infoId != null) mMod.addInfo(infoId, mParsedLog);
}
public void generate() {
if (mCh == null) {
return;
}
new LogToolbar(mCh);
DocNode log = new Block(mCh).addStyle("log");
int cnt = mParsedLog.size();
for (int i = 0; i < cnt; i++) {
LogLine lg = mParsedLog.get(i);
log.add(lg);
}
}
}
</span>
Load 扩展使用
<span style="color:#333333"><plugin name="ExamplePlugin">
<load>
<filter section="DUMP OF SERVICE dropbox" chapterName="DUMP/DUMP OF SERVICE dropbox" infoId="dumpdropboxlog" />
</load>
</plugin></span>
HTML 报告截图:
扩展 generate功能
code 实现
在 com.sonyericsson.chkbugreport.plugins.extxml.log.java 内部类 LogState 中:
两种方式获取需要筛选的Log:
- 使用 BugReportModule.java 获取 Log 的 key(infoId)
- 使用 Section 对象的 mShortName,在 Section 中获取 Log
<span style="color:#333333"> public LogLines getParsedLog(BugReportModule mod) { LogLines parsedLog = new LogLines(); int cnt = getLineCount(); for (int i = 0; i < cnt; i++) { LogLine log = new LogLine(mod, getLine(i), LogLine.FMT_UNKNOWN, null); parsedLog.add(log); } return parsedLog; }</span>
generate 扩展使用
<span style="color:#333333"><plugin name="ExamplePlugin">
<load>
<filter section="DUMP OF SERVICE dropbox" chapterName="DUMP/DUMP OF SERVICE dropbox" infoId="dumpdropboxlog" />
</load>
<generate>
<chapter name="WT Special characters/DUMP OF SERVICE dropbox">
<text> DUMP OF SERVICE dropbox </text>
<log>
<filter log="dumpdropboxlog" matchLine="Kernel panic"/>
<filter log="DUMP OF SERVICE dropbox" matchLine="SYSTEM_LAST_KMSG"/>
</log>
</chapter>
</generate>
</plugin>
</span>
在 generate/chapter/log 标签中log参数可以是从 BugReportModule.java 中获取 Log 的 key(infoId),也可以是 Section 对象的 mShortName。
注意:推荐使用 matchLine 过滤,这个是原始Log的匹配,其他 matchTag、matchMsg、matchProc 针对上层,做过处理
HTML 报告截图:
增添 hook功能
code 实现
对比 ChkBugReport工具 for Android 3 中 KernelLogPlugin 的hook扩展实现 ExtXMLPlugin 的扩展,并添加代码:
<span style="color:#333333"> private Hooks mHooks = new Hooks(this);
@Override
public void reset() {
mLogs.clear();
mHooks.reset();
}
@Override
public void onHook(Module mod, XMLNode hook) {
mHooks.add(hook);
}
@Override
public void hook(Module mod) {
// Execute the "hook" tag
for (XMLNode hook : mXml) {
if (!"hook".equals(hook.getName())) continue;
String into = hook.getAttr("into");
if (into == null) {
mod.printErr(4, TAG + "Missing 'into' attribute in hook tag, ignoring whole tag!");
this.onHook(mod, hook);
continue;
}
Plugin dst = mod.getPlugin(into);
if (dst == null) {
mod.printErr(4, TAG + "Cannot find plugin to hook into: " + into);
continue;
}
dst.onHook(mod, hook);
}
}
@Override
public void load(Module mod) {
// Execute the "load" tag
XMLNode load = mXml.getChild("load");
if (load == null) {
// <load> tag is missing, do nothing.
return;
}
BugReportModule br = (BugReportModule) mod;
for (XMLNode chTag : load) {
String tag = chTag.getName();
if ("filter".equals(tag)) {
String section = chTag.getAttr("section");
String chapterName = chTag.getAttr("chapterName");
String infoId = chTag.getAttr("infoId");
br.printOut(2, TAG + " section [" + section + "] , chapterName [" + chapterName + "] , infoId [" + infoId + "]");
if(section == null) continue;
loadLog(br, section, chapterName, infoId);
}
}
// Execute the hooks
mHooks.execute(br);
}</span>
hook 扩展使用
<span style="color:#333333"><plugin name="ExamplePlugin">
<hook>
<filter matchLine="Kernel panic">
<note text="Kernel panic" error="true"/>
</filter>
<filter matchLine="Kernel panic">
<bug title="Kernel panic" text="!!!底层重启了!!!系统重启了!!!" prio="100" type="phone err" />
</filter>
<filter matchLine="SYSTEM_LAST_KMSG">
<hide />
</filter>
</hook>
<load>
<filter section="DUMP OF SERVICE dropbox" chapterName="DUMP/DUMP OF SERVICE dropbox" infoId="dumpdropboxlog" />
</load>
<generate>
<chapter name="WT Special characters/DUMP OF SERVICE dropbox">
<text> DUMP OF SERVICE dropbox </text>
<log>
<filter log="dumpdropboxlog" matchLine="Kernel panic"/>
<filter log="dumpdropboxlog" matchLine="SYSTEM_LAST_KMSG"/>
</log>
</chapter>
</generate>
</plugin></span>
HTML 报告截图:
hook功能缺陷:
- note:功能生效
- bug:功能生效,但跳转Log链接错误
- hide:不生效,同 ChkBugReport工具 for Android 3 一样