enterprise_app_agent.mm 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. // Copyright 2021 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #import "ios/chrome/app/enterprise_app_agent.h"
  5. #include "base/check.h"
  6. #include "components/policy/core/common/cloud/cloud_policy_client.h"
  7. #import "components/policy/core/common/cloud/machine_level_user_cloud_policy_manager.h"
  8. #import "components/policy/core/common/policy_namespace.h"
  9. #import "ios/chrome/app/application_delegate/app_state.h"
  10. #include "ios/chrome/app/application_delegate/startup_information.h"
  11. #import "ios/chrome/app/enterprise_loading_screen_view_controller.h"
  12. #import "ios/chrome/app/tests_hook.h"
  13. #include "ios/chrome/browser/application_context.h"
  14. #import "ios/chrome/browser/policy/browser_policy_connector_ios.h"
  15. #include "ios/chrome/browser/policy/chrome_browser_cloud_management_controller_ios.h"
  16. #import "ios/chrome/browser/policy/chrome_browser_cloud_management_controller_observer_bridge.h"
  17. #import "ios/chrome/browser/policy/cloud_policy_client_observer_bridge.h"
  18. #import "ios/chrome/browser/ui/first_run/first_run_util.h"
  19. #import "ios/chrome/browser/ui/main/scene_state.h"
  20. #if !defined(__has_feature) || !__has_feature(objc_arc)
  21. #error "This file requires ARC support."
  22. #endif
  23. namespace {
  24. constexpr CGFloat kTimeout = 30;
  25. } // namespace
  26. @interface EnterpriseAppAgent () <
  27. ChromeBrowserCloudManagementControllerObserver,
  28. CloudPolicyClientObserver,
  29. SceneStateObserver> {
  30. std::unique_ptr<ChromeBrowserCloudManagementControllerObserverBridge>
  31. _cloudManagementControllerObserver;
  32. std::unique_ptr<CloudPolicyClientObserverBridge> _cloudPolicyClientObserver;
  33. BrowserPolicyConnectorIOS* _policyConnector;
  34. }
  35. // The app state for the app.
  36. @property(nonatomic, weak, readonly) AppState* appState;
  37. // Browser policy connector for iOS.
  38. @property(nonatomic, assign) BrowserPolicyConnectorIOS* policyConnector;
  39. // YES if enterprise launch screen has been dismissed.
  40. @property(nonatomic, assign) BOOL launchScreenDismissed;
  41. @end
  42. @implementation EnterpriseAppAgent
  43. - (void)dealloc {
  44. for (SceneState* scene in _appState.connectedScenes) {
  45. [scene removeObserver:self];
  46. }
  47. [_appState removeObserver:self];
  48. }
  49. - (void)setAppState:(AppState*)appState {
  50. // This should only be called once!
  51. DCHECK(!_appState);
  52. _appState = appState;
  53. [appState addObserver:self];
  54. for (SceneState* scene in appState.connectedScenes) {
  55. [scene addObserver:self];
  56. }
  57. }
  58. #pragma mark - AppStateObserver
  59. - (void)appState:(AppState*)appState
  60. willTransitionToInitStage:(InitStage)nextInitStage {
  61. if (nextInitStage != InitStageEnterprise) {
  62. return;
  63. }
  64. // Ensure to have the information available on time.
  65. self.appState.startupInformation.isFirstRun =
  66. ShouldPresentFirstRunExperience();
  67. }
  68. - (void)appState:(AppState*)appState sceneConnected:(SceneState*)sceneState {
  69. [sceneState addObserver:self];
  70. }
  71. - (void)appState:(AppState*)appState
  72. didTransitionFromInitStage:(InitStage)previousInitStage {
  73. if (appState.initStage == InitStageEnterprise) {
  74. if ([self shouldShowEnterpriseLoadScreen]) {
  75. _cloudManagementControllerObserver = std::make_unique<
  76. ChromeBrowserCloudManagementControllerObserverBridge>(
  77. self,
  78. self.policyConnector->chrome_browser_cloud_management_controller());
  79. policy::CloudPolicyClient* client =
  80. self.policyConnector->machine_level_user_cloud_policy_manager()
  81. ->core()
  82. ->client();
  83. _cloudPolicyClientObserver =
  84. std::make_unique<CloudPolicyClientObserverBridge>(self, client);
  85. self.launchScreenDismissed = NO;
  86. for (SceneState* scene in appState.connectedScenes) {
  87. if (scene.activationLevel > SceneActivationLevelBackground) {
  88. [self showUIInScene:scene];
  89. }
  90. }
  91. // Ensure to never stay stuck on enterprise launch screen.
  92. __weak EnterpriseAppAgent* weakSelf = self;
  93. dispatch_after(
  94. dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kTimeout * NSEC_PER_SEC)),
  95. dispatch_get_main_queue(), ^{
  96. if (!weakSelf.launchScreenDismissed) {
  97. [weakSelf cloudPolicyDidError:nullptr];
  98. }
  99. });
  100. } else {
  101. [self.appState queueTransitionToNextInitStage];
  102. }
  103. }
  104. if (previousInitStage == InitStageEnterprise) {
  105. // Nothing left to do; clean up.
  106. _cloudManagementControllerObserver = nullptr;
  107. _cloudPolicyClientObserver = nullptr;
  108. // Let the following line at the end of the block.
  109. [self.appState removeAgent:self];
  110. }
  111. }
  112. #pragma mark - SceneStateObserver
  113. - (void)sceneState:(SceneState*)sceneState
  114. transitionedToActivationLevel:(SceneActivationLevel)level {
  115. if (self.appState.initStage == InitStageEnterprise &&
  116. level > SceneActivationLevelBackground) {
  117. [self showUIInScene:sceneState];
  118. }
  119. }
  120. #pragma mark - ChromeBrowserCloudManagementControllerObserverBridge
  121. - (void)policyRegistrationDidCompleteSuccessfuly:(BOOL)succeeded {
  122. if (!succeeded && !self.launchScreenDismissed) {
  123. self.launchScreenDismissed = YES;
  124. [self.appState queueTransitionToNextInitStage];
  125. }
  126. }
  127. #pragma mark - CloudPolicyClientObserverBridge
  128. - (void)cloudPolicyWasFetched:(policy::CloudPolicyClient*)client {
  129. if (!self.launchScreenDismissed) {
  130. self.launchScreenDismissed = YES;
  131. [self.appState queueTransitionToNextInitStage];
  132. }
  133. }
  134. - (void)cloudPolicyDidError:(policy::CloudPolicyClient*)client {
  135. if (!self.launchScreenDismissed) {
  136. self.launchScreenDismissed = YES;
  137. [self.appState queueTransitionToNextInitStage];
  138. }
  139. }
  140. - (void)cloudPolicyRegistrationChanged:(policy::CloudPolicyClient*)client {
  141. // Ignored as for initialization, only registration and fetch completion
  142. // results are needed.
  143. }
  144. #pragma mark - private
  145. - (void)showUIInScene:(SceneState*)sceneState {
  146. if ([sceneState.window.rootViewController
  147. isKindOfClass:[EnterpriseLoadScreenViewController class]]) {
  148. return;
  149. }
  150. sceneState.window.rootViewController =
  151. [[EnterpriseLoadScreenViewController alloc] init];
  152. [sceneState.window makeKeyAndVisible];
  153. }
  154. - (BOOL)shouldShowEnterpriseLoadScreen {
  155. self.policyConnector = GetApplicationContext()->GetBrowserPolicyConnector();
  156. // `policyConnector` is nullptr if policy is not enabled.
  157. if (!self.policyConnector) {
  158. return NO;
  159. }
  160. // `machineLevelUserCloudPolicyManager` is nullptr if the DM token needed
  161. // for fetch is explicitly invalid or if enrollment tokens and DM token are
  162. // empty.
  163. policy::MachineLevelUserCloudPolicyManager*
  164. machineLevelUserCloudPolicyManager =
  165. self.policyConnector->machine_level_user_cloud_policy_manager();
  166. return self.appState.startupInformation.isFirstRun &&
  167. self.policyConnector->chrome_browser_cloud_management_controller()
  168. ->IsEnabled() &&
  169. machineLevelUserCloudPolicyManager &&
  170. !machineLevelUserCloudPolicyManager->IsFirstPolicyLoadComplete(
  171. policy::POLICY_DOMAIN_CHROME);
  172. }
  173. @end