Commit 26432eba authored by John McCutchan's avatar John McCutchan Committed by GitHub

Boot the application directly even when hot reloading. (#6948)

- [x] Remove the two stage initial boot process.
- [x] Remove the loader screen app.
- [x] Don't report reload times for the initial reload because we are
switching from a snapshot to source and that will always be worst case.
parent 292ba09b
This directory contains a small Flutter application that is run while
an application is being copied onto the device.
...@@ -17,7 +17,6 @@ import 'base/logger.dart'; ...@@ -17,7 +17,6 @@ import 'base/logger.dart';
import 'base/process.dart'; import 'base/process.dart';
import 'base/utils.dart'; import 'base/utils.dart';
import 'build_info.dart'; import 'build_info.dart';
import 'cache.dart';
import 'dart/package_map.dart'; import 'dart/package_map.dart';
import 'devfs.dart'; import 'devfs.dart';
import 'device.dart'; import 'device.dart';
...@@ -37,15 +36,6 @@ HotRunnerConfig get hotRunnerConfig => context[HotRunnerConfig]; ...@@ -37,15 +36,6 @@ HotRunnerConfig get hotRunnerConfig => context[HotRunnerConfig];
const bool kHotReloadDefault = true; const bool kHotReloadDefault = true;
String getDevFSLoaderScript() {
return path.absolute(path.join(Cache.flutterRoot,
'packages',
'flutter',
'bin',
'loader',
'loader_app.dart'));
}
class DartDependencySetBuilder { class DartDependencySetBuilder {
DartDependencySetBuilder(this.mainScriptPath, DartDependencySetBuilder(this.mainScriptPath,
this.projectRootPath, this.projectRootPath,
...@@ -123,6 +113,8 @@ class HotRunner extends ResidentRunner { ...@@ -123,6 +113,8 @@ class HotRunner extends ResidentRunner {
AssetBundle get bundle => _bundle; AssetBundle get bundle => _bundle;
final bool benchmarkMode; final bool benchmarkMode;
final Map<String, int> benchmarkData = new Map<String, int>(); final Map<String, int> benchmarkData = new Map<String, int>();
// The initial launch is from a snapshot.
bool _runningFromSnapshot = true;
@override @override
Future<int> run({ Future<int> run({
...@@ -203,13 +195,13 @@ class HotRunner extends ResidentRunner { ...@@ -203,13 +195,13 @@ class HotRunner extends ResidentRunner {
await startEchoingDeviceLog(_package); await startEchoingDeviceLog(_package);
printTrace('Launching loader on ${device.name}...'); printStatus('Launching ${getDisplayPath(_mainPath)} on ${device.name}...');
// Start the loader. // Start the application.
Future<LaunchResult> futureResult = device.startApp( Future<LaunchResult> futureResult = device.startApp(
_package, _package,
debuggingOptions.buildMode, debuggingOptions.buildMode,
mainPath: getDevFSLoaderScript(), mainPath: _mainPath,
debuggingOptions: debuggingOptions, debuggingOptions: debuggingOptions,
platformArgs: platformArgs, platformArgs: platformArgs,
route: route, route: route,
...@@ -219,7 +211,7 @@ class HotRunner extends ResidentRunner { ...@@ -219,7 +211,7 @@ class HotRunner extends ResidentRunner {
LaunchResult result = await futureResult; LaunchResult result = await futureResult;
if (!result.started) { if (!result.started) {
printError('Error launching DevFS loader on ${device.name}.'); printError('Error launching application on ${device.name}.');
await stopEchoingDeviceLog(); await stopEchoingDeviceLog();
return 2; return 2;
} }
...@@ -248,16 +240,8 @@ class HotRunner extends ResidentRunner { ...@@ -248,16 +240,8 @@ class HotRunner extends ResidentRunner {
printError('Error initializing DevFS: $error'); printError('Error initializing DevFS: $error');
return 3; return 3;
} }
_loaderShowMessage('Connecting...', progress: 0); bool devfsResult = await _updateDevFS();
_loaderShowExplanation('You can use hot reload to update your app on the fly, without restarting it.');
bool devfsResult = await _updateDevFS(
progressReporter: (int progress, int max) {
if (progress % 10 == 0)
_loaderShowMessage('Syncing files to device...', progress: progress, max: max);
}
);
if (!devfsResult) { if (!devfsResult) {
_loaderShowMessage('Failed.');
printError('Could not perform initial file synchronization.'); printError('Could not perform initial file synchronization.');
return 3; return 3;
} }
...@@ -265,20 +249,10 @@ class HotRunner extends ResidentRunner { ...@@ -265,20 +249,10 @@ class HotRunner extends ResidentRunner {
await vmService.vm.refreshViews(); await vmService.vm.refreshViews();
printTrace('Connected to ${vmService.vm.mainView}.'); printTrace('Connected to ${vmService.vm.mainView}.');
printStatus('Running ${getDisplayPath(_mainPath)} on ${device.name}...');
_loaderShowMessage('Launching...');
await _launchFromDevFS(_package, _mainPath);
printTrace('Application running.');
setupTerminal(); setupTerminal();
registerSignalHandlers(); registerSignalHandlers();
printTrace('Finishing file synchronization');
// Finish the file sync now.
await _updateDevFS();
appStartedCompleter?.complete(); appStartedCompleter?.complete();
if (benchmarkMode) { if (benchmarkMode) {
...@@ -316,21 +290,6 @@ class HotRunner extends ResidentRunner { ...@@ -316,21 +290,6 @@ class HotRunner extends ResidentRunner {
} }
} }
void _loaderShowMessage(String message, { int progress, int max }) {
currentView.uiIsolate.flutterLoaderShowMessage(message);
if (progress != null) {
currentView.uiIsolate.flutterLoaderSetProgress(progress.toDouble());
currentView.uiIsolate.flutterLoaderSetProgressMax(max?.toDouble() ?? 0.0);
} else {
currentView.uiIsolate.flutterLoaderSetProgress(0.0);
currentView.uiIsolate.flutterLoaderSetProgressMax(-1.0);
}
}
void _loaderShowExplanation(String explanation) {
currentView.uiIsolate.flutterLoaderShowExplanation(explanation);
}
DevFS _devFS; DevFS _devFS;
Future<Uri> _initDevFS() { Future<Uri> _initDevFS() {
...@@ -421,6 +380,8 @@ class HotRunner extends ResidentRunner { ...@@ -421,6 +380,8 @@ class HotRunner extends ResidentRunner {
restartTimer.stop(); restartTimer.stop();
printTrace('Restart performed in ' printTrace('Restart performed in '
'${getElapsedAsMilliseconds(restartTimer.elapsed)}.'); '${getElapsedAsMilliseconds(restartTimer.elapsed)}.');
// We are now running from sources.
_runningFromSnapshot = false;
if (benchmarkMode) { if (benchmarkMode) {
benchmarkData['hotRestartMillisecondsToFrame'] = benchmarkData['hotRestartMillisecondsToFrame'] =
restartTimer.elapsed.inMilliseconds; restartTimer.elapsed.inMilliseconds;
...@@ -475,6 +436,13 @@ class HotRunner extends ResidentRunner { ...@@ -475,6 +436,13 @@ class HotRunner extends ResidentRunner {
Future<OperationResult> _reloadSources({ bool pause: false }) async { Future<OperationResult> _reloadSources({ bool pause: false }) async {
if (currentView.uiIsolate == null) if (currentView.uiIsolate == null)
throw 'Application isolate not found'; throw 'Application isolate not found';
// The initial launch is from a script snapshot. When we reload from source
// on top of a script snapshot, the first reload will be a worst case reload
// because all of the sources will end up being dirty (library paths will
// change from host path to a device path). Subsequent reloads will
// not be affected, so we resume reporting reload times on the second
// reload.
final bool shouldReportReloadTime = !_runningFromSnapshot;
Stopwatch reloadTimer = new Stopwatch(); Stopwatch reloadTimer = new Stopwatch();
reloadTimer.start(); reloadTimer.start();
bool updatedDevFS = await _updateDevFS(); bool updatedDevFS = await _updateDevFS();
...@@ -482,8 +450,16 @@ class HotRunner extends ResidentRunner { ...@@ -482,8 +450,16 @@ class HotRunner extends ResidentRunner {
return new OperationResult(1, 'Dart Source Error'); return new OperationResult(1, 'Dart Source Error');
String reloadMessage; String reloadMessage;
try { try {
String entryPath = path.relative(_mainPath, from: _projectRootPath);
String deviceEntryPath =
_devFS.baseUri.resolve(entryPath).toFilePath();
String devicePackagesPath =
_devFS.baseUri.resolve('.packages').toFilePath();
Map<String, dynamic> reloadReport = Map<String, dynamic> reloadReport =
await currentView.uiIsolate.reloadSources(pause: pause); await currentView.uiIsolate.reloadSources(
pause: pause,
rootLibPath: deviceEntryPath,
packagesPath: devicePackagesPath);
if (!_validateReloadReport(reloadReport)) { if (!_validateReloadReport(reloadReport)) {
// Reload failed. // Reload failed.
flutterUsage.sendEvent('hot', 'reload-reject'); flutterUsage.sendEvent('hot', 'reload-reject');
...@@ -510,6 +486,8 @@ class HotRunner extends ResidentRunner { ...@@ -510,6 +486,8 @@ class HotRunner extends ResidentRunner {
} }
// Reload the isolate. // Reload the isolate.
await currentView.uiIsolate.reload(); await currentView.uiIsolate.reload();
// We are now running from source.
_runningFromSnapshot = false;
// Check if the isolate is paused. // Check if the isolate is paused.
final ServiceEvent pauseEvent = currentView.uiIsolate.pauseEvent; final ServiceEvent pauseEvent = currentView.uiIsolate.pauseEvent;
if ((pauseEvent != null) && (pauseEvent.isPauseEvent)) { if ((pauseEvent != null) && (pauseEvent.isPauseEvent)) {
...@@ -534,11 +512,13 @@ class HotRunner extends ResidentRunner { ...@@ -534,11 +512,13 @@ class HotRunner extends ResidentRunner {
reloadTimer.stop(); reloadTimer.stop();
printTrace('Hot reload performed in ' printTrace('Hot reload performed in '
'${getElapsedAsMilliseconds(reloadTimer.elapsed)}.'); '${getElapsedAsMilliseconds(reloadTimer.elapsed)}.');
if (benchmarkMode) { if (benchmarkMode) {
benchmarkData['hotReloadMillisecondsToFrame'] = benchmarkData['hotReloadMillisecondsToFrame'] =
reloadTimer.elapsed.inMilliseconds; reloadTimer.elapsed.inMilliseconds;
} }
flutterUsage.sendTiming('hot', 'reload', reloadTimer.elapsed); if (shouldReportReloadTime)
flutterUsage.sendTiming('hot', 'reload', reloadTimer.elapsed);
return new OperationResult(OperationResult.ok.code, reloadMessage); return new OperationResult(OperationResult.ok.code, reloadMessage);
} }
......
...@@ -759,11 +759,21 @@ class Isolate extends ServiceObjectOwner { ...@@ -759,11 +759,21 @@ class Isolate extends ServiceObjectOwner {
static final int kIsolateReloadBarred = 1005; static final int kIsolateReloadBarred = 1005;
Future<Map<String, dynamic>> reloadSources({ bool pause: false }) async { Future<Map<String, dynamic>> reloadSources(
{ bool pause: false,
String rootLibPath,
String packagesPath}) async {
try { try {
Map<String, dynamic> response = await invokeRpcRaw( Map<String, dynamic> arguments = <String, dynamic>{
'_reloadSources', <String, dynamic>{ 'pause': pause } 'pause': pause
); };
if (rootLibPath != null) {
arguments['rootLibUri'] = rootLibPath;
}
if (packagesPath != null) {
arguments['packagesUri'] = packagesPath;
}
Map<String, dynamic> response = await invokeRpcRaw('_reloadSources', arguments);
return response; return response;
} on rpc.RpcException catch(e) { } on rpc.RpcException catch(e) {
return new Future<Map<String, dynamic>>.error(<String, dynamic>{ return new Future<Map<String, dynamic>>.error(<String, dynamic>{
...@@ -800,36 +810,6 @@ class Isolate extends ServiceObjectOwner { ...@@ -800,36 +810,6 @@ class Isolate extends ServiceObjectOwner {
return invokeFlutterExtensionRpcRaw('ext.flutter.debugDumpRenderTree'); return invokeFlutterExtensionRpcRaw('ext.flutter.debugDumpRenderTree');
} }
// Loader page extension methods.
void flutterLoaderShowMessage(String message) {
// Invoke loaderShowMessage; ignore any returned errors.
invokeRpcRaw('ext.flutter.loaderShowMessage', <String, dynamic> {
'value': message
}).catchError((dynamic error) => null);
}
void flutterLoaderShowExplanation(String explanation) {
// Invoke loaderShowExplanation; ignore any returned errors.
invokeRpcRaw('ext.flutter.loaderShowExplanation', <String, dynamic> {
'value': explanation
}).catchError((dynamic error) => null);
}
void flutterLoaderSetProgress(double progress) {
// Invoke loaderSetProgress; ignore any returned errors.
invokeRpcRaw('ext.flutter.loaderSetProgress', <String, dynamic>{
'loaderSetProgress': progress
}).catchError((dynamic error) => null);
}
void flutterLoaderSetProgressMax(double max) {
// Invoke loaderSetProgressMax; ignore any returned errors.
invokeRpcRaw('ext.flutter.loaderSetProgressMax', <String, dynamic>{
'loaderSetProgressMax': max
}).catchError((dynamic error) => null);
}
static bool _isMethodNotFoundException(dynamic e) { static bool _isMethodNotFoundException(dynamic e) {
return (e is rpc.RpcException) && return (e is rpc.RpcException) &&
(e.code == rpc_error_code.METHOD_NOT_FOUND); (e.code == rpc_error_code.METHOD_NOT_FOUND);
......
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