From 5cd3d2c9f0988277436a85d65ea5623a60bf80bc Mon Sep 17 00:00:00 2001 From: Makoto Onuki Date: Wed, 13 Jun 2018 17:46:37 -0700 Subject: [PATCH] Add some hostside scripts to make life easier - Take a heapdump and open it with ahat on the browser: runhat2 PID_OR_PROCESS_NAME - Take thread stacktrace dump stacktrace PID_OR_PROCESS_NAME TODO: Remove runhat? Is there anyone still using it? Bug: 110088132 Test: stacktrace system_server Test: stacktrace $(pid system_server) Test: stacktrace com.android.systemui Test: runhat2 system_server Change-Id: I8ee4b51ac9097d5342d2d4209407a4b8ac4d5945 --- scripts/bash_util.bash | 96 ++++++++++++++++++++++++++++++++++++++++++ scripts/runahat | 57 +++++++++++++++++++++++++ scripts/stacktrace | 64 ++++++++++++++++++++++++++++ 3 files changed, 217 insertions(+) create mode 100644 scripts/bash_util.bash create mode 100755 scripts/runahat create mode 100755 scripts/stacktrace diff --git a/scripts/bash_util.bash b/scripts/bash_util.bash new file mode 100644 index 000000000..d03e42661 --- /dev/null +++ b/scripts/bash_util.bash @@ -0,0 +1,96 @@ +# Copyright (C) 2018 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +script_name="${0##*/}" +script_dir="${0%/*}" + +# Exit with 1 with printing a given message on stderr. +function die() { + echo "$script_name: ERROR: $@" 1>&2 + exit 1 +} + +# Print a given message on stderr. +function warn() { + echo "$script_name: WARN: $@" 1>&2 +} + +# Print a given message on stderr. +function info() { + echo "$script_name: $@" 1>&2 +} + +# Wrapper around "adb". +function do_adb() { + adb $ADB_OPTIONS "$@" +} + +# Return the timestamp of the most recent log line, which can be later used with logcat -t or -T. +function get_last_logcat_timestamp() { + # Output will be like this. Extract the timestamp. + #--------- beginning of main + #06-14 00:04:43.909 3993 3993 E QtiImsExtUtils: isCarrierConfigEnabled bundle is null + + do_adb logcat -t 1 | awk '(match($0, "^[0-9]")){print $1 " " $2}' +} + +# If $1 is a number, just print it. Otherwise use adb shell pidof to try to resolve it into a pid. +function resolve_pid() { + local name="$1" + + if [[ -z "$name" ]] ;then + return 1 + fi + + if [[ "$name" =~ ^[0-9]+$ ]] ; then + echo "$name" + return 0 + fi + local pid="$(do_adb shell pidof "$name")" + if [[ -z "$pid" ]] ; then + die "unknown process: $name" + fi + echo "$pid" +} + +# Find available local port. Optionally take the starting port from $1. +function find_open_port() { + local port="${1:-10000}" # Take the start port from $1 with 10000 as the default. + + while true; do + if netstat -an | grep -qw "$port"; then + port=$(( $port + 1 )) + continue + fi + break # Found + done + + echo "$port" +} + +# Create a temp file name with a timestamp. +function make_temp_file() { + local suffix="$1" + local dir="${TMPDIR:-${TEMP:-/tmp}}" + + while true; do + local file="$dir/temp-$(date '+%Y%m%d-%H%M%S')-$$$suffix" + if ! [[ -e "$file" ]] ; then + touch "$file" # Note it's a bit racy.. + echo "$file" + return 0 + fi + sleep 0.5 # Ugh. + done +} \ No newline at end of file diff --git a/scripts/runahat b/scripts/runahat new file mode 100755 index 000000000..885262aef --- /dev/null +++ b/scripts/runahat @@ -0,0 +1,57 @@ +#!/bin/bash + +# Copyright (C) 2018 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -e +. "${0%/*}"/bash_util.bash + +function usage() { + cat 1>&2 <<"EOF" + + $script_name: Get heapdump from a process and open in ahat. + + Usage: $script_name PID_OR_PROCESS_NAME + +EOF + exit 1 +} + +pid="$(resolve_pid "$1" || usage)" + +dev_file=/data/local/tmp/heapdump.prof +local_file="$(make_temp_file .prof)" + + +info "Getting heap dump from $pid ..." +do_adb shell am dumpheap -g "$pid" "$dev_file" + + +info "Pulling the dump file to $local_file ..." +do_adb pull "$dev_file" "$local_file" + + +info "Looking for available port ..." +port=$(find_open_port 11000) +info "Using port $port" + +( + sleep 2 + info "Starting the browser ..." + setsid "${AHAT_BROWSER:-google-chrome}" http://localhost:$port +) & + + +info "Opening $local_file with ahat ..." +ahat -p $port "$local_file" \ No newline at end of file diff --git a/scripts/stacktrace b/scripts/stacktrace new file mode 100755 index 000000000..8eec33026 --- /dev/null +++ b/scripts/stacktrace @@ -0,0 +1,64 @@ +#!/bin/bash + +# Copyright (C) 2018 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -e +. "${0%/*}"/bash_util.bash + +function usage() { + cat 1>&2 <<"EOF" + + $script_name: print stacktrace of an android process. + + Usage: $script_name PID_OR_PROCESS_NAME + +EOF + exit 1 +} + +pid="$(resolve_pid "$1" || usage)" + +info "Dumping stacktrace from pid $pid ..." + +# Send sigquit to initiate stacktrace. +ts="$(get_last_logcat_timestamp)" +do_adb shell kill -s sigquit "$pid" + + +# Watch logcat to catch finish, and then obtain the filename. + +# First, set up a timer for timeout. +( + sleep 10 + warn "Timed out waiting for tombstoned. (wrong PID?)" + kill -s usr1 $$ +) & +timer_pid=$! + +trap 'exit 0' USR1 + +# --------- beginning of main +# 06-14 00:12:57.384 1058 925 925 E /system/bin/tombstoned: Traces for pid 1204 written to: /data/anr/trace_01 + +info "Waiting for tombstoned to finish writing..." + +log="$(do_adb logcat -T "$ts" -e "Traces for pid $pid written to" -m 1 | sed -e 1d)" # Remoe the header + +file="${log## }" # Remove everything until the last space. + +do_adb shell cat "$file" || true # Somehow this returns 1? + +# Success, kill the timer process. +kill "$timer_pid" \ No newline at end of file