1. 使用addr2line工具定位crash点
/home/youtaos/android4.0.4/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi-addr2line -e /home/youtaos/chrome-git/chrome_webkit/out/target/product/generic/symbols/system/lib/libwebviewchromium.so -f 00e1fa08
2. find external/chromium_org/third_party/WebKit/ -name "*.cpp" | xargs grep "#if ENABLE" | awk -F ":" '{print $2}' | sort | uniq | wc -l
3. native log re-direct logcat
#include <android/log.h>
__android_log_print(ANDROID_LOG_DEBUG, "Tag", "JNI_OnLoad\n");
mk file:
LOCAL_LDFLAGS_Release := -L$(SYSROOT)/usr/lib // no use now.
LOCAL_SHARED_LIBRARIES := liblog
4. backtrace of c/c++
1> 首先系统中要有libcorkscrew.so, 可用adb shell到/system/lib下查看
2> 代码中直接使用Backtrace::getCallStack(); 实现代码如下:单独放在一个文件backtrace.cc中,编译到so文件即可。由于是调试chromium时使用,所以使用了chromimu中base/logging.h的log函数打印。(亲测可用)
当然了,log输出的只是pc的值,所以还需要addr2line转换为具体文件的某一行或函数
#include <stdio.h> #include <stdlib.h> #include <dlfcn.h> #include <corkscrew/backtrace.h> #include <corkscrew/map_info.h> #include <corkscrew/symbol_table.h> #include <corkscrew/ptrace.h> #include <corkscrew/demangle.h> #include "base/logging.h" #define MAX_DEPTH 31 #define MAX_BACKTRACE_LINE_LENGTH 8000 #define PATH "/system/lib/libcorkscrew.so" namespace Backtrace { typedef ssize_t (*unwindFn)(backtrace_frame_t*, size_t, size_t); typedef void (*unwindSymbFn)(const backtrace_frame_t*, size_t, backtrace_symbol_t*); typedef void (*unwindSymbFreeFn)(backtrace_symbol_t*, size_t); static void *gHandle = NULL; int getCallStack(void){ int result = 0; int count = 0; backtrace_frame_t mStack[MAX_DEPTH]; backtrace_symbol_t symbols[MAX_DEPTH]; unwindFn unwind_backtrace = NULL; unwindSymbFn get_backtrace_symbols = NULL; unwindSymbFreeFn free_backtrace_symbols = NULL; // open the so. if(gHandle == NULL) gHandle = dlopen(PATH, RTLD_NOW); if (gHandle == NULL) { LOG(ERROR)<<"siyt: ================== gHandle is NULL"; return result; } // get the interface for unwind and symbol analyse if(gHandle != NULL) unwind_backtrace = (unwindFn)dlsym(gHandle, "unwind_backtrace"); if(gHandle != NULL) get_backtrace_symbols = (unwindSymbFn)dlsym(gHandle, "get_backtrace_symbols"); if(gHandle != NULL) free_backtrace_symbols = (unwindSymbFreeFn)dlsym(gHandle, "free_backtrace_symbols"); if(!gHandle ||!unwind_backtrace ||!get_backtrace_symbols || !free_backtrace_symbols ){ //ALOGE("Error! cannot get unwind info: handle:%p %p %p %p", // gHandle, unwind_backtrace, get_backtrace_symbols, free_backtrace_symbols ); LOG(ERROR)<<"siyt: ================== Error! cannot get unwind info: handle:"<<(void *)gHandle<<", "<<(void *)unwind_backtrace <<", "<<(void *)get_backtrace_symbols<<", "<<(void *)free_backtrace_symbols; return result; } count= unwind_backtrace(mStack, 1, MAX_DEPTH); get_backtrace_symbols(mStack, count, symbols); LOG(ERROR)<<"siyt: ===============================Backtrace:"; char line[MAX_BACKTRACE_LINE_LENGTH] = {0}; const char* mapName = NULL; const char* symbolName = NULL; size_t fieldWidth = 0; for (int i = 0; i < count; i++) { mapName = symbols[i].map_name ? symbols[i].map_name : "<unknown>"; symbolName =symbols[i].demangled_name ? symbols[i].demangled_name : symbols[i].symbol_name; fieldWidth = (MAX_BACKTRACE_LINE_LENGTH - 80) / 2; if (symbolName) { uint32_t pc_offset = symbols[i].relative_pc - symbols[i].relative_symbol_addr; if (pc_offset) { snprintf(line, MAX_BACKTRACE_LINE_LENGTH, "#%02d pc %08x %s (%u)", i, symbols[i].relative_pc, mapName, pc_offset); } else { snprintf(line, MAX_BACKTRACE_LINE_LENGTH, "#%02d pc %08x %s", i, symbols[i].relative_pc, mapName); } } else { snprintf(line, MAX_BACKTRACE_LINE_LENGTH, "#%02d pc %08x %s", i, symbols[i].relative_pc, mapName); } LOG(ERROR)<<"siyt: "<<line; } free_backtrace_symbols(symbols, count); return result; } } // namespace Backtrace</span><span style="font-size: 18px;">
可以写一个简单的shell脚本,来自动转换,代码如下:
用法: 将log中的pc值放到一个文件中,shell脚本执行该文件即可。
#!/bin/sh if [ "$1" = "" ]; then echo "No input file." exit fi addrs=`cat $1 | awk '{print $7}'` # 获取pc地址值 #echo $addrs addr2line="$HOME/android4.0.4/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin/arm-eabi-addr2line -e" symbolsLib="$PWD/out/target/product/generic/symbols/system/lib/libwebviewchromium.so" for addr in $addrs do echo `$addr2line $symbolsLib $addr` done
使用ndk-stack打印crash log
./third_party/android_tools/ndk/ndk-stack -dump ~/log/1119-u1-8 -sym /home/xxx/chromium/src/out/Debug/lib/
5. android数据库操作error: SQLiteException: no such table
db.beginTransaction();
try{
//批量处理操作
//do something
db.execSQL("SQL语句", new Object[]{});
db.execSQL("SQL语句", new Object[]{});
//设置事务标志为成功,当结束事务时就会提交事务
db.setTransactionSuccessful(); // 如果在begin和end间没有set successful,则回滚,即之前sql语句执行失败。
}catch(Exception e){}
finally{
//结束事务
db.endTransaction();
}
endTransaction()之前调用了setTransactionSuccessful() 方法设置事务的标志为成功则提交事务,没有调用setTransactionSuccessful() 方法则回滚事务。
假设sql语句为create table,如果没有执行setTransactionSuccessful,则就在以后执行query等操作使就会找不到创建的table,即出现错误SQLiteException: no such table。原因就是create table没有成功,而是回滚了。