restartApp method

Future<void> restartApp()

Hands the staged update to the native installer or restart helper.

Implementation

Future<void> restartApp() async {
  final stagingPath = _stagingPath;
  final stageResult = _activeStageResult;
  final provenance = _stageProvenance;
  final provenanceSha256 = _stageProvenanceSha256;
  final client = _client;
  if (stagingPath == null ||
      stagingPath.isEmpty ||
      stageResult == null ||
      provenance == null ||
      provenanceSha256 == null ||
      client == null) {
    throw StateError("No downloaded update is ready to install.");
  }

  _state = const UpdateInstalling();
  _diagnosticsRecorder.record(
    stage: UpdateDiagnosticStage.install,
    level: UpdateDiagnosticLevel.info,
    message: "Install handoff started for $stagingPath",
  );
  _diagnosticsRecorder.record(
    stage: UpdateDiagnosticStage.install,
    level: UpdateDiagnosticLevel.info,
    message: "Relaunch attempt scheduled.",
  );
  emitUpdateTelemetry(
    telemetry,
    UpdateTelemetryEvent.installScheduled(
      stagingPath: stagingPath,
      version: _activeDescriptor?.version,
      channel: _activeDescriptor?.channel,
      platform: _activeDescriptor?.platform,
      artifactKind: _activeDescriptor?.artifact.kind,
      installStrategy: _activeDescriptor?.install.strategy,
    ),
  );
  notifyListeners();

  var dispatchAttempted = false;
  try {
    _validateNativeInstallTrust();
    final candidateTransactionId = _createInstallTransactionId();
    final receipt = await _writePendingRecoveryMarker(
      stagingPath,
      candidateTransactionId,
    );
    // Once the durable receipt exists, every failure from the dispatch
    // boundary is ambiguous to the app. Keep the marker until authenticated
    // recovery proves absence or terminal completion.
    dispatchAttempted = true;
    await dispatchVerifiedInstall(
      session: client,
      stageResult: stageResult,
      persistedTransaction: receipt,
    );
    final cleanupReport = _buildCleanupReport(
      stagingPath: stagingPath,
      cleanupAttempted: false,
    );
    _recordCleanupReport(cleanupReport);
    _state = UpdateInstalling(cleanupReport: cleanupReport);
    notifyListeners();
  } on Object catch (error) {
    if (!dispatchAttempted) {
      await _clearPendingRecoveryMarker();
    }
    _recordCleanupReport(
      _buildCleanupReport(
        stagingPath: stagingPath,
        cleanupAttempted: false,
        cleanupSucceeded: false,
        errorText: error.toString(),
      ),
    );
    _diagnosticsRecorder.record(
      stage: UpdateDiagnosticStage.install,
      level: UpdateDiagnosticLevel.error,
      message: "Install failed.",
      error: error,
    );
    _state = UpdateFailed(
      error,
      report: _buildProblemReport(
        error,
        updateVersion: _activeDescriptor?.version,
        stagingPath: stagingPath,
      ),
    );
    emitUpdateTelemetry(
      telemetry,
      UpdateTelemetryEvent.installFailed(
        stagingPath: stagingPath,
        version: _activeDescriptor?.version,
        channel: _activeDescriptor?.channel,
        platform: _activeDescriptor?.platform,
        artifactKind: _activeDescriptor?.artifact.kind,
        installStrategy: _activeDescriptor?.install.strategy,
        error: error,
      ),
    );
    notifyListeners();
    rethrow;
  }
}