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