mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
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.
This commit is contained in:
parent
292ba09b22
commit
26432eba30
@ -1,3 +0,0 @@
|
||||
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';
|
||||
import 'base/process.dart';
|
||||
import 'base/utils.dart';
|
||||
import 'build_info.dart';
|
||||
import 'cache.dart';
|
||||
import 'dart/package_map.dart';
|
||||
import 'devfs.dart';
|
||||
import 'device.dart';
|
||||
@ -37,15 +36,6 @@ HotRunnerConfig get hotRunnerConfig => context[HotRunnerConfig];
|
||||
|
||||
const bool kHotReloadDefault = true;
|
||||
|
||||
String getDevFSLoaderScript() {
|
||||
return path.absolute(path.join(Cache.flutterRoot,
|
||||
'packages',
|
||||
'flutter',
|
||||
'bin',
|
||||
'loader',
|
||||
'loader_app.dart'));
|
||||
}
|
||||
|
||||
class DartDependencySetBuilder {
|
||||
DartDependencySetBuilder(this.mainScriptPath,
|
||||
this.projectRootPath,
|
||||
@ -123,6 +113,8 @@ class HotRunner extends ResidentRunner {
|
||||
AssetBundle get bundle => _bundle;
|
||||
final bool benchmarkMode;
|
||||
final Map<String, int> benchmarkData = new Map<String, int>();
|
||||
// The initial launch is from a snapshot.
|
||||
bool _runningFromSnapshot = true;
|
||||
|
||||
@override
|
||||
Future<int> run({
|
||||
@ -203,13 +195,13 @@ class HotRunner extends ResidentRunner {
|
||||
|
||||
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(
|
||||
_package,
|
||||
debuggingOptions.buildMode,
|
||||
mainPath: getDevFSLoaderScript(),
|
||||
mainPath: _mainPath,
|
||||
debuggingOptions: debuggingOptions,
|
||||
platformArgs: platformArgs,
|
||||
route: route,
|
||||
@ -219,7 +211,7 @@ class HotRunner extends ResidentRunner {
|
||||
LaunchResult result = await futureResult;
|
||||
|
||||
if (!result.started) {
|
||||
printError('Error launching DevFS loader on ${device.name}.');
|
||||
printError('Error launching application on ${device.name}.');
|
||||
await stopEchoingDeviceLog();
|
||||
return 2;
|
||||
}
|
||||
@ -248,16 +240,8 @@ class HotRunner extends ResidentRunner {
|
||||
printError('Error initializing DevFS: $error');
|
||||
return 3;
|
||||
}
|
||||
_loaderShowMessage('Connecting...', progress: 0);
|
||||
_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);
|
||||
}
|
||||
);
|
||||
bool devfsResult = await _updateDevFS();
|
||||
if (!devfsResult) {
|
||||
_loaderShowMessage('Failed.');
|
||||
printError('Could not perform initial file synchronization.');
|
||||
return 3;
|
||||
}
|
||||
@ -265,20 +249,10 @@ class HotRunner extends ResidentRunner {
|
||||
await vmService.vm.refreshViews();
|
||||
printTrace('Connected to ${vmService.vm.mainView}.');
|
||||
|
||||
printStatus('Running ${getDisplayPath(_mainPath)} on ${device.name}...');
|
||||
_loaderShowMessage('Launching...');
|
||||
await _launchFromDevFS(_package, _mainPath);
|
||||
|
||||
printTrace('Application running.');
|
||||
|
||||
setupTerminal();
|
||||
|
||||
registerSignalHandlers();
|
||||
|
||||
printTrace('Finishing file synchronization');
|
||||
// Finish the file sync now.
|
||||
await _updateDevFS();
|
||||
|
||||
appStartedCompleter?.complete();
|
||||
|
||||
if (benchmarkMode) {
|
||||
@ -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;
|
||||
|
||||
Future<Uri> _initDevFS() {
|
||||
@ -421,6 +380,8 @@ class HotRunner extends ResidentRunner {
|
||||
restartTimer.stop();
|
||||
printTrace('Restart performed in '
|
||||
'${getElapsedAsMilliseconds(restartTimer.elapsed)}.');
|
||||
// We are now running from sources.
|
||||
_runningFromSnapshot = false;
|
||||
if (benchmarkMode) {
|
||||
benchmarkData['hotRestartMillisecondsToFrame'] =
|
||||
restartTimer.elapsed.inMilliseconds;
|
||||
@ -475,6 +436,13 @@ class HotRunner extends ResidentRunner {
|
||||
Future<OperationResult> _reloadSources({ bool pause: false }) async {
|
||||
if (currentView.uiIsolate == null)
|
||||
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();
|
||||
reloadTimer.start();
|
||||
bool updatedDevFS = await _updateDevFS();
|
||||
@ -482,8 +450,16 @@ class HotRunner extends ResidentRunner {
|
||||
return new OperationResult(1, 'Dart Source Error');
|
||||
String reloadMessage;
|
||||
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 =
|
||||
await currentView.uiIsolate.reloadSources(pause: pause);
|
||||
await currentView.uiIsolate.reloadSources(
|
||||
pause: pause,
|
||||
rootLibPath: deviceEntryPath,
|
||||
packagesPath: devicePackagesPath);
|
||||
if (!_validateReloadReport(reloadReport)) {
|
||||
// Reload failed.
|
||||
flutterUsage.sendEvent('hot', 'reload-reject');
|
||||
@ -510,6 +486,8 @@ class HotRunner extends ResidentRunner {
|
||||
}
|
||||
// Reload the isolate.
|
||||
await currentView.uiIsolate.reload();
|
||||
// We are now running from source.
|
||||
_runningFromSnapshot = false;
|
||||
// Check if the isolate is paused.
|
||||
final ServiceEvent pauseEvent = currentView.uiIsolate.pauseEvent;
|
||||
if ((pauseEvent != null) && (pauseEvent.isPauseEvent)) {
|
||||
@ -534,11 +512,13 @@ class HotRunner extends ResidentRunner {
|
||||
reloadTimer.stop();
|
||||
printTrace('Hot reload performed in '
|
||||
'${getElapsedAsMilliseconds(reloadTimer.elapsed)}.');
|
||||
|
||||
if (benchmarkMode) {
|
||||
benchmarkData['hotReloadMillisecondsToFrame'] =
|
||||
reloadTimer.elapsed.inMilliseconds;
|
||||
}
|
||||
flutterUsage.sendTiming('hot', 'reload', reloadTimer.elapsed);
|
||||
if (shouldReportReloadTime)
|
||||
flutterUsage.sendTiming('hot', 'reload', reloadTimer.elapsed);
|
||||
return new OperationResult(OperationResult.ok.code, reloadMessage);
|
||||
}
|
||||
|
||||
|
||||
@ -759,11 +759,21 @@ class Isolate extends ServiceObjectOwner {
|
||||
|
||||
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 {
|
||||
Map<String, dynamic> response = await invokeRpcRaw(
|
||||
'_reloadSources', <String, dynamic>{ 'pause': pause }
|
||||
);
|
||||
Map<String, dynamic> arguments = <String, dynamic>{
|
||||
'pause': pause
|
||||
};
|
||||
if (rootLibPath != null) {
|
||||
arguments['rootLibUri'] = rootLibPath;
|
||||
}
|
||||
if (packagesPath != null) {
|
||||
arguments['packagesUri'] = packagesPath;
|
||||
}
|
||||
Map<String, dynamic> response = await invokeRpcRaw('_reloadSources', arguments);
|
||||
return response;
|
||||
} on rpc.RpcException catch(e) {
|
||||
return new Future<Map<String, dynamic>>.error(<String, dynamic>{
|
||||
@ -800,36 +810,6 @@ class Isolate extends ServiceObjectOwner {
|
||||
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) {
|
||||
return (e is rpc.RpcException) &&
|
||||
(e.code == rpc_error_code.METHOD_NOT_FOUND);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user