Unverified Commit f6a55125 authored by Jenn Magder's avatar Jenn Magder Committed by GitHub

Add usage event for failed iOS project migration (#51879)

parent 94376395
......@@ -121,7 +121,7 @@ Future<int> _handleToolError(
}
// Report to both [Usage] and [CrashReportSender].
flutterUsage.sendException(error);
globals.flutterUsage.sendException(error);
await CrashReportSender.instance.sendReport(
error: error,
stackTrace: stackTrace,
......@@ -252,13 +252,13 @@ Future<String> _doctorText() async {
Future<int> _exit(int code) async {
// Prints the welcome message if needed.
flutterUsage.printWelcome();
globals.flutterUsage.printWelcome();
// Send any last analytics calls that are in progress without overly delaying
// the tool's exit (we wait a maximum of 250ms).
if (flutterUsage.enabled) {
if (globals.flutterUsage.enabled) {
final Stopwatch stopwatch = Stopwatch()..start();
await flutterUsage.ensureAnalyticsSent();
await globals.flutterUsage.ensureAnalyticsSent();
globals.printTrace('ensureAnalyticsSent: ${stopwatch.elapsedMilliseconds}ms');
}
......
......@@ -396,7 +396,7 @@ Future<void> buildGradleApp({
status.stop();
}
flutterUsage.sendTiming('build', 'gradle', sw.elapsed);
globals.flutterUsage.sendTiming('build', 'gradle', sw.elapsed);
if (exitCode != 0) {
if (detectedGradleError == null) {
......@@ -589,7 +589,7 @@ Future<void> buildGradleAar({
} finally {
status.stop();
}
flutterUsage.sendTiming('build', 'gradle-aar', sw.elapsed);
globals.flutterUsage.sendTiming('build', 'gradle-aar', sw.elapsed);
if (result.exitCode != 0) {
globals.printStatus(result.stdout, wrap: false);
......@@ -684,11 +684,11 @@ String _calculateSha(File file) {
final Stopwatch sw = Stopwatch()..start();
final List<int> bytes = file.readAsBytesSync();
globals.printTrace('calculateSha: reading file took ${sw.elapsedMilliseconds}us');
flutterUsage.sendTiming('build', 'apk-sha-read', sw.elapsed);
globals.flutterUsage.sendTiming('build', 'apk-sha-read', sw.elapsed);
sw.reset();
final String sha = _hex(sha1.convert(bytes).bytes);
globals.printTrace('calculateSha: computing sha took ${sw.elapsedMilliseconds}us');
flutterUsage.sendTiming('build', 'apk-sha-calc', sw.elapsed);
globals.flutterUsage.sendTiming('build', 'apk-sha-calc', sw.elapsed);
return sha;
}
......
......@@ -13,7 +13,6 @@ import '../compile.dart';
import '../globals.dart' as globals;
import '../macos/xcode.dart';
import '../project.dart';
import '../reporting/reporting.dart';
import 'context.dart';
import 'file_system.dart';
......@@ -341,7 +340,7 @@ class AOTSnapshotter {
if (reportTimings) {
globals.printStatus('$marker: ${sw.elapsedMilliseconds} ms.');
}
flutterUsage.sendTiming('build', analyticsVar, Duration(milliseconds: sw.elapsedMilliseconds));
globals.flutterUsage.sendTiming('build', analyticsVar, Duration(milliseconds: sw.elapsedMilliseconds));
return value;
}
}
......@@ -538,7 +538,7 @@ class _ResidentWebRunner extends ResidentWebRunner {
// Don't track restart times for dart2js builds or web-server devices.
if (debuggingOptions.buildInfo.isDebug && deviceIsDebuggable) {
flutterUsage.sendTiming('hot', 'web-incremental-restart', timer.elapsed);
globals.flutterUsage.sendTiming('hot', 'web-incremental-restart', timer.elapsed);
HotEvent(
'restart',
targetPlatform: getNameForTargetPlatform(TargetPlatform.web_javascript),
......
......@@ -89,7 +89,7 @@ class ConfigCommand extends FlutterCommand {
}
return
'\nSettings:\n$values\n\n'
'Analytics reporting is currently ${flutterUsage.enabled ? 'enabled' : 'disabled'}.';
'Analytics reporting is currently ${globals.flutterUsage.enabled ? 'enabled' : 'disabled'}.';
}
/// Return null to disable analytics recording of the `config` command.
......@@ -117,7 +117,7 @@ class ConfigCommand extends FlutterCommand {
// We send the analytics event *before* toggling the flag intentionally
// to be sure that opt-out events are sent correctly.
AnalyticsConfigEvent(enabled: value).send();
flutterUsage.enabled = value;
globals.flutterUsage.enabled = value;
globals.printStatus('Analytics reporting ${value ? 'enabled' : 'disabled'}.');
}
......
......@@ -8,6 +8,7 @@ import '../base/common.dart';
import '../base/os.dart';
import '../cache.dart';
import '../dart/pub.dart';
import '../globals.dart' as globals;
import '../project.dart';
import '../reporting/reporting.dart';
import '../runner/flutter_command.dart';
......@@ -97,11 +98,11 @@ class PackagesGetCommand extends FlutterCommand {
checkLastModified: false,
);
pubGetTimer.stop();
flutterUsage.sendTiming('pub', 'get', pubGetTimer.elapsed, label: 'success');
globals.flutterUsage.sendTiming('pub', 'get', pubGetTimer.elapsed, label: 'success');
// Not limiting to catching Exception because the exception is rethrown.
} catch (_) { // ignore: avoid_catches_without_on_clauses
pubGetTimer.stop();
flutterUsage.sendTiming('pub', 'get', pubGetTimer.elapsed, label: 'failure');
globals.flutterUsage.sendTiming('pub', 'get', pubGetTimer.elapsed, label: 'failure');
rethrow;
}
}
......
......@@ -20,7 +20,6 @@ import '../convert.dart';
import '../devfs.dart';
import '../globals.dart' as globals;
import '../project.dart';
import '../reporting/reporting.dart';
import 'fuchsia_pm.dart';
import 'fuchsia_sdk.dart';
......@@ -29,7 +28,7 @@ Future<void> _timedBuildStep(String name, Future<void> Function() action) async
final Stopwatch sw = Stopwatch()..start();
await action();
globals.printTrace('$name: ${sw.elapsedMilliseconds} ms.');
flutterUsage.sendTiming('build', name, Duration(milliseconds: sw.elapsedMilliseconds));
globals.flutterUsage.sendTiming('build', name, Duration(milliseconds: sw.elapsedMilliseconds));
}
Future<void> _validateCmxFile(FuchsiaProject fuchsiaProject) async {
......
......@@ -26,6 +26,7 @@ import 'ios/mac.dart';
import 'ios/plist_parser.dart';
import 'macos/xcode.dart';
import 'persistent_tool_state.dart';
import 'reporting/reporting.dart';
import 'version.dart';
import 'web/chrome.dart';
......@@ -35,6 +36,7 @@ Config get config => context.get<Config>();
Logger get logger => context.get<Logger>();
OperatingSystemUtils get os => context.get<OperatingSystemUtils>();
PersistentToolState get persistentToolState => PersistentToolState.instance;
Usage get flutterUsage => context.get<Usage>();
const FileSystem _kLocalFs = LocalFileSystem();
......
......@@ -9,6 +9,7 @@ import 'package:vm_service/vm_service_io.dart' as vm_service_io;
import '../base/io.dart';
import '../base/logger.dart';
import '../device.dart';
import '../globals.dart' as globals;
import '../mdns_discovery.dart';
import '../protocol_discovery.dart';
import '../reporting/reporting.dart';
......@@ -82,18 +83,18 @@ class FallbackDiscovery {
hostVmservicePort: hostVmservicePort,
);
if (result != null) {
UsageEvent(_kEventName, 'mdns-success').send();
UsageEvent(_kEventName, 'mdns-success', flutterUsage: globals.flutterUsage).send();
return result;
}
} on Exception catch (err) {
_logger.printTrace(err.toString());
}
_logger.printTrace('Failed to connect with mDNS, falling back to log scanning');
UsageEvent(_kEventName, 'mdns-failure').send();
UsageEvent(_kEventName, 'mdns-failure', flutterUsage: globals.flutterUsage).send();
try {
final Uri result = await _protocolDiscovery.uri;
UsageEvent(_kEventName, 'fallback-success').send();
UsageEvent(_kEventName, 'fallback-success', flutterUsage: globals.flutterUsage).send();
return result;
} on ArgumentError {
// In the event of an invalid InternetAddress, this code attempts to catch
......@@ -102,7 +103,7 @@ class FallbackDiscovery {
_logger.printTrace(err.toString());
}
_logger.printTrace('Failed to connect with log scanning');
UsageEvent(_kEventName, 'fallback-failure').send();
UsageEvent(_kEventName, 'fallback-failure', flutterUsage: globals.flutterUsage).send();
return null;
}
......@@ -141,7 +142,7 @@ class FallbackDiscovery {
}
final LibraryRef library = (isolateResponse as Isolate).rootLib;
if (library.uri.startsWith('package:$packageName')) {
UsageEvent(_kEventName, 'success').send();
UsageEvent(_kEventName, 'success', flutterUsage: globals.flutterUsage).send();
return Uri.parse('http://localhost:$hostPort');
}
}
......@@ -180,6 +181,7 @@ class FallbackDiscovery {
_kEventName,
eventAction,
label: eventLabel,
flutterUsage: globals.flutterUsage,
).send();
}
}
......@@ -90,13 +90,12 @@ Future<XcodeBuildResult> buildXcodeProject({
}
final List<IOSMigrator> migrators = <IOSMigrator>[
RemoveFrameworkLinkAndEmbeddingMigration(app.project, globals.logger, globals.xcode)
RemoveFrameworkLinkAndEmbeddingMigration(app.project, globals.logger, globals.xcode, globals.flutterUsage)
];
for (final IOSMigrator migrator in migrators) {
if (!migrator.migrate()) {
return XcodeBuildResult(success: false);
}
final IOSMigration migration = IOSMigration(migrators);
if (!migration.run()) {
return XcodeBuildResult(success: false);
}
if (!_checkXcodeVersion()) {
......@@ -302,7 +301,7 @@ Future<XcodeBuildResult> buildXcodeProject({
'Xcode build done.'.padRight(kDefaultStatusPadding + 1)
+ getElapsedAsSeconds(sw.elapsed).padLeft(5),
);
flutterUsage.sendTiming('build', 'xcode-ios', Duration(milliseconds: sw.elapsedMilliseconds));
globals.flutterUsage.sendTiming('build', 'xcode-ios', Duration(milliseconds: sw.elapsedMilliseconds));
// Run -showBuildSettings again but with the exact same parameters as the
// build. showBuildSettings is reported to ocassionally timeout. Here, we give
......
......@@ -10,20 +10,20 @@ import '../../base/logger.dart';
/// iOS project is generated from a template on Flutter project creation.
/// Sometimes (due to behavior changes in Xcode, CocoaPods, etc) these files need to be altered
/// from the original template.
class IOSMigrator {
abstract class IOSMigrator {
IOSMigrator(this.logger);
@protected
final Logger logger;
/// Returns whether migration was successful or was skipped.
bool migrate() {
return false;
}
bool migrate();
/// Return null if the line should be deleted.
String migrateLine(String line);
/// [processLine] should return null if the line should be deleted.
@protected
void processFileLines(File file, String Function(String) processLine) {
void processFileLines(File file) {
final List<String> lines = file.readAsLinesSync();
final StringBuffer newProjectContents = StringBuffer();
......@@ -31,7 +31,7 @@ class IOSMigrator {
bool migrationRequired = false;
for (final String line in lines) {
final String newProjectLine = processLine(line);
final String newProjectLine = migrateLine(line);
if (newProjectLine == null) {
logger.printTrace('Migrating $basename, removing:');
logger.printTrace(' $line');
......@@ -54,3 +54,21 @@ class IOSMigrator {
}
}
}
class IOSMigration {
IOSMigration(this.migrators);
final List<IOSMigrator> migrators;
bool run() {
for (final IOSMigrator migrator in migrators) {
if (!migrator.migrate()) {
// Migration failures should be more robust, with transactions and fallbacks.
// See https://github.com/flutter/flutter/issues/12573 and
// https://github.com/flutter/flutter/issues/40460
return false;
}
}
return true;
}
}
......@@ -2,10 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import '../../base/common.dart';
import '../../base/file_system.dart';
import '../../base/logger.dart';
import '../../macos/xcode.dart';
import '../../project.dart';
import '../../reporting/reporting.dart';
import 'ios_migrator.dart';
/// Xcode 11.4 requires linked and embedded frameworks to contain all targeted architectures before build phases are run.
......@@ -13,15 +15,18 @@ import 'ios_migrator.dart';
/// Remove the linking and embedding logic from the Xcode project to give the tool more control over these.
class RemoveFrameworkLinkAndEmbeddingMigration extends IOSMigrator {
RemoveFrameworkLinkAndEmbeddingMigration(
IosProject project,
Logger logger,
Xcode xcode,
) : _xcodeProjectInfoFile = project.xcodeProjectInfoFile,
IosProject project,
Logger logger,
Xcode xcode,
Usage usage,
) : _xcodeProjectInfoFile = project.xcodeProjectInfoFile,
_xcode = xcode,
_usage = usage,
super(logger);
final File _xcodeProjectInfoFile;
final Xcode _xcode;
final Usage _usage;
/// Inspect [project] for necessary migrations and rewrite files as needed.
@override
......@@ -35,78 +40,76 @@ class RemoveFrameworkLinkAndEmbeddingMigration extends IOSMigrator {
return true;
}
bool migrationFailure = false;
processFileLines(_xcodeProjectInfoFile, (String line) {
// App.framework Frameworks reference.
// isa = PBXFrameworksBuildPhase;
// files = (
// 3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
if (line.contains('3B80C3941E831B6300D905FE')) {
return null;
}
processFileLines(_xcodeProjectInfoFile);
// App.framework Embed Framework reference (build phase to embed framework).
// 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
if (line.contains('3B80C3951E831B6300D905FE')
|| line.contains('741F496821356857001E2961')) { // Ephemeral add-to-app variant.
return null;
}
return true;
}
// App.framework project file reference (seen in Xcode navigator pane).
// isa = PBXGroup;
// children = (
// 3B80C3931E831B6300D905FE /* App.framework */,
if (line.contains('3B80C3931E831B6300D905FE')
|| line.contains('741F496521356807001E2961')) { // Ephemeral add-to-app variant.
return null;
}
@override
String migrateLine(String line) {
// App.framework Frameworks reference.
// isa = PBXFrameworksBuildPhase;
// files = (
// 3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
if (line.contains('3B80C3941E831B6300D905FE')) {
return null;
}
// Flutter.framework Frameworks reference.
// isa = PBXFrameworksBuildPhase;
// files = (
// 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
if (line.contains('9705A1C61CF904A100538489')) {
return null;
}
// App.framework Embed Framework reference (build phase to embed framework).
// 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
if (line.contains('3B80C3951E831B6300D905FE')
|| line.contains('741F496821356857001E2961')) { // Ephemeral add-to-app variant.
return null;
}
// Flutter.framework Embed Framework reference (build phase to embed framework).
// 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
if (line.contains('9705A1C71CF904A300538489')
|| line.contains('741F496221355F47001E2961')) { // Ephemeral add-to-app variant.
return null;
}
// App.framework project file reference (seen in Xcode navigator pane).
// isa = PBXGroup;
// children = (
// 3B80C3931E831B6300D905FE /* App.framework */,
if (line.contains('3B80C3931E831B6300D905FE')
|| line.contains('741F496521356807001E2961')) { // Ephemeral add-to-app variant.
return null;
}
// Flutter.framework project file reference (seen in Xcode navigator pane).
// isa = PBXGroup;
// children = (
// 9740EEBA1CF902C7004384FC /* Flutter.framework */,
if (line.contains('9740EEBA1CF902C7004384FC')
|| line.contains('741F495E21355F27001E2961')) { // Ephemeral add-to-app variant.
return null;
}
// Flutter.framework Frameworks reference.
// isa = PBXFrameworksBuildPhase;
// files = (
// 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
if (line.contains('9705A1C61CF904A100538489')) {
return null;
}
// Embed and thin frameworks in a script instead of using Xcode's link / embed build phases.
const String thinBinaryScript = 'xcode_backend.sh\\" thin';
if (line.contains(thinBinaryScript) && !line.contains(' embed')) {
return line.replaceFirst(thinBinaryScript, 'xcode_backend.sh\\" embed_and_thin');
}
// Flutter.framework Embed Framework reference (build phase to embed framework).
// 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
if (line.contains('9705A1C71CF904A300538489')
|| line.contains('741F496221355F47001E2961')) { // Ephemeral add-to-app variant.
return null;
}
if (line.contains('/* App.framework ') || line.contains('/* Flutter.framework ')) {
migrationFailure = true;
}
// Flutter.framework project file reference (seen in Xcode navigator pane).
// isa = PBXGroup;
// children = (
// 9740EEBA1CF902C7004384FC /* Flutter.framework */,
if (line.contains('9740EEBA1CF902C7004384FC')
|| line.contains('741F495E21355F27001E2961')) { // Ephemeral add-to-app variant.
return null;
}
return line;
});
// Embed and thin frameworks in a script instead of using Xcode's link / embed build phases.
const String thinBinaryScript = 'xcode_backend.sh\\" thin';
if (line.contains(thinBinaryScript) && !line.contains(' embed')) {
return line.replaceFirst(thinBinaryScript, 'xcode_backend.sh\\" embed_and_thin');
}
if (migrationFailure) {
if (line.contains('/* App.framework ') || line.contains('/* Flutter.framework ')) {
// Print scary message if the user is on Xcode 11.4 or greater, or if Xcode isn't installed.
final bool xcodeIsInstalled = _xcode.isInstalled;
if(!xcodeIsInstalled || (_xcode.majorVersion > 11 || (_xcode.majorVersion == 11 && _xcode.minorVersion >= 4))) {
logger.printError('Your Xcode project requires migration. See https://flutter.dev/docs/development/ios-project-migration for details.');
return false;
UsageEvent('ios-migration', 'remove-frameworks', label: 'failure', flutterUsage: _usage).send();
throwToolExit('Your Xcode project requires migration. See https://flutter.dev/docs/development/ios-project-migration for details.');
}
}
return true;
return line;
}
}
......@@ -12,7 +12,6 @@ import '../cache.dart';
import '../globals.dart' as globals;
import '../plugins.dart';
import '../project.dart';
import '../reporting/reporting.dart';
/// Builds the Linux project through the Makefile.
Future<void> buildLinux(LinuxProject linuxProject, BuildInfo buildInfo, {String target = 'lib/main.dart'}) async {
......@@ -88,7 +87,7 @@ export PROJECT_DIR=${linuxProject.project.directory.path}
if (result != 0) {
throwToolExit('Build process failed');
}
flutterUsage.sendTiming('build', 'make-linux', Duration(milliseconds: sw.elapsedMilliseconds));
globals.flutterUsage.sendTiming('build', 'make-linux', Duration(milliseconds: sw.elapsedMilliseconds));
}
// Checks the template version of [project] against the current template
......
......@@ -10,7 +10,6 @@ import '../build_info.dart';
import '../globals.dart' as globals;
import '../ios/xcodeproj.dart';
import '../project.dart';
import '../reporting/reporting.dart';
import 'cocoapod_utils.dart';
/// Builds the macOS project through xcodebuild.
......@@ -93,5 +92,5 @@ Future<void> buildMacOS({
if (result != 0) {
throwToolExit('Build process failed');
}
flutterUsage.sendTiming('build', 'xcode-macos', Duration(milliseconds: sw.elapsedMilliseconds));
globals.flutterUsage.sendTiming('build', 'xcode-macos', Duration(milliseconds: sw.elapsedMilliseconds));
}
......@@ -326,7 +326,7 @@ class XCDevice {
if (errorProperties != null) {
final String errorMessage = _parseErrorMessage(errorProperties);
if (errorMessage.contains('not paired')) {
UsageEvent('device', 'ios-trust-failure').send();
UsageEvent('device', 'ios-trust-failure', flutterUsage: globals.flutterUsage).send();
}
_logger.printTrace(errorMessage);
......
......@@ -189,7 +189,7 @@ class MDnsObservatoryDiscovery {
final TargetPlatform targetPlatform = await device.targetPlatform;
switch (targetPlatform) {
case TargetPlatform.ios:
UsageEvent('ios-mdns', 'no-ipv4-link-local').send();
UsageEvent('ios-mdns', 'no-ipv4-link-local', flutterUsage: globals.flutterUsage).send();
globals.printError(
'The mDNS query for an attached iOS device failed. It may '
'be necessary to disable the "Personal Hotspot" on the device, and '
......
......@@ -53,7 +53,7 @@ class CrashReportSender {
}
final http.Client _client;
final Usage _usage = Usage.instance;
final Usage _usage = globals.flutterUsage;
Uri get _baseUrl {
final String overrideUrl = globals.platform.environment['FLUTTER_CRASH_SERVER_BASE_URL'];
......
......@@ -12,12 +12,14 @@ class UsageEvent {
UsageEvent(this.category, this.parameter, {
this.label,
this.value,
@required this.flutterUsage,
});
final String category;
final String parameter;
final String label;
final int value;
final Usage flutterUsage;
void send() {
flutterUsage.sendEvent(category, parameter, label: label, value: value);
......@@ -46,7 +48,7 @@ class HotEvent extends UsageEvent {
this.invalidatedSourcesCount,
this.transferTimeInMs,
this.overallTimeInMs,
}) : super('hot', parameter);
}) : super('hot', parameter, flutterUsage: globals.flutterUsage);
final String reason;
final String targetPlatform;
......@@ -101,6 +103,7 @@ class DoctorResultEvent extends UsageEvent {
'doctor-result',
'${validator.runtimeType}',
label: result.typeStr,
flutterUsage: globals.flutterUsage,
);
final DoctorValidator validator;
......@@ -126,7 +129,7 @@ class PubResultEvent extends UsageEvent {
PubResultEvent({
@required String context,
@required String result,
}) : super('pub-result', context, label: result);
}) : super('pub-result', context, label: result, flutterUsage: globals.flutterUsage);
}
/// An event that reports something about a build.
......@@ -143,6 +146,7 @@ class BuildEvent extends UsageEvent {
? 'unspecified'
: FlutterCommand.current.name,
label: label,
flutterUsage: globals.flutterUsage,
);
final String command;
......@@ -173,7 +177,7 @@ class CommandResultEvent extends UsageEvent {
CommandResultEvent(String commandPath, FlutterCommandResult result)
: assert(commandPath != null),
assert(result != null),
super(commandPath, result.toString());
super(commandPath, result.toString(), flutterUsage: globals.flutterUsage);
@override
void send() {
......@@ -211,5 +215,6 @@ class AnalyticsConfigEvent extends UsageEvent {
'analytics',
'enabled',
label: enabled ? 'true' : 'false',
flutterUsage: globals.flutterUsage,
);
}
......@@ -10,7 +10,6 @@ import 'package:http/http.dart' as http;
import 'package:meta/meta.dart';
import 'package:usage/usage_io.dart';
import '../base/context.dart';
import '../base/file_system.dart';
import '../base/io.dart';
import '../base/time.dart';
......
......@@ -66,8 +66,6 @@ Map<String, String> _useCdKeys(Map<CustomDimensions, String> parameters) {
MapEntry<String, String>(cdKey(k), v));
}
Usage get flutterUsage => Usage.instance;
abstract class Usage {
/// Create a new Usage instance; [versionOverride], [configDirOverride], and
/// [logFile] are used for testing.
......@@ -83,13 +81,10 @@ abstract class Usage {
logFile: logFile,
runningOnBot: runningOnBot);
/// Returns [Usage] active in the current app context.
static Usage get instance => context.get<Usage>();
/// Uses the global [Usage] instance to send a 'command' to analytics.
static void command(String command, {
Map<CustomDimensions, String> parameters,
}) => flutterUsage.sendCommand(command, parameters: _useCdKeys(parameters));
}) => globals.flutterUsage.sendCommand(command, parameters: _useCdKeys(parameters));
/// Whether this is the first run of the tool.
bool get isFirstRun;
......
......@@ -197,7 +197,7 @@ class HotRunner extends ResidentRunner {
}
globals.printStatus('reloadMethod took ${stopwatch.elapsedMilliseconds}');
flutterUsage.sendTiming('hot', 'ui', stopwatch.elapsed);
globals.flutterUsage.sendTiming('hot', 'ui', stopwatch.elapsed);
return OperationResult.ok;
}
......@@ -550,7 +550,7 @@ class HotRunner extends ResidentRunner {
restartTimer.elapsed.inMilliseconds);
// Send timing analytics.
flutterUsage.sendTiming('hot', 'restart', restartTimer.elapsed);
globals.flutterUsage.sendTiming('hot', 'restart', restartTimer.elapsed);
// In benchmark mode, make sure all stream notifications have finished.
if (benchmarkMode) {
......@@ -1024,7 +1024,7 @@ class HotRunner extends ResidentRunner {
}
// Only report timings if we reloaded a single view without any errors.
if ((reassembleViews.length == 1) && !failedReassemble && shouldReportReloadTime) {
flutterUsage.sendTiming('hot', 'reload', reloadDuration);
globals.flutterUsage.sendTiming('hot', 'reload', reloadDuration);
}
return OperationResult(
failedReassemble ? 1 : OperationResult.ok.code,
......
......@@ -601,7 +601,7 @@ abstract class FlutterCommand extends Command<void> {
overrides: <Type, Generator>{FlutterCommand: () => this},
body: () async {
// Prints the welcome message if needed.
flutterUsage.printWelcome();
globals.flutterUsage.printWelcome();
final String commandPath = await usagePath;
_registerSignalHandlers(commandPath, startTime);
FlutterCommandResult commandResult = FlutterCommandResult.fail();
......@@ -657,7 +657,7 @@ abstract class FlutterCommand extends Command<void> {
final String label = labels
.where((String label) => !isBlank(label))
.join('-');
flutterUsage.sendTiming(
globals.flutterUsage.sendTiming(
'flutter',
name,
// If the command provides its own end time, use it. Otherwise report
......
......@@ -23,7 +23,6 @@ import '../convert.dart';
import '../dart/package_map.dart';
import '../device.dart';
import '../globals.dart' as globals;
import '../reporting/reporting.dart';
import '../tester/flutter_tester.dart';
const String kFlutterRootEnvironmentVariableName = 'FLUTTER_ROOT'; // should point to //flutter/ (root of flutter/flutter repo)
......@@ -298,7 +297,7 @@ class FlutterCommandRunner extends CommandRunner<void> {
}
if (topLevelResults['suppress-analytics'] as bool) {
flutterUsage.suppressAnalytics = true;
globals.flutterUsage.suppressAnalytics = true;
}
_checkFlutterCopy();
......@@ -322,7 +321,7 @@ class FlutterCommandRunner extends CommandRunner<void> {
deviceManager.specifiedDeviceId = topLevelResults['device-id'] as String;
if (topLevelResults['version'] as bool) {
flutterUsage.sendCommand('version');
globals.flutterUsage.sendCommand('version');
String status;
if (machineFlag) {
status = const JsonEncoder.withIndent(' ').convert(globals.flutterVersion.toJson());
......
......@@ -18,7 +18,6 @@ import '../globals.dart' as globals;
import '../platform_plugins.dart';
import '../plugins.dart';
import '../project.dart';
import '../reporting/reporting.dart';
/// The [WebCompilationProxy] instance.
WebCompilationProxy get webCompilationProxy => context.get<WebCompilationProxy>();
......@@ -71,7 +70,7 @@ Future<void> buildWeb(
} finally {
status.stop();
}
flutterUsage.sendTiming('build', 'dart2js', Duration(milliseconds: sw.elapsedMilliseconds));
globals.flutterUsage.sendTiming('build', 'dart2js', Duration(milliseconds: sw.elapsedMilliseconds));
}
/// An indirection on web compilation.
......
......@@ -12,7 +12,6 @@ import '../cache.dart';
import '../globals.dart' as globals;
import '../plugins.dart';
import '../project.dart';
import '../reporting/reporting.dart';
import 'property_sheet.dart';
import 'visual_studio.dart';
......@@ -76,7 +75,7 @@ Future<void> buildWindows(WindowsProject windowsProject, BuildInfo buildInfo, {S
if (result != 0) {
throwToolExit('Build process failed. To view the stack trace, please run `flutter run -d windows -v`.');
}
flutterUsage.sendTiming('build', 'vs_build', Duration(milliseconds: sw.elapsedMilliseconds));
globals.flutterUsage.sendTiming('build', 'vs_build', Duration(milliseconds: sw.elapsedMilliseconds));
}
/// Writes the generatedPropertySheetFile with the configuration for the given build.
......
......@@ -48,18 +48,18 @@ void main() {
// Ensure we don't send anything when analytics is disabled.
testUsingContext("doesn't send when disabled", () async {
int count = 0;
flutterUsage.onSend.listen((Map<String, dynamic> data) => count++);
globals.flutterUsage.onSend.listen((Map<String, dynamic> data) => count++);
flutterUsage.enabled = false;
globals.flutterUsage.enabled = false;
await createProject(tempDir);
expect(count, 0);
flutterUsage.enabled = true;
globals.flutterUsage.enabled = true;
await createProject(tempDir);
expect(count, flutterUsage.isFirstRun ? 0 : 4);
expect(count, globals.flutterUsage.isFirstRun ? 0 : 4);
count = 0;
flutterUsage.enabled = false;
globals.flutterUsage.enabled = false;
final DoctorCommand doctorCommand = DoctorCommand();
final CommandRunner<void>runner = createTestCommandRunner(doctorCommand);
await runner.run(<String>['doctor']);
......@@ -76,15 +76,15 @@ void main() {
// Ensure we don't send for the 'flutter config' command.
testUsingContext("config doesn't send", () async {
int count = 0;
flutterUsage.onSend.listen((Map<String, dynamic> data) => count++);
globals.flutterUsage.onSend.listen((Map<String, dynamic> data) => count++);
flutterUsage.enabled = false;
globals.flutterUsage.enabled = false;
final ConfigCommand command = ConfigCommand();
final CommandRunner<void> runner = createTestCommandRunner(command);
await runner.run(<String>['config']);
expect(count, 0);
flutterUsage.enabled = true;
globals.flutterUsage.enabled = true;
await runner.run(<String>['config']);
expect(count, 0);
}, overrides: <Type, Generator>{
......@@ -282,7 +282,7 @@ void main() {
testUsingContext("don't send on bots with unknown version", () async {
int count = 0;
flutterUsage.onSend.listen((Map<String, dynamic> data) => count++);
globals.flutterUsage.onSend.listen((Map<String, dynamic> data) => count++);
await createTestCommandRunner().run(<String>['--version']);
expect(count, 0);
......@@ -297,8 +297,8 @@ void main() {
testUsingContext("don't send on bots even when opted in", () async {
int count = 0;
flutterUsage.onSend.listen((Map<String, dynamic> data) => count++);
flutterUsage.enabled = true;
globals.flutterUsage.onSend.listen((Map<String, dynamic> data) => count++);
globals.flutterUsage.enabled = true;
await createTestCommandRunner().run(<String>['--version']);
expect(count, 0);
......
......@@ -192,7 +192,7 @@ void main() {
testUsingContext('analytics sent on success', () async {
MockDirectory.findCache = true;
await pub.get(context: PubContext.flutterTests, checkLastModified: false);
verify(flutterUsage.sendEvent('pub-result', 'flutter-tests', label: 'success')).called(1);
verify(globals.flutterUsage.sendEvent('pub-result', 'flutter-tests', label: 'success')).called(1);
}, overrides: <Type, Generator>{
FileSystem: () => MockFileSystem(),
ProcessManager: () => MockProcessManager(0),
......@@ -212,7 +212,7 @@ void main() {
} on ToolExit {
// Ignore.
}
verify(flutterUsage.sendEvent('pub-result', 'flutter-tests', label: 'failure')).called(1);
verify(globals.flutterUsage.sendEvent('pub-result', 'flutter-tests', label: 'failure')).called(1);
}, overrides: <Type, Generator>{
FileSystem: () => MockFileSystem(),
ProcessManager: () => MockProcessManager(1),
......@@ -232,7 +232,7 @@ void main() {
} on ToolExit {
// Ignore.
}
verify(flutterUsage.sendEvent('pub-result', 'flutter-tests', label: 'version-solving-failed')).called(1);
verify(globals.flutterUsage.sendEvent('pub-result', 'flutter-tests', label: 'version-solving-failed')).called(1);
}, overrides: <Type, Generator>{
FileSystem: () => MockFileSystem(),
ProcessManager: () => MockProcessManager(
......
......@@ -223,7 +223,7 @@ void main() {
final OperationResult result = await residentRunner.restart(fullRestart: false);
expect(result.fatal, true);
expect(result.code, 1);
verify(flutterUsage.sendEvent('hot', 'exception', parameters: <String, String>{
verify(globals.flutterUsage.sendEvent('hot', 'exception', parameters: <String, String>{
cdKey(CustomDimensions.hotEventTargetPlatform):
getNameForTargetPlatform(TargetPlatform.android_arm),
cdKey(CustomDimensions.hotEventSdkName): 'Example',
......@@ -254,7 +254,7 @@ void main() {
final OperationResult result = await residentRunner.restart(fullRestart: false);
expect(result.fatal, false);
expect(result.code, 0);
expect(verify(flutterUsage.sendEvent('hot', 'reload',
expect(verify(globals.flutterUsage.sendEvent('hot', 'reload',
parameters: captureAnyNamed('parameters'))).captured[0],
containsPair(cdKey(CustomDimensions.hotEventTargetPlatform),
getNameForTargetPlatform(TargetPlatform.android_arm)),
......@@ -284,7 +284,7 @@ void main() {
final OperationResult result = await residentRunner.restart(fullRestart: true);
expect(result.fatal, false);
expect(result.code, 0);
expect(verify(flutterUsage.sendEvent('hot', 'restart',
expect(verify(globals.flutterUsage.sendEvent('hot', 'restart',
parameters: captureAnyNamed('parameters'))).captured[0],
containsPair(cdKey(CustomDimensions.hotEventTargetPlatform),
getNameForTargetPlatform(TargetPlatform.android_arm)),
......@@ -328,7 +328,7 @@ void main() {
final OperationResult result = await residentRunner.restart(fullRestart: true);
expect(result.fatal, true);
expect(result.code, 1);
verify(flutterUsage.sendEvent('hot', 'exception', parameters: <String, String>{
verify(globals.flutterUsage.sendEvent('hot', 'exception', parameters: <String, String>{
cdKey(CustomDimensions.hotEventTargetPlatform):
getNameForTargetPlatform(TargetPlatform.android_arm),
cdKey(CustomDimensions.hotEventSdkName): 'Example',
......
......@@ -324,7 +324,7 @@ void main() {
expect(result.code, 0);
verify(mockResidentCompiler.accept()).called(2);
// ensure that analytics are sent.
final Map<String, String> config = verify(Usage.instance.sendEvent('hot', 'restart',
final Map<String, String> config = verify(globals.flutterUsage.sendEvent('hot', 'restart',
parameters: captureAnyNamed('parameters'))).captured.first as Map<String, String>;
expect(config, allOf(<Matcher>[
......@@ -333,7 +333,7 @@ void main() {
containsPair('cd29', 'false'),
containsPair('cd30', 'true'),
]));
verify(Usage.instance.sendTiming('hot', 'web-incremental-restart', any)).called(1);
verify(globals.flutterUsage.sendTiming('hot', 'web-incremental-restart', any)).called(1);
}, overrides: <Type, Generator>{
Usage: () => MockFlutterUsage(),
}));
......@@ -377,7 +377,7 @@ void main() {
expect(result.code, 0);
verify(mockResidentCompiler.accept()).called(2);
// ensure that analytics are sent.
final Map<String, String> config = verify(Usage.instance.sendEvent('hot', 'restart',
final Map<String, String> config = verify(globals.flutterUsage.sendEvent('hot', 'restart',
parameters: captureAnyNamed('parameters'))).captured.first as Map<String, String>;
expect(config, allOf(<Matcher>[
......@@ -386,7 +386,7 @@ void main() {
containsPair('cd29', 'false'),
containsPair('cd30', 'true'),
]));
verify(Usage.instance.sendTiming('hot', 'web-incremental-restart', any)).called(1);
verify(globals.flutterUsage.sendTiming('hot', 'web-incremental-restart', any)).called(1);
}, overrides: <Type, Generator>{
Usage: () => MockFlutterUsage(),
}));
......@@ -422,7 +422,7 @@ void main() {
expect(result.code, 0);
verify(mockResidentCompiler.accept()).called(2);
// ensure that analytics are sent.
verifyNever(Usage.instance.sendTiming('hot', 'web-incremental-restart', any));
verifyNever(globals.flutterUsage.sendTiming('hot', 'web-incremental-restart', any));
}, overrides: <Type, Generator>{
Usage: () => MockFlutterUsage(),
}));
......@@ -455,7 +455,7 @@ void main() {
));
expect(await residentWebRunner.run(), 1);
verifyNever(Usage.instance.sendTiming('hot', 'web-restart', any));
verifyNever(globals.flutterUsage.sendTiming('hot', 'web-restart', any));
}, overrides: <Type, Generator>{
Usage: () => MockFlutterUsage(),
}));
......@@ -488,7 +488,7 @@ void main() {
expect(result.code, 1);
expect(result.message, contains('Failed to recompile application.'));
verifyNever(Usage.instance.sendTiming('hot', 'web-restart', any));
verifyNever(globals.flutterUsage.sendTiming('hot', 'web-restart', any));
}, overrides: <Type, Generator>{
Usage: () => MockFlutterUsage(),
}));
......
......@@ -10,6 +10,7 @@ import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart' as io;
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import 'package:flutter_tools/src/reporting/github_template.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:flutter_tools/src/runner/flutter_command.dart';
......@@ -67,7 +68,7 @@ void main() {
// exception on the first attempt, the second attempt tries to report the
// *original* crash, and not the crash from the first crash report
// attempt.
final CrashingUsage crashingUsage = flutterUsage as CrashingUsage;
final CrashingUsage crashingUsage = globals.flutterUsage as CrashingUsage;
expect(crashingUsage.sentException, 'an exception % --');
}, overrides: <Type, Generator>{
Platform: () => FakePlatform(environment: <String, String>{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment