1#!/bin/bash
2#
3# Copyright 2019, 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
17usage() {
18    cat <<EOF
19Usage: launch_application package activity | parse_metrics --package <name> --timestamp <timestamp> [OPTIONS]...
20
21  Reads from stdin the result of 'am start' metrics. May also parse logcat
22  for additional metrics.
23
24  Output form:
25
26    MetricName_unit=numeric_value
27    MetricName2_unit=numeric_value2
28
29  This may block until all desired metrics are parsed from logcat.
30  To get a list of metrics without doing real parsing, use --simulate.
31
32  To add package-specific metrics, add a script called 'metrics/\$full_package_name'
33  that exposes additional metrics in same way as above.
34
35  (required)
36    -p, --package <name>        package of the app that is being used
37    -ts, --timestamp <name>     logcat timestamp [only looks at logcat entries after this timestamp].
38
39  (optional)
40    -s, --simulate              prints dummy values instead of real metrics
41    -a, --activity <name>       activity to use (default: inferred)
42    -h, --help                  usage information (this)
43    -v, --verbose               enable extra verbose printing
44    -t, --timeout <sec>         how many seconds to timeout when trying to wait for logcat to change
45    -rfd, --reportfullydrawn    wait for report fully drawn (default: off)
46EOF
47}
48
49DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
50source "$DIR/lib/common"
51
52report_fully_drawn="n"
53package=""
54activity=""
55timeout=5
56simulate="n"
57parse_arguments() {
58  while [[ $# -gt 0 ]]; do
59    case "$1" in
60      -h|--help)
61        usage
62        exit 0
63        ;;
64      -p|--package)
65        package="$2"
66        shift
67        ;;
68      -a|--activity)
69        activity="$2"
70        shift
71        ;;
72      -v|--verbose)
73        export verbose="y"
74        ;;
75      -t|--timeout)
76        timeout="$2"
77        shift
78        ;;
79      -ts|--timestamp)
80        timestamp="$2"
81        shift
82        ;;
83      -s|--simulate)
84        simulate="y"
85        ;;
86      -rfd|--reportfullydrawn)
87        report_fully_drawn="y"
88        ;;
89
90
91      *)
92        echo "Invalid argument: $1" >&2
93        exit 1
94    esac
95    shift
96  done
97}
98
99# Main entry point
100if [[ $# -eq 0 ]]; then
101  usage
102  exit 1
103else
104  parse_arguments "$@"
105
106  # if we do not have have package exit early with an error
107  [[ "$package" == "" ]] && echo "--package not specified" 1>&2 && exit 64
108
109  # ignore timestamp for --simulate. it's optional.
110  if [[ $simulate == y ]]; then
111    timestamp=0
112  fi
113
114  # if we do not have timestamp, exit early with an error
115  [[ "$timestamp" == "" ]] && echo "--timestamp not specified" 1>&2 && exit 64
116
117  if [[ "$activity" == "" ]] && [[ "$simulate" != "y" ]]; then
118    activity="$(get_activity_name "$package")"
119    if [[ "$activity" == "" ]]; then
120      echo "Activity name could not be found, invalid package name?" 1>&2
121      exit 64
122    else
123      verbose_print "Activity name inferred: " "$activity"
124    fi
125  fi
126fi
127
128parse_metric_from_logcat() {
129  local metric_name="$1"
130  local pattern="$2"
131  local re_pattern="$3"
132  local retcode
133  local result
134  local sec
135  local ms
136
137  # parse logcat for 'Displayed...' and that other one...
138
139  # 05-06 14:34:08.854 29460 29481 I ActivityTaskManager: Displayed com.google.android.dialer/.extensions.GoogleDialtactsActivity: +361ms
140  verbose_print "parse_metric_from_logcat: $re_pattern"
141
142
143  echo -ne "$metric_name="
144
145  if [[ $simulate == y ]]; then
146    echo "-1"
147    return 0
148  fi
149
150  result="$(logcat_extract_pattern "$timeout" "$timestamp" "$pattern" "$re_pattern")"
151  retcode=$?
152
153  if [[ $retcode -ne 0 ]]; then
154    # Timed out before finding the pattern. Could also mean the pattern is wrong.
155    echo "Parse $re_pattern from logcat TIMED OUT after $timeout seconds." >&2
156    echo "-$?"
157    return $retcode
158  fi
159
160  # "10s123ms" -> "10s123"
161  result=${result/ms/}
162  if [[ $result =~ s ]]; then
163    ms=${result/*s/}
164    sec=${result/s*/}
165  else
166    sec=0
167    ms=$result
168  fi
169  ((result=sec*1000+ms))
170
171  echo "$result"
172  return $retcode
173}
174
175
176total_time="-1"
177if [[ $simulate != y ]]; then
178  verbose_print 'logcat timestamp NOW: ' $(logcat_save_timestamp)
179
180  # parse stdin for 'am start' result
181  while read -t "$timeout" -r input_line; do
182    verbose_print 'stdin:' "$input_line"
183    if [[ $input_line == *TotalTime:* ]]; then
184      total_time="$(echo "$input_line" | sed 's/TotalTime: \([[:digit:]]\+\)/\1/g')"
185      # but keep reading the rest from stdin until <EOF>
186    fi
187  done
188fi
189
190echo "TotalTime_ms=$total_time"
191
192# parse logcat for 'Displayed...' and that other one...
193
194# 05-06 14:34:08.854 29460 29481 I ActivityTaskManager: Displayed com.google.android.dialer/.extensions.GoogleDialtactsActivity: +361ms
195pattern="ActivityTaskManager: Displayed ${package}"
196re_pattern='.*Displayed[[:blank:]]\+'"${package}"'[/][^[:blank:]]\+[[:blank:]]+\([[:digit:]]\+ms\|[[:digit:]]\+s[[:digit:]]\+ms\).*'
197
198parse_metric_from_logcat "Displayed_ms" "$pattern" "$re_pattern"
199
200# Only track ReportFullyDrawn with --reportfullydrawn/-rfd flags
201if [[ $report_fully_drawn == y ]]; then
202  # 01-16 17:31:44.550 11172 11204 I ActivityTaskManager: Fully drawn com.google.android.GoogleCamera/com.android.camera.CameraLauncher: +10s897ms
203  pattern="ActivityTaskManager: Fully drawn ${package}"
204  #re_pattern='.*Fully drawn[[:blank:]]\+'"${package}"'[/][^[:blank:]]\+[[:blank:]]+\([[:digit:]]\+\).*'
205  re_pattern='.*Fully drawn[[:blank:]]\+'"${package}"'[/][^[:blank:]]\+[[:blank:]]+\([[:digit:]]\+ms\|[[:digit:]]\+s[[:digit:]]\+ms\).*'
206
207  parse_metric_from_logcat "Fully_drawn_ms" "$pattern" "$re_pattern"
208fi
209
210# also call into package-specific scripts if there are additional metrics
211if [[ -x "$DIR/metrics/$package" ]]; then
212  source "$DIR/metrics/$package" "$timestamp"
213else
214  verbose_print parse_metrics: no per-package metrics script found at "$DIR/metrics/$package"
215fi
216