1 # functions and definitions for workload automation scripts 2 # 3 # See recentfling.sh, systemapps.sh, and other scripts that use 4 # these definitions. 5 # 6 7 dflttracecategories="gfx input view am rs power sched freq idle load memreclaim" 8 dfltAppList="gmail hangouts chrome youtube camera photos play maps calendar earth calculator sheets docs home" 9 generateActivities=0 10 11 # default activities. Can dynamically generate with -g. 12 gmailActivity='com.google.android.gm/com.google.android.gm.ConversationListActivityGmail' 13 clockActivity='com.google.android.deskclock/com.android.deskclock.DeskClock' 14 hangoutsActivity='com.google.android.talk/com.google.android.talk.SigningInActivity' 15 chromeActivity='com.android.chrome/_not_used' 16 contactsActivity='com.google.android.contacts/com.android.contacts.activities.PeopleActivity' 17 youtubeActivity='com.google.android.youtube/com.google.android.apps.youtube.app.WatchWhileActivity' 18 cameraActivity='com.google.android.GoogleCamera/com.android.camera.CameraActivity' 19 playActivity='com.android.vending/com.google.android.finsky.activities.MainActivity' 20 feedlyActivity='com.devhd.feedly/com.devhd.feedly.Main' 21 photosActivity='com.google.android.apps.photos/com.google.android.apps.photos.home.HomeActivity' 22 mapsActivity='com.google.android.apps.maps/com.google.android.maps.MapsActivity' 23 calendarActivity='com.google.android.calendar/com.android.calendar.AllInOneActivity' 24 earthActivity='com.google.earth/com.google.earth.EarthActivity' 25 calculatorActivity='com.google.android.calculator/com.android.calculator2.Calculator' 26 calculatorLActivity='com.android.calculator2/com.android.calculator2.Calculator' 27 sheetsActivity='com.google.android.apps.docs.editors.sheets/com.google.android.apps.docs.app.NewMainProxyActivity' 28 docsActivity='com.google.android.apps.docs.editors.docs/com.google.android.apps.docs.app.NewMainProxyActivity' 29 operaActivity='com.opera.mini.native/com.opera.mini.android.Browser' 30 firefoxActivity='org.mozilla.firefox/org.mozilla.firefox.App' 31 suntempleActivity='com.BrueComputing.SunTemple/com.epicgames.ue4.GameActivity' 32 homeActivity='com.google.android.googlequicksearchbox/com.google.android.launcher.GEL' 33 34 function showUsage { 35 echo "$0: unrecognized option: $1" 36 echo; echo "Usage: $0 [options]" 37 echo "-e : stop on error" 38 echo "-i iterations" 39 echo "-n : keep trace files" 40 echo "-o output file" 41 echo "-s device : adb device" 42 echo "-t trace categories" 43 echo "-g : generate activity strings" 44 } 45 46 DEVICE=unknown 47 48 # handle args 49 while [ $# -gt 0 ] 50 do 51 case "$1" in 52 (-d) DEVICE=$2; shift;; 53 (-e) stoponerror=1;; 54 (-n) savetmpfiles=1;; 55 (-t) tracecategories=$2; shift;; 56 (-i) iterations=$2; shift;; 57 (-o) output=$2; shift;; 58 (-v) verbose=1;; 59 (-nz) compress=0;; 60 (-s) deviceName=$2; shift;; 61 (-g) generateActivities=1;; 62 (--) ;; 63 (*) 64 chk1=$(functions 2>/dev/null) 65 chk2=$(typeset -F 2>/dev/null) 66 67 if echo $chk1 $chk2 | grep -q processLocalOption; then 68 if ! processLocalOption "$1" "$2"; then 69 shift 70 fi 71 else 72 showUsage $1 73 exit 1 74 fi;; 75 esac 76 shift 77 done 78 79 # check if running on a device 80 if ls /etc/* 2>/dev/null | grep -q android.hardware; then 81 ADB="" 82 compress=0 83 isOnDevice=1 84 else 85 # do a throw-away adb in case the server is out-of-date 86 adb devices -l 2>&1 >/dev/null 87 88 if [ -z "$deviceName" ]; then 89 devInfo=$(adb devices -l | grep -v ^List | head -1) 90 else 91 devInfo=$(adb devices -l | grep $deviceName) 92 fi 93 set -- $devInfo 94 if [ -z $1 ]; then 95 echo Error: could not find device $deviceName 96 exit 1 97 fi 98 deviceName=$1 99 ADB="adb -s $deviceName shell " 100 if [ "$DEVICE" = "" -o "$DEVICE" = unknown ]; then 101 DEVICE=$(echo $4 | sed 's/product://') 102 fi 103 isOnDevice=0 104 fi 105 106 if [ $isOnDevice -gt 0 ]; then 107 case "$DEVICE" in 108 (bullhead|angler) 109 if ! echo $$ > /dev/cpuset/background/tasks; then 110 echo Could not put PID $$ in background 111 fi 112 ;; 113 (*) 114 ;; 115 esac 116 fi 117 118 # default values if not set by options or calling script 119 appList=${appList:=$dfltAppList} 120 savetmpfiles=${savetmpfiles:=0} 121 stoponerror=${stoponerror:=0} 122 verbose=${verbose:=0} 123 compress=${compress:=1} 124 iterations=${iterations:=5} 125 tracecategories=${tracecategories:=$dflttracecategories} 126 ADB=${ADB:=""} 127 output=${output:="./out"} 128 129 # clear the output file 130 if [ -f $output ]; then 131 > $output 132 fi 133 134 # ADB commands 135 AM_FORCE_START="${ADB}am start -W -S" 136 AM_START="${ADB}am start -W" 137 AM_START_NOWAIT="${ADB}am start" 138 AM_STOP="${ADB}am force-stop" 139 AM_LIST="${ADB}am stack list" 140 WHO="${ADB}whoami" 141 INPUT="${ADB}input" 142 PS="${ADB}ps" 143 144 function vout { 145 # debug output enabled by -v 146 if [ $verbose -gt 0 ]; then 147 echo DEBUG: $* >&2 148 echo DEBUG: $* >&2 >> $output 149 fi 150 } 151 152 function findtimestamp { 153 # extract timestamp from atrace log entry 154 while [ "$2" != "" -a "$2" != "tracing_mark_write" ] 155 do 156 shift 157 done 158 echo $1 159 } 160 161 function computeTimeDiff { 162 # Compute time diff given: startSeconds startNs endSeconds endNS 163 164 # strip leading zeros 165 startS=$(expr 0 + $1) 166 endS=$(expr 0 + $3) 167 if [ "$2" = N ]; then 168 startNs=0 169 endNs=0 170 else 171 startNs=$(expr 0 + $2) 172 endNs=$(expr 0 + $4) 173 fi 174 175 ((startMs=startS*1000 + startNs/1000000)) 176 ((endMs=endS*1000 + endNs/1000000)) 177 ((diff=endMs-startMs)) 178 echo $diff 179 } 180 181 function log2msec { 182 in=$1 183 in=${in:=0.0} 184 set -- $(echo $in | tr . " ") 185 186 # shell addition via (( )) doesn't like leading zeroes in msecs 187 # field so remove leading zeroes 188 msecfield=$(expr 0 + $2) 189 190 ((msec=$1*1000000+msecfield)) 191 ((msec=msec/1000)) 192 echo $msec 193 } 194 195 function getStartTime { 196 # extract event indicating beginning of start sequence 197 # a) look for a "launching" event indicating start from scratch 198 # b) look for another activity getting a pause event 199 _app=$1 200 traceout=$2 201 ret=0 202 s=$(grep "Binder.*tracing_mark_write.*launching" $traceout 2>/dev/null | head -1| tr [\(\)\[\] :] " ") 204 if [ -z "$s" ]; then 205 s=$(grep activityPause $traceout | head -1 2>/dev/null| tr [\(\)\[\] :] " ") 207 else 208 vout $_app was restarted! 209 ret=1 210 fi 211 vout STARTLOG: $s 212 log2msec $(findtimestamp $s) 213 return $ret 214 } 215 216 function getEndTime { 217 # extract event indicating end of start sequence. We use the 218 # first surfaceflinger event associated with the target activity 219 _app=$1 220 traceout=$2 221 f=$(grep "surfaceflinger.*tracing_mark_write.*$_app" $traceout 2>/dev/null | 222 grep -v Starting | head -1 | tr [\(\)\[\] :] " ") 224 if [ -z "$f" ]; then 225 # Hmm. sf symbols may not be there... get the pid 226 pid=$(${ADB}pidof /system/bin/surfaceflinger | tr "[ ]" "[ ]") 228 f=$(grep " <...>-$pid.*tracing_mark_write.*$_app" $traceout 2>/dev/null | 229 grep -v Starting | head -1 | tr [\(\)\[\] :] " ") 231 fi 232 vout ENDLOG: $f 233 log2msec $(findtimestamp $f) 234 } 235 236 function resetJankyFrames { 237 _gfxapp=$1 238 _gfxapp=${_gfxapp:="com.android.systemui"} 239 ${ADB}dumpsys gfxinfo $_gfxapp reset 2>&1 >/dev/null 240 } 241 242 function getJankyFrames { 243 _gfxapp=$1 244 _gfxapp=${_gfxapp:="com.android.systemui"} 245 246 # Note: no awk or sed on devices so have to do this 247 # purely with bash 248 total=0 249 janky=0 250 latency=0 251 ${ADB}dumpsys gfxinfo $_gfxapp | tr "\r" " " | egrep "9[059]th| frames" | while read line 252 do 253 if echo $line | grep -q "Total frames"; then 254 set -- $line 255 total=$4 256 elif echo $line | grep -q "Janky frames"; then 257 set -- $line 258 janky=$3 259 elif echo $line | grep -q "90th"; then 260 set -- $(echo $line | tr m " ") 261 l90=$3 262 elif echo $line | grep -q "95th"; then 263 set -- $(echo $line | tr m " ") 264 l95=$3 265 elif echo $line | grep -q "99th"; then 266 set -- $(echo $line | tr m " ") 267 l99=$3 268 echo $total $janky $l90 $l95 $l99 269 break 270 fi 271 done 272 } 273 274 function checkForDirectReclaim { 275 # look for any reclaim events in atrace output 276 _app=$1 277 traceout=$2 278 if grep -qi reclaim $traceout; then 279 return 1 280 fi 281 return 0 282 } 283 284 function startInstramentation { 285 _iter=$1 286 _iter=${_iter:=0} 287 enableAtrace=$2 288 enableAtrace=${enableAtrace:=1} 289 # Called at beginning of loop. Turn on instramentation like atrace 290 vout start instramentation $(date) 291 echo =============================== >> $output 292 echo Before iteration $_iter >> $output 293 echo =============================== >> $output 294 ${ADB}cat /proc/meminfo 2>&1 >> $output 295 ${ADB}dumpsys meminfo 2>&1 >> $output 296 if [ "$DEVICE" = volantis ]; then 297 ${ADB}cat /d/nvmap/iovmm/procrank 2>&1 >> $output 298 fi 299 if [ "$user" = root -a $enableAtrace -gt 0 ]; then 300 vout ${ADB}atrace -b 32768 --async_start $tracecategories 301 ${ADB}atrace -b 32768 --async_start $tracecategories >> $output 302 echo >> $output 303 fi 304 } 305 306 function stopInstramentation { 307 enableAtrace=$1 308 enableAtrace=${enableAtrace:=1} 309 if [ "$user" = root -a $enableAtrace -gt 0 ]; then 310 vout ${ADB}atrace --async_stop 311 ${ADB}atrace --async_stop > /dev/null 312 fi 313 } 314 315 function stopAndDumpInstramentation { 316 vout stop instramentation $(date) 317 echo =============================== >> $output 318 echo After iteration >> $output 319 echo =============================== >> $output 320 ${ADB}cat /proc/meminfo 2>&1 >> $output 321 ${ADB}dumpsys meminfo 2>&1 >> $output 322 if [ "$user" = root ]; then 323 traceout=$1 324 traceout=${traceout:=$output} 325 echo =============================== >> $traceout 326 echo TRACE >> $traceout 327 echo =============================== >> $traceout 328 if [ $compress -gt 0 ]; then 329 tmpTrace=./tmptrace.$$ 330 UNCOMPRESS=$CMDDIR/atrace-uncompress.py 331 > $tmpTrace 332 zarg="-z" 333 ${ADB}atrace -z -b 32768 --async_dump >> $tmpTrace 334 python $UNCOMPRESS $tmpTrace >> $traceout 335 rm -f $tmpTrace 336 else 337 ${ADB}atrace -b 32768 --async_dump > $traceout 338 fi 339 vout ${ADB}atrace $zarg -b 32768 --async_dump 340 vout ${ADB}atrace --async_stop 341 ${ADB}atrace --async_stop > /dev/null 342 fi 343 } 344 345 function getActivityName { 346 cmd="actName=\$${1}Activity" 347 eval $cmd 348 echo $actName 349 } 350 351 function getPackageName { 352 set -- $(getActivityName $1 | tr "[/]" "[ ]") 353 echo $1 354 } 355 356 function startActivityFromPackage { 357 if [ "$1" = home ]; then 358 doKeyevent HOME 359 echo 0 360 return 0 361 fi 362 vout $AM_START_NOWAIT -p "$(getPackageName $1)" -c android.intent.category.LAUNCHER -a android.intent.action.MAIN 363 $AM_START_NOWAIT -p "$(getPackageName $1)" -c android.intent.category.LAUNCHER -a android.intent.action.MAIN 2>&1 364 echo 0 365 } 366 367 function startActivity { 368 if [ "$1" = home ]; then 369 doKeyevent HOME 370 echo 0 371 return 0 372 elif [ "$1" = chrome ]; then 373 if [ "$DEVICE" = volantis -o "$DEVICE" = ariel ]; then 374 vout $AM_START_NOWAIT -p "$(getPackageName $1)" http://www.theverge.com 375 $AM_START_NOWAIT -p "$(getPackageName $1)" http://www.theverge.com > /dev/null 376 set -- 0 0 377 else 378 vout $AM_START -p "$(getPackageName $1)" http://www.theverge.com 379 set -- $($AM_START -p "$(getPackageName $1)" http://www.theverge.com | grep ThisTime) 380 fi 381 else 382 vout $AM_START "$(getActivityName $1)" 383 set -- $($AM_START "$(getActivityName $1)" | grep ThisTime) 384 fi 385 echo $2 | tr "[\r]" "[\n]" 386 } 387 388 function forceStartActivity { 389 if [ "$1" = chrome ]; then 390 vout $AM_START -p "$(getPackageName $1)" http://www.theverge.com 391 set -- $($AM_FORCE_START -p "$(getPackageName $1)" http://www.theverge.com | grep ThisTime) 392 else 393 vout $AM_FORCE_START "$(getActivityName $1)" 394 set -- $($AM_FORCE_START "$(getActivityName $1)" | grep ThisTime) 395 fi 396 echo $2 | tr "[\r]" "[\n]" 397 } 398 399 function checkActivity { 400 # requires root 401 actName="$(getActivityName $1)" 402 $AM_LIST | grep $actName 403 } 404 405 #function stopActivity { 406 # vout $AM_STOP $(getActivityName $1) 407 # $AM_STOP $(getActivityName $1) 408 #} 409 410 function doSwipe { 411 vout ${ADB}input swipe $* 412 ${ADB}nice input swipe $* 413 } 414 415 function doText { 416 echo $* > ./tmpOutput 417 vout ${ADB}input text \"$*\" 418 ${ADB}input text "$(cat ./tmpOutput)" 419 rm -f ./tmpOutput 420 } 421 422 function doTap { 423 vout ${ADB}input tap $* 424 ${ADB}input tap $* 425 } 426 427 function doKeyevent { 428 vout $INPUT keyevent $* 429 $INPUT keyevent $* 430 } 431 432 function checkIsRunning { 433 p=$1 434 shift 435 if ! $PS | grep $p | grep -qv grep; then 436 handleError $*: $p is not running 437 exit 1 438 fi 439 } 440 441 function checkStartTime { 442 vout checkStartTime $1 v $2 443 if [ -z "$2" ]; then 444 echo false 445 return 2 446 fi 447 if [ "$1" -gt "$2" ]; then 448 echo false 449 return 1 450 fi 451 echo true 452 return 0 453 } 454 455 function handleError { 456 echo Error: $* 457 stopAndDumpInstramentation 458 if [ $stoponerror -gt 0 ]; then 459 exit 1 460 fi 461 } 462 463 user=root 464 if ${ADB}ls /data 2>/dev/null | grep -q "Permission denied"; then 465 user=shell 466 fi 467 vout User is $user 468 469 if [ $generateActivities -gt 0 ]; then 470 if [ $isOnDevice -gt 0 ]; then 471 echo Error: cannot generate activity list when run on device 472 exit 1 473 fi 474 echo Generating activities... 475 for app in $appList 476 do 477 startActivityFromPackage $app 2>&1 > /dev/null 478 act=$(${ADB}am stack list | grep $(getPackageName $app) | sed -e 's/ //' | head -1 | awk '{ print $2; }') 480 eval "${app}Activity=$act" 481 echo "ACTIVITY: $app --> $(getActivityName $app)" 482 done 483 fi 484 485