示例#1
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('adb_path', help='Path to adb command')
    parser.add_argument('agi_dir', help='Path to AGI build')
    parser.add_argument('out_dir', help='Path to output directory')
    args = parser.parse_args()

    #### Early checks and sanitization
    assert os.path.isfile(args.adb_path)
    adb_path = os.path.abspath(args.adb_path)
    assert os.path.isdir(args.agi_dir)
    agi_dir = os.path.abspath(args.agi_dir)
    assert os.path.isdir(args.out_dir)
    out_dir = os.path.abspath(args.out_dir)
    gapit_path = os.path.join(agi_dir, 'gapit')

    #### Create BotUtil with relevant adb and gapit paths
    bu = botutil.BotUtil(adb_path)
    bu.set_gapit_path(gapit_path)

    #### Test parameters
    test_params = {}
    required_keys = ['gfxtrace']
    botutil.load_params(test_params, required_keys=required_keys)
    assert os.path.isfile(test_params['gfxtrace'])

    #### Profile
    gapit_args = [
        '-gapir-os', 'android', '-gapir-nofallback', test_params['gfxtrace']
    ]

    with open(os.path.join(out_dir, 'profile.stdout'), 'w') as f:
        p = bu.gapit('profile', gapit_args, stdout=f)
    return p.returncode
示例#2
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('adb_path', help='Path to adb command')
    parser.add_argument('agi_dir', help='Path to AGI build')
    parser.add_argument('out_dir', help='Path to output directory')
    args = parser.parse_args()

    #### Early checks and sanitization
    assert os.path.isfile(args.adb_path)
    adb_path = os.path.abspath(args.adb_path)
    assert os.path.isdir(args.agi_dir)
    agi_dir = os.path.abspath(args.agi_dir)
    assert os.path.isdir(args.out_dir)
    out_dir = os.path.abspath(args.out_dir)
    gapit_path = os.path.join(agi_dir, 'gapit')

    #### Create BotUtil with relevant adb and gapit paths
    bu = botutil.BotUtil(adb_path)
    bu.set_gapit_path(gapit_path)

    #### Test parameters
    test_params = {}
    botutil.load_params(test_params)

    #### Here add your debug experiments
    # For instance, list packages installed on the device:
    botutil.runcmd(['adb', 'shell', 'pm', 'list', 'packages'])
示例#3
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('adb_path', help='Path to adb command')
    parser.add_argument('agi_dir', help='Path to AGI build')
    parser.add_argument('out_dir', help='Path to output directory')
    args = parser.parse_args()

    #### Early checks and sanitization
    assert os.path.isfile(args.adb_path)
    adb_path = os.path.abspath(args.adb_path)
    assert os.path.isdir(args.agi_dir)
    agi_dir = os.path.abspath(args.agi_dir)
    assert os.path.isdir(args.out_dir)
    out_dir = os.path.abspath(args.out_dir)
    gapit_path = os.path.join(agi_dir, 'gapit')

    #### Create BotUtil with relevant adb and gapit paths
    bu = botutil.BotUtil(adb_path)
    bu.set_gapit_path(gapit_path)

    #### Load test parameters
    test_params = {}
    # Do not require 'apk' and 'package' params, as some drivers are just
    # obtained by system update.
    botutil.load_params(test_params)

    #### Install APK if need be
    if 'apk' in test_params.keys():
        if not 'package' in test_params.keys():
            botutil.log('Error: have "apk" but no "package" in params.json')
            return 1
        bu.install_apk(test_params)

    #### Call gapit command
    gapit_args = ['-os', 'android']
    p = bu.gapit('validate_gpu_profiling', gapit_args)
    return p.returncode
示例#4
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('adb_path', help='Path to adb command')
    parser.add_argument('agi_dir', help='Path to AGI build')
    parser.add_argument('out_dir', help='Path to output directory')
    args = parser.parse_args()

    #### Early checks and sanitization
    assert os.path.isfile(args.adb_path)
    adb_path = os.path.abspath(args.adb_path)
    assert os.path.isdir(args.agi_dir)
    agi_dir = os.path.abspath(args.agi_dir)
    assert os.path.isdir(args.out_dir)
    out_dir = os.path.abspath(args.out_dir)
    gapit_path = os.path.join(agi_dir, 'gapit')

    #### Create BotUtil with relevant adb and gapit paths
    bu = botutil.BotUtil(adb_path)
    bu.set_gapit_path(gapit_path)

    #### Test parameters
    test_params = {
        'startframe': '100',
        'numframes': '5',
        'observe_frames': '1',
        'api': 'vulkan',
    }
    required_keys = ['apk', 'package', 'activity']
    botutil.load_params(test_params, required_keys=required_keys)

    #### Install APK
    bu.install_apk(test_params)

    #### Trace the app
    gfxtrace = os.path.join(out_dir, test_params['package'] + '.gfxtrace')
    args = [
        '-api', test_params['api'],
        '-start-at-frame', test_params['startframe'],
        '-capture-frames', test_params['numframes'],
        '-observe-frames', test_params['observe_frames'],
        '-out', gfxtrace
    ]

    if 'additionalargs' in test_params.keys():
        args += ['-additionalargs', test_params['additionalargs']]

    args += [test_params['package'] + '/' + test_params['activity']]

    p = bu.gapit('trace', args)
    if p.returncode != 0:
        return 1

    #### Stop the app asap for device cool-down
    bu.adb(['shell', 'am', 'force-stop', test_params['package']])

    #### Replay
    # Use the 'sxs-frames' mode that generates a series of PNGs rather
    # than an mp4 video. This makes inspection easier, and removes the
    # dependency on ffmpeg on the running hosts.
    videooutfile = os.path.join(out_dir, test_params['package'] + '.frame.png')
    gapit_args = [
        '-gapir-nofallback',
        '-type', 'sxs-frames',
        '-frames-minimum', test_params['numframes'],
        '-out', videooutfile,
        gfxtrace
    ]
    p = bu.gapit('video', gapit_args)
    if p.returncode != 0:
        return p.returncode

    #### Screenshot test to retrieve mid-frame resources
    # This is meant to test the command buffer splitter, which is invoked to be
    # able to retrieve the framebuffer in the middle of a render pass. We ask
    # for the framebuffer at the 5th draw call, this number was choosen because:
    # it is low enough to be present in most frames (i.e. we expect frames to
    # have at least 5 draw calls), and it hopefully falls in the middle of a
    # renderpass. Also, we don't want to have a random number here, as we want
    # to keep the tests as reproducible as feasible.
    screenshotfile = os.path.join(out_dir, test_params['package'] + '.png')
    gapit_args = [
        '-executeddraws', '5',
        '-out', screenshotfile,
        gfxtrace
    ]
    p = bu.gapit('screenshot', gapit_args)
    if p.returncode != 0:
        return p.returncode

    #### Frame profiler
    # Check that frame profiling generates valid JSON
    profile_json = os.path.join(out_dir, test_params['package'] + '.profiling.json')
    gapit_args = [
        '-json',
        '-out', profile_json,
        gfxtrace
    ]
    p = bu.gapit('profile', gapit_args)
    if p.returncode != 0:
        return p.returncode
    assert botutil.is_valid_json(profile_json)

    #### Frame graph
    # Check that framegraph generates valid JSON
    framegraph_json = os.path.join(out_dir, test_params['package'] + '.framegraph.json')
    gapit_args = [
        '-json', framegraph_json,
        gfxtrace
    ]
    p = bu.gapit('framegraph', gapit_args)
    if p.returncode != 0:
        return p.returncode
    assert botutil.is_valid_json(framegraph_json)

    #### All tests have passed, return success
    return 0
示例#5
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('adb_path', help='Path to adb command')
    parser.add_argument('agi_dir', help='Path to AGI build')
    parser.add_argument('out_dir', help='Path to output directory')
    args = parser.parse_args()

    #### Early checks and sanitization
    assert os.path.isfile(args.adb_path)
    adb_path = os.path.abspath(args.adb_path)
    assert os.path.isdir(args.agi_dir)
    agi_dir = os.path.abspath(args.agi_dir)
    assert os.path.isdir(args.out_dir)
    out_dir = os.path.abspath(args.out_dir)
    gapit_path = os.path.join(agi_dir, 'gapit')

    #### Create BotUtil with relevant adb and gapit paths
    bu = botutil.BotUtil(adb_path)
    bu.set_gapit_path(gapit_path)

    #### Test parameters
    test_params = {}
    required_keys = ['apk', 'package', 'activity', 'perfetto_config']
    botutil.load_params(test_params, required_keys=required_keys)

    #### Install APK
    bu.install_apk(test_params)

    #### Retrieve device-specific perfetto config
    p = bu.adb(['shell', 'getprop', 'ro.product.device'])
    device = p.stdout.rstrip()
    if not device in test_params['perfetto_config'].keys():
        botutil.log('Error: no perfetto config found for device: ' + device)
        return 1
    perfetto_config = test_params['perfetto_config'][device]
    if not os.path.isfile(perfetto_config):
        botutil.log('Error: perfetto config file not found: ' +
                    perfetto_config)
        return 1

    #### Trace the app
    perfetto_trace = os.path.join(out_dir,
                                  test_params['package'] + '.perfetto')
    gapit_args = [
        '-api', 'perfetto', '-for', '5s', '-perfetto', perfetto_config, '-out',
        perfetto_trace
    ]

    if 'additionalargs' in test_params.keys():
        gapit_args += ['-additionalargs', test_params['additionalargs']]

    gapit_args += [test_params['package'] + '/' + test_params['activity']]

    p = bu.gapit('trace', gapit_args)
    if p.returncode != 0:
        return 1

    #### Stop the app asap for device cool-down
    bu.adb(['shell', 'am', 'force-stop', test_params['package']])

    #### Check perfetto trace validity by formatting it to JSON
    perfetto_json = perfetto_trace.replace('.perfetto', '.json')
    gapit_args = [
        '-mode', 'metrics', '-format', 'json', '-out', perfetto_json,
        perfetto_trace
    ]
    p = bu.gapit('perfetto', gapit_args)
    return p.returncode
示例#6
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('timeout', type=int, help='Timeout (duration limit for this test), in seconds')
    parser.add_argument('test_dir', help='Path to test directory, e.g. tests/foobar')
    parser.add_argument('out_dir', help='Path to output directory')
    args = parser.parse_args()

    #### Early checks and sanitization
    assert os.path.isdir(args.test_dir)
    test_dir = os.path.abspath(args.test_dir)
    assert os.path.isdir(args.out_dir)
    out_dir = os.path.abspath(args.out_dir)
    # bot-scripts/ contains test scripts
    assert os.path.isdir('bot-scripts')
    # agi/ contains the AGI build
    assert os.path.isdir('agi')
    agi_dir = os.path.abspath('agi')

    #### Create BotUtil object with adb path
    adb_path = os.path.abspath(which('adb'))
    bu = botutil.BotUtil(adb_path)

    #### Print AGI build properties (AGI version, build commit SHA)
    cmd = ['cat', os.path.join(agi_dir, 'build.properties')]
    botutil.runcmd(cmd)

    #### Check test parameters
    test_params = {}
    params_file = os.path.join(test_dir, 'params.json')
    assert os.path.isfile(params_file)
    with open(params_file, 'r') as f:
        test_params = json.load(f)
    assert 'script' in test_params.keys()
    test_script = os.path.abspath(os.path.join('bot-scripts', test_params['script']))
    assert os.path.isfile(test_script)

    #### Timeout: make room for pre-script checks and post-script cleanup.
    # All durations are in seconds.
    cleanup_timeout = 15
    if args.timeout < cleanup_timeout:
        print('Error: timeout must be higher than the time for cleanup duration ({} sec)'.format(cleanup_timeout))
        return 1
    test_timeout = args.timeout - cleanup_timeout

    #### Check Android device access
    # This first adb command may take a while if the adb deamon has to launch
    p = bu.adb(['shell', 'true'], timeout=10)
    if p.returncode != 0:
        print('Error: zero or more than one device connected')
        return 1
    # Print device fingerprint
    p = bu.adb(['shell', 'getprop', 'ro.build.fingerprint'])
    print('Device fingerprint: ' + p.stdout)

    #### Prepare device
    # Wake up and unlock screen: use the "wakeup keyevent + wm dismiss-keyguard"
    # sequence to unlock the device. The wakeup keyevent (224) call may take
    # more than a second to return, hence the extended timeout.
    bu.adb(['shell', 'input', 'keyevent', '224'], timeout=2)
    time.sleep(2)
    # TODO(b/157444640): Temporary workaround: touch the screen before unlocking it to bypass a possible "Android preview" notification
    bu.adb(['shell', 'input', 'touchscreen', 'tap', '100', '100'])
    time.sleep(1)
    bu.adb(['shell', 'wm', 'dismiss-keyguard'])
    time.sleep(1)
    # Turn brightness to a minimum, to prevent device to get too hot
    bu.adb(['shell', 'settings', 'put', 'system', 'screen_brightness', '0'])
    # Make sure to have the screen "stay awake" during the test, we turn off the screen ourselves at the end
    bu.adb(['shell', 'settings', 'put', 'global', 'stay_on_while_plugged_in', '7'])
    # Avoid "Viewing full screen" notifications that makes app loose focus
    bu.adb(['shell', 'settings', 'put', 'secure', 'immersive_mode_confirmations', 'confirmed'])
    # Remove any implicit vulkan layers
    bu.adb(['shell', 'settings', 'delete', 'global', 'enable_gpu_debug_layers'])
    bu.adb(['shell', 'settings', 'delete', 'global', 'gpu_debug_app'])
    bu.adb(['shell', 'settings', 'delete', 'global', 'gpu_debug_layers'])
    bu.adb(['shell', 'settings', 'delete', 'global', 'gpu_debug_layer_app'])
    # Clean up logcat, can take a few seconds
    bu.adb(['logcat', '-c'], timeout=5)

    #### Launch test script
    print('Start test script "{}" with timeout of {} seconds'.format(test_script, test_timeout))
    cmd = [test_script, adb_path, agi_dir, out_dir]
    test_returncode = None
    stdout_filename = os.path.abspath(os.path.join(out_dir, 'stdout.txt'))
    stderr_filename = os.path.abspath(os.path.join(out_dir, 'stderr.txt'))
    with open(stdout_filename, 'w') as stdout_file:
        with open(stderr_filename, 'w') as stderr_file:
            try:
                p = subprocess.run(cmd, timeout=test_timeout, cwd=test_dir, stdout=stdout_file, stderr=stderr_file)
                test_returncode = p.returncode
            except subprocess.TimeoutExpired as err:
                # Mirror returncode from unix 'timeout' command
                test_returncode = 124

    #### Dump the logcat
    logcat_file = os.path.join(out_dir, 'logcat.txt')
    with open(logcat_file, 'w') as f:
        cmd = [adb_path, 'logcat', '-d']
        p = subprocess.run(cmd, timeout=5, check=True, stdout=f)

    #### Dump test outputs
    with open(stdout_filename, 'r') as f:
        print('#### Test stdout:')
        print(f.read())
    with open(stderr_filename, 'r') as f:
        print('#### Test stderr:')
        print(f.read())
    print('#### Test returncode:')
    print(test_returncode)

    #### Turn off the device screen
    # Key "power" (26) toggle between screen off and on, so first make sure to
    # have the screen on with key "wake up" (224), then press "power" (26).
    # The screen wakeup (224) call sometimes takes more than a second to return,
    # hence the extended timeout.
    bu.adb(['shell', 'input', 'keyevent', '224'], timeout=2)
    # Wait a bit to let any kind of device wake up animation terminate
    time.sleep(2)
    bu.adb(['shell', 'input', 'keyevent', '26'])

    #### Force-stop AGI and test app
    for abi in ['armeabiv7a', 'arm64v8a']:
        bu.adb(['shell', 'am', 'force-stop', 'com.google.android.gapid.' + abi])
    if 'package' in test_params.keys():
        bu.adb(['shell', 'am', 'force-stop', test_params['package']])

    #### Test may fail halfway through, salvage any gfxtrace
    gfxtraces = glob.glob(os.path.join(test_dir, '*.gfxtrace'))
    # Do not salvage a gfxtrace that is listed as a test input
    if ('gfxtrace' in test_params.keys()):
        g = os.path.join(test_dir, test_params['gfxtrace'])
        if g in gfxtraces:
            gfxtraces.remove(g)
    if len(gfxtraces) != 0:
        salvage_dir = os.path.join(out_dir, 'harness-salvage')
        os.makedirs(salvage_dir, exist_ok=True)
        for gfx in gfxtraces:
            dest = os.path.join(salvage_dir, os.path.basename(gfx))
            os.rename(gfx, dest)

    #### Analyze the return code
    print('#### Test status:')
    if test_returncode == 124:
        print('TIMEOUT')
        print('Sleep a bit more to trigger a Swarming-level timeout, to disambiguate a timeout from a crash')
        time.sleep(cleanup_timeout)
    elif test_returncode != 0:
        print('FAIL')
    else:
        print('PASS')
    return test_returncode