# functions and definitions for workload automation scripts
#
# See recentfling.sh, systemapps.sh, and other scripts that use
# these definitions.
#
dflttracecategories="gfx input view am rs power sched freq idle load memreclaim"
dfltAppList="gmail hangouts chrome youtube camera photos play maps calendar earth calculator sheets docs home"
generateActivities=0
# default activities. Can dynamically generate with -g.
gmailActivity='com.google.android.gm/com.google.android.gm.ConversationListActivityGmail'
clockActivity='com.google.android.deskclock/com.android.deskclock.DeskClock'
hangoutsActivity='com.google.android.talk/com.google.android.talk.SigningInActivity'
chromeActivity='com.android.chrome/_not_used'
contactsActivity='com.google.android.contacts/com.android.contacts.activities.PeopleActivity'
youtubeActivity='com.google.android.youtube/com.google.android.apps.youtube.app.WatchWhileActivity'
cameraActivity='com.google.android.GoogleCamera/com.android.camera.CameraActivity'
playActivity='com.android.vending/com.google.android.finsky.activities.MainActivity'
feedlyActivity='com.devhd.feedly/com.devhd.feedly.Main'
photosActivity='com.google.android.apps.photos/com.google.android.apps.photos.home.HomeActivity'
mapsActivity='com.google.android.apps.maps/com.google.android.maps.MapsActivity'
calendarActivity='com.google.android.calendar/com.android.calendar.AllInOneActivity'
earthActivity='com.google.earth/com.google.earth.EarthActivity'
calculatorActivity='com.google.android.calculator/com.android.calculator2.Calculator'
calculatorLActivity='com.android.calculator2/com.android.calculator2.Calculator'
sheetsActivity='com.google.android.apps.docs.editors.sheets/com.google.android.apps.docs.app.NewMainProxyActivity'
docsActivity='com.google.android.apps.docs.editors.docs/com.google.android.apps.docs.app.NewMainProxyActivity'
operaActivity='com.opera.mini.native/com.opera.mini.android.Browser'
firefoxActivity='org.mozilla.firefox/org.mozilla.firefox.App'
suntempleActivity='com.BrueComputing.SunTemple/com.epicgames.ue4.GameActivity'
homeActivity='com.google.android.googlequicksearchbox/com.google.android.launcher.GEL'
function showUsage {
echo "$0: unrecognized option: $1"
echo; echo "Usage: $0 [options]"
echo "-e : stop on error"
echo "-i iterations"
echo "-n : keep trace files"
echo "-o output file"
echo "-s device : adb device"
echo "-t trace categories"
echo "-g : generate activity strings"
}
DEVICE=unknown
# handle args
while [ $# -gt 0 ]
do
case "$1" in
(-d) DEVICE=$2; shift;;
(-e) stoponerror=1;;
(-n) savetmpfiles=1;;
(-t) tracecategories=$2; shift;;
(-i) iterations=$2; shift;;
(-o) output=$2; shift;;
(-v) verbose=1;;
(-nz) compress=0;;
(-s) deviceName=$2; shift;;
(-g) generateActivities=1;;
(--) ;;
(*)
chk1=$(functions 2>/dev/null)
chk2=$(typeset -F 2>/dev/null)
if echo $chk1 $chk2 | grep -q processLocalOption; then
if ! processLocalOption "$1" "$2"; then
shift
fi
else
showUsage $1
exit 1
fi;;
esac
shift
done
# check if running on a device
if ls /etc/* 2>/dev/null | grep -q android.hardware; then
ADB=""
compress=0
isOnDevice=1
else
# do a throw-away adb in case the server is out-of-date
adb devices -l 2>&1 >/dev/null
if [ -z "$deviceName" ]; then
devInfo=$(adb devices -l | grep -v ^List | head -1)
else
devInfo=$(adb devices -l | grep $deviceName)
fi
set -- $devInfo
if [ -z $1 ]; then
echo Error: could not find device $deviceName
exit 1
fi
deviceName=$1
ADB="adb -s $deviceName shell "
if [ "$DEVICE" = "" -o "$DEVICE" = unknown ]; then
DEVICE=$(echo $4 | sed 's/product://')
fi
isOnDevice=0
fi
if [ $isOnDevice -gt 0 ]; then
case "$DEVICE" in
(bullhead|angler)
if ! echo $$ > /dev/cpuset/background/tasks; then
echo Could not put PID $$ in background
fi
;;
(*)
;;
esac
fi
# default values if not set by options or calling script
appList=${appList:=$dfltAppList}
savetmpfiles=${savetmpfiles:=0}
stoponerror=${stoponerror:=0}
verbose=${verbose:=0}
compress=${compress:=1}
iterations=${iterations:=5}
tracecategories=${tracecategories:=$dflttracecategories}
ADB=${ADB:=""}
output=${output:="./out"}
# clear the output file
if [ -f $output ]; then
> $output
fi
# ADB commands
AM_FORCE_START="${ADB}am start -W -S"
AM_START="${ADB}am start -W"
AM_START_NOWAIT="${ADB}am start"
AM_STOP="${ADB}am force-stop"
AM_LIST="${ADB}am stack list"
WHO="${ADB}whoami"
INPUT="${ADB}input"
PS="${ADB}ps"
function vout {
# debug output enabled by -v
if [ $verbose -gt 0 ]; then
echo DEBUG: $* >&2
echo DEBUG: $* >&2 >> $output
fi
}
function findtimestamp {
# extract timestamp from atrace log entry
while [ "$2" != "" -a "$2" != "tracing_mark_write" ]
do
shift
done
echo $1
}
function computeTimeDiff {
# Compute time diff given: startSeconds startNs endSeconds endNS
# strip leading zeros
startS=$(expr 0 + $1)
endS=$(expr 0 + $3)
if [ "$2" = N ]; then
startNs=0
endNs=0
else
startNs=$(expr 0 + $2)
endNs=$(expr 0 + $4)
fi
((startMs=startS*1000 + startNs/1000000))
((endMs=endS*1000 + endNs/1000000))
((diff=endMs-startMs))
echo $diff
}
function log2msec {
in=$1
in=${in:=0.0}
set -- $(echo $in | tr . " ")
# shell addition via (( )) doesn't like leading zeroes in msecs
# field so remove leading zeroes
msecfield=$(expr 0 + $2)
((msec=$1*1000000+msecfield))
((msec=msec/1000))
echo $msec
}
function getStartTime {
# extract event indicating beginning of start sequence
# a) look for a "launching" event indicating start from scratch
# b) look for another activity getting a pause event
_app=$1
traceout=$2
ret=0
s=$(grep "Binder.*tracing_mark_write.*launching" $traceout 2>/dev/null | head -1| tr [\(\)\[\]
:] " ")
if [ -z "$s" ]; then
s=$(grep activityPause $traceout | head -1 2>/dev/null| tr [\(\)\[\]
:] " ")
else
vout $_app was restarted!
ret=1
fi
vout STARTLOG: $s
log2msec $(findtimestamp $s)
return $ret
}
function getEndTime {
# extract event indicating end of start sequence. We use the
# first surfaceflinger event associated with the target activity
_app=$1
traceout=$2
f=$(grep "surfaceflinger.*tracing_mark_write.*$_app" $traceout 2>/dev/null |
grep -v Starting | head -1 | tr [\(\)\[\]
:] " ")
if [ -z "$f" ]; then
# Hmm. sf symbols may not be there... get the pid
pid=$(${ADB}pidof /system/bin/surfaceflinger | tr "[
]" "[ ]")
f=$(grep " <...>-$pid.*tracing_mark_write.*$_app" $traceout 2>/dev/null |
grep -v Starting | head -1 | tr [\(\)\[\]
:] " ")
fi
vout ENDLOG: $f
log2msec $(findtimestamp $f)
}
function resetJankyFrames {
_gfxapp=$1
_gfxapp=${_gfxapp:="com.android.systemui"}
${ADB}dumpsys gfxinfo $_gfxapp reset 2>&1 >/dev/null
}
function getJankyFrames {
_gfxapp=$1
_gfxapp=${_gfxapp:="com.android.systemui"}
# Note: no awk or sed on devices so have to do this
# purely with bash
total=0
janky=0
latency=0
${ADB}dumpsys gfxinfo $_gfxapp | tr "\r" " " | egrep "9[059]th| frames" | while read line
do
if echo $line | grep -q "Total frames"; then
set -- $line
total=$4
elif echo $line | grep -q "Janky frames"; then
set -- $line
janky=$3
elif echo $line | grep -q "90th"; then
set -- $(echo $line | tr m " ")
l90=$3
elif echo $line | grep -q "95th"; then
set -- $(echo $line | tr m " ")
l95=$3
elif echo $line | grep -q "99th"; then
set -- $(echo $line | tr m " ")
l99=$3
echo $total $janky $l90 $l95 $l99
break
fi
done
}
function checkForDirectReclaim {
# look for any reclaim events in atrace output
_app=$1
traceout=$2
if grep -qi reclaim $traceout; then
return 1
fi
return 0
}
function startInstramentation {
_iter=$1
_iter=${_iter:=0}
enableAtrace=$2
enableAtrace=${enableAtrace:=1}
# Called at beginning of loop. Turn on instramentation like atrace
vout start instramentation $(date)
echo =============================== >> $output
echo Before iteration $_iter >> $output
echo =============================== >> $output
${ADB}cat /proc/meminfo 2>&1 >> $output
${ADB}dumpsys meminfo 2>&1 >> $output
if [ "$DEVICE" = volantis ]; then
${ADB}cat /d/nvmap/iovmm/procrank 2>&1 >> $output
fi
if [ "$user" = root -a $enableAtrace -gt 0 ]; then
vout ${ADB}atrace -b 32768 --async_start $tracecategories
${ADB}atrace -b 32768 --async_start $tracecategories >> $output
echo >> $output
fi
}
function stopInstramentation {
enableAtrace=$1
enableAtrace=${enableAtrace:=1}
if [ "$user" = root -a $enableAtrace -gt 0 ]; then
vout ${ADB}atrace --async_stop
${ADB}atrace --async_stop > /dev/null
fi
}
function stopAndDumpInstramentation {
vout stop instramentation $(date)
echo =============================== >> $output
echo After iteration >> $output
echo =============================== >> $output
${ADB}cat /proc/meminfo 2>&1 >> $output
${ADB}dumpsys meminfo 2>&1 >> $output
if [ "$user" = root ]; then
traceout=$1
traceout=${traceout:=$output}
echo =============================== >> $traceout
echo TRACE >> $traceout
echo =============================== >> $traceout
if [ $compress -gt 0 ]; then
tmpTrace=./tmptrace.$$
UNCOMPRESS=$CMDDIR/atrace-uncompress.py
> $tmpTrace
zarg="-z"
${ADB}atrace -z -b 32768 --async_dump >> $tmpTrace
python $UNCOMPRESS $tmpTrace >> $traceout
rm -f $tmpTrace
else
${ADB}atrace -b 32768 --async_dump > $traceout
fi
vout ${ADB}atrace $zarg -b 32768 --async_dump
vout ${ADB}atrace --async_stop
${ADB}atrace --async_stop > /dev/null
fi
}
function getActivityName {
cmd="actName=\$${1}Activity"
eval $cmd
echo $actName
}
function getPackageName {
set -- $(getActivityName $1 | tr "[/]" "[ ]")
echo $1
}
function startActivityFromPackage {
if [ "$1" = home ]; then
doKeyevent HOME
echo 0
return 0
fi
vout $AM_START_NOWAIT -p "$(getPackageName $1)" -c android.intent.category.LAUNCHER -a android.intent.action.MAIN
$AM_START_NOWAIT -p "$(getPackageName $1)" -c android.intent.category.LAUNCHER -a android.intent.action.MAIN 2>&1
echo 0
}
function startActivity {
if [ "$1" = home ]; then
doKeyevent HOME
echo 0
return 0
elif [ "$1" = chrome ]; then
if [ "$DEVICE" = volantis -o "$DEVICE" = ariel ]; then
vout $AM_START_NOWAIT -p "$(getPackageName $1)" http://www.theverge.com
$AM_START_NOWAIT -p "$(getPackageName $1)" http://www.theverge.com > /dev/null
set -- 0 0
else
vout $AM_START -p "$(getPackageName $1)" http://www.theverge.com
set -- $($AM_START -p "$(getPackageName $1)" http://www.theverge.com | grep ThisTime)
fi
else
vout $AM_START "$(getActivityName $1)"
set -- $($AM_START "$(getActivityName $1)" | grep ThisTime)
fi
echo $2 | tr "[\r]" "[\n]"
}
function forceStartActivity {
if [ "$1" = chrome ]; then
vout $AM_START -p "$(getPackageName $1)" http://www.theverge.com
set -- $($AM_FORCE_START -p "$(getPackageName $1)" http://www.theverge.com | grep ThisTime)
else
vout $AM_FORCE_START "$(getActivityName $1)"
set -- $($AM_FORCE_START "$(getActivityName $1)" | grep ThisTime)
fi
echo $2 | tr "[\r]" "[\n]"
}
function checkActivity {
# requires root
actName="$(getActivityName $1)"
$AM_LIST | grep $actName
}
#function stopActivity {
# vout $AM_STOP $(getActivityName $1)
# $AM_STOP $(getActivityName $1)
#}
function doSwipe {
vout ${ADB}input swipe $*
${ADB}nice input swipe $*
}
function doText {
echo $* > ./tmpOutput
vout ${ADB}input text \"$*\"
${ADB}input text "$(cat ./tmpOutput)"
rm -f ./tmpOutput
}
function doTap {
vout ${ADB}input tap $*
${ADB}input tap $*
}
function doKeyevent {
vout $INPUT keyevent $*
$INPUT keyevent $*
}
function checkIsRunning {
p=$1
shift
if ! $PS | grep $p | grep -qv grep; then
handleError $*: $p is not running
exit 1
fi
}
function checkStartTime {
vout checkStartTime $1 v $2
if [ -z "$2" ]; then
echo false
return 2
fi
if [ "$1" -gt "$2" ]; then
echo false
return 1
fi
echo true
return 0
}
function handleError {
echo Error: $*
stopAndDumpInstramentation
if [ $stoponerror -gt 0 ]; then
exit 1
fi
}
user=root
if ${ADB}ls /data 2>/dev/null | grep -q "Permission denied"; then
user=shell
fi
vout User is $user
if [ $generateActivities -gt 0 ]; then
if [ $isOnDevice -gt 0 ]; then
echo Error: cannot generate activity list when run on device
exit 1
fi
echo Generating activities...
for app in $appList
do
startActivityFromPackage $app 2>&1 > /dev/null
act=$(${ADB}am stack list | grep $(getPackageName $app) | sed -e 's/
//' | head -1 | awk '{ print $2; }')
eval "${app}Activity=$act"
echo "ACTIVITY: $app --> $(getActivityName $app)"
done
fi