0%

adbbugreport原理

使用

7.0以上

1
adb bugreport bugreport.zip

7.0以下

1
adb bugreport > bugreport.txt

关键词

bugreport,dumpstate,dumpsys

源码

main.cpp

1
2
3
4
5
6
int main(int argc, char* argv[], char* envp[]) {
__adb_argv = const_cast<const char**>(argv);
__adb_envp = const_cast<const char**>(envp);
adb_trace_init(argv);
return adb_commandline(argc - 1, const_cast<const char**>(argv + 1));
}

这里是adb的启动入口,因为argv[0]为adb本身,所以这里argc-1 ,argv地址指向adb的第一个参数
eg :adb a b c argv[adb,a,b,c]

commandline.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
int adb_commandline(int argc, const char** argv) {

...
while (argc > 0) {
if (!strcmp(argv[0], "server")) {
is_server = true;
} else if (!strcmp(argv[0], "nodaemon")) {
no_daemon = true;
} else if (!strcmp(argv[0], "fork-server")) {
/* this is a special flag used only when the ADB client launches the ADB Server */
is_daemon = true;
} else if (!strcmp(argv[0], "--reply-fd")) {
if (argc < 2) error_exit("--reply-fd requires an argument");
const char* reply_fd_str = argv[1];
argc--;
argv++;
ack_reply_fd = strtol(reply_fd_str, nullptr, 10);
if (!_is_valid_ack_reply_fd(ack_reply_fd)) {
fprintf(stderr, "adb: invalid reply fd \"%s\"\n", reply_fd_str);
return 1;
}
} else if (!strncmp(argv[0], "-s", 2)) {
if (isdigit(argv[0][2])) {
serial = argv[0] + 2;
} else {
if (argc < 2 || argv[0][2] != '\0') error_exit("-s requires an argument");
serial = argv[1];
argc--;
argv++;
}
} else if (!strncmp(argv[0], "-t", 2)) {
const char* id;
if (isdigit(argv[0][2])) {
id = argv[0] + 2;
} else {
id = argv[1];
argc--;
argv++;
}
transport_id = strtoll(id, const_cast<char**>(&id), 10);
if (*id != '\0') {
error_exit("invalid transport id");
}
} else if (!strcmp(argv[0], "-d")) {
transport_type = kTransportUsb;
} else if (!strcmp(argv[0], "-e")) {
transport_type = kTransportLocal;
} else if (!strcmp(argv[0], "-a")) {
gListenAll = 1;
} else if (!strncmp(argv[0], "-H", 2)) {
if (argv[0][2] == '\0') {
if (argc < 2) error_exit("-H requires an argument");
server_host_str = argv[1];
argc--;
argv++;
} else {
server_host_str = argv[0] + 2;
}
} else if (!strncmp(argv[0], "-P", 2)) {
if (argv[0][2] == '\0') {
if (argc < 2) error_exit("-P requires an argument");
server_port_str = argv[1];
argc--;
argv++;
} else {
server_port_str = argv[0] + 2;
}
} else if (!strcmp(argv[0], "-L")) {
if (argc < 2) error_exit("-L requires an argument");
server_socket_str = argv[1];
argc--;
argv++;
} else {
/* out of recognized modifiers and flags */
break;
}
argc--;
argv++;
}

...
//二级参数

/* adb_connect() commands */
if (!strcmp(argv[0], "devices")) {
const char *listopt;
if (argc < 2) {
listopt = "";
} else if (argc == 2 && !strcmp(argv[1], "-l")) {
listopt = argv[1];
} else {
error_exit("adb devices [-l]");
}

std::string query = android::base::StringPrintf("host:%s%s", argv[0], listopt);
std::string error;
if (!adb_check_server_version(&error)) {
error_exit("failed to check server version: %s", error.c_str());
}
printf("List of devices attached\n");
return adb_query_command(query);
}
else if (!strcmp(argv[0], "connect")) {
if (argc != 2) error_exit("usage: adb connect <host>[:<port>]");

std::string query = android::base::StringPrintf("host:connect:%s", argv[1]);
return adb_query_command(query);
}
else if (!strcmp(argv[0], "disconnect")) {
if (argc > 2) error_exit("usage: adb disconnect [<host>[:<port>]]");

std::string query = android::base::StringPrintf("host:disconnect:%s",
(argc == 2) ? argv[1] : "");
return adb_query_command(query);
} else if (!strcmp(argv[0], "abb")) {
return adb_abb(argc, argv);
} else if (!strcmp(argv[0], "emu")) {
return adb_send_emulator_command(argc, argv, serial);
} else if (!strcmp(argv[0], "shell")) {
return adb_shell(argc, argv);
} else if (!strcmp(argv[0], "kill-server")) {
return adb_kill_server() ? 0 : 1;
} else if (!strcmp(argv[0], "sideload")) {
if (argc != 2) error_exit("sideload requires an argument");
if (adb_sideload_install(argv[1], false /* rescue_mode */)) {
return 1;
} else {
return 0;
}
} else if (!strcmp(argv[0], "remount") ||
!strcmp(argv[0], "reboot") ||
!strcmp(argv[0], "reboot-bootloader") ||
!strcmp(argv[0], "reboot-fastboot") ||
!strcmp(argv[0], "usb") ||
!strcmp(argv[0], "disable-verity") ||
!strcmp(argv[0], "enable-verity")) {
// clang-format on
std::string command;
if (!strcmp(argv[0], "reboot-bootloader")) {
command = "reboot:bootloader";
} else if (!strcmp(argv[0], "reboot-fastboot")) {
command = "reboot:fastboot";
} else if (argc > 1) {
command = android::base::StringPrintf("%s:%s", argv[0], argv[1]);
} else {
command = android::base::StringPrintf("%s:", argv[0]);
}
return adb_connect_command(command);
} else if (!strcmp(argv[0], "root") || !strcmp(argv[0], "unroot")) {
return adb_root(argv[0]) ? 0 : 1;
} else if (!strcmp(argv[0], "bugreport")) {
Bugreport bugreport;
return bugreport.DoIt(argc, argv);
}
...
}

adb_commandline函数主要是对argv进行解析,并调用相应的处理函数,这里我们关注的是bugreport, strcmp函数返回0表示argv[0]和”bugreport”相等 这里取非则可以执行bugreport.DoIt

bugreport.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
int Bugreport::DoIt(int argc, const char** argv) {
//bugreport path ,如果大于 bugreport后面有查过1个参数,则error
if (argc > 2) error_exit("usage: adb bugreport [PATH]");

// Gets bugreportz version.
std::string bugz_stdout, bugz_stderr;
DefaultStandardStreamsCallback version_callback(&bugz_stdout, &bugz_stderr);
int status = SendShellCommand("bugreportz -v", false, &version_callback);
std::string bugz_version = android::base::Trim(bugz_stderr);
std::string bugz_output = android::base::Trim(bugz_stdout);

if (status != 0 || bugz_version.empty()) {
D("'bugreportz' -v results: status=%d, stdout='%s', stderr='%s'", status,
bugz_output.c_str(), bugz_version.c_str());
if (argc == 1) {
// Device does not support bugreportz: if called as 'adb bugreport', just falls out to
// the flat-file version.
fprintf(stderr,
"Failed to get bugreportz version, which is only available on devices "
"running Android 7.0 or later.\nTrying a plain-text bug report instead.\n");
return SendShellCommand("bugreport", false);
}

// But if user explicitly asked for a zipped bug report, fails instead (otherwise calling
// 'bugreport' would generate a lot of output the user might not be prepared to handle).
fprintf(stderr,
"Failed to get bugreportz version: 'bugreportz -v' returned '%s' (code %d).\n"
"If the device does not run Android 7.0 or above, try 'adb bugreport' instead.\n",
bugz_output.c_str(), status);
return status != 0 ? status : -1;
}

std::string dest_file, dest_dir;
//如果只有bugreport ,后面没有路径
if (argc == 1) {
// No args - use current directory
if (!getcwd(&dest_dir)) { //dest_dir赋值当前路径
perror("adb: getcwd failed");
return 1;
}
} else {
// Check whether argument is a directory or file
if (directory_exists(argv[1])) { //如果是文件夹,dest_dir 赋值
dest_dir = argv[1]; //
} else {
dest_file = argv[1]; //如果是文件,dest_file赋值
}
}
//如果dest_file为空,则补全dest_file bugreport.zip
if (dest_file.empty()) {
// Uses a default value until device provides the proper name
dest_file = "bugreport.zip";
} else {
//如果没有以.zip 结尾,结尾补全.zip
if (!android::base::EndsWithIgnoreCase(dest_file, ".zip")) {
dest_file += ".zip";
}
}

bool show_progress = true;
std::string bugz_command = "bugreportz -p";
if (bugz_version == "1.0") {
// 1.0 does not support progress notifications, so print a disclaimer
// message instead.
fprintf(stderr,
"Bugreport is in progress and it could take minutes to complete.\n"
"Please be patient and do not cancel or disconnect your device "
"until it completes.\n");
show_progress = false;
bugz_command = "bugreportz";
}
// 手机和电脑通信获取bugreport
BugreportStandardStreamsCallback bugz_callback(dest_dir, dest_file, show_progress, this);
return SendShellCommand(bugz_command, false, &bugz_callback);
}

这里主要是对bugreport后面的argv进行处理,最后调用了bugreportz,bugreportz是一个可执行文件

android/aosp/frameworks/native/cmds/bugreportz/main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
int main(int argc, char* argv[]) {
bool show_progress = false;
if (argc > 1) {
/* parse arguments */
int c;
while ((c = getopt(argc, argv, "hpv")) != -1) {
switch (c) {
case 'h':
show_usage();
return EXIT_SUCCESS;
case 'p':
show_progress = true;
break;
case 'v':
show_version();
return EXIT_SUCCESS;
default:
show_usage();
return EXIT_FAILURE;
}
}
}

// TODO: code below was copy-and-pasted from bugreport.cpp (except by the
// timeout value);
// should be reused instead.

// Start the dumpstatez service.
property_set("ctl.start", "dumpstatez");

// 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("FAIL:Failed to connect to dumpstatez service: %s\n", strerror(errno));
return EXIT_FAILURE;
}

// Set a timeout so that if nothing is read in 10 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 = 10 * 60;
tv.tv_usec = 0;
if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
fprintf(stderr,
"WARNING: Cannot set socket timeout, bugreportz might hang indefinitely: %s\n",
strerror(errno));
}

int ret = bugreportz(s, show_progress);

if (close(s) == -1) {
fprintf(stderr, "WARNING: error closing socket: %s\n", strerror(errno));
ret = EXIT_FAILURE;
}
return ret;
}

启动一个dumpstate服务,通过socket去连接dumpstate服务,下面我们看dumpstate的入口

android/aosp/frameworks/native/cmds/dumpstate/main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int main(int argc, char* argv[]) {
if (ShouldStartServiceAndWait(argc, argv)) {
int ret;
if ((ret = android::os::DumpstateService::Start()) != android::OK) {
MYLOGE("Unable to start 'dumpstate' service: %d", ret);
exit(1);
}
MYLOGI("'dumpstate' service started and will wait for a call to startBugreport()");

// Waits forever for an incoming connection.
// TODO(b/111441001): should this time out?
android::IPCThreadState::self()->joinThreadPool();
return 0;
} else {
return run_main(argc, argv);
}
}

这里是dumpstate的启动入口,这里调用了dumpstate的run_main函数

android/aosp/frameworks/native/cmds/dumpstate/dumpstate.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
int run_main(int argc, char* argv[]) {
Dumpstate::RunStatus status = ds.ParseCommandlineAndRun(argc, argv);

switch (status) {
case Dumpstate::RunStatus::OK:
exit(0);
case Dumpstate::RunStatus::HELP:
ShowUsage();
exit(0);
case Dumpstate::RunStatus::INVALID_INPUT:
fprintf(stderr, "Invalid combination of args\n");
ShowUsage();
exit(1);
case Dumpstate::RunStatus::ERROR:
FALLTHROUGH_INTENDED;
case Dumpstate::RunStatus::USER_CONSENT_DENIED:
FALLTHROUGH_INTENDED;
case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
exit(2);
}
}

Dumpstate::RunStatus Dumpstate::ParseCommandlineAndRun(int argc, char* argv[]) {
std::unique_ptr<Dumpstate::DumpOptions> options = std::make_unique<Dumpstate::DumpOptions>();
Dumpstate::RunStatus status = options->Initialize(argc, argv);
if (status == Dumpstate::RunStatus::OK) {
SetOptions(std::move(options));
// When directly running dumpstate binary, the output is not expected to be written
// to any external file descriptor.
assert(options_->bugreport_fd.get() == -1);

// calling_uid and calling_package are for user consent to share the bugreport with
// an app; they are irrelvant here because bugreport is only written to a local
// directory, and not shared.
status = Run(-1 /* calling_uid */, "" /* calling_package */);
}
return status;
}

Dumpstate::RunStatus Dumpstate::Run(int32_t calling_uid, const std::string& calling_package) {
Dumpstate::RunStatus status = RunInternal(calling_uid, calling_package);
if (listener_ != nullptr) {
switch (status) {
case Dumpstate::RunStatus::OK:
listener_->onFinished();
break;
case Dumpstate::RunStatus::HELP:
break;
case Dumpstate::RunStatus::INVALID_INPUT:
listener_->onError(IDumpstateListener::BUGREPORT_ERROR_INVALID_INPUT);
break;
case Dumpstate::RunStatus::ERROR:
listener_->onError(IDumpstateListener::BUGREPORT_ERROR_RUNTIME_ERROR);
break;
case Dumpstate::RunStatus::USER_CONSENT_DENIED:
listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_DENIED_CONSENT);
break;
case Dumpstate::RunStatus::USER_CONSENT_TIMED_OUT:
listener_->onError(IDumpstateListener::BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
break;
}
}
return status;
}

启动流程比较长,我们可以直接可以看dumpstate.cpp的核心代码

dumpstate.cpp 核心代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
#define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
#define ALT_PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops-0"
#define BLK_DEV_SYS_DIR "/sys/block"

#define RECOVERY_DIR "/cache/recovery"
#define RECOVERY_DATA_DIR "/data/misc/recovery"
#define UPDATE_ENGINE_LOG_DIR "/data/misc/update_engine_log"
#define LOGPERSIST_DATA_DIR "/data/misc/logd"
#define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
#define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
#define XFRM_STAT_PROC_FILE "/proc/net/xfrm_stat"
#define WLUTIL "/vendor/xbin/wlutil"
#define WMTRACE_DATA_DIR "/data/misc/wmtrace"

// TODO(narayan): Since this information has to be kept in sync
// with tombstoned, we should just put it in a common header.
//
// File: system/core/debuggerd/tombstoned/tombstoned.cpp
static const std::string TOMBSTONE_DIR = "/data/tombstones/";
static const std::string TOMBSTONE_FILE_PREFIX = "tombstone_";
static const std::string ANR_DIR = "/data/anr/";
static const std::string ANR_FILE_PREFIX = "anr_";


static Dumpstate::RunStatus DumpstateDefault() {
// Try to dump anrd trace if the daemon is running.
dump_anrd_trace();

// Invoking the following dumpsys calls before DumpTraces() to try and
// keep the system stats as close to its initial state as possible.
RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysCritical);

/* collect stack traces from Dalvik and native processes (needs root) */
RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpTraces, &dump_traces_path);

/* Run some operations that require root. */
ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX, !ds.IsZipping());
ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping());

ds.AddDir(RECOVERY_DIR, true);
ds.AddDir(RECOVERY_DATA_DIR, true);
ds.AddDir(UPDATE_ENGINE_LOG_DIR, true);
ds.AddDir(LOGPERSIST_DATA_DIR, false);
if (!PropertiesHelper::IsUserBuild()) {
ds.AddDir(PROFILE_DATA_DIR_CUR, true);
ds.AddDir(PROFILE_DATA_DIR_REF, true);
}
add_mountinfo();
DumpIpTablesAsRoot();

// Capture any IPSec policies in play. No keys are exposed here.
RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"}, CommandOptions::WithTimeout(10).Build());

// Dump IPsec stats. No keys are exposed here.
DumpFile("XFRM STATS", XFRM_STAT_PROC_FILE);

// Run ss as root so we can see socket marks.
RunCommand("DETAILED SOCKET STATE", {"ss", "-eionptu"}, CommandOptions::WithTimeout(10).Build());

// Run iotop as root to show top 100 IO threads
RunCommand("IOTOP", {"iotop", "-n", "1", "-m", "100"});

// Gather shared memory buffer info if the product implements it
struct stat st;
if (!stat("/product/bin/dmabuf_dump", &st)) {
RunCommand("Dmabuf dump", {"/product/bin/dmabuf_dump"});
}

if (!DropRootUser()) {
return Dumpstate::RunStatus::ERROR;
}

RETURN_IF_USER_DENIED_CONSENT();
return dumpstate(); // dumpstate
}


static Dumpstate::RunStatus dumpstate() {
DurationReporter duration_reporter("DUMPSTATE");

// Dump various things. Note that anything that takes "long" (i.e. several seconds) should
// check intermittently (if it's intrerruptable like a foreach on pids) and/or should be wrapped
// in a consent check (via RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK).
dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
RunCommand("UPTIME", {"uptime"});
DumpBlockStatFiles();
dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd");
DumpFile("MEMORY INFO", "/proc/meminfo");
RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o",
"pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"});

RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "PROCRANK", {"procrank"}, AS_ROOT_20);

DumpFile("VIRTUAL MEMORY STATS", "/proc/vmstat");
DumpFile("VMALLOC INFO", "/proc/vmallocinfo");
DumpFile("SLAB INFO", "/proc/slabinfo");
DumpFile("ZONEINFO", "/proc/zoneinfo");
DumpFile("PAGETYPEINFO", "/proc/pagetypeinfo");
DumpFile("BUDDYINFO", "/proc/buddyinfo");
DumpFile("FRAGMENTATION INFO", "/d/extfrag/unusable_index");

DumpFile("KERNEL WAKE SOURCES", "/d/wakeup_sources");
DumpFile("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
DumpFile("KERNEL SYNC", "/d/sync");

RunCommand("PROCESSES AND THREADS",
{"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"});

RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "LIBRANK", {"librank"},
CommandOptions::AS_ROOT);

DumpHals();

RunCommand("PRINTENV", {"printenv"});
RunCommand("NETSTAT", {"netstat", "-nW"});
struct stat s;
if (stat("/proc/modules", &s) != 0) {
MYLOGD("Skipping 'lsmod' because /proc/modules does not exist\n");
} else {
RunCommand("LSMOD", {"lsmod"});
}

if (__android_logger_property_get_bool(
"ro.logd.kernel", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE)) {
DoKernelLogcat();
} else {
do_dmesg();
}

RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT);

RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(for_each_pid, do_showmap, "SMAPS OF ALL PROCESSES");

for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)");

/* Dump Bluetooth HCI logs */
ds.AddDir("/data/misc/bluetooth/logs", true);

if (!ds.do_early_screenshot_) {
MYLOGI("taking late screenshot\n");
ds.TakeScreenshot();
}

DoLogcat();

AddAnrTraceFiles();

// NOTE: tombstones are always added as separate entries in the zip archive
// and are not interspersed with the main report.
const bool tombstones_dumped = AddDumps(ds.tombstone_data_.begin(), ds.tombstone_data_.end(),
"TOMBSTONE", true /* add_to_zip */);
if (!tombstones_dumped) {
printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR.c_str());
}

DumpPacketStats();

RunDumpsys("EBPF MAP STATS", {"netd", "trafficcontroller"});

DoKmsg();

DumpIpAddrAndRules();

dump_route_tables();

RunCommand("ARP CACHE", {"ip", "-4", "neigh", "show"});
RunCommand("IPv6 ND CACHE", {"ip", "-6", "neigh", "show"});
RunCommand("MULTICAST ADDRESSES", {"ip", "maddr"});

RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysHigh);

RunCommand("SYSTEM PROPERTIES", {"getprop"});

RunCommand("STORAGED IO INFO", {"storaged", "-u", "-p"});

RunCommand("FILESYSTEMS & FREE SPACE", {"df"});

RunCommand("LAST RADIO LOG", {"parse_radio_log", "/proc/last_radio_log"});

/* Binder state is expensive to look at as it uses a lot of memory. */
DumpFile("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
DumpFile("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
DumpFile("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions");
DumpFile("BINDER STATS", "/sys/kernel/debug/binder/stats");
DumpFile("BINDER STATE", "/sys/kernel/debug/binder/state");

RunDumpsys("WINSCOPE TRACE", {"window", "trace"});
/* Add window and surface trace files. */
if (!PropertiesHelper::IsUserBuild()) {
ds.AddDir(WMTRACE_DATA_DIR, false);
}

RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(ds.DumpstateBoard);

/* Migrate the ril_dumpstate to a device specific dumpstate? */
int rilDumpstateTimeout = android::base::GetIntProperty("ril.dumpstate.timeout", 0);
if (rilDumpstateTimeout > 0) {
// 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.
CommandOptions::CommandOptionsBuilder options =
CommandOptions::WithTimeout(rilDumpstateTimeout);
if (!PropertiesHelper::IsUserBuild()) {
options.AsRoot();
}
RunCommand("DUMP VENDOR RIL LOGS", {"vril-dump"}, options.Build());
}

printf("========================================================\n");
printf("== Android Framework Services\n");
printf("========================================================\n");

RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsysNormal);

printf("========================================================\n");
printf("== Checkins\n");
printf("========================================================\n");

RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"});

RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunDumpsys, "CHECKIN MEMINFO", {"meminfo", "--checkin"});

RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"});
RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"});
RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"});
RunDumpsys("CHECKIN PACKAGE", {"package", "--checkin"});

printf("========================================================\n");
printf("== Running Application Activities\n");
printf("========================================================\n");

// The following dumpsys internally collects output from running apps, so it can take a long
// time. So let's extend the timeout.

const CommandOptions DUMPSYS_COMPONENTS_OPTIONS = CommandOptions::WithTimeout(60).Build();

RunDumpsys("APP ACTIVITIES", {"activity", "-v", "all"}, DUMPSYS_COMPONENTS_OPTIONS);

printf("========================================================\n");
printf("== Running Application Services (platform)\n");
printf("========================================================\n");

RunDumpsys("APP SERVICES PLATFORM", {"activity", "service", "all-platform-non-critical"},
DUMPSYS_COMPONENTS_OPTIONS);

printf("========================================================\n");
printf("== Running Application Services (non-platform)\n");
printf("========================================================\n");

RunDumpsys("APP SERVICES NON-PLATFORM", {"activity", "service", "all-non-platform"},
DUMPSYS_COMPONENTS_OPTIONS);

printf("========================================================\n");
printf("== Running Application Providers (platform)\n");
printf("========================================================\n");

RunDumpsys("APP PROVIDERS PLATFORM", {"activity", "provider", "all-platform"},
DUMPSYS_COMPONENTS_OPTIONS);

printf("========================================================\n");
printf("== Running Application Providers (non-platform)\n");
printf("========================================================\n");

RunDumpsys("APP PROVIDERS NON-PLATFORM", {"activity", "provider", "all-non-platform"},
DUMPSYS_COMPONENTS_OPTIONS);

printf("========================================================\n");
printf("== Dropbox crashes\n");
printf("========================================================\n");

RunDumpsys("DROPBOX SYSTEM SERVER CRASHES", {"dropbox", "-p", "system_server_crash"});
RunDumpsys("DROPBOX SYSTEM APP CRASHES", {"dropbox", "-p", "system_app_crash"});

printf("========================================================\n");
printf("== Final progress (pid %d): %d/%d (estimated %d)\n", ds.pid_, ds.progress_->Get(),
ds.progress_->GetMax(), ds.progress_->GetInitialMax());
printf("========================================================\n");
printf("== dumpstate: done (id %d)\n", ds.id_);
printf("========================================================\n");

printf("========================================================\n");
printf("== Obtaining statsd metadata\n");
printf("========================================================\n");
// This differs from the usual dumpsys stats, which is the stats report data.
RunDumpsys("STATSDSTATS", {"stats", "--metadata"});
return Dumpstate::RunStatus::OK;
}

这里我们可以看到三个频繁出现的函数DumpFile,RunDumpsys,RunCommand,DumpFIle是Dump一个文件到stdout中,RunDumpsys是运行dumpsys可执行文件,RunCommand是在shell中运行命令

具体可以查看android/aosp/frameworks/native/cmds/dumpstate

ANR

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
static Dumpstate::RunStatus DumpstateDefault() {
// 获取ANR fd集合
ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX, !ds.IsZipping());
return dumpstate();
}

//添加anr 到输出中
static Dumpstate::RunStatus dumpstate() {
AddAnrTraceFiles();
}



static void AddAnrTraceFiles() {
const bool add_to_zip = ds.IsZipping() && ds.version_ == VERSION_SPLIT_ANR;

std::string anr_traces_dir = "/data/anr";
//添加anr到文件夹
AddAnrTraceDir(add_to_zip, anr_traces_dir);

RunCommand("ANR FILES", {"ls", "-lt", ANR_DIR});

// Slow traces for slow operations.
struct stat st;
int i = 0;
while (true) {
const std::string slow_trace_path =
anr_traces_dir + android::base::StringPrintf("slow%02d.txt", i);
if (stat(slow_trace_path.c_str(), &st)) {
// No traces file at this index, done with the files.
break;
}
ds.DumpFile("VM TRACES WHEN SLOW", slow_trace_path.c_str());
i++;
}
}




static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_dir) {
MYLOGD("AddAnrTraceDir(): dump_traces_file=%s, anr_traces_dir=%s\n", dump_traces_path,
anr_traces_dir.c_str());

// If we're here, dump_traces_path will always be a temporary file
// (created with mkostemp or similar) that contains dumps taken earlier
// on in the process.
if (dump_traces_path != nullptr) {
if (add_to_zip) {
ds.AddZipEntry(ZIP_ROOT_DIR + anr_traces_dir + "/traces-just-now.txt", dump_traces_path);
} else {
MYLOGD("Dumping current ANR traces (%s) to the main bugreport entry\n",
dump_traces_path);
ds.DumpFile("VM TRACES JUST NOW", dump_traces_path);
}

const int ret = unlink(dump_traces_path);
if (ret == -1) {
MYLOGW("Error unlinking temporary trace path %s: %s\n", dump_traces_path,
strerror(errno));
}
}

// Add a specific message for the first ANR Dump.
if (ds.anr_data_.size() > 0) {
//
AddDumps(ds.anr_data_.begin(), ds.anr_data_.begin() + 1,
"VM TRACES AT LAST ANR", add_to_zip);

// The "last" ANR will always be included as separate entry in the zip file. In addition,
// it will be present in the body of the main entry if |add_to_zip| == false.
//
// Historical ANRs are always included as separate entries in the bugreport zip file.
AddDumps(ds.anr_data_.begin() + ((add_to_zip) ? 1 : 0), ds.anr_data_.end(),
"HISTORICAL ANR", true /* add_to_zip */);
} else {
printf("*** NO ANRs to dump in %s\n\n", ANR_DIR.c_str());
}
}



static bool AddDumps(const std::vector<DumpData>::const_iterator start,
const std::vector<DumpData>::const_iterator end,
const char* type_name, const bool add_to_zip) {
bool dumped = false;
// 遍历 DumpData fd为 /data/anr/xxxx.txt
for (auto it = start; it != end; ++it) {
const std::string& name = it->name;
const int fd = it->fd;
dumped = true;

// Seek to the beginning of the file before dumping any data. A given
// DumpData entry might be dumped multiple times in the report.
//
// For example, the most recent ANR entry is dumped to the body of the
// main entry and it also shows up as a separate entry in the bugreport
// ZIP file.
if (lseek(fd, 0, SEEK_SET) != static_cast<off_t>(0)) {
MYLOGE("Unable to add %s to zip file, lseek failed: %s\n", name.c_str(),
strerror(errno));
}

if (ds.IsZipping() && add_to_zip) {
if (ds.AddZipEntryFromFd(ZIP_ROOT_DIR + name, fd, /* timeout = */ 0ms) != OK) {
MYLOGE("Unable to add %s to zip file, addZipEntryFromFd failed\n", name.c_str());
}
} else {
// 从fd开始复制
dump_file_from_fd(type_name, name.c_str(), fd);
}
}

return dumped;
}


int dump_file_from_fd(const char *title, const char *path, int fd) {
if (PropertiesHelper::IsDryRun()) return 0;

int flags = fcntl(fd, F_GETFL);
if (flags == -1) {
printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno));
return -1;
} else if (!(flags & O_NONBLOCK)) {
printf("*** %s: fd must have O_NONBLOCK set.\n", path);
return -1;
}
// 从一个fd 到 另一个fd ,另一个fd为STDOUT_FILENO 标准输出
return DumpFileFromFdToFd(title, path, fd, STDOUT_FILENO, PropertiesHelper::IsDryRun());
}



int DumpFileFromFdToFd(const std::string& title, const std::string& path_string, int fd, int out_fd,
bool dry_run) {
const char* path = path_string.c_str();
if (!title.empty()) {
dprintf(out_fd, "------ %s (%s", title.c_str(), path);

struct stat st;
// Only show the modification time of non-device files.
size_t path_len = strlen(path);
if ((path_len < 6 || memcmp(path, "/proc/", 6)) &&
(path_len < 5 || memcmp(path, "/sys/", 5)) &&
(path_len < 3 || memcmp(path, "/d/", 3)) && !fstat(fd, &st)) {
char stamp[80];
time_t mtime = st.st_mtime;
strftime(stamp, sizeof(stamp), "%Y-%m-%d %H:%M:%S", localtime(&mtime));
dprintf(out_fd, ": %s", stamp);
}
dprintf(out_fd, ") ------\n");
fsync(out_fd);
}
if (dry_run) {
if (out_fd != STDOUT_FILENO) {
// There is no title, but we should still print a dry-run message
dprintf(out_fd, "%s: skipped on dry run\n", path);
} else if (!title.empty()) {
dprintf(out_fd, "\t(skipped on dry run)\n");
}
fsync(out_fd);
return 0;
}
bool newline = false;
while (true) {
uint64_t start_time = Nanotime();
pollfd fds[] = { { .fd = fd, .events = POLLIN } };
int ret = TEMP_FAILURE_RETRY(poll(fds, arraysize(fds), 30 * 1000));
if (ret == -1) {
dprintf(out_fd, "*** %s: poll failed: %s\n", path, strerror(errno));
newline = true;
break;
} else if (ret == 0) {
uint64_t elapsed = Nanotime() - start_time;
dprintf(out_fd, "*** %s: Timed out after %.3fs\n", path, (float)elapsed / NANOS_PER_SEC);
newline = true;
break;
} else {
char buffer[65536];
ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
if (bytes_read > 0) {
//写出
android::base::WriteFully(out_fd, buffer, bytes_read);
newline = (buffer[bytes_read - 1] == '\n');
} else {
if (bytes_read == -1) {
dprintf(out_fd, "*** %s: Failed to read from fd: %s", path, strerror(errno));
newline = true;
}
break;
}
}
}

if (!newline) dprintf(out_fd, "\n");
if (!title.empty()) dprintf(out_fd, "\n");
return 0;
}



输出

adb bugreport a ,补全a.zip
image.png
image.png

adb bugreport /Users/juneleo/Desktop
image.png
image.png

adb bugreport
image.png
image.png