Commit ec752d81 authored by Devon Carew's avatar Devon Carew Committed by GitHub

send ext.flutter.debugDumpApp; ext.flutter.reassemble (#4810)

* send ext.flutter.debugDumpApp; ext.flutter.reassemble

* expose debugDumpRenderTree
parent 3cbb20d1
......@@ -56,6 +56,14 @@ abstract class RendererBinding extends BindingBase implements SchedulerBinding,
return true;
});
assert(() {
registerSignalServiceExtension(
name: 'debugDumpRenderTree',
callback: debugDumpRenderTree
);
return true;
});
assert(() {
// this service extension only works in checked mode
registerBoolServiceExtension(
......
......@@ -72,6 +72,11 @@ abstract class WidgetsBinding extends BindingBase implements GestureBinding, Ren
void initServiceExtensions() {
super.initServiceExtensions();
registerSignalServiceExtension(
name: 'debugDumpApp',
callback: debugDumpApp
);
registerBoolServiceExtension(
name: 'showPerformanceOverlay',
getter: () => WidgetsApp.showPerformanceOverlayOverride,
......
......@@ -191,6 +191,8 @@ abstract class Device {
bool get supportsRestart => false;
bool get restartSendsFrameworkInitEvent => true;
/// Restart the given app; the application will already have been launched with
/// [startApp].
Future<bool> restartApp(
......
......@@ -578,6 +578,9 @@ class IOSSimulator extends Device {
@override
bool get supportsRestart => run.useReloadSources;
@override
bool get restartSendsFrameworkInitEvent => false;
@override
Future<bool> restartApp(
ApplicationPackage package,
......@@ -587,7 +590,15 @@ class IOSSimulator extends Device {
}) 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
......
......@@ -9,8 +9,6 @@ import 'dart:io';
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 @@ class Observatory {
});
}
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 @@ class Observatory {
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 @@ class Observatory {
// 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
......
......@@ -82,9 +82,13 @@ class RunAndStayResident {
} 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 @@ class RunAndStayResident {
status.stop(showElapsedTime: true);
if (restartResult) {
if (restartResult && extensionAddedEvent != null) {
// TODO(devoncarew): We should restore the route here.
await extensionAddedEvent;
}
......@@ -255,6 +259,10 @@ class RunAndStayResident {
_stopApp();
} else if (useDevFS && lower == 'd') {
_updateDevFS();
} else if (lower == 'w') {
_debugDumpApp();
} else if (lower == 't') {
_debugDumpRenderTree();
}
});
}
......@@ -293,6 +301,14 @@ class RunAndStayResident {
});
}
void _debugDumpApp() {
observatory.flutterDebugDumpApp(observatory.firstIsolateId);
}
void _debugDumpRenderTree() {
observatory.flutterDebugDumpRenderTree(observatory.firstIsolateId);
}
DevFS devFS;
Future<Null> _updateDevFS() async {
......@@ -361,6 +377,7 @@ class RunAndStayResident {
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.');
......
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