| #!/bin/bash | 
 | # Copyright 2018 The Chromium Authors. All rights reserved. | 
 | # Use of this source code is governed by a BSD-style license that can be | 
 | # found in the LICENSE file. | 
 |  | 
 | set -e | 
 | shopt -s nullglob | 
 | shopt -s extglob | 
 |  | 
 | function kill_process() { | 
 |     name=$1 | 
 |     pid=$($adb shell "pidof $name" || true) | 
 |     if [ ! -z "$pid" ]; then | 
 |         echo "Killing $name..." | 
 |         $adb shell "kill $pid" | 
 |     else | 
 |         echo "$name is not running." | 
 |     fi | 
 | } | 
 |  | 
 | function get_data_file() { | 
 |     trace_file=$1 | 
 |     extension=$2 | 
 |     echo "${trace_file%.*}.$extension" | 
 | } | 
 |  | 
 | function get_logcat_file() { | 
 |     trace_file=$1 | 
 |     get_data_file "$trace_file" "logcat" | 
 | } | 
 |  | 
 | function get_meminfo_file() { | 
 |     trace_file=$1 | 
 |     tag=$2 | 
 |     get_data_file "$trace_file" "$tag.meminfo" | 
 | } | 
 |  | 
 | function analyze_trace_file() { | 
 |     trace_file=$1 | 
 |     trace_events_to_print=$2 | 
 |     logcat_file="$(get_logcat_file "$trace_file")" | 
 |     echo "Processes started / died:" | 
 |     grep -E "Start proc|died|MY-DBG" "$logcat_file" | 
 |  | 
 |     extractor_arguments="$trace_file" | 
 |     if [ ! -z "$trace_events_to_print" ]; then | 
 |         extractor_arguments="$extractor_arguments --print-events=$trace_events_to_print" | 
 |     fi | 
 |     "$this_path/systrace-extract-startup.py" $extractor_arguments | 
 | } | 
 |  | 
 | function analyze_meminfo_file() { | 
 |     meminfo_file=$1 | 
 |     if [ -f "$meminfo_file" ]; then | 
 |         echo "$meminfo_file" | 
 |         grep -A 5 "Total RAM" "$meminfo_file" | 
 |     fi | 
 | } | 
 |  | 
 | function capture_analyze_meminfo_file() { | 
 |     meminfo_file=$1 | 
 |     $adb shell "dumpsys meminfo" > "$meminfo_file" | 
 |     analyze_meminfo_file "$meminfo_file" | 
 | } | 
 |  | 
 | function echo_separator() { | 
 |     s="----------" | 
 |     echo | 
 |     echo "$s$s$s$s$s$s$s$s" # 8*10 | 
 | } | 
 |  | 
 | this_path="$(dirname "$0")" | 
 |  | 
 | adb="$ADB_PATH" | 
 |  | 
 | if [ -z "$adb" ]; then | 
 |     adb="$(which adb)" | 
 | fi | 
 | if [ -z "$adb" ]; then | 
 |     echo "Where's adb? Can't find it." | 
 |     exit 1 | 
 | fi | 
 |  | 
 | export ADB_PATH="$adb" | 
 |  | 
 | output_tag= | 
 | browser=chrome | 
 | trace_time=10 | 
 | cold=false | 
 | url= | 
 | atrace_categories= | 
 | killg=false | 
 | repeat= | 
 | analyze=false | 
 | meminfo=false | 
 | checktabs=false | 
 | taburl= | 
 | trace_events_to_print= | 
 | webapk_package= | 
 |  | 
 | for i in "$@"; do | 
 |     case $i in | 
 |         --help) | 
 |         echo "$(basename "$0") output-tag [options]" | 
 |         exit 0 | 
 |         ;; | 
 |         --browser=*) | 
 |         browser="${i#*=}" | 
 |         ;; | 
 |         --url=*) | 
 |         url="${i#*=}" | 
 |         ;; | 
 |         --warm) | 
 |         cold=false | 
 |         ;; | 
 |         --cold) | 
 |         cold=true | 
 |         ;; | 
 |         --atrace=*) | 
 |         atrace_categories="${i#*=}" | 
 |         ;; | 
 |         --killg) | 
 |         killg=true | 
 |         ;; | 
 |         --trace-time=*) | 
 |         trace_time="${i#*=}" | 
 |         ;; | 
 |         --repeat=*) | 
 |         repeat="${i#*=}" | 
 |         ;; | 
 |         --analyze) | 
 |         analyze=true | 
 |         ;; | 
 |         --meminfo) | 
 |         meminfo=true | 
 |         ;; | 
 |         --checktabs) | 
 |         checktabs=true | 
 |         ;; | 
 |         --taburl=*) | 
 |         taburl="${i#*=}" | 
 |         ;; | 
 |         --print-trace-events=*) | 
 |         trace_events_to_print="${i#*=}" | 
 |         ;; | 
 |         --webapk=*) | 
 |         webapk_package="${i#*=}" | 
 |         ;; | 
 |         --*) | 
 |         echo "Unknown option or missing option argument: $i" | 
 |         exit 1 | 
 |         ;; | 
 |         *) | 
 |         if [ -z "$output_tag" ]; then | 
 |             output_tag="$i" | 
 |         else | 
 |             echo "Unknown option: $i" | 
 |             exit 1 | 
 |         fi | 
 |         ;; | 
 |     esac | 
 |     if [ -z "$output_tag" ]; then | 
 |         echo "First argument must be the output tag." | 
 |         exit 1 | 
 |     fi | 
 |     shift | 
 | done | 
 |  | 
 | if [ -d "$output_tag" ]; then | 
 |     output_tag="${output_tag%%+(/)}/trace" | 
 | fi | 
 | specified_output_tag="$output_tag" | 
 |  | 
 | if [ $analyze = true ]; then | 
 |     for file in $output_tag*.html; do | 
 |         echo_separator | 
 |         echo "$file" | 
 |  | 
 |         analyze_meminfo_file "$(get_meminfo_file "$output_file" "before")" | 
 |         analyze_meminfo_file "$(get_meminfo_file "$output_file" "after")" | 
 |  | 
 |         echo | 
 |  | 
 |         analyze_trace_file "$file" "$print_trace_events" | 
 |     done | 
 |  | 
 |     exit 0 | 
 | fi | 
 |  | 
 | browser_package= | 
 | case $browser in | 
 |     chrome) | 
 |     browser_package="com.google.android.apps.chrome" | 
 |     ;; | 
 |     canary) | 
 |     browser_package="com.chrome.canary" | 
 |     browser="chrome_canary" | 
 |     ;; | 
 |     dev) | 
 |     browser_package="com.chrome.dev" | 
 |     ;; | 
 |     beta) | 
 |     browser_package="com.chrome.beta" | 
 |     ;; | 
 |     stable) | 
 |     browser_package="com.android.chrome" | 
 |     ;; | 
 |     *) | 
 |     echo "Unknown browser $browser" | 
 |     exit 1 | 
 | esac | 
 |  | 
 | profile_options= | 
 |  | 
 | profile_options="$profile_options --browser=$browser" | 
 | if [ ! "$browser" = "chrome" ]; then | 
 |     output_tag="$output_tag-$browser" | 
 | fi | 
 |  | 
 | profile_options="$profile_options --time=$trace_time" | 
 |  | 
 | if [ ! -z "$atrace_categories" ]; then | 
 |     profile_options="$profile_options --atrace-categories=$atrace_categories" | 
 |     output_tag="$output_tag-${atrace_categories//,/_}" | 
 | fi | 
 |  | 
 | if [ $cold = true ]; then | 
 |     profile_options="$profile_options --cold" | 
 |     output_tag="$output_tag-cold" | 
 | fi | 
 |  | 
 | profile_options="$profile_options --url=$url" | 
 | if [ ! -z "$url" ]; then | 
 |     output_tag="$output_tag-url" | 
 | fi | 
 |  | 
 | if [ ! -z "$webapk_package" ]; then | 
 |     output_tag="$output_tag-webapk" | 
 |     profile_options="$profile_options --webapk-package=$webapk_package" | 
 | fi | 
 |  | 
 | if [ $killg = true ]; then | 
 |     output_tag="$output_tag-killg" | 
 | fi | 
 |  | 
 | # Must be last for ease of globbing. | 
 | output_tag="$output_tag-${trace_time}s" | 
 |  | 
 | if [ $checktabs = true ] || [ $killg = true ] || [ ! -z "$taburl" ]; then | 
 |     $adb root > /dev/null | 
 | fi | 
 |  | 
 | # Make sure Chrome can write the trace file. | 
 | $adb shell "pm grant $browser_package android.permission.READ_EXTERNAL_STORAGE" | 
 | $adb shell "pm grant $browser_package android.permission.WRITE_EXTERNAL_STORAGE" | 
 |  | 
 | if [ ! -z "$taburl" ]; then | 
 |     echo "Opening $taburl in a single tab..." | 
 |     $adb shell "am force-stop $browser_package" | 
 |     $adb shell "rm -f /data/data/$browser_package/app_tabs/0/tab*" | 
 |     $adb shell "am start -a android.intent.action.VIEW \ | 
 |                     -n $browser_package/org.chromium.chrome.browser.ChromeTabbedActivity \ | 
 |                     -d $taburl" | 
 |     sleep 5 | 
 |     $adb shell "am start -a android.intent.action.MAIN -c android.intent.category.HOME" | 
 |     sleep 1 | 
 |     $adb shell "am force-stop $browser_package" | 
 |     echo | 
 | fi | 
 |  | 
 | repeat_count=1 | 
 | if [ ! -z "$repeat" ]; then | 
 |     repeat_count="$repeat" | 
 | fi | 
 |  | 
 | first_iteration=true | 
 | for iteration in $(seq "$repeat_count"); do | 
 |  | 
 |     if [ $first_iteration = true ]; then | 
 |         first_iteration=false | 
 |     else | 
 |         echo_separator | 
 |         sleep 2 | 
 |     fi | 
 |  | 
 |     if [ $killg = true ]; then | 
 |         echo "Preemptively killing g* processes..." | 
 |         $adb logcat -c | 
 |         kill_process "com.google.process.gapps" | 
 |         kill_process "com.google.android.gms" | 
 |         sleep 1 | 
 |         $adb logcat -d | grep -E "Start proc|died" || true | 
 |     fi | 
 |  | 
 |     echo | 
 |  | 
 |     if [ -z "$repeat" ]; then | 
 |         output_file="$output_tag.html" | 
 |         if [ -f "$output_file" ]; then | 
 |             for i in {2..1000}; do | 
 |                 output_file="$output_tag~$i.html" | 
 |                 if [ ! -f "$output_file" ]; then | 
 |                     break; | 
 |                 fi | 
 |             done | 
 |         fi | 
 |         if [ -f "$output_file" ]; then | 
 |             echo "Failed to find unoccupied output file. Last was: $output_file" | 
 |             exit 1 | 
 |         fi | 
 |     else | 
 |         output_file="$output_tag~${repeat_count}_$iteration.html" | 
 |         if [ -f "$output_file" ]; then | 
 |             echo "Output file already exists: $output_file" | 
 |             echo "Please add something unique to the tag ($specified_output_tag)." | 
 |             exit 1 | 
 |         fi | 
 |     fi | 
 |     echo "Output file: $output_file" | 
 |  | 
 |     logcat_file="$(get_logcat_file "$output_file")" | 
 |     echo "Logcat output file: $logcat_file" | 
 |  | 
 |     if [ $meminfo = true ]; then | 
 |         echo | 
 |         capture_analyze_meminfo_file "$(get_meminfo_file "$output_file" "before")" | 
 |     fi | 
 |  | 
 |     echo | 
 |  | 
 |     echo "Profiling with options: $profile_options" | 
 |     ./build/android/adb_profile_chrome_startup \ | 
 |         $profile_options \ | 
 |         "--output=$output_file" | 
 |  | 
 |     if [ $meminfo = true ]; then | 
 |         echo | 
 |         capture_analyze_meminfo_file "$(get_meminfo_file "$output_file" "after")" | 
 |     fi | 
 |  | 
 |     $adb shell "am force-stop $browser_package" | 
 |     $adb shell "killall logcat" > /dev/null 2>&1 || true | 
 |  | 
 |     $adb logcat -d > "${logcat_file}" | 
 |  | 
 |     rm -f chrome-profile-results-* | 
 |     $adb shell "rm -f /sdcard/Download/chrome-profile-results-*" | 
 |  | 
 |     echo | 
 |  | 
 |     analyze_trace_file "$output_file" "$trace_events_to_print" | 
 |  | 
 |     if [ $checktabs = true ]; then | 
 |         # Yields empty string when value is -1 | 
 |         active_tab_id="$( \ | 
 |             $adb shell "cat /data/data/$browser_package/shared_prefs/${browser_package}_preferences.xml" \ | 
 |             | sed -n 's/^.*ACTIVE_TAB_ID" value="\([0-9]\{1,3\}\).*$/\1/p')" | 
 |         # Yields empty string when there is no 'tab' file | 
 |         tab_id="$( \ | 
 |             $adb shell ls /data/data/$browser_package/app_tabs/0 \ | 
 |             | sed -n 's/tab\([0-9]\{1,3\}\)\s*/\1/p')" | 
 |         if [ "$active_tab_id" != "$tab_id" ]; then | 
 |             echo "Tab IDs don't match (active_tab_id=$active_tab_id, tab_id=$tab_id), last result is not reliable." | 
 |             exit 1 | 
 |         fi | 
 |     fi | 
 | done |