Commit 11df9fa2 authored by Olivier Robin's avatar Olivier Robin Committed by Commit Bot

Fix safe mode exit crash

Scene UI is not initialized in safe mode.
When exiting safe mode, initialize the UI of the sceneState
before continuing the startup sequence.

Bug: 1137310
Change-Id: I61c4a3faeed8d7728a8ecbb1b191e8621e72e4f2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2476280
Commit-Queue: Olivier Robin <olivierrobin@chromium.org>
Reviewed-by: default avatarStepan Khapugin <stkhapugin@chromium.org>
Reviewed-by: default avatarMark Cogan <marq@chromium.org>
Cr-Commit-Position: refs/heads/master@{#818898}
parent 04474306
......@@ -32,9 +32,9 @@ class ChromeBrowserState;
// On iOS 12, called when the mainSceneState is set.
- (void)appState:(AppState*)appState sceneConnected:(SceneState*)sceneState;
// Called when the first scene becomes active.
// Called when the first scene initializes its UI.
- (void)appState:(AppState*)appState
firstSceneActivated:(SceneState*)sceneState;
firstSceneHasInitializedUI:(SceneState*)sceneState;
// Called after the app exits safe mode.
- (void)appStateDidExitSafeMode:(AppState*)appState;
......
......@@ -139,6 +139,9 @@ NSString* const kStartupAttemptReset = @"StartupAttempReset";
// never reset.
@property(nonatomic, assign) BOOL firstSceneHasActivated;
// This flag is set when the first scene has initialized its UI and never reset.
@property(nonatomic, assign) BOOL firstSceneHasInitializedUI;
// The current blocker target if any.
@property(nonatomic, weak, readwrite) id<UIBlockerTarget> uiBlockerTarget;
......@@ -698,14 +701,21 @@ initWithBrowserLauncher:(id<BrowserLauncher>)browserLauncher
return self.uiBlockerTarget;
}
#pragma mark - SceneStateObserver
- (void)sceneStateHasInitializedUI:(SceneState*)sceneState {
if (self.firstSceneHasInitializedUI) {
return;
}
self.firstSceneHasInitializedUI = YES;
[self.observers appState:self firstSceneHasInitializedUI:sceneState];
}
- (void)sceneState:(SceneState*)sceneState
transitionedToActivationLevel:(SceneActivationLevel)level {
if (level >= SceneActivationLevelForegroundActive) {
if (!self.firstSceneHasActivated) {
self.firstSceneHasActivated = YES;
[self.observers appState:self firstSceneActivated:sceneState];
if (self.isInSafeMode) {
// Safe mode can only be started when there's a window, so the actual
// safe mode has been postponed until now.
......
......@@ -603,14 +603,8 @@ void MainControllerAuthenticationServiceDelegate::ClearBrowsingData(
// Called when the first scene becomes active.
- (void)appState:(AppState*)appState
firstSceneActivated:(SceneState*)sceneState {
if (appState.isInSafeMode) {
return;
}
[self startUpAfterFirstWindowCreated];
}
- (void)appStateDidExitSafeMode:(AppState*)appState {
firstSceneHasInitializedUI:(SceneState*)sceneState {
DCHECK(!appState.isInSafeMode);
[self startUpAfterFirstWindowCreated];
}
......
......@@ -153,9 +153,6 @@ const char kMultiWindowOpenInNewWindowHistogram[] =
// browser state level UrlLoadingService instances.
@property(nonatomic, assign) SceneUrlLoadingService* sceneURLLoadingService;
// A flag that keeps track of the UI initialization for the controlled scene.
@property(nonatomic, assign) BOOL hasInitializedUI;
// Returns YES if the settings are presented, either from
// self.settingsNavigationController or from SigninCoordinator.
@property(nonatomic, assign, readonly, getter=isSettingsViewPresented)
......@@ -306,8 +303,8 @@ const char kMultiWindowOpenInNewWindowHistogram[] =
// ends.
return;
}
BOOL initializingUIInColdStart =
level > SceneActivationLevelBackground && !self.hasInitializedUI;
BOOL initializingUIInColdStart = level > SceneActivationLevelBackground &&
!self.sceneState.hasInitializedUI;
if (initializingUIInColdStart) {
[self initializeUI];
if (IsMultiwindowSupported()) {
......@@ -362,7 +359,8 @@ const char kMultiWindowOpenInNewWindowHistogram[] =
}
}
if (self.hasInitializedUI && level == SceneActivationLevelUnattached) {
if (self.sceneState.hasInitializedUI &&
level == SceneActivationLevelUnattached) {
if (IsMultiwindowSupported()) {
if (@available(iOS 13, *)) {
if (IsMultipleScenesSupported()) {
......@@ -551,12 +549,12 @@ const char kMultiWindowOpenInNewWindowHistogram[] =
#pragma mark - private
- (void)initializeUI {
if (self.hasInitializedUI) {
if (self.sceneState.hasInitializedUI) {
return;
}
[self startUpChromeUI];
self.hasInitializedUI = YES;
self.sceneState.hasInitializedUI = YES;
}
// Returns YES if restore prompt can be shown.
......@@ -745,7 +743,7 @@ const char kMultiWindowOpenInNewWindowHistogram[] =
// This method completely destroys all of the UI. It should be called when the
// scene is disconnected.
- (void)teardownUI {
if (!self.hasInitializedUI) {
if (!self.sceneState.hasInitializedUI) {
return; // Nothing to do.
}
......@@ -776,7 +774,7 @@ const char kMultiWindowOpenInNewWindowHistogram[] =
[self.browserViewWrangler shutdown];
self.browserViewWrangler = nil;
self.hasInitializedUI = NO;
self.sceneState.hasInitializedUI = NO;
[self.sceneState.appState removeObserver:self];
}
......
......@@ -100,6 +100,9 @@ typedef NS_ENUM(NSUInteger, SceneActivationLevel) {
// |UISceneDelegate scene:continueUserActivity:| and needs to be opened.
@property(nonatomic) NSUserActivity* pendingUserActivity;
// A flag that keeps track of the UI initialization for the controlled scene.
@property(nonatomic, assign) BOOL hasInitializedUI;
// Adds an observer to this scene state. The observers will be notified about
// scene state changes per SceneStateObserver protocol.
- (void)addObserver:(id<SceneStateObserver>)observer;
......
......@@ -113,6 +113,16 @@
[self.observers sceneState:self transitionedToActivationLevel:newLevel];
}
- (void)setHasInitializedUI:(BOOL)hasInitializedUI {
if (_hasInitializedUI == hasInitializedUI) {
return;
}
_hasInitializedUI = hasInitializedUI;
if (hasInitializedUI) {
[self.observers sceneStateHasInitializedUI:self];
}
}
- (id<BrowserInterfaceProvider>)interfaceProvider {
return self.controller.interfaceProvider;
}
......
......@@ -26,6 +26,8 @@ enum SceneActivationLevel : NSUInteger;
- (void)sceneStateWillHideModalOverlay:(SceneState*)sceneState;
// Notifies when presentingModalOverlay has been set to false.
- (void)sceneStateDidHideModalOverlay:(SceneState*)sceneState;
// Notifies when hasInitializedUI has been set.
- (void)sceneStateHasInitializedUI:(SceneState*)sceneState;
// Notifies when URLContexts have been added to |URLContextsToOpen|.
- (void)sceneState:(SceneState*)sceneState
hasPendingURLs:(NSSet<UIOpenURLContext*>*)URLContexts
......
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