bugreport是什么,怎么用?

Android系统想要成为一个功能完备,生态繁荣的操作系统,那就必须提供完整的应用开发环境。而在应用开发中,app程序的调试分析是日常生产中进程会进行的工作。Android为了方便开发人员分析整个系统平台和某个app在运行一段时间之内的所有信息,专门开发了bugreport工具。这个工具使用起来十分简单,只要在终端执行(linux或者win):

adb bugreport > bugreport.txt

即可生成bugreport文件。但是有一个问题是,这个生成的文件有的时候异常庞大,能够达到15M+,想一想对于一个txt文本格式的文件内容长度达到了15M+是一个什么概念,如果使用文本工具打开查看将是一个噩梦。因此google针对android 5.0(api 21)以上的系统开发了一个叫做battery historian的分析工具,这个工具就是用来解析这个txt文本文件,然后使用web图形的形式展现出来,这样出来的效果更加人性化,更加可读。它的基本界面像下面这个样子:
Android adb bugreport工具分析和使用_第1张图片
目前google已经将bettery historian开源了,开源项目的地址:
https://github.com/google/battery-historian
google写了一个比较详细的说明文档,大家可以自行查阅一下。这个工具可以查看以下信息:

BrightnessCPU runningCharging onCharging statusHealthJobSchedulerKernel only uptimeLevelPackage activePartial wakelockPhone scanningPhone statePlugPluggedScreenTemperatureTop appVoltageWifi onWifi runningWifi supplicant

数据还是比较详细的。
当然,同样的bugreport数据也可以有不同的解析和阅读方式,你如果不太喜欢google的battery historian的话,你还有别的选择,那就是选择Sony开源的ChkBugReport,这个工具提供了不同于battery historian的视角去解读bugreport文件,界面简单明了:
Android adb bugreport工具分析和使用_第2张图片
这个项目的文档:
http://developer.sonymobile.com/2012/01/25/new-bugreport-analysis-tool-released-as-open-source/
开源地址首页:
https://github.com/sonyxperiadev/ChkBugReport
这里说明一下,笔者使用过ChkBugReport这个工具,感觉很不错,最好结合google的battery historian;另外ChkBugReport这个工具还有一点bug,不过不影响使用。

bugreport的原理是什么?

下面我们简要分析一下adb bugreport运行的原理。我们知道,使用bugreport只要执行adb bugreport命令就可以了,因此我们的分析肯定是从adbd这个daemon进程开始,我们查看这个进程的代码的时候发现这里处理了bugreport选项:
[email protected]/core/adb/commandline.cpp
这里写图片描述
我们可以清楚地看到,这里判断如果附带的参数是bugreport的话,那就直接调用send_shell_command函数处理,这个函数的代码比较简单,我们就不分析了,这个函数的功能就是使用shell执行参数中的命令,因此我们这里相当于执行了bugreport命令。
在android设备中,bugreport命令存在于system/bin/目录下,这是一个可执行文件,所以我们要查看这个可执行文件实现的地方,它的实现代码在/frameworks/native/cmds/bugreport/目录下:
这里写图片描述
我们看到,bugreport的实现是比较简单的,只有一个Android.mk和一个cpp实现代码,我们先看一下Android.mk文件:
Android adb bugreport工具分析和使用_第3张图片
这里我们看到该目录下的代码会被编译成一个名字叫做bugreport的可执行文件,这就是我们想要找的。现在我们看一下bugreport.cpp文件的实现,这个文件中代码比较简单,只有一个main函数:

// This program will trigger the dumpstate service to start a call to// dumpstate, then connect to the dumpstate local client to read the// output. All of the dumpstate output is written to stdout, including// any errors encountered while reading/writing the output.int main() {  // Start the dumpstate service.  property_set("ctl.start", "dumpstate");  // Socket will not be available until service starts.  int s;  for (int i = 0; i < 20; i++) {    s = socket_local_client("dumpstate", ANDROID_SOCKET_NAMESPACE_RESERVED,                            SOCK_STREAM);    if (s >= 0)      break;    // Try again in 1 second.    sleep(1);  }  if (s == -1) {    printf("Failed to connect to dumpstate service: %s\n", strerror(errno));    return 1;  }  // Set a timeout so that if nothing is read in 3 minutes, we'll stop  // reading and quit. No timeout in dumpstate is longer than 60 seconds,  // so this gives lots of leeway in case of unforeseen time outs.  struct timeval tv;  tv.tv_sec = 3 * 60;  tv.tv_usec = 0;  if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {    printf("WARNING: Cannot set socket timeout: %s\n", strerror(errno));  }  while (1) {    char buffer[65536];    ssize_t bytes_read = TEMP_FAILURE_RETRY(read(s, buffer, sizeof(buffer)));    if (bytes_read == 0) {      break;    } else if (bytes_read == -1) {      // EAGAIN really means time out, so change the errno.      if (errno == EAGAIN) {        errno = ETIMEDOUT;      }      printf("\nBugreport read terminated abnormally (%s).\n", strerror(errno));      break;    }    ssize_t bytes_to_send = bytes_read;    ssize_t bytes_written;    do {      bytes_written = TEMP_FAILURE_RETRY(write(STDOUT_FILENO,                                               buffer + bytes_read - bytes_to_send,                                               bytes_to_send));      if (bytes_written == -1) {        printf("Failed to write data to stdout: read %zd, trying to send %zd (%s)\n",               bytes_read, bytes_to_send, strerror(errno));        return 1;      }      bytes_to_send -= bytes_written;    } while (bytes_written != 0 && bytes_to_send > 0);  }  close(s);  return 0;}

这里的代码非常简单,主要的逻辑就是:
1.启动dumpstate service
2. 和dumpstate service建立socket链接
3. 从socket中读取数据,并且答应到stdout中
4. 读取完成之后关闭socket,然后退出
因此,我们分析的重点需要转移到dumpstate中了。这里说明一下,前面启动dumpstate service的方法是使用系统属性来实现,这个属性的改变消息会被init进程收到,然后init进程会启动dumpstate这个服务。
dumpstate其实也是一个可执行文件,也存在于system/bin目录下。现在我们明白了,其实bugreport就是dumpstate,只是bugreport将dumpstate包装了一下而已。
现在我们需要分析一下dumpstate的实现,它的实现代码在:frameworks/native/cmds/dumpstate目录下,我们看下这个目录下的代码结构:
Android adb bugreport工具分析和使用_第4张图片
这里的代码也是十分简单,只要少数的几个实现文件,其中main函数在dumpstate.c文件中,这个main函数我们这里不详细分析了,总结下它的主要工作:
1. 根据启动参数,初始化相关资源
2. 如果启动参数中带有-s的话(init启动会加上这个参数),就表示使用socket,那么就启动socket,并且在这个socket中等待链接。
3. 如果client端(也就是bugreport进程)链接成功,那就初始化所要用到的内存,并且设置优先级为较高优先级,防止被OOM干掉。
4. 然后使用vibrator震动一下(如果设备有这个硬件的话),提示用户开始截取log了
5. 调用dumpstate函数开始真正的dump工作
6. dump完成之后再次调用vibrator震动3次,提示用户dump完成。
现在我们看下dumpstate函数的实现:

/* dumps the current system state to stdout */static void dumpstate() {    unsigned long timeout;    time_t now = time(NULL);    char build[PROPERTY_VALUE_MAX], fingerprint[PROPERTY_VALUE_MAX];    char radio[PROPERTY_VALUE_MAX], bootloader[PROPERTY_VALUE_MAX];    char network[PROPERTY_VALUE_MAX], date[80];    char build_type[PROPERTY_VALUE_MAX];    property_get("ro.build.display.id", build, "(unknown)");    property_get("ro.build.fingerprint", fingerprint, "(unknown)");    property_get("ro.build.type", build_type, "(unknown)");    property_get("ro.baseband", radio, "(unknown)");    property_get("ro.bootloader", bootloader, "(unknown)");    property_get("gsm.operator.alpha", network, "(unknown)");    strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now));    printf("========================================================\n");    printf("== dumpstate: %s\n", date);    printf("========================================================\n");    printf("\n");    printf("Build: %s\n", build);    printf("Build fingerprint: '%s'\n", fingerprint); /* format is important for other tools */    printf("Bootloader: %s\n", bootloader);    printf("Radio: %s\n", radio);    printf("Network: %s\n", network);    printf("Kernel: ");    dump_file(NULL, "/proc/version");    printf("Command line: %s\n", strtok(cmdline_buf, "\n"));    printf("\n");    dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");    run_command("UPTIME", 10, "uptime", NULL);    dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);    dump_file("MEMORY INFO", "/proc/meminfo");    run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-t", NULL);    run_command("PROCRANK", 20, "procrank", NULL);    dump_file("VIRTUAL MEMORY STATS", "/proc/vmstat");    dump_file("VMALLOC INFO", "/proc/vmallocinfo");    dump_file("SLAB INFO", "/proc/slabinfo");    dump_file("ZONEINFO", "/proc/zoneinfo");    dump_file("PAGETYPEINFO", "/proc/pagetypeinfo");    dump_file("BUDDYINFO", "/proc/buddyinfo");    dump_file("FRAGMENTATION INFO", "/d/extfrag/unusable_index");    dump_file("KERNEL WAKELOCKS", "/proc/wakelocks");    dump_file("KERNEL WAKE SOURCES", "/d/wakeup_sources");    dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");    dump_file("KERNEL SYNC", "/d/sync");    run_command("PROCESSES", 10, "ps", "-P", NULL);    run_command("PROCESSES AND THREADS", 10, "ps", "-t", "-p", "-P", NULL);    run_command("PROCESSES (SELINUX LABELS)", 10, "ps", "-Z", NULL);    run_command("LIBRANK", 10, "librank", NULL);    do_dmesg();    run_command("LIST OF OPEN FILES", 10, SU_PATH, "root", "lsof", NULL);    for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES");    for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");    if (screenshot_path[0]) {        ALOGI("taking screenshot\n");        run_command(NULL, 10, "/system/bin/screencap", "-p", screenshot_path, NULL);        ALOGI("wrote screenshot: %s\n", screenshot_path);    }    // dump_file("EVENT LOG TAGS", "/etc/event-log-tags");    // calculate timeout    timeout = logcat_timeout("main") + logcat_timeout("system") + logcat_timeout("crash");    if (timeout < 20000) {        timeout = 20000;    }    run_command("SYSTEM LOG", timeout / 1000, "logcat", "-v", "threadtime", "-d", "*:v", NULL);    timeout = logcat_timeout("events");    if (timeout < 20000) {        timeout = 20000;    }    run_command("EVENT LOG", timeout / 1000, "logcat", "-b", "events", "-v", "threadtime", "-d", "*:v", NULL);    timeout = logcat_timeout("radio");    if (timeout < 20000) {        timeout = 20000;    }    run_command("RADIO LOG", timeout / 1000, "logcat", "-b", "radio", "-v", "threadtime", "-d", "*:v", NULL);    run_command("LOG STATISTICS", 10, "logcat", "-b", "all", "-S", NULL);    /* show the traces we collected in main(), if that was done */    if (dump_traces_path != NULL) {        dump_file("VM TRACES JUST NOW", dump_traces_path);    }    /* only show ANR traces if they're less than 15 minutes old */    struct stat st;    char anr_traces_path[PATH_MAX];    property_get("dalvik.vm.stack-trace-file", anr_traces_path, "");    if (!anr_traces_path[0]) {        printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");    } else {      int fd = TEMP_FAILURE_RETRY(open(anr_traces_path,                                       O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));      if (fd < 0) {          printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno));      } else {          dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_path, fd);      }    }    /* slow traces for slow operations */    if (anr_traces_path[0] != 0) {        int tail = strlen(anr_traces_path)-1;        while (tail > 0 && anr_traces_path[tail] != '/') {            tail--;        }        int i = 0;        while (1) {            sprintf(anr_traces_path+tail+1, "slow%02d.txt", i);            if (stat(anr_traces_path, &st)) {                // No traces file at this index, done with the files.                break;            }            dump_file("VM TRACES WHEN SLOW", anr_traces_path);            i++;        }    }    int dumped = 0;    for (size_t i = 0; i < NUM_TOMBSTONES; i++) {        if (tombstone_data[i].fd != -1) {            dumped = 1;            dump_file_from_fd("TOMBSTONE", tombstone_data[i].name, tombstone_data[i].fd);            tombstone_data[i].fd = -1;        }    }    if (!dumped) {        printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR);    }    dump_file("NETWORK DEV INFO", "/proc/net/dev");    dump_file("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");    dump_file("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");    dump_file("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");    dump_file("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");    if (!stat(PSTORE_LAST_KMSG, &st)) {        /* Also TODO: Make console-ramoops CAP_SYSLOG protected. */        dump_file("LAST KMSG", PSTORE_LAST_KMSG);    } else {        /* TODO: Make last_kmsg CAP_SYSLOG protected. b/5555691 */        dump_file("LAST KMSG", "/proc/last_kmsg");    }    /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */    run_command("LAST LOGCAT", 10, "logcat", "-L", "-v", "threadtime",                                             "-b", "all", "-d", "*:v", NULL);    /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */    run_command("NETWORK INTERFACES", 10, "ip", "link", NULL);    run_command("IPv4 ADDRESSES", 10, "ip", "-4", "addr", "show", NULL);    run_command("IPv6 ADDRESSES", 10, "ip", "-6", "addr", "show", NULL);    run_command("IP RULES", 10, "ip", "rule", "show", NULL);    run_command("IP RULES v6", 10, "ip", "-6", "rule", "show", NULL);    dump_route_tables();    run_command("ARP CACHE", 10, "ip", "-4", "neigh", "show", NULL);    run_command("IPv6 ND CACHE", 10, "ip", "-6", "neigh", "show", NULL);    run_command("IPTABLES", 10, SU_PATH, "root", "iptables", "-L", "-nvx", NULL);    run_command("IP6TABLES", 10, SU_PATH, "root", "ip6tables", "-L", "-nvx", NULL);    run_command("IPTABLE NAT", 10, SU_PATH, "root", "iptables", "-t", "nat", "-L", "-nvx", NULL);    /* no ip6 nat */    run_command("IPTABLE RAW", 10, SU_PATH, "root", "iptables", "-t", "raw", "-L", "-nvx", NULL);    run_command("IP6TABLE RAW", 10, SU_PATH, "root", "ip6tables", "-t", "raw", "-L", "-nvx", NULL);    run_command("WIFI NETWORKS", 20,            SU_PATH, "root", "wpa_cli", "IFNAME=wlan0", "list_networks", NULL);#ifdef FWDUMP_bcmdhd    run_command("ND OFFLOAD TABLE", 5,            SU_PATH, "root", "wlutil", "nd_hostip", NULL);    run_command("DUMP WIFI INTERNAL COUNTERS (1)", 20,            SU_PATH, "root", "wlutil", "counters", NULL);    run_command("ND OFFLOAD STATUS (1)", 5,            SU_PATH, "root", "wlutil", "nd_status", NULL);#endif    dump_file("INTERRUPTS (1)", "/proc/interrupts");    run_command("NETWORK DIAGNOSTICS", 10, "dumpsys", "connectivity", "--diag", NULL);#ifdef FWDUMP_bcmdhd    run_command("DUMP WIFI STATUS", 20,            SU_PATH, "root", "dhdutil", "-i", "wlan0", "dump", NULL);    run_command("DUMP WIFI INTERNAL COUNTERS (2)", 20,            SU_PATH, "root", "wlutil", "counters", NULL);    run_command("ND OFFLOAD STATUS (2)", 5,            SU_PATH, "root", "wlutil", "nd_status", NULL);#endif    dump_file("INTERRUPTS (2)", "/proc/interrupts");    print_properties();    run_command("VOLD DUMP", 10, "vdc", "dump", NULL);    run_command("SECURE CONTAINERS", 10, "vdc", "asec", "list", NULL);    run_command("FILESYSTEMS & FREE SPACE", 10, "df", NULL);    run_command("LAST RADIO LOG", 10, "parse_radio_log", "/proc/last_radio_log", NULL);    printf("------ BACKLIGHTS ------\n");    printf("LCD brightness=");    dump_file(NULL, "/sys/class/leds/lcd-backlight/brightness");    printf("Button brightness=");    dump_file(NULL, "/sys/class/leds/button-backlight/brightness");    printf("Keyboard brightness=");    dump_file(NULL, "/sys/class/leds/keyboard-backlight/brightness");    printf("ALS mode=");    dump_file(NULL, "/sys/class/leds/lcd-backlight/als");    printf("LCD driver registers:\n");    dump_file(NULL, "/sys/class/leds/lcd-backlight/registers");    printf("\n");    /* Binder state is expensive to look at as it uses a lot of memory. */    dump_file("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");    dump_file("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");    dump_file("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");    dump_file("BINDER STATS", "/sys/kernel/debug/binder/stats");    dump_file("BINDER STATE", "/sys/kernel/debug/binder/state");    printf("========================================================\n");    printf("== Board\n");    printf("========================================================\n");    dumpstate_board();    printf("\n");    /* Migrate the ril_dumpstate to a dumpstate_board()? */    char ril_dumpstate_timeout[PROPERTY_VALUE_MAX] = {0};    property_get("ril.dumpstate.timeout", ril_dumpstate_timeout, "30");    if (strnlen(ril_dumpstate_timeout, PROPERTY_VALUE_MAX - 1) > 0) {        if (0 == strncmp(build_type, "user", PROPERTY_VALUE_MAX - 1)) {            // su does not exist on user builds, so try running without it.            // This way any implementations of vril-dump that do not require            // root can run on user builds.            run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),                    "vril-dump", NULL);        } else {            run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),                    SU_PATH, "root", "vril-dump", NULL);        }    }    printf("========================================================\n");    printf("== Android Framework Services\n");    printf("========================================================\n");    /* the full dumpsys is starting to take a long time, so we need       to increase its timeout.  we really need to do the timeouts in       dumpsys itself... */    run_command("DUMPSYS", 60, "dumpsys", NULL);    printf("========================================================\n");    printf("== Checkins\n");    printf("========================================================\n");    run_command("CHECKIN BATTERYSTATS", 30, "dumpsys", "batterystats", "-c", NULL);    run_command("CHECKIN MEMINFO", 30, "dumpsys", "meminfo", "--checkin", NULL);    run_command("CHECKIN NETSTATS", 30, "dumpsys", "netstats", "--checkin", NULL);    run_command("CHECKIN PROCSTATS", 30, "dumpsys", "procstats", "-c", NULL);    run_command("CHECKIN USAGESTATS", 30, "dumpsys", "usagestats", "-c", NULL);    run_command("CHECKIN PACKAGE", 30, "dumpsys", "package", "--checkin", NULL);    printf("========================================================\n");    printf("== Running Application Activities\n");    printf("========================================================\n");    run_command("APP ACTIVITIES", 30, "dumpsys", "activity", "all", NULL);    printf("========================================================\n");    printf("== Running Application Services\n");    printf("========================================================\n");    run_command("APP SERVICES", 30, "dumpsys", "activity", "service", "all", NULL);    printf("========================================================\n");    printf("== Running Application Providers\n");    printf("========================================================\n");    run_command("APP SERVICES", 30, "dumpsys", "activity", "provider", "all", NULL);    printf("========================================================\n");    printf("== dumpstate: done\n");    printf("========================================================\n");}

上面的代码比较长,是因为所要dump的模块太多,但是基本逻辑还是比较清楚的,我们看到基本的数据来源就是:
1.系统属性
2./proc和/sys节点文件
3.执行shell命令获得相关输出
4.logcat输出
5.Android Framework Services信息基本使用dumpsys命令通过binder调用服务中的dump函数获得信息
这里我们需要看一下dumpsys命令的实现,这个命令也是比较简单,实现全部在main函数中:

int main(int argc, char* const argv[]){    signal(SIGPIPE, SIG_IGN);    sp sm = defaultServiceManager();    fflush(stdout);    if (sm == NULL) {        ALOGE("Unable to get default service manager!");        aerr << "dumpsys: Unable to get default service manager!" << endl;        return 20;    }    Vector services;    Vector args;    bool showListOnly = false;    if ((argc == 2) && (strcmp(argv[1], "-l") == 0)) {        showListOnly = true;    }    if ((argc == 1) || showListOnly) {        services = sm->listServices();        services.sort(sort_func);        args.add(String16("-a"));    } else {        services.add(String16(argv[1]));        for (int i=2; i.add(String16(argv[i]));        }    }    const size_t N = services.size();    if (N > 1) {        // first print a list of the current services        aout << "Currently running services:" << endl;        for (size_t i=0; i service = sm->checkService(services[i]);            if (service != NULL) {                aout << "  " << services[i] << endl;            }        }    }    if (showListOnly) {        return 0;    }    for (size_t i=0; i service = sm->checkService(services[i]);        if (service != NULL) {            if (N > 1) {                aout << "------------------------------------------------------------"                        "-------------------" << endl;                aout << "DUMP OF SERVICE " << services[i] << ":" << endl;            }            int err = service->dump(STDOUT_FILENO, args);            if (err != 0) {                aerr << "Error dumping service info: (" << strerror(err)                        << ") " << services[i] << endl;            }        } else {            aerr << "Can't find service: " << services[i] << endl;        }    }    return 0;}

我们看到它的代码逻辑就是,通过Binder的SM查找参数中的service,然后通过:

int err = service->dump(STDOUT_FILENO, args);

这句来调用service的dump函数。
dumpstate会调用到所有binder中的service的dump函数,因为dumpstate函数执行了这一句:

/* the full dumpsys is starting to take a long time, so we need   to increase its timeout.  we really need to do the timeouts in   dumpsys itself... */run_command("DUMPSYS", 60, "dumpsys", NULL);

直接执行dumpsys,没有参数,并且注释中也说的很清楚,就是采集所有的信息。这会执行以下service的dump函数(执行dumpsys | grep “DUMP OF SERVICE”可以看到):

DUMP OF SERVICE DockObserver:DUMP OF SERVICE SurfaceFlinger:DUMP OF SERVICE accessibility:DUMP OF SERVICE account:DUMP OF SERVICE activity:DUMP OF SERVICE alarm:DUMP OF SERVICE android.security.keystore:DUMP OF SERVICE android.service.gatekeeper.IGateKeeperService:DUMP OF SERVICE appops:DUMP OF SERVICE appwidget:DUMP OF SERVICE assetatlas:DUMP OF SERVICE audio:DUMP OF SERVICE backup:DUMP OF SERVICE battery:DUMP OF SERVICE batteryproperties:DUMP OF SERVICE batterystats:DUMP OF SERVICE bluetooth_manager:DUMP OF SERVICE carrier_config:DUMP OF SERVICE clipboard:DUMP OF SERVICE commontime_management:DUMP OF SERVICE connectivity:DUMP OF SERVICE consumer_ir:DUMP OF SERVICE content:DUMP OF SERVICE country_detector:DUMP OF SERVICE cpuinfo:DUMP OF SERVICE dbinfo:DUMP OF SERVICE device_policy:DUMP OF SERVICE deviceidle:DUMP OF SERVICE devicestoragemonitor:DUMP OF SERVICE diskstats:DUMP OF SERVICE display:DUMP OF SERVICE display.qservice:DUMP OF SERVICE dreams:DUMP OF SERVICE drm.drmManager:DUMP OF SERVICE dropbox:DUMP OF SERVICE ethernet:DUMP OF SERVICE fingerprint:DUMP OF SERVICE gfxinfo:DUMP OF SERVICE graphicsstats:DUMP OF SERVICE imms:DUMP OF SERVICE input:DUMP OF SERVICE input_method:DUMP OF SERVICE iphonesubinfo:DUMP OF SERVICE isms:DUMP OF SERVICE isub:DUMP OF SERVICE jobscheduler:DUMP OF SERVICE launcherapps:DUMP OF SERVICE location:DUMP OF SERVICE lock_settings:DUMP OF SERVICE media.audio_flinger:DUMP OF SERVICE media.audio_policy:DUMP OF SERVICE media.camera:DUMP OF SERVICE media.camera.proxy:DUMP OF SERVICE media.player:DUMP OF SERVICE media.radio:DUMP OF SERVICE media.resource_manager:DUMP OF SERVICE media.sound_trigger_hw:DUMP OF SERVICE media_projection:DUMP OF SERVICE media_router:DUMP OF SERVICE media_session:DUMP OF SERVICE meminfo:DUMP OF SERVICE midi:DUMP OF SERVICE mount:DUMP OF SERVICE netpolicy:DUMP OF SERVICE netstats:DUMP OF SERVICE network_management:DUMP OF SERVICE network_score:DUMP OF SERVICE nfc:DUMP OF SERVICE notification:DUMP OF SERVICE package:DUMP OF SERVICE permission:DUMP OF SERVICE persistent_data_block:DUMP OF SERVICE phone:DUMP OF SERVICE power:DUMP OF SERVICE print:DUMP OF SERVICE processinfo:DUMP OF SERVICE procstats:DUMP OF SERVICE restrictions:DUMP OF SERVICE rttmanager:DUMP OF SERVICE samplingprofiler:DUMP OF SERVICE scheduling_policy:DUMP OF SERVICE search:DUMP OF SERVICE sensorservice:DUMP OF SERVICE serial:DUMP OF SERVICE servicediscovery:DUMP OF SERVICE simphonebook:DUMP OF SERVICE sip:DUMP OF SERVICE statusbar:DUMP OF SERVICE telecom:DUMP OF SERVICE telephony.registry:DUMP OF SERVICE textservices:DUMP OF SERVICE trust:DUMP OF SERVICE uimode:DUMP OF SERVICE updatelock:DUMP OF SERVICE usagestats:DUMP OF SERVICE usb:DUMP OF SERVICE user:DUMP OF SERVICE vibrator:DUMP OF SERVICE voiceinteraction:DUMP OF SERVICE wallpaper:DUMP OF SERVICE webviewupdate:DUMP OF SERVICE wifi:DUMP OF SERVICE wifip2p:DUMP OF SERVICE wifiscanner:DUMP OF SERVICE window:

这里总结以下,上面的bugreport整体逻辑如下图描述(如果图片太小看不清,请下载图片并查看):
Android adb bugreport工具分析和使用_第5张图片

adb bugreport的其他选项

bugreport本身并没有什么选项,主要是通过dumpsys等命令配合完成,详见battery historian项目主页:https://github.com/google/battery-historian,以下是个总结:
1). 重置电池统计信息:

adb shell dumpsys batterystats --reset

2). Wakelock analysis全部wakelock信息:

adb shell dumpsys batterystats --enable full-wake-history

3). Kernel trace analysis分析内核,主要分析wakeup source和wakelock activities,首先使能kernel分析:

$ adb root$ adb shell# Set the events to trace.$ echo "power:wakeup_source_activate" >> /d/tracing/set_event$ echo "power:wakeup_source_deactivate" >> /d/tracing/set_event# The default trace size for most devices is 1MB, which is relatively low and might cause the logs to overflow.# 8MB to 10MB should be a decent size for 5-6 hours of logging.$ echo 8192 > /d/tracing/buffer_size_kb$ echo 1 > /d/tracing/tracing_on

然后获得log:

$ echo 0 > /d/tracing/tracing_on$ adb pull /d/tracing/trace # Take a bug report at this time.$ adb bugreport > bugreport.txt

更多相关文章

  1. Android 的 那些 秘密代码
  2. Systrace 分析性能工具使用方法详解
  3. 使用FlowDroid生成Android应用程序的函数调用图
  4. Android超炫图片浏览器代码
  5. [eclipse]android开发如何查看源代码文件(android source)
  6. Android之A面试题④应用程序内部启动Activity过程(startActivity)
  7. 第101讲:Android源代码下载指南(图解)
  8. 下一代Android渠道打包工具
  9. Android操作系统安全(分层结构、应用沙盒、安全进程通信、Android

随机推荐

  1. 多个Android device offline处理命令
  2. android之android studio的NDK环境搭建
  3. Android(安卓)客户端与服务器交互方式
  4. Android(安卓)一套完整的 Socket 解决方
  5. Android两个recyview直接的item拖动
  6. Android定义一个不消失的悬停通知栏
  7. android---菜单栏选项
  8. Android(安卓)11 Beta 2 和平台稳定性里
  9. android获取屏幕分辨率
  10. the android sdk folder can no longer b