summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorWei Wang2018-03-23 13:32:21 -0500
committerWei Wang2018-03-23 13:33:16 -0500
commit5e129f1497bade6618be989bf73050108b30c010 (patch)
treed49d569a47716af8832883ab2e2a919d57d679f2 /tools
parentb966052d2c360bb5b7157ca8ef1015a569848e74 (diff)
downloadplatform-packages-services-car-5e129f1497bade6618be989bf73050108b30c010.tar.gz
platform-packages-services-car-5e129f1497bade6618be989bf73050108b30c010.tar.xz
platform-packages-services-car-5e129f1497bade6618be989bf73050108b30c010.zip
Move boottime tools to system/extra
Bug: 65481007 Test: Build Change-Id: I250ef87a6b580c30b15ea78fec32bbdb1bc78de7
Diffstat (limited to 'tools')
-rw-r--r--tools/bootanalyze/Android.mk20
-rw-r--r--tools/bootanalyze/README.md15
-rwxr-xr-xtools/bootanalyze/bootanalyze.py818
-rw-r--r--tools/bootanalyze/bugreport_anayze.py386
-rw-r--r--tools/bootanalyze/config.yaml78
-rw-r--r--tools/bootanalyze/stressfs/Android.mk29
-rw-r--r--tools/bootanalyze/stressfs/AndroidManifest.xml38
-rw-r--r--tools/bootanalyze/stressfs/proguard.flags3
-rw-r--r--tools/bootanalyze/stressfs/src/com/android/car/test/stressfs/WritingActivity.java61
-rw-r--r--tools/bootanalyze/stressfs/src/com/android/car/test/stressfs/WritingService.java186
-rw-r--r--tools/bootio/Android.mk76
-rw-r--r--tools/bootio/README.md24
-rw-r--r--tools/bootio/bootio.cpp162
-rw-r--r--tools/bootio/bootio.rc10
-rw-r--r--tools/bootio/bootio_collector.cpp381
-rw-r--r--tools/bootio/bootio_collector.h39
-rw-r--r--tools/bootio/protos.proto55
-rw-r--r--tools/bootio/sepolicy/bootio.te12
-rw-r--r--tools/bootio/sepolicy/domain.te2
-rw-r--r--tools/bootio/sepolicy/file.te2
-rw-r--r--tools/bootio/sepolicy/file_contexts5
21 files changed, 0 insertions, 2402 deletions
diff --git a/tools/bootanalyze/Android.mk b/tools/bootanalyze/Android.mk
deleted file mode 100644
index 5df0dd83..00000000
--- a/tools/bootanalyze/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
1# Copyright (C) 2017 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14#
15#
16
17LOCAL_PATH := $(call my-dir)
18
19# Include the sub-makefiles
20include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tools/bootanalyze/README.md b/tools/bootanalyze/README.md
deleted file mode 100644
index d6e0412f..00000000
--- a/tools/bootanalyze/README.md
+++ /dev/null
@@ -1,15 +0,0 @@
1# bootanalyze #
2
3The bootanalyze tool helps to profile boot timing.
4
5Per specific product modify config.yaml file to include
6events you are looking for. Config should look like:
7
8 stop_event: <logcat log message which will terminate log collection after reboot>
9 events:
10 event1_name: <pattern that matches log message>
11 event2_.....
12
13On some devise clock is showing incorrect time for first couple of seconds after boot.
14To ensure correct adjustment of time, one has to include event in config that will
15be present in dmesg log after clock correction.
diff --git a/tools/bootanalyze/bootanalyze.py b/tools/bootanalyze/bootanalyze.py
deleted file mode 100755
index b8783585..00000000
--- a/tools/bootanalyze/bootanalyze.py
+++ /dev/null
@@ -1,818 +0,0 @@
1#!/usr/bin/python
2
3# Copyright (C) 2016 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17"""Tool to analyze logcat and dmesg logs.
18
19bootanalyze read logcat and dmesg loga and determines key points for boot.
20"""
21
22import argparse
23import collections
24import datetime
25import math
26import operator
27import os
28import re
29import select
30import subprocess
31import sys
32import time
33import threading
34import yaml
35
36from datetime import datetime, date
37
38
39TIME_DMESG = "\[\s*(\d+\.\d+)\]"
40TIME_LOGCAT = "[0-9]+\.?[0-9]*"
41KERNEL_TIME_KEY = "kernel"
42BOOT_ANIM_END_TIME_KEY = "BootAnimEnd"
43KERNEL_BOOT_COMPLETE = "BootComplete_kernel"
44LOGCAT_BOOT_COMPLETE = "BootComplete"
45LAUNCHER_START = "LauncherStart"
46BOOT_TIME_TOO_BIG = 200.0
47MAX_RETRIES = 5
48DEBUG = False
49ADB_CMD = "adb"
50TIMING_THRESHOLD = 5.0
51BOOT_PROP = "\[ro\.boottime\.([^\]]+)\]:\s+\[(\d+)\]"
52BOOTLOADER_TIME_PROP = "\[ro\.boot\.boottime\]:\s+\[([^\]]+)\]"
53
54max_wait_time = BOOT_TIME_TOO_BIG
55
56def main():
57 global ADB_CMD
58
59 args = init_arguments()
60
61 if args.iterate < 1:
62 raise Exception('Number of iteration must be >=1');
63
64 if args.iterate > 1 and not args.reboot:
65 print "Forcing reboot flag"
66 args.reboot = True
67
68 if args.serial:
69 ADB_CMD = "%s %s" % ("adb -s", args.serial)
70
71 error_time = BOOT_TIME_TOO_BIG * 10
72 if args.errortime:
73 error_time = float(args.errortime)
74 if args.maxwaittime:
75 global max_wait_time
76 max_wait_time = float(args.maxwaittime)
77
78 components_to_monitor = {}
79 if args.componentmonitor:
80 items = args.componentmonitor.split(",")
81 for item in items:
82 kv = item.split("=")
83 key = kv[0]
84 value = float(kv[1])
85 components_to_monitor[key] = value
86
87 cfg = yaml.load(args.config)
88
89 if args.stressfs:
90 if run_adb_cmd('install -r -g ' + args.stressfs) != 0:
91 raise Exception('StressFS APK not installed');
92
93 if args.iterate > 1 and args.bootchart:
94 run_adb_shell_cmd_as_root('touch /data/bootchart/enabled')
95
96 search_events_pattern = {key: re.compile(pattern)
97 for key, pattern in cfg['events'].iteritems()}
98 timing_events_pattern = {key: re.compile(pattern)
99 for key, pattern in cfg['timings'].iteritems()}
100 shutdown_events_pattern = {key: re.compile(pattern)
101 for key, pattern in cfg['shutdown_events'].iteritems()}
102
103 data_points = {}
104 kernel_timing_points = collections.OrderedDict()
105 logcat_timing_points = collections.OrderedDict()
106 boottime_points = collections.OrderedDict()
107 boot_chart_file_name_prefix = "bootchart-" + datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
108 systrace_file_name_prefix = "systrace-" + datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
109 shutdown_event_all = collections.OrderedDict()
110 shutdown_timing_event_all = collections.OrderedDict()
111 for it in range(0, args.iterate):
112 if args.iterate > 1:
113 print "Run: {0}".format(it)
114 attempt = 1
115 processing_data = None
116 timings = None
117 boottime_events = None
118 while attempt <= MAX_RETRIES and processing_data is None:
119 attempt += 1
120 processing_data, kernel_timings, logcat_timings, boottime_events, shutdown_events,\
121 shutdown_timing_events = iterate(\
122 args, search_events_pattern, timing_events_pattern, shutdown_events_pattern, cfg,\
123 error_time, components_to_monitor)
124 if shutdown_events:
125 for k, v in shutdown_events.iteritems():
126 events = shutdown_event_all.get(k)
127 if not events:
128 events = []
129 shutdown_event_all[k] = events
130 events.append(v)
131 if shutdown_timing_events:
132 for k, v in shutdown_timing_events.iteritems():
133 events = shutdown_timing_event_all.get(k)
134 if not events:
135 events = []
136 shutdown_timing_event_all[k] = events
137 events.append(v)
138 if not processing_data or not boottime_events:
139 # Processing error
140 print "Failed to collect valid samples for run {0}".format(it)
141 continue
142 if args.bootchart:
143 grab_bootchart(boot_chart_file_name_prefix + "_run_" + str(it))
144
145 if args.systrace:
146 grab_systrace(systrace_file_name_prefix + "_run_" + str(it))
147 for k, v in processing_data.iteritems():
148 if k not in data_points:
149 data_points[k] = []
150 data_points[k].append(v['value'])
151
152 if kernel_timings is not None:
153 for k, v in kernel_timings.iteritems():
154 if k not in kernel_timing_points:
155 kernel_timing_points[k] = []
156 kernel_timing_points[k].append(v)
157 if logcat_timings is not None:
158 for k, v in logcat_timings.iteritems():
159 if k not in logcat_timing_points:
160 logcat_timing_points[k] = []
161 logcat_timing_points[k].append(v)
162
163 for k, v in boottime_events.iteritems():
164 if not k in boottime_points:
165 boottime_points[k] = []
166 boottime_points[k].append(v)
167
168 if args.stressfs:
169 run_adb_cmd('uninstall com.android.car.test.stressfs')
170 run_adb_shell_cmd('"rm -rf /storage/emulated/0/stressfs_data*"')
171
172 if args.iterate > 1:
173 print "-----------------"
174 print "\nshutdown events after {0} runs".format(args.iterate)
175 print '{0:30}: {1:<7} {2:<7} {3}'.format("Event", "Mean", "stddev", "#runs")
176 for item in shutdown_event_all.items():
177 num_runs = len(item[1])
178 print '{0:30}: {1:<7.5} {2:<7.5} {3} {4}'.format(
179 item[0], sum(item[1])/num_runs, stddev(item[1]),\
180 "*time taken" if item[0].startswith("init.") else "",\
181 num_runs if num_runs != args.iterate else "")
182 print "\nshutdown timing events after {0} runs".format(args.iterate)
183 print '{0:30}: {1:<7} {2:<7} {3}'.format("Event", "Mean", "stddev", "#runs")
184 for item in shutdown_timing_event_all.items():
185 num_runs = len(item[1])
186 print '{0:30}: {1:<7.5} {2:<7.5} {3} {4}'.format(
187 item[0], sum(item[1])/num_runs, stddev(item[1]),\
188 "*time taken" if item[0].startswith("init.") else "",\
189 num_runs if num_runs != args.iterate else "")
190
191 print "-----------------"
192 print "ro.boottime.* after {0} runs".format(args.iterate)
193 print '{0:30}: {1:<7} {2:<7} {3}'.format("Event", "Mean", "stddev", "#runs")
194 for item in boottime_points.items():
195 num_runs = len(item[1])
196 print '{0:30}: {1:<7.5} {2:<7.5} {3} {4}'.format(
197 item[0], sum(item[1])/num_runs, stddev(item[1]),\
198 "*time taken" if item[0].startswith("init.") else "",\
199 num_runs if num_runs != args.iterate else "")
200
201 if args.timings:
202 dump_timings_points_summary("Kernel", kernel_timing_points, args)
203 dump_timings_points_summary("Logcat", logcat_timing_points, args)
204
205
206 print "-----------------"
207 print "Avg values after {0} runs".format(args.iterate)
208 print '{0:30}: {1:<7} {2:<7} {3}'.format("Event", "Mean", "stddev", "#runs")
209
210 average_with_stddev = []
211 for item in data_points.items():
212 average_with_stddev.append((item[0], sum(item[1])/len(item[1]), stddev(item[1]),\
213 len(item[1])))
214 for item in sorted(average_with_stddev, key=lambda entry: entry[1]):
215 print '{0:30}: {1:<7.5} {2:<7.5} {3}'.format(
216 item[0], item[1], item[2], item[3] if item[3] != args.iterate else "")
217
218 run_adb_shell_cmd_as_root('rm /data/bootchart/enabled')
219
220
221def dump_timings_points_summary(msg_header, timing_points, args):
222 averaged_timing_points = []
223 for item in timing_points.items():
224 average = sum(item[1])/len(item[1])
225 std_dev = stddev(item[1])
226 averaged_timing_points.append((item[0], average, std_dev, len(item[1])))
227
228 print "-----------------"
229 print msg_header + " timing in order, Avg time values after {0} runs".format(args.iterate)
230 print '{0:30}: {1:<7} {2:<7} {3}'.format("Event", "Mean", "stddev", "#runs")
231 for item in averaged_timing_points:
232 print '{0:30}: {1:<7.5} {2:<7.5} {3}'.format(
233 item[0], item[1], item[2], item[3] if item[3] != args.iterate else "")
234
235 print "-----------------"
236 print msg_header + " timing top items, Avg time values after {0} runs".format(args.iterate)
237 print '{0:30}: {1:<7} {2:<7} {3}'.format("Event", "Mean", "stddev", "#runs")
238 for item in sorted(averaged_timing_points, key=lambda entry: entry[1], reverse=True):
239 if item[1] < TIMING_THRESHOLD:
240 break
241 print '{0:30}: {1:<7.5} {2:<7.5} {3}'.format(
242 item[0], item[1], item[2], item[3] if item[3] != args.iterate else "")
243
244def capture_bugreport(bugreport_hint, boot_complete_time):
245 now = datetime.now()
246 bugreport_file = ("bugreport-%s-" + bugreport_hint + "-%s.zip") \
247 % (now.strftime("%Y-%m-%d-%H-%M-%S"), str(boot_complete_time))
248 print "Boot up time too big, will capture bugreport %s" % (bugreport_file)
249 os.system(ADB_CMD + " bugreport " + bugreport_file)
250
251def generate_timing_points(timing_events, timings):
252 timing_points = collections.OrderedDict()
253 for k, l in timing_events.iteritems():
254 for v in l:
255 name, time_v = extract_timing(v, timings)
256 if name and time_v:
257 if v.find("SystemServerTimingAsync") > 0:
258 name = "(" + name + ")"
259 new_name = name
260 name_index = 0
261 while timing_points.get(new_name): # if the name is already taken, append #digit
262 name_index += 1
263 new_name = name + "#" + str(name_index)
264 name = new_name
265 if k.endswith("_secs"):
266 timing_points[name] = time_v * 1000.0
267 else:
268 timing_points[name] = time_v
269 return timing_points
270
271def dump_timing_points(msg_header, timing_points):
272 print msg_header + " event timing in time order, key: time"
273 for item in timing_points.items():
274 print '{0:30}: {1:<7.5}'.format(item[0], item[1])
275 print "-----------------"
276 print msg_header + " event timing top items"
277 for item in sorted(timing_points.items(), key=operator.itemgetter(1), reverse = True):
278 if item[1] < TIMING_THRESHOLD:
279 break
280 print '{0:30}: {1:<7.5}'.format(
281 item[0], item[1])
282 print "-----------------"
283
284def handle_reboot_log(capture_log_on_error, shutdown_events_pattern, components_to_monitor):
285 shutdown_events, shutdown_timing_events = collect_logcat_for_shutdown(capture_log_on_error,\
286 shutdown_events_pattern, components_to_monitor)
287 print "\nshutdown events: time"
288 for item in shutdown_events.items():
289 print '{0:30}: {1:<7.5}'.format(item[0], item[1])
290 print "\nshutdown timing events: time"
291 for item in shutdown_timing_events.items():
292 print '{0:30}: {1:<7.5}'.format(item[0], item[1])
293 return shutdown_events, shutdown_timing_events
294
295def iterate(args, search_events_pattern, timings_pattern, shutdown_events_pattern, cfg, error_time,\
296 components_to_monitor):
297 shutdown_events = None
298 shutdown_timing_events = None
299 if args.reboot:
300 # sleep to make sure that logcat reader is reading before adb is gone by reboot. ugly but make
301 # impl simple.
302 t = threading.Thread(target = lambda : (time.sleep(2), reboot(args.serial, args.stressfs != '',\
303 args.permissive, args.adb_reboot)))
304 t.start()
305 shutdown_events, shutdown_timing_events = handle_reboot_log(True, shutdown_events_pattern,\
306 components_to_monitor)
307 t.join()
308
309 dmesg_events, kernel_timing_events = collect_events(search_events_pattern, ADB_CMD +\
310 ' shell su root dmesg -w', timings_pattern,\
311 [ KERNEL_BOOT_COMPLETE ], True)
312
313 logcat_stop_events = [ LOGCAT_BOOT_COMPLETE, KERNEL_BOOT_COMPLETE, LAUNCHER_START]
314 if args.fs_check:
315 logcat_stop_events.append("FsStat")
316 logcat_events, logcat_timing_events = collect_events(
317 search_events_pattern, ADB_CMD + ' logcat -b all -v epoch', timings_pattern,\
318 logcat_stop_events, False)
319 logcat_event_time = extract_time(
320 logcat_events, TIME_LOGCAT, float);
321 logcat_original_time = extract_time(
322 logcat_events, TIME_LOGCAT, str);
323 dmesg_event_time = extract_time(
324 dmesg_events, TIME_DMESG, float);
325 boottime_events = fetch_boottime_property()
326 events = {}
327 diff_time = 0
328 max_time = 0
329 events_to_correct = []
330 replaced_from_dmesg = set()
331
332 time_correction_delta = 0
333 time_correction_time = 0
334 if ('time_correction_key' in cfg
335 and cfg['time_correction_key'] in logcat_events):
336 match = search_events[cfg['time_correction_key']].search(
337 logcat_events[cfg['time_correction_key']])
338 if match and logcat_event_time[cfg['time_correction_key']]:
339 time_correction_delta = float(match.group(1))
340 time_correction_time = logcat_event_time[cfg['time_correction_key']]
341
342 debug("time_correction_delta = {0}, time_correction_time = {1}".format(
343 time_correction_delta, time_correction_time))
344
345 for k, v in logcat_event_time.iteritems():
346 if v <= time_correction_time:
347 logcat_event_time[k] += time_correction_delta
348 v = v + time_correction_delta
349 debug("correcting event to event[{0}, {1}]".format(k, v))
350
351 if not logcat_event_time.get(KERNEL_TIME_KEY):
352 print "kernel time not captured in logcat, cannot get time diff"
353 return None, None, None, None
354 diffs = []
355 diffs.append((logcat_event_time[KERNEL_TIME_KEY], logcat_event_time[KERNEL_TIME_KEY]))
356 if logcat_event_time.get(BOOT_ANIM_END_TIME_KEY) and dmesg_event_time.get(BOOT_ANIM_END_TIME_KEY):
357 diffs.append((logcat_event_time[BOOT_ANIM_END_TIME_KEY],\
358 logcat_event_time[BOOT_ANIM_END_TIME_KEY] -\
359 dmesg_event_time[BOOT_ANIM_END_TIME_KEY]))
360 if not dmesg_event_time.get(KERNEL_BOOT_COMPLETE):
361 print "BootAnimEnd time or BootComplete-kernel not captured in both log" +\
362 ", cannot get time diff"
363 return None, None, None, None
364 diffs.append((logcat_event_time[KERNEL_BOOT_COMPLETE],\
365 logcat_event_time[KERNEL_BOOT_COMPLETE] - dmesg_event_time[KERNEL_BOOT_COMPLETE]))
366
367 for k, v in logcat_event_time.iteritems():
368 debug("event[{0}, {1}]".format(k, v))
369 events[k] = v
370 if k in dmesg_event_time:
371 debug("{0} is in dmesg".format(k))
372 events[k] = dmesg_event_time[k]
373 replaced_from_dmesg.add(k)
374 else:
375 events_to_correct.append(k)
376
377 diff_prev = diffs[0]
378 for k in events_to_correct:
379 diff = diffs[0]
380 while diff[0] < events[k] and len(diffs) > 1:
381 diffs.pop(0)
382 diff_prev = diff
383 diff = diffs[0]
384 events[k] = events[k] - diff[1]
385 if events[k] < 0.0:
386 if events[k] < -0.1: # maybe previous one is better fit
387 events[k] = events[k] + diff[1] - diff_prev[1]
388 else:
389 events[k] = 0.0
390
391 data_points = collections.OrderedDict()
392
393 print "-----------------"
394 print "ro.boottime.*: time"
395 for item in boottime_events.items():
396 print '{0:30}: {1:<7.5} {2}'.format(item[0], item[1],\
397 "*time taken" if item[0].startswith("init.") else "")
398 print "-----------------"
399
400 if args.timings:
401 kernel_timing_points = generate_timing_points(kernel_timing_events, timings_pattern)
402 logcat_timing_points = generate_timing_points(logcat_timing_events, timings_pattern)
403 dump_timing_points("Kernel", kernel_timing_points)
404 dump_timing_points("Logcat", logcat_timing_points)
405
406 for item in sorted(events.items(), key=operator.itemgetter(1)):
407 data_points[item[0]] = {
408 'value': item[1],
409 'from_dmesg': item[0] in replaced_from_dmesg,
410 'logcat_value': logcat_original_time[item[0]]
411 }
412 # add times with bootloader
413 if events.get("BootComplete") and boottime_events.get("bootloader"):
414 total = events["BootComplete"] + boottime_events["bootloader"]
415 data_points["*BootComplete+Bootloader"] = {
416 'value': total,
417 'from_dmesg': False,
418 'logcat_value': 0.0
419 }
420 if events.get("LauncherStart") and boottime_events.get("bootloader"):
421 total = events["LauncherStart"] + boottime_events["bootloader"]
422 data_points["*LauncherStart+Bootloader"] = {
423 'value': total,
424 'from_dmesg': False,
425 'logcat_value': 0.0
426 }
427 for k, v in data_points.iteritems():
428 print '{0:30}: {1:<7.5} {2:1} ({3})'.format(
429 k, v['value'], '*' if v['from_dmesg'] else '', v['logcat_value'])
430
431 print '\n* - event time was obtained from dmesg log\n'
432
433 if events[LOGCAT_BOOT_COMPLETE] > error_time and not args.ignore:
434 capture_bugreport("bootuptoolong", events[LOGCAT_BOOT_COMPLETE])
435
436 for k, v in components_to_monitor.iteritems():
437 logcat_value_measured = logcat_timing_points.get(k)
438 kernel_value_measured = kernel_timing_points.get(k)
439 data_from_data_points = data_points.get(k)
440 if logcat_value_measured and logcat_value_measured > v:
441 capture_bugreport(k + "-" + str(logcat_value_measured), events[LOGCAT_BOOT_COMPLETE])
442 break
443 elif kernel_value_measured and kernel_value_measured > v:
444 capture_bugreport(k + "-" + str(kernel_value_measured), events[LOGCAT_BOOT_COMPLETE])
445 break
446 elif data_from_data_points and data_from_data_points['value'] * 1000.0 > v:
447 capture_bugreport(k + "-" + str(data_from_data_points['value']), events[LOGCAT_BOOT_COMPLETE])
448 break
449
450 if args.fs_check:
451 fs_stat = None
452 if logcat_events.get("FsStat"):
453 fs_stat_pattern = cfg["events"]["FsStat"]
454 m = re.search(fs_stat_pattern, logcat_events.get("FsStat"))
455 if m:
456 fs_stat = m.group(1)
457 print 'fs_stat:', fs_stat
458
459 if fs_stat:
460 fs_stat_val = int(fs_stat, 0)
461 if (fs_stat_val & ~0x17) != 0:
462 capture_bugreport("fs_stat_" + fs_stat, events[LOGCAT_BOOT_COMPLETE])
463
464 return data_points, kernel_timing_points, logcat_timing_points, boottime_events, shutdown_events,\
465 shutdown_timing_events
466
467def debug(string):
468 if DEBUG:
469 print string
470
471def extract_timing(s, patterns):
472 for k, p in patterns.iteritems():
473 m = p.search(s)
474 if m:
475 g_dict = m.groupdict()
476 return g_dict['name'], float(g_dict['time'])
477 return None, None
478
479def init_arguments():
480 parser = argparse.ArgumentParser(description='Measures boot time.')
481 parser.add_argument('-r', '--reboot', dest='reboot',
482 action='store_true',
483 help='reboot device for measurement', )
484 parser.add_argument('-c', '--config', dest='config',
485 default='config.yaml', type=argparse.FileType('r'),
486 help='config file for the tool', )
487 parser.add_argument('-s', '--stressfs', dest='stressfs',
488 default='', type=str,
489 help='APK file for the stressfs tool used to write to the data partition ' +\
490 'during shutdown')
491 parser.add_argument('-n', '--iterate', dest='iterate', type=int, default=1,
492 help='number of time to repeat the measurement', )
493 parser.add_argument('-g', '--ignore', dest='ignore', action='store_true',
494 help='ignore too big values error', )
495 parser.add_argument('-t', '--timings', dest='timings', action='store_true',
496 help='print individual component times', default=True, )
497 parser.add_argument('-p', '--serial', dest='serial', action='store',
498 help='android device serial number')
499 parser.add_argument('-e', '--errortime', dest='errortime', action='store',
500 help='handle bootup time bigger than this as error')
501 parser.add_argument('-w', '--maxwaittime', dest='maxwaittime', action='store',
502 help='wait for up to this time to collect logs. Retry after this time.' +\
503 ' Default is 200 sec.')
504 parser.add_argument('-f', '--fs_check', dest='fs_check',
505 action='store_true',
506 help='check fs_stat after reboot', )
507 parser.add_argument('-a', '--adb_reboot', dest='adb_reboot',
508 action='store_true',
509 help='reboot with adb reboot', )
510 parser.add_argument('-v', '--permissive', dest='permissive',
511 action='store_true',
512 help='set selinux into permissive before reboot', )
513 parser.add_argument('-m', '--componentmonitor', dest='componentmonitor', action='store',
514 help='capture bugreport if specified timing component is taking more than ' +\
515 'certain time. Unlike errortime, the result will not be rejected in' +\
516 'averaging. Format is key1=time1,key2=time2...')
517 parser.add_argument('-b', '--bootchart', dest='bootchart',
518 action='store_true',
519 help='collect bootchart from the device.', )
520 parser.add_argument('-y', '--systrace', dest='systrace',
521 action='store_true',
522 help='collect systrace from the device. kernel trace should be already enabled', )
523 return parser.parse_args()
524
525def handle_zygote_event(zygote_pids, events, event, line):
526 words = line.split()
527 if len(words) > 1:
528 pid = int(words[1])
529 if len(zygote_pids) == 2:
530 if pid == zygote_pids[1]: # secondary
531 event = event + "-secondary"
532 elif len(zygote_pids) == 1:
533 if zygote_pids[0] != pid: # new pid, need to decide if old ones were secondary
534 primary_pid = min(pid, zygote_pids[0])
535 secondary_pid = max(pid, zygote_pids[0])
536 zygote_pids.pop()
537 zygote_pids.append(primary_pid)
538 zygote_pids.append(secondary_pid)
539 if pid == primary_pid: # old one was secondary:
540 move_to_secondary = []
541 for k, l in events.iteritems():
542 if k.startswith("zygote"):
543 move_to_secondary.append((k, l))
544 for item in move_to_secondary:
545 del events[item[0]]
546 if item[0].endswith("-secondary"):
547 print "Secondary already exists for event %s while found new pid %d, primary %d "\
548 % (item[0], secondary_pid, primary_pid)
549 else:
550 events[item[0] + "-secondary"] = item[1]
551 else:
552 event = event + "-secondary"
553 else:
554 zygote_pids.append(pid)
555 events[event] = line
556
557def update_name_if_already_exist(events, name):
558 existing_event = events.get(name)
559 i = 0
560 new_name = name
561 while existing_event:
562 i += 1
563 new_name = name + "_" + str(i)
564 existing_event = events.get(new_name)
565 return new_name
566
567def collect_logcat_for_shutdown(capture_log_on_error, shutdown_events_pattern,\
568 log_capture_conditions):
569 events = collections.OrderedDict()
570 # shutdown does not have timing_events but calculated from checking Xyz - XyzDone / XyzTimeout
571 timing_events = collections.OrderedDict()
572 process = subprocess.Popen(ADB_CMD + ' logcat -b all -v epoch', shell=True,
573 stdout=subprocess.PIPE);
574 lines = []
575 capture_log = False
576 shutdown_start_time = 0
577 while (True):
578 line = process.stdout.readline().lstrip().rstrip()
579 if not line:
580 break
581 lines.append(line)
582 event = get_boot_event(line, shutdown_events_pattern);
583 if not event:
584 continue
585 time = extract_a_time(line, TIME_LOGCAT, float)
586 if not time:
587 print "cannot get time from: " + line
588 continue
589 if shutdown_start_time == 0:
590 shutdown_start_time = time
591 time = time - shutdown_start_time
592 events[event] = time
593 time_limit1 = log_capture_conditions.get(event)
594 if time_limit1 and time_limit1 <= time:
595 capture_log = True
596 pair_event = None
597 if event.endswith('Done'):
598 pair_event = event[:-4]
599 elif event.endswith('Timeout'):
600 pair_event = event[:-7]
601 if capture_log_on_error:
602 capture_log = True
603 if not pair_event:
604 continue
605 start_time = events.get(pair_event)
606 if not start_time:
607 print "No start event for " + event
608 continue
609 time_spent = time - start_time
610 timing_event_name = pair_event + "Duration"
611 timing_events[timing_event_name] = time_spent
612 time_limit2 = log_capture_conditions.get(timing_event_name)
613 if time_limit2 and time_limit2 <= time_spent:
614 capture_log = True
615
616 if capture_log:
617 now = datetime.now()
618 log_file = ("shutdownlog-error-%s.txt") % (now.strftime("%Y-%m-%d-%H-%M-%S"))
619 print "Shutdown error, capture log to %s" % (log_file)
620 with open(log_file, 'w') as f:
621 f.write('\n'.join(lines))
622 return events, timing_events
623
624
625def collect_events(search_events, command, timings, stop_events, disable_timing_after_zygote):
626 events = collections.OrderedDict()
627 timing_events = {}
628 process = subprocess.Popen(command, shell=True,
629 stdout=subprocess.PIPE);
630 data_available = stop_events is None
631 zygote_pids = []
632 start_time = time.time()
633 zygote_found = False
634
635 line = None
636 read_poll = select.poll()
637 read_poll.register(process.stdout, select.POLLIN)
638 while True:
639 time_left = start_time + max_wait_time - time.time()
640 if time_left <= 0:
641 print "timeout waiting for event, continue", time_left
642 break
643 read_r = read_poll.poll(time_left * 1000.0)
644 if len(read_r) > 0 and read_r[0][1] == select.POLLIN:
645 line = process.stdout.readline()
646 else:
647 print "poll timeout waiting for event, continue", time_left
648 break
649 if not data_available:
650 print "Collecting data samples from '%s'. Please wait...\n" % command
651 data_available = True
652 event = get_boot_event(line, search_events);
653 if event:
654 debug("event[{0}] captured: {1}".format(event, line))
655 if event == "starting_zygote":
656 events[event] = line
657 zygote_found = True
658 elif event.startswith("zygote"):
659 handle_zygote_event(zygote_pids, events, event, line)
660 else:
661 new_event = update_name_if_already_exist(events, event)
662 events[new_event] = line
663 if event in stop_events:
664 stop_events.remove(event)
665 print "remaining stop_events:", stop_events
666 if len(stop_events) == 0:
667 break;
668
669 timing_event = get_boot_event(line, timings);
670 if timing_event and (not disable_timing_after_zygote or not zygote_found):
671 if timing_event not in timing_events:
672 timing_events[timing_event] = []
673 timing_events[timing_event].append(line)
674 debug("timing_event[{0}] captured: {1}".format(timing_event, line))
675
676 process.terminate()
677 return events, timing_events
678
679def fetch_boottime_property():
680 cmd = ADB_CMD + ' shell su root getprop'
681 events = {}
682 process = subprocess.Popen(cmd, shell=True,
683 stdout=subprocess.PIPE);
684 out = process.stdout
685 pattern = re.compile(BOOT_PROP)
686 pattern_bootloader = re.compile(BOOTLOADER_TIME_PROP)
687 bootloader_time = 0.0
688 for line in out:
689 match = pattern.match(line)
690 if match:
691 if match.group(1).startswith("init."):
692 events[match.group(1)] = float(match.group(2)) / 1000.0 #ms to s
693 else:
694 events[match.group(1)] = float(match.group(2)) / 1000000000.0 #ns to s
695 match = pattern_bootloader.match(line)
696 if match:
697 items = match.group(1).split(",")
698 for item in items:
699 entry_pair = item.split(":")
700 entry_name = entry_pair[0]
701 time_spent = float(entry_pair[1]) / 1000 #ms to s
702 if entry_name != "SW":
703 bootloader_time = bootloader_time + time_spent
704 ordered_event = collections.OrderedDict()
705 if bootloader_time != 0.0:
706 ordered_event["bootloader"] = bootloader_time;
707 for item in sorted(events.items(), key=operator.itemgetter(1)):
708 ordered_event[item[0]] = item[1]
709 return ordered_event
710
711
712def get_boot_event(line, events):
713 for event_key, event_pattern in events.iteritems():
714 if event_pattern.search(line):
715 return event_key
716 return None
717
718def extract_a_time(line, pattern, date_transform_function):
719 found = re.findall(pattern, line)
720 if len(found) > 0:
721 return date_transform_function(found[0])
722 else:
723 return None
724
725def extract_time(events, pattern, date_transform_function):
726 result = collections.OrderedDict()
727 for event, data in events.iteritems():
728 time = extract_a_time(data, pattern, date_transform_function)
729 if time:
730 result[event] = time
731 else:
732 print "Failed to find time for event: ", event, data
733 return result
734
735
736def do_reboot(serial, use_adb_reboot):
737 original_devices = subprocess.check_output("adb devices", shell=True)
738 if use_adb_reboot:
739 print 'Rebooting the device using adb reboot'
740 run_adb_cmd('reboot')
741 else:
742 print 'Rebooting the device using svc power reboot'
743 run_adb_shell_cmd_as_root('svc power reboot')
744 # Wait for the device to go away
745 retry = 0
746 while retry < 20:
747 current_devices = subprocess.check_output("adb devices", shell=True)
748 if original_devices != current_devices:
749 if not serial or (serial and current_devices.find(serial) < 0):
750 return True
751 time.sleep(1)
752 retry += 1
753 return False
754
755def reboot(serial, use_stressfs, permissive, use_adb_reboot):
756 if use_stressfs:
757 print 'Starting write to data partition'
758 run_adb_shell_cmd('am start' +\
759 ' -n com.android.car.test.stressfs/.WritingActivity' +\
760 ' -a com.android.car.test.stressfs.START')
761 # Give this app some time to start.
762 time.sleep(1)
763 if permissive:
764 run_adb_shell_cmd_as_root('setenforce 0')
765
766 retry = 0
767 while retry < 5:
768 if do_reboot(serial, use_adb_reboot):
769 break
770 retry += 1
771
772 print 'Waiting the device'
773 run_adb_cmd('wait-for-device')
774
775def run_adb_cmd(cmd):
776 return subprocess.call(ADB_CMD + ' ' + cmd, shell=True)
777
778def run_adb_shell_cmd(cmd):
779 return subprocess.call(ADB_CMD + ' shell ' + cmd, shell=True)
780
781def run_adb_shell_cmd_as_root(cmd):
782 return subprocess.call(ADB_CMD + ' shell su root ' + cmd, shell=True)
783
784def logcat_time_func(offset_year):
785 def f(date_str):
786 ndate = datetime.datetime.strptime(str(offset_year) + '-' +
787 date_str, '%Y-%m-%d %H:%M:%S.%f')
788 return datetime_to_unix_time(ndate)
789 return f
790
791def datetime_to_unix_time(ndate):
792 return time.mktime(ndate.timetuple()) + ndate.microsecond/1000000.0
793
794def stddev(data):
795 items_count = len(data)
796 avg = sum(data) / items_count
797 sq_diffs_sum = sum([(v - avg) ** 2 for v in data])
798 variance = sq_diffs_sum / items_count
799 return math.sqrt(variance)
800
801def grab_bootchart(boot_chart_file_name):
802 subprocess.call("./system/core/init/grab-bootchart.sh", shell=True)
803 print "Saving boot chart as " + boot_chart_file_name + ".tgz"
804 subprocess.call('cp /tmp/android-bootchart/bootchart.tgz ./' + boot_chart_file_name + '.tgz',\
805 shell=True)
806 subprocess.call('cp ./bootchart.png ./' + boot_chart_file_name + '.png', shell=True)
807
808def grab_systrace(systrace_file_name):
809 trace_file = systrace_file_name + "_trace.txt"
810 with open(trace_file, 'w') as f:
811 f.write("TRACE:\n")
812 run_adb_shell_cmd_as_root("cat /d/tracing/trace >> " + trace_file)
813 html_file = systrace_file_name + ".html"
814 subprocess.call("./external/chromium-trace/systrace.py --from-file=" + trace_file + " -o " +\
815 html_file, shell=True)
816
817if __name__ == '__main__':
818 main()
diff --git a/tools/bootanalyze/bugreport_anayze.py b/tools/bootanalyze/bugreport_anayze.py
deleted file mode 100644
index 2575ebf6..00000000
--- a/tools/bootanalyze/bugreport_anayze.py
+++ /dev/null
@@ -1,386 +0,0 @@
1#!/usr/bin/python
2
3# Copyright (C) 2017 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17"""Tool to analyze boot-up time from bugreport."""
18
19import argparse
20import collections
21import datetime
22import math
23import operator
24import os
25import re
26import select
27import subprocess
28import sys
29import time
30import threading
31import yaml
32
33from datetime import datetime, date
34
35DBG = True
36
37LOG_START_PATTERN = r"""\-\-\-\-\-\-\s(.*)\s\-\-\-\-\-\-"""
38LOG_END_PATTERN = r"""\-\-\-\-\-\-\s\S.*\s\-\-\-\-\-\-"""
39
40KERNEL_LOG_TITLE = "KERNEL LOG"
41SYSYEM_LOG_TITLE = "SYSTEM LOG"
42LAST_KMSG_TITLE = "LAST KMSG"
43LAST_LOGCAT_TITLE = "LAST LOGCAT"
44
45SYSTEM_PROPS_TITLE = "SYSTEM PROPERTIES"
46
47TIME_DMESG = "\[\s*(\d+\.\d+)\]"
48TIME_LOGCAT = "(\d+)\-(\d+)\s(\d+):(\d+):(\d+\.\d+)"
49
50NATIVE_CRASH_START_PATTERN = "I\sDEBUG\s+:\s\*\*\*\s\*\*\*"
51NATIVE_CRASH_PATTERN = "I\sDEBUG\s+:"
52JAVA_CRASH_START_PATTERN = "E\sAndroidRuntime:\sFATAL\sEXCEPTION"
53JAVA_CRASH_PATTERN = "E\sAndroidRuntime:\s"
54
55EPOCH = datetime.utcfromtimestamp(0)
56
57def init_arguments():
58 parser = argparse.ArgumentParser(description='Measures boot time from bugreport.')
59 parser.add_argument('-c', '--config', dest='config',
60 default='config.yaml', type=argparse.FileType('r'),
61 help='config file for the tool')
62 parser.add_argument('bugreport_file', nargs=1, help='bugreport txt file',
63 type=argparse.FileType('r'))
64 parser.add_argument('-n', '--iterate', dest='iterate', type=int, default=1,
65 help='number of time to repeat the measurement', )
66 return parser.parse_args()
67
68# Event per each reboot, for distinghishing current boot from last boot
69class Events:
70 def __init__(self):
71 self.events = collections.OrderedDict() #K: keyword, V:time in ms
72 self.timings = collections.OrderedDict()
73 self.shutdown_events = collections.OrderedDict()
74 self.java_crash = collections.OrderedDict() #K:time, V:list of crash infos, each entry per line
75 self.native_crash = collections.OrderedDict()
76
77 def reset_events_time(self, delta):
78 new_events = collections.OrderedDict()
79 for entry in self.events.iteritems():
80 new_events[entry[0]] = entry[1] - delta
81 self.events = new_events
82 if len(self.native_crash) > 0:
83 new_crash = collections.OrderedDict()
84 for entry in self.native_crash.iteritems():
85 new_crash[entry[0] - delta] = entry[1]
86 self.native_crash = new_crash
87 if len(self.java_crash) > 0:
88 new_crash = collections.OrderedDict()
89 for entry in self.java_crash.iteritems():
90 new_crash[entry[0] - delta] = entry[1]
91 self.java_crash = new_crash
92
93 def reset_shutdown_events_time(self):
94 if len(self.shutdown_events) == 0:
95 return
96 time_offset = 0
97 new_events = collections.OrderedDict()
98 for entry in self.shutdown_events.iteritems():
99 if time_offset == 0:
100 time_offset = entry[1]
101 new_events[entry[0]] = entry[1] - time_offset
102 self.shutdown_events = new_events
103
104 def dump_dict(self, d):
105 for entry in d.iteritems():
106 print ' {0:30}: {1}'.format(entry[0], entry[1])
107
108 def dump_crash(self, time, stack):
109 print " Crash time:", time, " stack:"
110 print ' '.join(stack)
111
112 def dump(self):
113 if len(self.events) > 0:
114 print "\n***Events:"
115 self.dump_dict(self.events)
116 if len(self.timings) > 0:
117 print "\n***Timings top 20"
118 timings_sorted = sorted(self.timings.items(), key = lambda item: item[1], reverse=True)
119 nums_to_dump = min(20, len(timings_sorted))
120 for i in range(nums_to_dump):
121 print ' {0:30}: {1}'.format(timings_sorted[i][0], timings_sorted[i][1])
122 print "\n***Timings:"
123 self.dump_dict(self.timings)
124 if len(self.shutdown_events) > 0:
125 print "\n***Shutdown Events (time relative to the begining of shutdown) :"
126 self.dump_dict(self.shutdown_events)
127 if len(self.native_crash) > 0:
128 print "\n***Native crash founds:", len(self.native_crash)
129 for entry in self.native_crash.iteritems():
130 self.dump_crash(entry[0], entry[1])
131 if len(self.java_crash) > 0:
132 print "\n***Java crash founds:", len(self.java_crash)
133 for entry in self.java_crash.iteritems():
134 self.dump_crash(entry[0], entry[1])
135
136class Parser:
137 def __init__(self, config_file, bugreport_file):
138 self.re_log_start = re.compile(LOG_START_PATTERN)
139 self.re_log_end = re.compile(LOG_END_PATTERN)
140 self.f = bugreport_file
141 cfg = yaml.load(config_file)
142 self.event_patterns = {key: re.compile(pattern)
143 for key, pattern in cfg['events'].iteritems()}
144 self.timing_patterns = {key: re.compile(pattern)
145 for key, pattern in cfg['timings'].iteritems()}
146 self.shutdown_event_patterns = {key: re.compile(pattern)
147 for key, pattern in cfg['shutdown_events'].iteritems()}
148 self.current_boot_kernel = Events()
149 self.current_boot_logcat = Events()
150 self.last_boot_kernel = Events()
151 self.last_boot_logcat = Events()
152 self.boottime_props = collections.OrderedDict() # K:prop, V:boot time, added in boot time order
153 self.bootloader_time = 0
154 self.re_time_dmesg = re.compile(TIME_DMESG)
155 self.re_time_logcat = re.compile(TIME_LOGCAT)
156 self.re_native_crash_start = re.compile(NATIVE_CRASH_START_PATTERN)
157 self.re_native_crash = re.compile(NATIVE_CRASH_PATTERN)
158 self.re_java_crash_start = re.compile(JAVA_CRASH_START_PATTERN)
159 self.re_java_crash = re.compile(JAVA_CRASH_PATTERN)
160
161 def match_an_event(self, event_patterns, line):
162 for event_key, event_pattern in event_patterns.iteritems():
163 m = event_pattern.search(line)
164 if m:
165 return event_key, m
166 return None, None
167
168 def get_event_time(self, line, is_kernel):
169 if is_kernel:
170 m = self.re_time_dmesg.search(line)
171 if not m:
172 print "Cannot get time from log:", line
173 return -1
174 return int(float(m.group(1)) * 1000)
175 else:
176 m = self.re_time_logcat.search(line)
177 if not m:
178 print "Cannot get time from log:", line
179 return -1
180 mm = int(m.group(1))
181 dd = int(m.group(2))
182 hh = int(m.group(3))
183 min = int(m.group(4))
184 usecs = int(float(m.group(5)) * 1000000)
185 secs = usecs / 1000000
186 usecs = usecs - 1000000 * secs
187 dt = datetime(2017, mm, dd, hh, min, secs, usecs)
188 return int((dt - EPOCH).total_seconds() * 1000)
189
190 def queue_crash(self, event, crash_time, crash_stacks, is_native_crash):
191 stacks = list(crash_stacks)
192 if is_native_crash:
193 event.native_crash[crash_time] = stacks
194 else:
195 event.java_crash[crash_time] = stacks
196
197 def check_crash(self, event, orig_line):
198 line = orig_line
199 crash_time = 0
200 crash_stacks = []
201 is_native_crash = True
202 while len(line) > 0:
203 m = self.re_native_crash_start.search(line)
204 if m:
205 if len(crash_stacks) > 0:
206 self.queue_crash(event, crash_time, crash_stacks, is_native_crash)
207 crash_stacks = []
208 is_native_crash = True
209 crash_stacks.append(line)
210 crash_time = self.get_event_time(line, False)
211 line = self.f.readline()
212 continue
213 m = self.re_native_crash.search(line)
214 if m:
215 crash_stacks.append(line)
216 line = self.f.readline()
217 continue
218 m = self.re_java_crash_start.search(line)
219 if m:
220 if len(crash_stacks) > 0:
221 self.queue_crash(event, crash_time, crash_stacks, is_native_crash)
222 crash_stacks = []
223 is_native_crash = False
224 crash_stacks.append(line)
225 crash_time = self.get_event_time(line, False)
226 line = self.f.readline()
227 continue
228 m = self.re_java_crash.search(line)
229 if m:
230 crash_stacks.append(line)
231 line = self.f.readline()
232 continue
233 # reaching here means not crash, so return new line
234 if line != orig_line:
235 return line
236 else:
237 return self.f.readline()
238
239
240
241 def handle_events(self, event, is_kernel):
242 line = self.f.readline()
243 while len(line) > 0 and not self.re_log_end.match(line):
244 key, m = self.match_an_event(self.event_patterns, line)
245 if m:
246 event.events[key] = self.get_event_time(line, is_kernel)
247 line = self.f.readline()
248 continue
249 key, m = self.match_an_event(self.timing_patterns, line)
250 if m:
251 name = m.group('name')
252 time = float(m.group('time'))
253 if key.endswith('_secs'):
254 time = time * 1000
255 event.timings[name] = int(time)
256 line = self.f.readline()
257 continue
258 key, m = self.match_an_event(self.shutdown_event_patterns, line)
259 if m:
260 event.shutdown_events[key] = self.get_event_time(line, is_kernel)
261 line = self.f.readline()
262 continue
263 if not is_kernel: # collect crash
264 line = self.check_crash(event, line)
265 continue
266 line = self.f.readline()
267
268 def handle_kernel_log(self):
269 if DBG:
270 print "start " + KERNEL_LOG_TITLE
271 self.handle_events(self.current_boot_kernel, True)
272
273 def handle_system_log(self):
274 if DBG:
275 print "start " + SYSYEM_LOG_TITLE
276 self.handle_events(self.current_boot_logcat, False)
277
278 def handle_last_kernel_log(self):
279 if DBG:
280 print "start " + LAST_KMSG_TITLE
281 self.handle_events(self.last_boot_kernel, True)
282
283 def handle_last_system_log(self):
284 if DBG:
285 print "start " + LAST_LOGCAT_TITLE
286 self.handle_events(self.last_boot_logcat, False)
287
288 def handle_system_props(self):
289 if DBG:
290 print "start " + SYSTEM_PROPS_TITLE
291 re_prop = re.compile(r"""\[(.+)\].*\[(.*)\]""")
292 RO_BOOTTIME_PROP = "ro.boottime."
293 boottime_props = {} # K: prop name, V: boot time in ms
294 line = self.f.readline()
295 while len(line) > 0 and not self.re_log_end.match(line):
296 m = re_prop.match(line)
297 if not m:
298 print "Cannot parse prop:", line
299 line = self.f.readline()
300 continue
301 if m.group(1).startswith(RO_BOOTTIME_PROP):
302 name = m.group(1)[len(RO_BOOTTIME_PROP):]
303 time = int(m.group(2)) / 1000000 # ns to ms
304 boottime_props[name] = time
305 elif m.group(1) == "ro.boot.boottime":
306 print "Found bootloader boottime ", line
307 entries = m.group(2).split(",")
308 for entry in entries:
309 values = entry.split(":")
310 if values[0] != "SW":
311 self.bootloader_time += int(values[1])
312 line = self.f.readline()
313 self.boottime_props = collections.OrderedDict(sorted(
314 boottime_props.items(), key = lambda item: item[1]))
315
316 def parse(self):
317 while (True):
318 l = self.f.readline()
319 if len(l) == 0: # EOF
320 return
321 m = self.re_log_start.match(l)
322 if not m:
323 continue
324 #print m.group(1)
325 if m.group(1).startswith(KERNEL_LOG_TITLE):
326 self.handle_kernel_log()
327 elif m.group(1).startswith(SYSYEM_LOG_TITLE):
328 self.handle_system_log()
329 elif m.group(1).startswith(SYSTEM_PROPS_TITLE):
330 self.handle_system_props()
331 elif m.group(1).startswith(LAST_KMSG_TITLE):
332 self.handle_last_kernel_log()
333 elif m.group(1).startswith(LAST_LOGCAT_TITLE):
334 self.handle_last_system_log()
335
336 def dump_props(self):
337 if self.bootloader_time != 0:
338 print "*bootloader time:", self.bootloader_time
339 if self.boottime_props:
340 print "*ro.boottime.*:"
341 for name, t in self.boottime_props.iteritems():
342 print ' {0:30}: {1}'.format(name, t)
343
344 def reset_event_times(self, kernel_event, logcat_event):
345 has_boot_complete = True
346 kernel_bootcomplete_time = kernel_event.events.get("BootComplete_kernel")
347 if not kernel_bootcomplete_time:
348 has_boot_complete = False
349 logcat_bootcomplete_time = logcat_event.events.get("BootComplete")
350 if not logcat_bootcomplete_time:
351 has_boot_complete = False
352 time_delta = 0
353 if has_boot_complete:
354 time_delta = logcat_bootcomplete_time - kernel_bootcomplete_time
355 else:
356 time_delta = logcat_event.events.values()[0] if len(logcat_event.events) > 0 else 0
357 logcat_event.reset_events_time(time_delta)
358 logcat_event.reset_shutdown_events_time()
359 kernel_event.reset_shutdown_events_time()
360 return has_boot_complete
361
362 def dump(self):
363 self.dump_props()
364 boot_complete_found = self.reset_event_times(self.current_boot_kernel, self.current_boot_logcat)
365 print "* Kernel dmesg:"
366 self.current_boot_kernel.dump()
367 print "\n\n* Logcat " + ("(time matched with kernel dmesg):" if boot_complete_found\
368 else "(time set relative to the first event):")
369 self.current_boot_logcat.dump()
370 print "\n\n\n==== Data from last boot ==="
371 boot_complete_found = self.reset_event_times(self.last_boot_kernel, self.last_boot_logcat)
372 print "\n\n* Last Kernel dmesg:"
373 self.last_boot_kernel.dump()
374 print "\n\n* Last Logcat " + ("(time matched with kernel dmesg):" if boot_complete_found \
375 else "(time set relative to the first event):")
376 self.last_boot_logcat.dump()
377
378def main():
379 args = init_arguments()
380
381 parser = Parser(args.config, args.bugreport_file[0])
382 parser.parse()
383 parser.dump()
384
385if __name__ == '__main__':
386 main()
diff --git a/tools/bootanalyze/config.yaml b/tools/bootanalyze/config.yaml
deleted file mode 100644
index 37f2891b..00000000
--- a/tools/bootanalyze/config.yaml
+++ /dev/null
@@ -1,78 +0,0 @@
1#YAML
2time_correction_key: correction
3timings:
4 system_server: SystemServerTiming(Async)?\s*:\s*(?P<name>\S+) took to complete:\s(?P<time>[0-9]+)ms
5 fs_shutdown: (?P<name>boot_fs_shutdown),(?P<time>[0-9]+),([0-9]+)
6 ueventd_secs: ueventd:\s(?P<name>\S.+)\stook\s(?P<time>[.0-9]+)\sseconds
7 init_command_ms: init:\sCommand\s(?P<name>\S.+)\sreturned.*took\s(?P<time>[.0-9]+)ms
8 init_service_exec_secs: init:\sService\s.*exec\s\S+\s\((?P<name>\S.+)\).*pid.*\swaiting\stook\s(?P<time>[.0-9]+)\sseconds
9 zygote64_timing: (?P<name>Zygote64Timing\:\s\S+)\stook\sto\scomplete\:\s(?P<time>[0-9]+)ms
10 zygote32_timing: (?P<name>Zygote32Timing\:\s\S+)\stook\sto\scomplete\:\s(?P<time>[0-9]+)ms
11events:
12 kernel: Linux version
13 android_init_1st_stage: init first stage started
14 android_init_2st_stage: init second stage started
15 late_init: processing action \(late-init\)
16 fs: processing action \(fs\)
17 post-fs: processing action \(post-fs\)
18 late-fs: processing action \(late-fs\)
19 post-fs-data: processing action \(post-fs-data\)
20 nonencrypted: processing action \(nonencrypted\)
21 vold: starting service 'vold'
22 starting_zygote: starting service 'zygote'
23 starting_zygote_secondary: starting service 'zygote_secondary'
24 load_persist_props_action: processing action \(load_persist_props_action\)
25 early-boot: processing action \(early-boot\)
26 boot: processing action \(boot\)
27 ueventd: Starting service 'ueventd'
28 system_mounted: target=/system
29 data_mounted: target=/data
30 correction: Updating system time diff=([0-9]+\.?[0-9]*), cuttime=([0-9]+)
31 servicemanager_start_by_init: starting service 'servicemanager'
32 zygoteInit: START com.android.internal.os.ZygoteInit
33 ZygoteMainSystemServer: app_process\smain\swith\sargv.*\-\-start\-system\-server
34 ZygoteMainOthers: app_process\smain\swith\sargv
35 zygote_preload_start: Zygote\s*:\s*begin preload
36 zygote_preload_classes_start: Zygote\s*:\s*Preloading classes...
37 zygote_preload_res_start: Zygote\s*:\s*Preloading resources...
38 zygote_preload_end: Zygote\s*:\s*end preload
39 zygote_create_system_server: Zygote\s*:\s*System server process [0-9]* has been created
40 SystemServer_start: Entered the Android system server!
41 system_server_ready: Enabled StrictMode for system server main
42 PackageManagerInit_start: SystemServer\s*:\s*StartPackageManagerService
43 BluetoothService_start: Starting com.android.server.BluetoothService
44 SystemUi_start: for service com.android.systemui/.
45 CarLauncherReady: Em.Overview:\s*onResume
46 CarService_start: for service com.android.car/.CarService
47 BootAnimStart: starting service 'bootanim'
48 BootAnimSfWait: BootAnimation:\sWaiting\sfor\sSurfaceFlinger\stook\s
49 BootAnimShowStart: BootAnimation:\sBootAnimationShownTiming\sstart\stime
50 BootAnimStopRequest: TELLING SURFACE FLINGER WE ARE BOOTED
51 BootAnimEnd: Service 'bootanim'
52 KeyguardStart: KeyguardServiceDelegate.*\*\*\* Keyguard started
53 KeyguardConnected: KeyguardServiceDelegate.*\*\*\* Keyguard connected
54 KeyguardShown: KeyguardServiceDelegate.*\*\*\*\* SHOWN CALLED \*\*\*\*
55 BootComplete: Starting phase 1000
56 BootComplete_kernel: processing action \(sys\.boot_completed=1\)
57 LauncherStart: START.*HOME.*(NexusLauncherActivity|GEL|LensPickerTrampolineActivity|SetupWizardActivity)
58 FsStat: fs_stat, partition:userdata stat:(0x\S+)
59shutdown_events:
60 ShutdownStart: ShutdownThread:\sNotifying thread to start shutdown
61 ShutdownBroadcast: ShutdownThread:\sSending shutdown broadcast
62 ShutdownActivityManagerService: ShutdownThread:\sShutting down activity manager
63 ShutdownPackageManagerService: ShutdownThread:\sShutting down package manager
64 ShutdownNfc: ShutdownThread:\sTurning off NFC
65 ShutdownBt: ShutdownThread:\sDisabling Bluetooth
66 ShutdownRadio: ShutdownThread:\sTurning off cellular radios
67 ShutdownRadiosWait: ShutdownThread:\sWaiting for NFC, Bluetooth and Radio
68 ShutdownBtDone: ShutdownThread:\sBluetooth turned off
69 ShutdownRadioDone: ShutdownThread:\sRadio turned off
70 ShutdownNfcDone: ShutdownThread:\sNFC turned off
71 ShutdownRadiosWaitDone: ShutdownThread:\sNFC, Radio and Bluetooth shutdown complete
72 ShutdownRadiosWaitTimeout: ShutdownThread:\sTimed out waiting for NFC, Radio and Bluetooth shutdown
73 ShutdownStorageManagerSerivce: ShutdownThread:\sShutting down StorageManagerService
74 ShutdownStorageManagerSerivceDone: ShutdownThread:\sResult code [\d]+ from StorageManagerService\.shutdown
75 ShutdownStorageManagerSerivceTimeout: ShutdownThread:\sShutdown wait timed out
76 ShutdownStartDone: ShutdownThread:\sPerforming low-level shutdown
77 ShutdownInitAction: init\s+:\sprocessing action \(sys\.shutdown\.requested
78 ShutdownInitFsShutdown: init\s+:\sShutdown timeout
diff --git a/tools/bootanalyze/stressfs/Android.mk b/tools/bootanalyze/stressfs/Android.mk
deleted file mode 100644
index 2e54e64b..00000000
--- a/tools/bootanalyze/stressfs/Android.mk
+++ /dev/null
@@ -1,29 +0,0 @@
1# Copyright (C) 2017 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14#
15#
16
17LOCAL_PATH := $(call my-dir)
18
19include $(CLEAR_VARS)
20
21LOCAL_PACKAGE_NAME := StressFS
22LOCAL_SRC_FILES := $(call all-java-files-under, src)
23
24LOCAL_MODULE_TAGS := tests
25LOCAL_SDK_VERSION := current
26
27LOCAL_PROGUARD_FLAG_FILES := proguard.flags
28
29include $(BUILD_PACKAGE)
diff --git a/tools/bootanalyze/stressfs/AndroidManifest.xml b/tools/bootanalyze/stressfs/AndroidManifest.xml
deleted file mode 100644
index 8713c511..00000000
--- a/tools/bootanalyze/stressfs/AndroidManifest.xml
+++ /dev/null
@@ -1,38 +0,0 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- Copyright (C) 2017 The Android Open Source Project
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15-->
16
17<manifest xmlns:android="http://schemas.android.com/apk/res/android"
18 package="com.android.car.test.stressfs">
19
20 <original-package android:name="com.android.car.test.stressfs" />
21
22 <uses-sdk android:minSdkVersion="25"
23 android:targetSdkVersion="25" />
24 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
25
26 <application android:label="Stress Filesystem"
27 android:directBootAware="true"
28 android:allowBackup="false">
29
30 <activity android:name=".WritingActivity">
31 <intent-filter>
32 <action android:name="com.android.car.test.stressfs.START" />
33 </intent-filter>
34 </activity>
35 <service android:name=".WritingService">
36 </service>
37 </application>
38</manifest>
diff --git a/tools/bootanalyze/stressfs/proguard.flags b/tools/bootanalyze/stressfs/proguard.flags
deleted file mode 100644
index 1e5ff3dd..00000000
--- a/tools/bootanalyze/stressfs/proguard.flags
+++ /dev/null
@@ -1,3 +0,0 @@
1-verbose
2-keep public class * extends android.app.Activity
3-keep public class * extends android.app.Service
diff --git a/tools/bootanalyze/stressfs/src/com/android/car/test/stressfs/WritingActivity.java b/tools/bootanalyze/stressfs/src/com/android/car/test/stressfs/WritingActivity.java
deleted file mode 100644
index 6fe5cc61..00000000
--- a/tools/bootanalyze/stressfs/src/com/android/car/test/stressfs/WritingActivity.java
+++ /dev/null
@@ -1,61 +0,0 @@
1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.car.test.stressfs;
17
18import android.app.Activity;
19import android.content.ComponentName;
20import android.content.Context;
21import android.content.Intent;
22import android.content.ServiceConnection;
23import android.os.Bundle;
24import android.os.IBinder;
25
26/**
27 * Used to instantiate the WritingService service at a high priority.
28 */
29public class WritingActivity extends Activity {
30
31 private static final String TAG = "StressFS";
32
33 /**
34 * Activity-wide connection to keep the service going.
35 * Not used for any specific interaction.
36 */
37 private ServiceConnection mConnection = new ServiceConnection() {
38 /** No-op */
39 public void onServiceConnected(ComponentName className, IBinder service) {
40 // Nothing to do.
41 }
42
43 /** No-op */
44 public void onServiceDisconnected(ComponentName className) {
45 // Nothing to do.
46 }
47 };
48
49 @Override
50 public void onCreate(Bundle savedInstanceState) {
51 super.onCreate(savedInstanceState);
52 bindService(
53 new Intent(
54 getIntent().getAction(),
55 getIntent().getData(),
56 this,
57 WritingService.class),
58 mConnection,
59 Context.BIND_AUTO_CREATE);
60 }
61}
diff --git a/tools/bootanalyze/stressfs/src/com/android/car/test/stressfs/WritingService.java b/tools/bootanalyze/stressfs/src/com/android/car/test/stressfs/WritingService.java
deleted file mode 100644
index 0db75d45..00000000
--- a/tools/bootanalyze/stressfs/src/com/android/car/test/stressfs/WritingService.java
+++ /dev/null
@@ -1,186 +0,0 @@
1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.car.test.stressfs;
17
18import android.app.Service;
19import android.app.Notification;
20import android.app.NotificationChannel;
21import android.content.Context;
22import android.content.Intent;
23import android.net.Uri;
24import android.os.Binder;
25import android.os.Bundle;
26import android.os.Environment;
27import android.os.IBinder;
28import android.util.Log;
29import android.R.drawable;
30
31import java.io.*;
32import java.util.*;
33
34/**
35 * Used to stress the file writing before and during shutdown to help ensure
36 * that the filesystem shuts down at the right time, in a consistent manner,
37 * and does not get corrupted.
38 *
39 * Writes to two files - one on the data partition, one on the external storage
40 * partition - simultaneous in two separate threads; starting over after a
41 * certain amount of data is written.
42 *
43 * This class is intended to be invoked from the shell. For a 64KB file
44 * written in 1KB chunks, invoke from the host workstation:
45 * adb install -g StressFS.apk
46 * adb shell am start \
47 * -n com.android.car.test.stressfs/.WritingActivity \
48 * -a com.android.car.test.stressfs.START
49 * -d "stressfs://start?block=1024\&file=65536"
50 *
51 * After reboot:
52 * adb uninstall com.android.car.test.stressfs
53 * adb shell "rm -rf /storage/emulated/0/stressfs_data*"
54 *
55 * On boot after running this while shutting down, fsck should flag any
56 * corruption that it sees resulting from this running. The goal is to set the
57 * shutdown sequence in a manner that does not corrupt so that this check can
58 * be avoided.
59 */
60public class WritingService extends Service {
61
62 private static final String TAG = "StressFS";
63
64 private static final String ACTION_START = "com.android.car.test.stressfs.START";
65
66 private static final int DEFAULT_BLOCK_SIZE = 4096;
67 private static final int DEFAULT_FILE_SIZE = 16 * 1024 * 1024;
68
69 private static final String FILENAME_PREFIX = "stressfs_data_";
70
71 private static final int NOTIFICATION_ID = 100;
72
73 /** Continuously writes test data to a specified file. */
74 private static class WriteToDisk extends Thread {
75 private final String mLogTag;
76 private final File mFile;
77 private final int mFileSize;
78 private final byte[] mTestData;
79
80 public WriteToDisk(
81 String logTag,
82 File file,
83 int fileSize,
84 byte[] testData) {
85 mLogTag = logTag;
86 mFile = file;
87 mFileSize = fileSize;
88 mTestData = testData;
89 }
90
91 /** Writes data to a file, restarting once the maximum amount of data is reached.*/
92 @Override
93 public void run() {
94 Log.d(TAG, mLogTag + " thread started");
95 while (true) {
96 try {
97 FileOutputStream fos = new FileOutputStream(mFile);
98 // Write in chunks until the amount of data requested
99 // is written.
100 for (int j = 0; j < mFileSize; j += mTestData.length) {
101 fos.write(mTestData);
102 }
103 fos.close();
104 } catch (FileNotFoundException e) {
105 Log.e(TAG, "File not found: ", e);
106 } catch (IOException e) {
107 Log.e(TAG, "IO error: ", e);
108 }
109 }
110 }
111 }
112
113 /** Raises service priority and starts the writing threads. */
114 @Override
115 public IBinder onBind(Intent intent) {
116 Notification notification =
117 new Notification.Builder(this, NotificationChannel.DEFAULT_CHANNEL_ID)
118 .setContentTitle("Stress Filesystem service running.")
119 .setSmallIcon(drawable.ic_menu_save)
120 .build();
121
122 // Raise priority of this service.
123 startForeground(NOTIFICATION_ID, notification);
124
125 File dataPartitionFile = getFileStreamPath(FILENAME_PREFIX + UUID.randomUUID());
126 File externalPartitionFile = new File(
127 Environment.getExternalStorageDirectory(), FILENAME_PREFIX + UUID.randomUUID());
128
129 Log.i(TAG, "External storage state: " +
130 Environment.getExternalStorageState(externalPartitionFile));
131
132 Uri data = intent.getData();
133 if (data != null) {
134 Log.i(TAG, "Data: " + data.toString());
135 }
136 int blockSize = getQueryParam(data, "block", DEFAULT_BLOCK_SIZE);
137 int fileSize = getQueryParam(data, "file", DEFAULT_FILE_SIZE);
138 Log.i(TAG, "Block Size: " + blockSize);
139 Log.i(TAG, "File Size: " + fileSize);
140
141 if (fileSize % blockSize != 0) {
142 Log.w(TAG, "File size should be a multiple of block size.");
143 }
144
145 // Populate some test data.
146 StringBuilder builder = new StringBuilder(blockSize);
147 for (int i = 0; i < builder.capacity(); i++) {
148 builder.append((char)(i % 26 + 'A'));
149 }
150 byte[] testData = new String(builder).getBytes();
151
152 // Spawn two threads - one to write to the /data partition, one to
153 // write to the SD card.
154 new WriteToDisk("data", dataPartitionFile, fileSize, testData).start();
155 new WriteToDisk("external", externalPartitionFile, fileSize, testData).start();
156
157 // No need to return a binder interface, since there is no more
158 // interaction needed from the activity starting the service.
159 return null;
160 }
161
162 /** Keeps service alive once started. */
163 @Override
164 public int onStartCommand(Intent intent, int flags, int startId) {
165 return START_STICKY;
166 }
167
168 /** Parses an integer query parameter from the input Uri. */
169 private int getQueryParam(Uri data, String key, int defaultValue) {
170 if (data == null) {
171 return defaultValue;
172 }
173 String inValString = data.getQueryParameter(key);
174 if (inValString != null) {
175 try {
176 int inVal = Integer.parseInt(inValString);
177 if (inVal != 0) {
178 return inVal;
179 }
180 } catch (NumberFormatException e) {
181 return defaultValue;
182 }
183 }
184 return defaultValue;
185 }
186}
diff --git a/tools/bootio/Android.mk b/tools/bootio/Android.mk
deleted file mode 100644
index e4db8355..00000000
--- a/tools/bootio/Android.mk
+++ /dev/null
@@ -1,76 +0,0 @@
1#
2# Copyright (C) 2016 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16
17LOCAL_PATH := $(call my-dir)
18
19bootio_lib_src_files := \
20 protos.proto \
21 bootio_collector.cpp \
22
23bootio_src_files := \
24 bootio.cpp \
25
26bootio_shared_libs := \
27 libbase \
28 libcutils \
29 liblog \
30 libprotobuf-cpp-lite \
31
32bootio_cflags := \
33 -Wall \
34 -Werror \
35 -Wextra \
36
37define bootio_proto_include
38$(call local-generated-sources-dir)/proto/$(LOCAL_PATH)
39endef
40
41# bootio static library
42# -----------------------------------------------------------------------------
43
44include $(CLEAR_VARS)
45
46LOCAL_MODULE := libbootio
47LOCAL_MODULE_CLASS := SHARED_LIBRARIES
48
49LOCAL_C_INCLUDES := \
50 $(LOCAL_PATH)/.. \
51 $(call bootio_proto_include) \
52
53LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
54LOCAL_CFLAGS := $(bootio_cflags)
55LOCAL_SHARED_LIBRARIES := $(bootio_shared_libs)
56LOCAL_PROTOC_OPTIMIZE_TYPE := lite
57LOCAL_SRC_FILES := $(bootio_lib_src_files)
58
59include $(BUILD_SHARED_LIBRARY)
60
61
62# bootio binary
63# -----------------------------------------------------------------------------
64
65include $(CLEAR_VARS)
66
67LOCAL_MODULE := bootio
68LOCAL_CFLAGS := $(bootio_cflags)
69LOCAL_SHARED_LIBRARIES := \
70 $(bootio_shared_libs) \
71 libbootio \
72
73LOCAL_INIT_RC := bootio.rc
74LOCAL_SRC_FILES := $(bootio_src_files)
75
76include $(BUILD_EXECUTABLE)
diff --git a/tools/bootio/README.md b/tools/bootio/README.md
deleted file mode 100644
index ca075ded..00000000
--- a/tools/bootio/README.md
+++ /dev/null
@@ -1,24 +0,0 @@
1# bootio #
2
3The bootio tool records I/O for processes during boot.
4To use bootio kernel must be compiled with this flags:
5
6 CONFIG_TASKSTATS=y
7 CONFIG_TASK_DELAY_ACCT=y
8 CONFIG_TASK_XACCT=y
9 CONFIG_TASK_IO_ACCOUNTING=y
10
11To use bootio make sure it's included in product config for the board.
12Create file /data/misc/bootio/start with a command like the following:
13
14 adb shell 'echo "$TIMEOUT $SAMPLES" > /data/misc/bootio/start'
15
16Where the value of $TIMEOUT corresponds to the desired bootio period in
17seconds and $SAMPLES corresponds to the desired number of samples.
18
19Note: /data/misc/bootio/start is not deleted automatically, so don't
20forget to delete it when you're done collecting data.
21
22To see collected logs run:
23
24 adb shell bootio -p
diff --git a/tools/bootio/bootio.cpp b/tools/bootio/bootio.cpp
deleted file mode 100644
index 629d04a7..00000000
--- a/tools/bootio/bootio.cpp
+++ /dev/null
@@ -1,162 +0,0 @@
1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17// The bootio tool provides options to collect I/O stats for processes during boot.
18
19#include <vector>
20#include <getopt.h>
21#include <unistd.h>
22#include <android-base/file.h>
23#include <android-base/logging.h>
24#include <android-base/strings.h>
25#include <log/log.h>
26
27#include "bootio_collector.h"
28
29namespace android {
30
31#define LOG_ROOT "/data/misc/bootio"
32#define LOG_START_FILE LOG_ROOT"/start"
33#define SELF_IO "/proc/self/io"
34
35static const int LOG_TIMEOUT_INDEX = 0;
36static const int LOG_SAMPLES_INDEX = 1;
37static const int LOG_MAX_TIMEOUT = 120;
38static const int LOG_MAX_SAMPLES = 30;
39
40void ShowHelp(const char *cmd) {
41 fprintf(stderr, "Usage: %s [options]\n", cmd);
42 fprintf(stderr,
43 "options include:\n"
44 " -h, --help Show this help\n"
45 " -p, --print Dump the boot io data to the console\n"
46 "\nNo options will start data collection process.\n");
47}
48
49void PrintBootIo() {
50 printf("Boot I/O:\n");
51 printf("------------\n");
52 std::unique_ptr <BootioCollector> collector(new BootioCollector(LOG_ROOT));
53 if (collector.get() == NULL) {
54 LOG(ERROR) << "Failed to create data collector";
55 return;
56 }
57 collector->Print();
58}
59
60void StartDataCollection() {
61 if (access(SELF_IO, F_OK) == -1) {
62 LOG(ERROR) << "Kernel doesn't support I/O profiling.";
63 printf("Kernel doesn't support I/O profiling.");
64 return;
65 }
66
67 int timeout = 0;
68 int samples = 0;
69
70 std::string start;
71 android::base::ReadFileToString(LOG_START_FILE, &start);
72
73 if (!start.empty()) {
74 std::vector <std::string> components = android::base::Split(start, " ");
75 if (components.size() != 2) {
76 LOG(ERROR) << "Invalid value in start file." << start;
77 return;
78 }
79 timeout = atoi(components.at(LOG_TIMEOUT_INDEX).c_str());
80 samples = atoi(components.at(LOG_SAMPLES_INDEX).c_str());
81 } else {
82 LOG(INFO) << "No profiling requested. Exiting";
83 printf("Boot I/O: no profiling requested. Exiting.\n");
84 return;
85 }
86 if (timeout <= 0 || samples <= 0) {
87 LOG(ERROR) << "Boot I/O: failed to parse string:" << start;
88 printf("Boot I/O: failed to parse string: %s\n", start.c_str());
89 return;
90 }
91 if (samples > timeout || samples > LOG_MAX_SAMPLES || timeout > LOG_MAX_TIMEOUT) {
92 LOG(ERROR) << "Bad values for bootio. timeout=" << timeout <<
93 " samples=" << samples << " Max timeout=" << LOG_MAX_TIMEOUT <<
94 " Max samples=" << LOG_MAX_SAMPLES;
95 return;
96 }
97 LOG(INFO) << "Boot I/O: collecting data. samples=" << samples << "timeout=" << timeout;
98 printf("Boot I/O: collecting data\ntimeout=%d, samples=%d\n",
99 timeout, samples);
100 std::unique_ptr <BootioCollector> collector(new BootioCollector(LOG_ROOT));
101 if (collector.get() == NULL) {
102 LOG(ERROR) << "Failed to create data collector";
103 return;
104 }
105 collector->StartDataCollection(timeout, samples);
106}
107
108}
109
110int main(int argc, char **argv) {
111 android::base::InitLogging(argv);
112
113 LOG(INFO) << "Bootio started";
114
115 int optionIndex = 0;
116 static const struct option longOptions[] = {
117 {"help", no_argument, NULL, 'h'},
118 {"print", no_argument, NULL, 'p'},
119 {NULL, 0, NULL, 0}
120 };
121
122 int opt = 0;
123 bool startCollection = true;
124 while ((opt = getopt_long(argc, argv, "hlpr:", longOptions, &optionIndex)) != -1) {
125 switch (opt) {
126 case 0: {
127 const std::string option_name = longOptions[optionIndex].name;
128 LOG(ERROR) << "Invalid option: " << option_name;
129 break;
130 }
131
132 case 'h': {
133 android::ShowHelp(argv[0]);
134 startCollection = false;
135 break;
136 }
137
138 case 'p': {
139 android::PrintBootIo();
140 startCollection = false;
141 break;
142 }
143
144 default: {
145 DCHECK_EQ(opt, '?');
146
147 // |optopt| is an external variable set by getopt representing
148 // the value of the invalid option.
149 LOG(ERROR) << "Invalid option: " << optopt;
150 android::ShowHelp(argv[0]);
151 return EXIT_FAILURE;
152 }
153 }
154 }
155
156 if (startCollection) {
157 android::StartDataCollection();
158 }
159
160 return 0;
161}
162
diff --git a/tools/bootio/bootio.rc b/tools/bootio/bootio.rc
deleted file mode 100644
index f0074cb4..00000000
--- a/tools/bootio/bootio.rc
+++ /dev/null
@@ -1,10 +0,0 @@
1# This file is the LOCAL_INIT_RC file for the bootio command.
2
3service bootio /system/bin/bootio
4 class main
5 user root
6 group root
7 oneshot
8
9on post-fs-data
10 mkdir /data/misc/bootio 0755 root shell
diff --git a/tools/bootio/bootio_collector.cpp b/tools/bootio/bootio_collector.cpp
deleted file mode 100644
index 495a9aa4..00000000
--- a/tools/bootio/bootio_collector.cpp
+++ /dev/null
@@ -1,381 +0,0 @@
1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "bootio_collector.h"
18#include <android-base/logging.h>
19#include <android-base/file.h>
20#include <log/log.h>
21#include "protos.pb.h"
22#include "time.h"
23#include <unordered_map>
24#include <inttypes.h>
25#include <dirent.h>
26
27namespace android {
28
29#define CPU_STAT_FILE "/proc/stat"
30#define SAMPLES_FILE "/samples"
31#define PID_STAT_FILE "/proc/%d/stat"
32#define PID_CMDLINE_FILE "/proc/%d/cmdline"
33#define PID_IO_FILE "/proc/%d/io"
34#define PROC_DIR "/proc"
35
36static const int MAX_LINE = 256;
37
38#define die(...) { LOG(ERROR) << (__VA_ARGS__); exit(EXIT_FAILURE); }
39
40void PopulateCpu(CpuData& cpu) {
41 long unsigned utime, ntime, stime, itime;
42 long unsigned iowtime, irqtime, sirqtime;
43 FILE *file;
44 file = fopen(CPU_STAT_FILE, "r");
45 if (!file) die("Could not open /proc/stat.\n");
46 fscanf(file, "cpu %lu %lu %lu %lu %lu %lu %lu", &utime, &ntime, &stime,
47 &itime, &iowtime, &irqtime, &sirqtime);
48 fclose(file);
49 cpu.set_utime(utime);
50 cpu.set_ntime(ntime);
51 cpu.set_stime(stime);
52 cpu.set_itime(itime);
53 cpu.set_iowtime(iowtime);
54 cpu.set_irqtime(irqtime);
55 cpu.set_sirqtime(sirqtime);
56}
57
58void ClearPreviousResults(std::string path) {
59 std::string err;
60 if (!android::base::RemoveFileIfExists(path, &err)) {
61 LOG(ERROR) << "failed to remove the file " << path << " " << err;
62 return;
63 }
64}
65
66int ReadIo(char *filename, AppSample *sample) {
67 FILE *file;
68 char line[MAX_LINE];
69 unsigned int rchar, wchar, syscr, syscw, readbytes, writebytes;
70
71 file = fopen(filename, "r");
72 if (!file) return 1;
73 while (fgets(line, MAX_LINE, file)) {
74 sscanf(line, "rchar: %u", &rchar);
75 sscanf(line, "wchar: %u", &wchar);
76 sscanf(line, "syscr: %u", &syscr);
77 sscanf(line, "syscw: %u", &syscw);
78 sscanf(line, "read_bytes: %u", &readbytes);
79 sscanf(line, "write_bytes: %u", &writebytes);
80 }
81 fclose(file);
82 sample->set_rchar(rchar);
83 sample->set_wchar(wchar);
84 sample->set_syscr(syscr);
85 sample->set_syscw(syscw);
86 sample->set_readbytes(readbytes);
87 sample->set_writebytes(writebytes);
88 return 0;
89}
90
91int ReadStatForName(char *filename, AppData *app) {
92 FILE *file;
93 char buf[MAX_LINE], *open_paren, *close_paren;
94
95 file = fopen(filename, "r");
96 if (!file) return 1;
97 fgets(buf, MAX_LINE, file);
98 fclose(file);
99
100 /* Split at first '(' and last ')' to get process name. */
101 open_paren = strchr(buf, '(');
102 close_paren = strrchr(buf, ')');
103 if (!open_paren || !close_paren) return 1;
104
105 *open_paren = *close_paren = '\0';
106 if (!app->has_tname()) {
107 app->set_tname(open_paren + 1, close_paren - open_paren - 1);
108 }
109 return 0;
110}
111
112int ReadStat(char *filename, AppSample *sample) {
113 FILE *file;
114 char buf[MAX_LINE], *open_paren, *close_paren;
115
116 file = fopen(filename, "r");
117 if (!file) return 1;
118 fgets(buf, MAX_LINE, file);
119 fclose(file);
120
121 /* Split at first '(' and last ')' to get process name. */
122 open_paren = strchr(buf, '(');
123 close_paren = strrchr(buf, ')');
124 if (!open_paren || !close_paren) return 1;
125
126 uint64_t utime;
127 uint64_t stime;
128 uint64_t rss;
129
130 /* Scan rest of string. */
131 sscanf(close_paren + 1,
132 " %*c " "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
133 "%" PRIu64 /*SCNu64*/
134 "%" PRIu64 /*SCNu64*/ "%*d %*d %*d %*d %*d %*d %*d %*d "
135 "%" PRIu64 /*SCNu64*/ "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d",
136 &utime,
137 &stime,
138 &rss);
139 sample->set_utime(utime);
140 sample->set_stime(stime);
141 sample->set_rss(rss);
142
143 return 0;
144}
145
146int ReadCmdline(char *filename, AppData *app) {
147 FILE *file;
148 char line[MAX_LINE];
149
150 line[0] = '\0';
151 file = fopen(filename, "r");
152 if (!file) return 1;
153 fgets(line, MAX_LINE, file);
154 fclose(file);
155 if (strlen(line) > 0) {
156 app->set_name(line, strlen(line));
157 } else {
158 app->set_name("N/A");
159 }
160 return 0;
161};
162
163void ReadProcData(std::unordered_map<int, AppData*>& pidDataMap, DataContainer& dataContainer,
164 time_t currentTimeUtc, time_t currentUptime) {
165 DIR *procDir;
166 struct dirent *pidDir;
167 pid_t pid;
168 char filename[64];
169 procDir = opendir(PROC_DIR);
170 if (!procDir) die("Could not open /proc.\n");
171 while ((pidDir = readdir(procDir))) {
172 if (!isdigit(pidDir->d_name[0])) {
173 continue;
174 }
175 pid = atoi(pidDir->d_name);
176 AppData *data;
177
178 // TODO: in theory same pid can be shared for multiple processes,
179 // might need add extra check.
180 if (pidDataMap.count(pid) == 0) {
181 data = dataContainer.add_app();
182 data->set_pid(pid);
183 sprintf(filename, PID_STAT_FILE, pid);
184 ReadStatForName(filename, data);
185 sprintf(filename, PID_CMDLINE_FILE, pid);
186 ReadCmdline(filename, data);
187 pidDataMap[pid] = data;
188 } else {
189 data = pidDataMap[pid];
190 }
191 AppSample *sample = data->add_samples();
192 sample->set_timestamp(currentTimeUtc);
193 sample->set_uptime(currentUptime);
194
195 sprintf(filename, PID_STAT_FILE, pid);
196 ReadStat(filename, sample);
197
198 sprintf(filename, PID_IO_FILE, pid);
199 ReadIo(filename, sample);
200 }
201}
202
203uint64_t SumCpuValues(CpuData& cpu) {
204 return cpu.utime() + cpu.ntime() + cpu.stime() + cpu.itime() + cpu.iowtime() +
205 cpu.irqtime() + cpu.sirqtime();
206}
207
208time_t GetUptime() {
209 std::string uptime_str;
210 if (!android::base::ReadFileToString("/proc/uptime", &uptime_str)) {
211 LOG(ERROR) << "Failed to read /proc/uptime";
212 return -1;
213 }
214
215 // Cast intentionally rounds down.
216 return static_cast<time_t>(strtod(uptime_str.c_str(), NULL));
217}
218
219struct Stats {
220 int uptime;
221 float cpu;
222 uint64_t rbytes;
223 uint64_t wbytes;
224};
225
226void PrintPids(DataContainer& data, std::unordered_map<int, uint64_t>& cpuDataMap) {
227 printf("rchar: number of bytes the process read, using any read-like system call "
228 "(from files, pipes, tty...).\n");
229 printf("wchar: number of bytes the process wrote using any write-like system call.\n");
230 printf("wchar: number of bytes the process wrote using any write-like system call.\n");
231 printf("syscr: number of write-like system call invocations that the process performed.\n");
232 printf("rbytes: number of bytes the process directly read from disk.\n");
233 printf("wbytes: number of bytes the process originally dirtied in the page-cache "
234 "(assuming they will go to disk later).\n\n");
235
236 std::unique_ptr<AppSample> bootZeroSample(new AppSample());
237 std::map<int, Stats> statsMap;
238 // Init stats map
239 Stats emptyStat {0, 0., 0, 0};
240 for (auto it = cpuDataMap.begin(); it != cpuDataMap.end(); it++) {
241 statsMap[it->first] = emptyStat;
242 }
243 for (int i = 0; i < data.app_size(); i++) {
244 const AppData appData = data.app(i);
245 printf("\n-----------------------------------------------------------------------------\n");
246 printf("PID:\t%u\n", appData.pid());
247 printf("Name:\t%s\n", appData.name().c_str());
248 printf("ThName:\t%s\n", appData.tname().c_str());
249 printf("%-15s%-13s%-13s%-13s%-13s%-13s%-13s%-13s\n", "Uptime inter.", "rchar", "wchar",
250 "syscr", "syscw", "rbytes", "wbytes", "cpu%");
251 const AppSample *olderSample = NULL;
252 const AppSample *newerSample = NULL;
253 bool isFirstSample = true;
254 for (int j = 0; j < appData.samples_size(); j++) {
255 olderSample = newerSample;
256 newerSample = &(appData.samples(j));
257 if (olderSample == NULL) {
258 olderSample = bootZeroSample.get();
259 }
260 float cpuLoad = 0.;
261 uint64_t cpuDelta;
262 if (isFirstSample) {
263 cpuDelta = cpuDataMap[newerSample->timestamp()];
264 } else {
265 cpuDelta = cpuDataMap[newerSample->timestamp()] -
266 cpuDataMap[olderSample->timestamp()];
267 }
268 if (cpuDelta != 0) {
269 cpuLoad = (newerSample->utime() - olderSample->utime() +
270 newerSample->stime() - olderSample->stime()) * 100. / cpuDelta;
271 }
272 Stats& stats = statsMap[newerSample->timestamp()];
273 stats.uptime = newerSample->uptime();
274 stats.cpu += cpuLoad;
275 stats.rbytes += (newerSample->readbytes() - olderSample->readbytes());
276 stats.wbytes += (newerSample->writebytes() - olderSample->writebytes());
277
278 // Note that all of these are explicitly `long long`s, not int64_t,
279 // so we can't use PRId64 here.
280#define NUMBER "%-13lld"
281 printf("%5lld - %-5lld " NUMBER NUMBER NUMBER NUMBER NUMBER NUMBER "%-9.2f\n",
282#undef NUMBER
283 olderSample->uptime(),
284 newerSample->uptime(),
285 newerSample->rchar() - olderSample->rchar(),
286 newerSample->wchar() - olderSample->wchar(),
287 newerSample->syscr() - olderSample->syscr(),
288 newerSample->syscw() - olderSample->syscw(),
289 newerSample->readbytes() - olderSample->readbytes(),
290 newerSample->writebytes() - olderSample->writebytes(),
291 cpuLoad);
292 isFirstSample = false;
293 }
294 printf("-----------------------------------------------------------------------------\n");
295#define NUMBER "%-13lld"
296 printf("%-15s" NUMBER NUMBER NUMBER NUMBER NUMBER NUMBER "\n",
297#undef NUMBER
298 "Total",
299 newerSample->rchar(),
300 newerSample->wchar(),
301 newerSample->syscr(),
302 newerSample->syscw(),
303 newerSample->readbytes(),
304 newerSample->writebytes());
305 }
306 printf("\nAggregations\n%-10s%-13s%-13s%-13s\n",
307 "Total",
308 "rbytes",
309 "wbytes",
310 "cpu%");
311
312 for (auto it = statsMap.begin(); it != statsMap.end(); it++) {
313 printf("%-10u%-13" PRIu64 "%-13" PRIu64 "%-9.2f\n",
314 it->second.uptime,
315 it->second.rbytes,
316 it->second.wbytes,
317 it->second.cpu);
318 }
319}
320
321}
322
323BootioCollector::BootioCollector(std::string path) {
324 DCHECK_EQ('/', path.back());
325 path_ = path;
326}
327
328void BootioCollector::StartDataCollection(int timeout, int samples) {
329 android::ClearPreviousResults(getStoragePath());
330 int remaining = samples + 1;
331 int delayS = timeout / samples;
332
333 std::unordered_map < int, AppData * > pidDataMap;
334 std::unique_ptr <DataContainer> data(new DataContainer());
335 while (remaining > 0) {
336 time_t currentTimeUtc = time(nullptr);
337 time_t currentUptime = android::GetUptime();
338 CpuData *cpu = data->add_cpu();
339 cpu->set_timestamp(currentTimeUtc);
340 cpu->set_uptime(currentUptime);
341 android::PopulateCpu(*cpu);
342 android::ReadProcData(pidDataMap, *data.get(), currentTimeUtc, currentUptime);
343 remaining--;
344 if (remaining == 0) {
345 continue;
346 }
347 sleep(delayS);
348 }
349 std::string file_data;
350 if (!data->SerializeToString(&file_data)) {
351 LOG(ERROR) << "Failed to serialize";
352 return;
353 }
354 if (!android::base::WriteStringToFile(file_data, getStoragePath())) {
355 LOG(ERROR) << "Failed to write samples";
356 }
357}
358
359void BootioCollector::Print() {
360 std::string file_data;
361 if (!android::base::ReadFileToString(getStoragePath(), &file_data)) {
362 printf("Failed to read data from file.\n");
363 return;
364 }
365 std::unique_ptr <DataContainer> data(new DataContainer());
366 if (!data->ParsePartialFromString(file_data)) {
367 printf("Failed to parse data.\n");
368 return;
369 }
370 std::unordered_map<int, uint64_t> cpuDataMap;
371 for (int i = 0; i < data->cpu_size(); i++) {
372 CpuData cpu_data = data->cpu(i);
373 cpuDataMap[cpu_data.timestamp()] = android::SumCpuValues(cpu_data);
374 }
375 android::PrintPids(*data.get(), cpuDataMap);
376}
377
378
379std::string BootioCollector::getStoragePath() {
380 return path_ + SAMPLES_FILE;
381}
diff --git a/tools/bootio/bootio_collector.h b/tools/bootio/bootio_collector.h
deleted file mode 100644
index 7296e6f9..00000000
--- a/tools/bootio/bootio_collector.h
+++ /dev/null
@@ -1,39 +0,0 @@
1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef BOOTIO_COLLECTOR_H_
18#define BOOTIO_COLLECTOR_H_
19
20#include <string>
21#include <android-base/macros.h>
22
23class BootioCollector {
24public:
25 BootioCollector(std::string path);
26
27 void StartDataCollection(int timeout, int samples);
28
29 void Print();
30
31private:
32 std::string getStoragePath();
33
34 std::string path_;
35
36 DISALLOW_COPY_AND_ASSIGN(BootioCollector);
37};
38
39#endif // BOOTIO_COLLECTOR_H_
diff --git a/tools/bootio/protos.proto b/tools/bootio/protos.proto
deleted file mode 100644
index d5674ece..00000000
--- a/tools/bootio/protos.proto
+++ /dev/null
@@ -1,55 +0,0 @@
1// Copyright (C) 2016 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15syntax = "proto2";
16
17option optimize_for = LITE_RUNTIME;
18
19message DataContainer {
20 repeated AppData app = 1;
21 repeated CpuData cpu = 2;
22};
23
24message CpuData {
25 required int64 timestamp = 1;
26 required int64 uptime = 2;
27 required int64 utime = 3;
28 required int64 ntime = 4;
29 required int64 stime = 5;
30 required int64 itime = 6;
31 required int64 iowtime = 7;
32 required int64 irqtime = 9;
33 required int64 sirqtime = 10;
34}
35
36message AppData {
37 required int32 pid = 1;
38 required string tname = 2;
39 required string name = 3;
40 repeated AppSample samples = 4;
41}
42
43message AppSample {
44 required int64 timestamp = 1;
45 required int64 uptime = 2;
46 required int64 rchar = 3;
47 required int64 wchar = 4;
48 required int64 syscr = 5;
49 required int64 syscw = 6;
50 required int64 readbytes = 7;
51 required int64 writebytes = 8;
52 required int64 utime = 9;
53 required int64 stime = 10;
54 required int64 rss = 11;
55};
diff --git a/tools/bootio/sepolicy/bootio.te b/tools/bootio/sepolicy/bootio.te
deleted file mode 100644
index cd0fb80d..00000000
--- a/tools/bootio/sepolicy/bootio.te
+++ /dev/null
@@ -1,12 +0,0 @@
1# bootio command
2type bootio, domain, coredomain;
3type bootio_exec, exec_type, file_type;
4
5init_daemon_domain(bootio)
6
7# Allow persistent storage in /data/misc/bootio.
8#allow bootio bootio_data_file:dir rw_dir_perms;
9#allow bootio bootio_data_file:file create_file_perms;
10
11# Read access to pseudo filesystems (for /proc/stats, proc/io/io, etc).
12#r_dir_file(bootio, proc)
diff --git a/tools/bootio/sepolicy/domain.te b/tools/bootio/sepolicy/domain.te
deleted file mode 100644
index af42fe7e..00000000
--- a/tools/bootio/sepolicy/domain.te
+++ /dev/null
@@ -1,2 +0,0 @@
1# dontaudit bootio kernel:system module_request;
2allow bootio kernel:fd use; \ No newline at end of file
diff --git a/tools/bootio/sepolicy/file.te b/tools/bootio/sepolicy/file.te
deleted file mode 100644
index 0320bc83..00000000
--- a/tools/bootio/sepolicy/file.te
+++ /dev/null
@@ -1,2 +0,0 @@
1# /data/misc subdirectories
2type bootio_data_file, file_type, data_file_type, core_data_file_type;
diff --git a/tools/bootio/sepolicy/file_contexts b/tools/bootio/sepolicy/file_contexts
deleted file mode 100644
index 071227c2..00000000
--- a/tools/bootio/sepolicy/file_contexts
+++ /dev/null
@@ -1,5 +0,0 @@
1# System files
2/system/bin/bootio u:object_r:bootio_exec:s0
3
4# Misc data
5/data/misc/bootio(/.*)? u:object_r:bootio_data_file:s0