android_device_start_test.dart 9.41 KB
Newer Older
1 2 3 4 5 6 7
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:file/memory.dart';
import 'package:flutter_tools/src/android/android_device.dart';
import 'package:flutter_tools/src/android/android_sdk.dart';
8
import 'package:flutter_tools/src/android/application_package.dart';
9
import 'package:flutter_tools/src/base/file_system.dart';
10 11
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/platform.dart';
12 13
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/device.dart';
14
import 'package:test/fake.dart';
15 16

import '../../src/common.dart';
17
import '../../src/fake_process_manager.dart';
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42

const FakeCommand kAdbVersionCommand = FakeCommand(
  command: <String>['adb', 'version'],
  stdout: 'Android Debug Bridge version 1.0.39',
);

const FakeCommand kStartServer = FakeCommand(
  command: <String>['adb', 'start-server'],
);

const FakeCommand kShaCommand = FakeCommand(
  command: <String>[
    'adb',
    '-s',
    '1234',
    'shell',
    'echo',
    '-n',
    '',
    '>',
    '/data/local/tmp/sky.FlutterApp.sha1',
  ],
);

void main() {
43 44 45
  late FileSystem fileSystem;
  late FakeProcessManager processManager;
  late AndroidSdk androidSdk;
46 47

  setUp(() {
48
    processManager = FakeProcessManager.empty();
49
    fileSystem = MemoryFileSystem.test();
50
    androidSdk = FakeAndroidSdk();
51 52 53 54 55 56 57
  });

  for (final TargetPlatform targetPlatform in <TargetPlatform>[
    TargetPlatform.android_arm,
    TargetPlatform.android_arm64,
    TargetPlatform.android_x64,
  ]) {
58
    testWithoutContext('AndroidDevice.startApp allows release builds on $targetPlatform', () async {
59 60
      final String arch = getNameForAndroidArch(
        getAndroidArchForName(getNameForTargetPlatform(targetPlatform)));
61 62 63 64
      final AndroidDevice device = AndroidDevice('1234', modelID: 'TestModel',
        fileSystem: fileSystem,
        processManager: processManager,
        logger: BufferLogger.test(),
65
        platform: FakePlatform(),
66 67
        androidSdk: androidSdk,
      );
68
      final File apkFile = fileSystem.file('app-debug.apk')..createSync();
69 70
      final AndroidApk apk = AndroidApk(
        id: 'FlutterApp',
71
        applicationPackage: apkFile,
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
        launchActivity: 'FlutterActivity',
        versionCode: 1,
      );

      processManager.addCommand(kAdbVersionCommand);
      processManager.addCommand(kStartServer);

      // This configures the target platform of the device.
      processManager.addCommand(FakeCommand(
        command: const <String>['adb', '-s', '1234', 'shell', 'getprop'],
        stdout: '[ro.product.cpu.abi]: [$arch]',
      ));
      processManager.addCommand(const FakeCommand(
        command: <String>['adb', '-s', '1234', 'shell', 'am', 'force-stop', 'FlutterApp'],
      ));
      processManager.addCommand(const FakeCommand(
        command: <String>['adb', '-s', '1234', 'shell', 'pm', 'list', 'packages', 'FlutterApp'],
      ));
      processManager.addCommand(const FakeCommand(
91
        command: <String>['adb', '-s', '1234', 'install', '-t', '-r', 'app-debug.apk'],
92 93 94 95 96 97 98 99 100 101 102
      ));
      processManager.addCommand(kShaCommand);
      processManager.addCommand(const FakeCommand(
        command: <String>[
          'adb',
          '-s',
          '1234',
          'shell',
          'am',
          'start',
          '-a',
103 104 105
          'android.intent.action.MAIN',
          '-c',
          'android.intent.category.LAUNCHER',
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
          '-f',
          '0x20000000',
          '--ez', 'enable-dart-profiling', 'true',
          'FlutterActivity',
        ],
      ));

      final LaunchResult launchResult = await device.startApp(
        apk,
        prebuiltApplication: true,
        debuggingOptions: DebuggingOptions.disabled(
          BuildInfo.release,
        ),
        platformArgs: <String, dynamic>{},
      );

      expect(launchResult.started, true);
123
      expect(processManager, hasNoRemainingExpectations);
124 125 126
    });
  }

127 128 129 130 131
  testWithoutContext('AndroidDevice.startApp does not allow release builds on x86', () async {
    final AndroidDevice device = AndroidDevice('1234', modelID: 'TestModel',
      fileSystem: fileSystem,
      processManager: processManager,
      logger: BufferLogger.test(),
132
      platform: FakePlatform(),
133 134
      androidSdk: androidSdk,
    );
135
    final File apkFile = fileSystem.file('app-debug.apk')..createSync();
136 137
    final AndroidApk apk = AndroidApk(
      id: 'FlutterApp',
138
      applicationPackage: apkFile,
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
      launchActivity: 'FlutterActivity',
      versionCode: 1,
    );

    processManager.addCommand(kAdbVersionCommand);
    processManager.addCommand(kStartServer);

    // This configures the target platform of the device.
    processManager.addCommand(const FakeCommand(
      command: <String>['adb', '-s', '1234', 'shell', 'getprop'],
      stdout: '[ro.product.cpu.abi]: [x86]',
    ));

    final LaunchResult launchResult = await device.startApp(
      apk,
      prebuiltApplication: true,
      debuggingOptions: DebuggingOptions.disabled(
        BuildInfo.release,
      ),
      platformArgs: <String, dynamic>{},
    );

    expect(launchResult.started, false);
162
    expect(processManager, hasNoRemainingExpectations);
163 164
  });

165 166 167 168 169
  testWithoutContext('AndroidDevice.startApp forwards all supported debugging options', () async {
    final AndroidDevice device = AndroidDevice('1234', modelID: 'TestModel',
      fileSystem: fileSystem,
      processManager: processManager,
      logger: BufferLogger.test(),
170
      platform: FakePlatform(),
171 172
      androidSdk: androidSdk,
    );
173
    final File apkFile = fileSystem.file('app-debug.apk')..createSync();
174 175
    final AndroidApk apk = AndroidApk(
      id: 'FlutterApp',
176
      applicationPackage: apkFile,
177 178 179 180 181 182 183 184 185 186 187
      launchActivity: 'FlutterActivity',
      versionCode: 1,
    );

    // These commands are required to install and start the app
    processManager.addCommand(kAdbVersionCommand);
    processManager.addCommand(kStartServer);
    processManager.addCommand(const FakeCommand(
      command: <String>['adb', '-s', '1234', 'shell', 'getprop'],
    ));
    processManager.addCommand(const FakeCommand(
188
      command: <String>['adb', '-s', '1234', 'shell', 'am', 'force-stop', '--user', '10', 'FlutterApp'],
189 190
    ));
    processManager.addCommand(const FakeCommand(
191
      command: <String>['adb', '-s', '1234', 'shell', 'pm', 'list', 'packages', '--user', '10', 'FlutterApp'],
192 193
    ));
    processManager.addCommand(const FakeCommand(
194 195 196 197 198 199 200 201 202
      command: <String>[
        'adb',
        '-s',
        '1234',
        'install',
        '-t',
        '-r',
        '--user',
        '10',
203
        'app-debug.apk',
204
      ],
205
      stdout: '\n\nThe Dart VM service is listening on http://127.0.0.1:456\n\n',
206 207 208 209 210 211 212
    ));
    processManager.addCommand(kShaCommand);
    processManager.addCommand(const FakeCommand(
      command: <String>[
        'adb',
        '-s',
        '1234',
213 214
        'shell',
        '-x',
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
        'logcat',
        '-v',
        'time',
      ],
    ));

    // This command contains all launch arguments.
    processManager.addCommand(const FakeCommand(
      command: <String>[
        'adb',
        '-s',
        '1234',
        'shell',
        'am',
        'start',
        '-a',
231 232 233
        'android.intent.action.MAIN',
        '-c',
        'android.intent.category.LAUNCHER',
234 235 236 237 238 239 240
        '-f',
        '0x20000000',
        // The DebuggingOptions arguments go here.
        '--ez', 'enable-dart-profiling', 'true',
        '--ez', 'enable-software-rendering', 'true',
        '--ez', 'skia-deterministic-rendering', 'true',
        '--ez', 'trace-skia', 'true',
241 242
        '--es', 'trace-allowlist', 'bar,baz',
        '--es', 'trace-skia-allowlist', 'skia.a,skia.b',
243 244 245 246
        '--ez', 'trace-systrace', 'true',
        '--ez', 'endless-trace-buffer', 'true',
        '--ez', 'dump-skp-on-shader-compilation', 'true',
        '--ez', 'cache-sksl', 'true',
247
        '--ez', 'purge-persistent-cache', 'true',
248
        '--ez', 'enable-impeller', 'true',
249 250 251 252
        '--ez', 'enable-checked-mode', 'true',
        '--ez', 'verify-entry-points', 'true',
        '--ez', 'start-paused', 'true',
        '--ez', 'disable-service-auth-codes', 'true',
253
        '--es', 'dart-flags', 'foo,--null_assertions',
254 255
        '--ez', 'use-test-fonts', 'true',
        '--ez', 'verbose-logging', 'true',
256
        '--user', '10',
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271
        'FlutterActivity',
      ],
    ));

    final LaunchResult launchResult = await device.startApp(
      apk,
      prebuiltApplication: true,
      debuggingOptions: DebuggingOptions.enabled(
        BuildInfo.debug,
        startPaused: true,
        disableServiceAuthCodes: true,
        dartFlags: 'foo',
        enableSoftwareRendering: true,
        skiaDeterministicRendering: true,
        traceSkia: true,
272
        traceAllowlist: 'bar,baz',
273
        traceSkiaAllowlist: 'skia.a,skia.b',
274 275 276 277
        traceSystrace: true,
        endlessTraceBuffer: true,
        dumpSkpOnShaderCompilation: true,
        cacheSkSL: true,
278
        purgePersistentCache: true,
279 280
        useTestFonts: true,
        verboseSystemLogs: true,
281
        nullAssertions: true,
282
        enableImpeller: true,
283 284
      ),
      platformArgs: <String, dynamic>{},
285
      userIdentifier: '10',
286 287 288 289
    );

    // This fails to start due to observatory discovery issues.
    expect(launchResult.started, false);
290
    expect(processManager, hasNoRemainingExpectations);
291 292 293
  });
}

294 295 296 297 298 299 300
class FakeAndroidSdk extends Fake implements AndroidSdk {
  @override
  String get adbPath => 'adb';

  @override
  bool get licensesAvailable => false;
}