1#!/bin/bash 2# Copyright 2018, 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 16if [[ -z $ANDROID_BUILD_TOP ]]; then 17 echo "Please run source build/envsetup.sh first" >&2 18 exit 1 19fi 20 21source $ANDROID_BUILD_TOP/build/envsetup.sh 22 23verbose_print() { 24 if [[ "$verbose" == "y" ]]; then 25 echo "$@" >&2 26 fi 27} 28 29remote_pidof() { 30 local procname="$1" 31 adb shell ps | grep "$procname" | awk '{print $2;}' 32} 33 34remote_pkill() { 35 local procname="$1" 36 shift 37 38 local the_pids=$(remote_pidof "$procname") 39 local pid 40 41 for pid in $the_pids; do 42 verbose_print adb shell kill "$@" "$pid" 43 adb shell kill "$@" "$pid" 44 done 45} 46 47get_activity_name() { 48 local package="$1" 49 local action_key="android.intent.action.MAIN:" 50 51 # Example query-activities output being parsed: 52 # 53 # Activity #14: 54 # priority=0 preferredOrder=0 match=0x108000 specificIndex=-1 isDefault=true 55 # com.google.android.videos/com.google.android.youtube.videos.EntryPoint 56 # Activity #15: 57 # priority=0 preferredOrder=0 match=0x108000 specificIndex=-1 isDefault=true 58 # com.google.android.youtube/.app.honeycomb.Shell$HomeActivity 59 60 # Given package 'com.google.android.youtube' return '.app.honeycomb.Shell$HomeActivity' 61 62 local activity_line="$(adb shell cmd package query-activities --brief -a android.intent.action.MAIN -c android.intent.category.LAUNCHER | grep "$package/")" 63 IFS="/" read -a array <<< "$activity_line" 64 local activity_name="${array[1]}" 65 66 # Activities starting with '.' are shorthand for having their package name prefixed. 67 if [[ $activity_name == .* ]]; then 68 activity_name="${package}${activity_name}" 69 fi 70 echo "$activity_name" 71} 72 73# Use with logcat_from_timestamp to skip all past log-lines. 74logcat_save_timestamp() { 75 adb shell 'date -u +"%Y-%m-%d %H:%M:%S.%N"' 76} 77 78# Roll forward logcat to only show events 79# since the specified timestamp. 80# 81# i.e. don't look at historical logcat, 82# only look at FUTURE logcat. 83# 84# First use 'logcat_save_timestamp' 85# Then do whatever action you want. 86# Then use 'logcat_from_timestamp_bg $timestamp' 87logcat_from_timestamp_bg() { 88 local timestamp="$1" 89 shift # drop timestamp from args. 90 verbose_print adb logcat -T \"$timestamp\" \"$@\" 91 adb logcat -v UTC -T "$timestamp" "$@" & 92 logcat_from_timestamp_pid=$! 93} 94 95# Starting at timestamp $2, wait until we seen pattern $3 96# or until a timeout happens in $1 seconds. 97# If successful, also echo the line that matched the pattern. 98# 99# Set VERBOSE_LOGCAT=1 to debug every line of logcat it tries to parse. 100logcat_select_pattern() { 101 local timeout="$1" 102 local timestamp="$2" 103 local pattern="$3" 104 105 local logcat_fd 106 107 coproc logcat_fd { 108 kill_children_quietly() { 109 kill "$logcat_pidd" 110 wait "$logcat_pidd" 2>/dev/null 111 } 112 113 trap 'kill_children_quietly' EXIT # kill logcat when this coproc is killed. 114 115 # run logcat in the background so it can be killed. 116 logcat_from_timestamp_bg "$timestamp" 117 logcat_pidd=$logcat_from_timestamp_pid 118 wait "$logcat_pidd" 119 } 120 local logcat_pid="$!" 121 verbose_print "[LOGCAT] Spawn pid $logcat_pid" 122 123 local timeout_ts="$(date -d "now + ${timeout} seconds" '+%s')" 124 local now_ts="0" 125 126 local return_code=1 127 128 verbose_print "logcat_wait_for_pattern begin" 129 130 while read -t "$timeout" -r -u "${logcat_fd[0]}" logcat_output; do 131 if (( $VERBOSE_LOGCAT )); then 132 verbose_print "LOGCAT: $logcat_output" 133 fi 134 if [[ "$logcat_output:" == *"$pattern"* ]]; then 135 verbose_print "LOGCAT: " "$logcat_output" 136 verbose_print "WE DID SEE PATTERN" '<<' "$pattern" '>>.' 137 echo "$logcat_output" 138 return_code=0 139 break 140 fi 141 now_ts="$(date -d "now" '+%s')" 142 if (( now_ts >= timeout_ts )); then 143 verbose_print "DID TIMEOUT BEFORE SEEING ANYTHING (timeout=$timeout seconds) " '<<' "$pattern" '>>.' 144 break 145 fi 146 done 147 148 # Don't leave logcat lying around since it will keep going. 149 kill "$logcat_pid" 150 # Suppress annoying 'Terminated...' message. 151 wait "$logcat_pid" 2>/dev/null 152 153 verbose_print "[LOGCAT] $logcat_pid should be killed" 154 155 return $return_code 156} 157 158# Starting at timestamp $2, wait until we seen pattern $3 159# or until a timeout happens in $1 seconds. 160# 161# Set VERBOSE_LOGCAT=1 to debug every line of logcat it tries to parse. 162logcat_wait_for_pattern() { 163 logcat_select_pattern "$@" > /dev/null 164} 165 166# Starting at timestamp $2, wait until we seen pattern $3 167# or until a timeout happens in $1 seconds. 168# If successful, extract with the regular expression pattern in #4 169# and return the first capture group. 170# 171# Set VERBOSE_LOGCAT=1 to debug every line of logcat it tries to parse. 172logcat_extract_pattern() { 173 local timeout="$1" 174 local timestamp="$2" 175 local pattern="$3" 176 local re_pattern="$4" 177 178 local result 179 local exit_code 180 181 result="$(logcat_select_pattern "$@")" 182 exit_code=$? 183 184 if [[ $exit_code -ne 0 ]]; then 185 return $exit_code 186 fi 187 188 echo "$result" | sed 's/'"$re_pattern"'/\1/g' 189} 190 191# Join array 192# FOO=(a b c) 193# join_by , "${FOO[@]}" #a,b,c 194join_by() { 195 local IFS="$1" 196 shift 197 echo "$*" 198} 199