77import os
88import glob
99import re
10+ import time
1011
1112from logging import getLogger
1213from collections import namedtuple
@@ -60,7 +61,6 @@ def parseargs(self):
6061 parseonlyparser .add_argument ('--device-type' , choices = ['android' ,'ios' ],type = str .lower ,help = 'Device type for testing' , dest = 'devicetype' )
6162 parseonlyparser .add_argument ('--package-path' , help = 'Location of test application' , dest = 'packagepath' )
6263 parseonlyparser .add_argument ('--package-name' , help = 'Classname of application' , dest = 'packagename' )
63- parseonlyparser .add_argument ('--exit-code' , help = 'Success exit code' , dest = 'expectedexitcode' )
6464 parseonlyparser .add_argument ('--startup-iterations' , help = 'Startups to run (1+)' , type = int , default = 5 , dest = 'startupiterations' )
6565 self .add_common_arguments (parseonlyparser )
6666
@@ -143,7 +143,6 @@ def parseargs(self):
143143 self .packagepath = args .packagepath
144144 self .packagename = args .packagename
145145 self .devicetype = args .devicetype
146- self .expectedexitcode = args .expectedexitcode
147146 self .startupiterations = args .startupiterations
148147
149148 if args .scenarioname :
@@ -305,20 +304,42 @@ def run(self):
305304 startup .runtests (self .traits )
306305
307306
308- elif self .testtype == const .DEVICESTARTUP :
307+ elif self .testtype == const .DEVICESTARTUP :
308+ # ADB Key Event corresponding numbers: https://gist.github.com/arjunv/2bbcca9a1a1c127749f8dcb6d36fb0bc
309+ # Regex used to split the response from starting the activity and saving each value
310+ #Example:
311+ # Starting: Intent { cmp=net.dot.HelloAndroid/net.dot.MainActivity }
312+ # Status: ok
313+ # LaunchState: COLD
314+ # Activity: net.dot.HelloAndroid/net.dot.MainActivity
315+ # TotalTime: 241
316+ # WaitTime: 242
317+ # Complete
318+ # Saves: [Intent { cmp=net.dot.HelloAndroid/net.dot.MainActivity }, ok, COLD, net.dot.HelloAndroid/net.dot.MainActivity, 241, 242]
319+ # Split results (start at 0) (List is Starting (Intent activity), Status (ok...), LaunchState ([HOT, COLD, WARM]), Activity (started activity name), TotalTime(toFrameOne), WaitTime(toFullLoad))
320+ runSplitRegex = ":\s(.+)"
321+ screenWasOff = False
309322 getLogger ().info ("Clearing potential previous run nettraces" )
310- for file in glob .glob (os .path .join (const .TRACEDIR , 'PerfTest' , 'trace*.nettrace ' )):
323+ for file in glob .glob (os .path .join (const .TRACEDIR , 'PerfTest' , 'runoutput.trace ' )):
311324 if exists (file ):
312325 getLogger ().info ("Removed: " + os .path .join (const .TRACEDIR , file ))
313326 os .remove (file )
314-
327+
315328 cmdline = xharnesscommand () + [self .devicetype , 'state' , '--adb' ]
316329 adb = RunCommand (cmdline , verbose = True )
317330 adb .run ()
318- cmdline = [adb .stdout .strip (), 'shell' , 'mkdir' , '-p' , '/sdcard/PerfTest' ]
331+
332+ # Do not remove, XHarness install seems to fail without an adb command called before the xharness command
333+ getLogger ().info ("Preparing ADB" )
334+ cmdline = [
335+ adb .stdout .strip (),
336+ 'shell' ,
337+ 'wm' ,
338+ 'size'
339+ ]
319340 RunCommand (cmdline , verbose = True ).run ()
320341
321- cmdline = xharnesscommand () + [
342+ installCmd = xharnesscommand () + [
322343 self .devicetype ,
323344 'install' ,
324345 '--app' , self .packagepath ,
@@ -328,48 +349,129 @@ def run(self):
328349 const .TRACEDIR ,
329350 '-v'
330351 ]
352+ RunCommand (installCmd , verbose = True ).run ()
331353
332- RunCommand (cmdline , verbose = True ).run ()
333-
354+ getLogger ().info ("Completed install, running shell." )
355+ cmdline = [
356+ adb .stdout .strip (),
357+ 'shell' ,
358+ f'cmd package resolve-activity --brief { self .packagename } | tail -n 1'
359+ ]
360+ getActivity = RunCommand (cmdline , verbose = True )
361+ getActivity .run ()
362+ getLogger ().info (f"Target Activity { getActivity .stdout } " )
363+
364+ # More setup stuff
365+ checkScreenOnCmd = [
366+ adb .stdout .strip (),
367+ 'shell' ,
368+ f'dumpsys input_method | grep mInteractive'
369+ ]
370+ checkScreenOn = RunCommand (checkScreenOnCmd , verbose = True )
371+ checkScreenOn .run ()
372+
373+ keyInputCmd = [
374+ adb .stdout .strip (),
375+ 'shell' ,
376+ 'input' ,
377+ 'keyevent'
378+ ]
334379
380+ if ("mInteractive=false" in checkScreenOn .stdout ):
381+ # Turn on the screen to make interactive and see if it worked
382+ getLogger ().info ("Screen was off, turning on." )
383+ screenWasOff = True
384+ RunCommand (keyInputCmd + ['26' ], verbose = True ).run () # Press the power key
385+ RunCommand (keyInputCmd + ['82' ], verbose = True ).run () # Unlock the screen with menu key (only works if it is not a password lock)
386+
387+ checkScreenOn = RunCommand (checkScreenOnCmd , verbose = True )
388+ checkScreenOn .run ()
389+ if ("mInteractive=false" in checkScreenOn .stdout ):
390+ getLogger ().exception ("Failed to make screen interactive." )
391+
392+ # Actual testing some run stuff
393+ getLogger ().info ("Test run to check if permissions are needed" )
394+ activityname = getActivity .stdout
395+
396+ startAppCmd = [
397+ adb .stdout .strip (),
398+ 'shell' ,
399+ 'am' ,
400+ 'start-activity' ,
401+ '-W' ,
402+ '-n' ,
403+ activityname
404+ ]
405+ testRun = RunCommand (startAppCmd , verbose = True )
406+ testRun .run ()
407+ testRunStats = re .findall (runSplitRegex , testRun .stdout ) # Split results saving value (List: Starting, Status, LaunchState, Activity, TotalTime, WaitTime)
408+ getLogger ().info (f"Test run activity: { testRunStats [3 ]} " )
409+
410+ stopAppCmd = [
411+ adb .stdout .strip (),
412+ 'shell' ,
413+ 'am' ,
414+ 'force-stop' ,
415+ self .packagename
416+ ]
417+ RunCommand (stopAppCmd , verbose = True ).run ()
418+
419+ if "com.google.android.permissioncontroller" in testRunStats [3 ]:
420+ # On perm screen, use the buttons to close it. it will stay away until the app is reinstalled
421+ RunCommand (keyInputCmd + ['22' ], verbose = True ).run () # Select next button
422+ time .sleep (1 )
423+ RunCommand (keyInputCmd + ['22' ], verbose = True ).run () # Select next button
424+ time .sleep (1 )
425+ RunCommand (keyInputCmd + ['66' ], verbose = True ).run () # Press enter to close main perm screen
426+ time .sleep (1 )
427+ RunCommand (keyInputCmd + ['22' ], verbose = True ).run () # Select next button
428+ time .sleep (1 )
429+ RunCommand (keyInputCmd + ['66' ], verbose = True ).run () # Press enter to close out of second screen
430+ time .sleep (1 )
431+
432+ # Check to make sure it worked
433+ testRun = RunCommand (startAppCmd , verbose = True )
434+ testRun .run ()
435+ testRunStats = re .findall (runSplitRegex , testRun .stdout )
436+ getLogger ().info (f"Test run activity: { testRunStats [3 ]} " )
437+ RunCommand (stopAppCmd , verbose = True ).run ()
438+
439+ if "com.google.android.permissioncontroller" in testRunStats [3 ]:
440+ getLogger ().exception ("Failed to get past permission screen, run locally to see if enough next button presses were used." )
441+
442+ allResults = []
335443 for i in range (self .startupiterations ):
336- cmdline = xharnesscommand () + [
337- 'android' ,
338- 'run' ,
339- '-o' ,
340- const .TRACEDIR ,
341- '--package-name' ,
342- self .packagename ,
343- '-v' ,
344- '--arg=env:COMPlus_EnableEventPipe=1' ,
345- '--arg=env:COMPlus_EventPipeOutputStreaming=1' ,
346- '--arg=env:COMPlus_EventPipeOutputPath=/sdcard/PerfTest/trace%s.nettrace' % (i + 1 ),
347- '--arg=env:COMPlus_EventPipeCircularMB=10' ,
348- '--arg=env:COMPlus_EventPipeConfig=Microsoft-Windows-DotNETRuntime:10:5' ,
349- '--expected-exit-code' ,
350- self .expectedexitcode ,
351- '--dev-out' ,
352- '/sdcard/PerfTest/'
353- ]
354-
355- RunCommand (cmdline , verbose = True ).run ()
356-
357- cmdline = xharnesscommand () + [
444+ startStats = RunCommand (startAppCmd , verbose = True )
445+ startStats .run ()
446+ RunCommand (stopAppCmd , verbose = True ).run ()
447+ allResults .append (startStats .stdout ) # Save results (List is Intent, Status, LaunchState Activity, TotalTime, WaitTime)
448+ time .sleep (3 ) # Delay in seconds for ensuring a cold start
449+
450+ getLogger ().info ("Stopping App for uninstall" )
451+ RunCommand (stopAppCmd , verbose = True ).run ()
452+
453+ getLogger ().info ("Uninstalling app" )
454+ uninstallAppCmd = xharnesscommand () + [
358455 'android' ,
359456 'uninstall' ,
360457 '--package-name' ,
361458 self .packagename
362459 ]
460+ RunCommand (uninstallAppCmd , verbose = True ).run ()
363461
364- RunCommand (cmdline , verbose = True ).run ()
365-
366- cmdline = [adb .stdout .strip (), 'shell' , 'rm' , '-r' , '/sdcard/PerfTest' ]
367- RunCommand (cmdline , verbose = True ).run ()
368-
462+ if screenWasOff :
463+ RunCommand (keyInputCmd + ['26' ], verbose = True ).run () # Turn the screen back off
369464
465+ # Create traces to store the data so we can keep the current general parse trace flow
466+ getLogger ().info (f"Logs: \n { allResults } " )
467+ os .makedirs (f"{ const .TRACEDIR } /PerfTest" , exist_ok = True )
468+ traceFile = open (f"{ const .TRACEDIR } /PerfTest/runoutput.trace" , "w" )
469+ for result in allResults :
470+ traceFile .write (result )
471+ traceFile .close ()
370472
371473 startup = StartupWrapper ()
372- self .traits .add_traits (overwrite = True , apptorun = "app" , startupmetric = const .STARTUP_DEVICETIMETOMAIN , tracefolder = 'PerfTest/' , tracename = 'trace*.nettrace ' , scenarioname = 'Device Startup - Android %s' % (self .packagename ))
474+ self .traits .add_traits (overwrite = True , apptorun = "app" , startupmetric = const .STARTUP_DEVICETIMETOMAIN , tracefolder = 'PerfTest/' , tracename = 'runoutput.trace ' , scenarioname = 'Device Startup - Android %s' % (self .packagename ))
373475 startup .parsetraces (self .traits )
374476
375477 elif self .testtype == const .SOD :
0 commit comments