# 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