send ext.flutter.debugDumpApp; ext.flutter.reassemble (#4810) * send ext.flutter.debugDumpApp; ext.flutter.reassemble * expose debugDumpRenderTree
diff --git a/packages/flutter/lib/src/rendering/binding.dart b/packages/flutter/lib/src/rendering/binding.dart index 7b9838d..aae4567 100644 --- a/packages/flutter/lib/src/rendering/binding.dart +++ b/packages/flutter/lib/src/rendering/binding.dart
@@ -57,6 +57,14 @@ }); assert(() { + registerSignalServiceExtension( + name: 'debugDumpRenderTree', + callback: debugDumpRenderTree + ); + return true; + }); + + assert(() { // this service extension only works in checked mode registerBoolServiceExtension( name: 'repaintRainbow',
diff --git a/packages/flutter/lib/src/widgets/binding.dart b/packages/flutter/lib/src/widgets/binding.dart index e2c98c1..d4a134a 100644 --- a/packages/flutter/lib/src/widgets/binding.dart +++ b/packages/flutter/lib/src/widgets/binding.dart
@@ -72,6 +72,11 @@ void initServiceExtensions() { super.initServiceExtensions(); + registerSignalServiceExtension( + name: 'debugDumpApp', + callback: debugDumpApp + ); + registerBoolServiceExtension( name: 'showPerformanceOverlay', getter: () => WidgetsApp.showPerformanceOverlayOverride,
diff --git a/packages/flutter_tools/lib/src/device.dart b/packages/flutter_tools/lib/src/device.dart index e23e27e..6786712 100644 --- a/packages/flutter_tools/lib/src/device.dart +++ b/packages/flutter_tools/lib/src/device.dart
@@ -191,6 +191,8 @@ bool get supportsRestart => false; + bool get restartSendsFrameworkInitEvent => true; + /// Restart the given app; the application will already have been launched with /// [startApp]. Future<bool> restartApp(
diff --git a/packages/flutter_tools/lib/src/ios/simulators.dart b/packages/flutter_tools/lib/src/ios/simulators.dart index 7f71142..6cf8a4e 100644 --- a/packages/flutter_tools/lib/src/ios/simulators.dart +++ b/packages/flutter_tools/lib/src/ios/simulators.dart
@@ -579,6 +579,9 @@ bool get supportsRestart => run.useReloadSources; @override + bool get restartSendsFrameworkInitEvent => false; + + @override Future<bool> restartApp( ApplicationPackage package, LaunchResult result, { @@ -587,7 +590,15 @@ }) async { if (observatory.firstIsolateId == null) throw 'Application isolate not found'; - return observatory.reloadSources(observatory.firstIsolateId); + Event result = await observatory.reloadSources(observatory.firstIsolateId); + dynamic error = result.response['reloadError']; + if (error != null) { + printError('Error reloading application sources: $error'); + return false; + } else { + await observatory.flutterReassemble(observatory.firstIsolateId); + return true; + } } @override
diff --git a/packages/flutter_tools/lib/src/observatory.dart b/packages/flutter_tools/lib/src/observatory.dart index 37f8de4..5ec6750 100644 --- a/packages/flutter_tools/lib/src/observatory.dart +++ b/packages/flutter_tools/lib/src/observatory.dart
@@ -9,8 +9,6 @@ import 'package:json_rpc_2/json_rpc_2.dart' as rpc; import 'package:web_socket_channel/io.dart'; -import 'globals.dart'; - class Observatory { Observatory._(this.peer, this.port) { peer.registerMethod('streamNotify', (rpc.Parameters event) { @@ -115,7 +113,7 @@ }); } - Future<bool> reloadSources(String isolateId) async { + Future<Response> reloadSources(String isolateId) async { Completer<Event> whenIsolateReloads = new Completer<Event>(); StreamSubscription<Event> sub = onIsolateEvent .where((Event event) => event.kind == 'IsolateReload') @@ -123,11 +121,7 @@ try { await sendRequest('_reloadSources', <String, dynamic>{ 'isolateId': isolateId }); - Event event = await whenIsolateReloads.future.timeout(new Duration(seconds: 20)); - dynamic error = event.response['reloadError']; - if (error != null) - printError('Error reloading application sources: $error'); - return error == null; + return await whenIsolateReloads.future.timeout(new Duration(seconds: 20)); } finally { await sub.cancel(); } @@ -215,6 +209,25 @@ // Flutter extension methods. + Future<Response> flutterDebugDumpApp(String isolateId) { + return peer.sendRequest('ext.flutter.debugDumpApp', <String, dynamic>{ + 'isolateId': isolateId + }).then((dynamic result) => new Response(result)); + } + + Future<Response> flutterDebugDumpRenderTree(String isolateId) { + return peer.sendRequest('ext.flutter.debugDumpRenderTree', <String, dynamic>{ + 'isolateId': isolateId + }).then((dynamic result) => new Response(result)); + } + + /// Causes the application to pick up any changed code. + Future<Response> flutterReassemble(String isolateId) { + return peer.sendRequest('ext.flutter.reassemble', <String, dynamic>{ + 'isolateId': isolateId + }).then((dynamic result) => new Response(result)); + } + Future<Response> flutterExit(String isolateId) { return peer.sendRequest('ext.flutter.exit', <String, dynamic>{ 'isolateId': isolateId
diff --git a/packages/flutter_tools/lib/src/run.dart b/packages/flutter_tools/lib/src/run.dart index 495d7eb..efa7ce2 100644 --- a/packages/flutter_tools/lib/src/run.dart +++ b/packages/flutter_tools/lib/src/run.dart
@@ -82,9 +82,13 @@ } else { Status status = logger.startProgress('Re-starting application...'); - Future<Event> extensionAddedEvent = observatory.onExtensionEvent - .where((Event event) => event.extensionKind == 'Flutter.FrameworkInitialization') - .first; + Future<Event> extensionAddedEvent; + + if (device.restartSendsFrameworkInitEvent) { + extensionAddedEvent = observatory.onExtensionEvent + .where((Event event) => event.extensionKind == 'Flutter.FrameworkInitialization') + .first; + } bool restartResult = await device.restartApp( _package, @@ -95,7 +99,7 @@ status.stop(showElapsedTime: true); - if (restartResult) { + if (restartResult && extensionAddedEvent != null) { // TODO(devoncarew): We should restore the route here. await extensionAddedEvent; } @@ -255,6 +259,10 @@ _stopApp(); } else if (useDevFS && lower == 'd') { _updateDevFS(); + } else if (lower == 'w') { + _debugDumpApp(); + } else if (lower == 't') { + _debugDumpRenderTree(); } }); } @@ -293,6 +301,14 @@ }); } + void _debugDumpApp() { + observatory.flutterDebugDumpApp(observatory.firstIsolateId); + } + + void _debugDumpRenderTree() { + observatory.flutterDebugDumpRenderTree(observatory.firstIsolateId); + } + DevFS devFS; Future<Null> _updateDevFS() async { @@ -361,6 +377,7 @@ void _printHelp() { String restartText = device.supportsRestart ? ', "r" or F5 to restart the app,' : ''; printStatus('Type "h" or F1 for help$restartText and "q", F10, or ctrl-c to quit.'); + printStatus('Type "w" to print the widget hierarchy of the app, and "t" for the render tree.'); if (useDevFS) printStatus('Type "d" to send modified project files to the the client\'s DevFS.');