| #!/bin/bash | |
| # | |
| # Copyright 2019, 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. | |
| usage() { | |
| cat <<EOF | |
| Usage: launch_application package activity | parse_metrics --package <name> --timestamp <timestamp> [OPTIONS]... | |
| Reads from stdin the result of 'am start' metrics. May also parse logcat | |
| for additional metrics. | |
| Output form: | |
| MetricName_unit=numeric_value | |
| MetricName2_unit=numeric_value2 | |
| This may block until all desired metrics are parsed from logcat. | |
| To get a list of metrics without doing real parsing, use --simulate. | |
| To add package-specific metrics, add a script called 'metrics/\$full_package_name' | |
| that exposes additional metrics in same way as above. | |
| (required) | |
| -p, --package <name> package of the app that is being used | |
| -ts, --timestamp <name> logcat timestamp [only looks at logcat entries after this timestamp]. | |
| (optional) | |
| -s, --simulate prints dummy values instead of real metrics | |
| -a, --activity <name> activity to use (default: inferred) | |
| -h, --help usage information (this) | |
| -v, --verbose enable extra verbose printing | |
| -t, --timeout <sec> how many seconds to timeout when trying to wait for logcat to change | |
| -rfd, --reportfullydrawn wait for report fully drawn (default: off) | |
| EOF | |
| } | |
| DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" | |
| source "$DIR/lib/common" | |
| report_fully_drawn="n" | |
| package="" | |
| activity="" | |
| timeout=5 | |
| simulate="n" | |
| parse_arguments() { | |
| while [[ $# -gt 0 ]]; do | |
| case "$1" in | |
| -h|--help) | |
| usage | |
| exit 0 | |
| ;; | |
| -p|--package) | |
| package="$2" | |
| shift | |
| ;; | |
| -a|--activity) | |
| activity="$2" | |
| shift | |
| ;; | |
| -v|--verbose) | |
| export verbose="y" | |
| ;; | |
| -t|--timeout) | |
| timeout="$2" | |
| shift | |
| ;; | |
| -ts|--timestamp) | |
| timestamp="$2" | |
| shift | |
| ;; | |
| -s|--simulate) | |
| simulate="y" | |
| ;; | |
| -rfd|--reportfullydrawn) | |
| report_fully_drawn="y" | |
| ;; | |
| *) | |
| echo "Invalid argument: $1" >&2 | |
| exit 1 | |
| esac | |
| shift | |
| done | |
| } | |
| # Main entry point | |
| if [[ $# -eq 0 ]]; then | |
| usage | |
| exit 1 | |
| else | |
| parse_arguments "$@" | |
| # if we do not have have package exit early with an error | |
| [[ "$package" == "" ]] && echo "--package not specified" 1>&2 && exit 64 | |
| # ignore timestamp for --simulate. it's optional. | |
| if [[ $simulate == y ]]; then | |
| timestamp=0 | |
| fi | |
| # if we do not have timestamp, exit early with an error | |
| [[ "$timestamp" == "" ]] && echo "--timestamp not specified" 1>&2 && exit 64 | |
| if [[ "$activity" == "" ]] && [[ "$simulate" != "y" ]]; then | |
| activity="$(get_activity_name "$package")" | |
| if [[ "$activity" == "" ]]; then | |
| echo "Activity name could not be found, invalid package name?" 1>&2 | |
| exit 64 | |
| else | |
| verbose_print "Activity name inferred: " "$activity" | |
| fi | |
| fi | |
| fi | |
| parse_metric_from_logcat() { | |
| local metric_name="$1" | |
| local pattern="$2" | |
| local re_pattern="$3" | |
| local retcode | |
| local result | |
| local sec | |
| local ms | |
| # parse logcat for 'Displayed...' and that other one... | |
| # 05-06 14:34:08.854 29460 29481 I ActivityTaskManager: Displayed com.google.android.dialer/.extensions.GoogleDialtactsActivity: +361ms | |
| verbose_print "parse_metric_from_logcat: $re_pattern" | |
| echo -ne "$metric_name=" | |
| if [[ $simulate == y ]]; then | |
| echo "-1" | |
| return 0 | |
| fi | |
| result="$(logcat_extract_pattern "$timeout" "$timestamp" "$pattern" "$re_pattern")" | |
| retcode=$? | |
| if [[ $retcode -ne 0 ]]; then | |
| # Timed out before finding the pattern. Could also mean the pattern is wrong. | |
| echo "Parse $re_pattern from logcat TIMED OUT after $timeout seconds." >&2 | |
| echo "-$?" | |
| return $retcode | |
| fi | |
| # "10s123ms" -> "10s123" | |
| result=${result/ms/} | |
| if [[ $result =~ s ]]; then | |
| ms=${result/*s/} | |
| sec=${result/s*/} | |
| else | |
| sec=0 | |
| ms=$result | |
| fi | |
| ((result=sec*1000+ms)) | |
| echo "$result" | |
| return $retcode | |
| } | |
| total_time="-1" | |
| if [[ $simulate != y ]]; then | |
| verbose_print 'logcat timestamp NOW: ' $(logcat_save_timestamp) | |
| # parse stdin for 'am start' result | |
| while read -t "$timeout" -r input_line; do | |
| verbose_print 'stdin:' "$input_line" | |
| if [[ $input_line == *TotalTime:* ]]; then | |
| total_time="$(echo "$input_line" | sed 's/TotalTime: \([[:digit:]]\+\)/\1/g')" | |
| # but keep reading the rest from stdin until <EOF> | |
| fi | |
| done | |
| fi | |
| echo "TotalTime_ms=$total_time" | |
| # parse logcat for 'Displayed...' and that other one... | |
| # 05-06 14:34:08.854 29460 29481 I ActivityTaskManager: Displayed com.google.android.dialer/.extensions.GoogleDialtactsActivity: +361ms | |
| pattern="ActivityTaskManager: Displayed ${package}" | |
| re_pattern='.*Displayed[[:blank:]]\+'"${package}"'[/][^[:blank:]]\+[[:blank:]]+\([[:digit:]]\+ms\|[[:digit:]]\+s[[:digit:]]\+ms\).*' | |
| parse_metric_from_logcat "Displayed_ms" "$pattern" "$re_pattern" | |
| # Only track ReportFullyDrawn with --reportfullydrawn/-rfd flags | |
| if [[ $report_fully_drawn == y ]]; then | |
| # 01-16 17:31:44.550 11172 11204 I ActivityTaskManager: Fully drawn com.google.android.GoogleCamera/com.android.camera.CameraLauncher: +10s897ms | |
| pattern="ActivityTaskManager: Fully drawn ${package}" | |
| #re_pattern='.*Fully drawn[[:blank:]]\+'"${package}"'[/][^[:blank:]]\+[[:blank:]]+\([[:digit:]]\+\).*' | |
| re_pattern='.*Fully drawn[[:blank:]]\+'"${package}"'[/][^[:blank:]]\+[[:blank:]]+\([[:digit:]]\+ms\|[[:digit:]]\+s[[:digit:]]\+ms\).*' | |
| parse_metric_from_logcat "Fully_drawn_ms" "$pattern" "$re_pattern" | |
| fi | |
| # also call into package-specific scripts if there are additional metrics | |
| if [[ -x "$DIR/metrics/$package" ]]; then | |
| source "$DIR/metrics/$package" "$timestamp" | |
| else | |
| verbose_print parse_metrics: no per-package metrics script found at "$DIR/metrics/$package" | |
| fi |