Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(235)

Side by Side Diff: chrome/browser/chromeos/arc/arc_session_manager.cc

Issue 2734873002: Fix ArcSessionManager state machine, part 2. (Closed)
Patch Set: Address comments. Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/chromeos/arc/arc_session_manager.h" 5 #include "chrome/browser/chromeos/arc/arc_session_manager.h"
6 6
7 #include <utility> 7 #include <utility>
8 8
9 #include "ash/common/shelf/shelf_delegate.h" 9 #include "ash/common/shelf/shelf_delegate.h"
10 #include "ash/common/wm_shell.h" 10 #include "ash/common/wm_shell.h"
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
155 // If ARC is being restarted, here do nothing, and just wait for its 155 // If ARC is being restarted, here do nothing, and just wait for its
156 // next run. 156 // next run.
157 VLOG(1) << "ARC session is stopped, but being restarted: " << reason; 157 VLOG(1) << "ARC session is stopped, but being restarted: " << reason;
158 return; 158 return;
159 } 159 }
160 160
161 // TODO(crbug.com/625923): Use |reason| to report more detailed errors. 161 // TODO(crbug.com/625923): Use |reason| to report more detailed errors.
162 if (arc_sign_in_timer_.IsRunning()) 162 if (arc_sign_in_timer_.IsRunning())
163 OnProvisioningFinished(ProvisioningResult::ARC_STOPPED); 163 OnProvisioningFinished(ProvisioningResult::ARC_STOPPED);
164 164
165 if (profile_->GetPrefs()->GetBoolean(prefs::kArcDataRemoveRequested)) { 165 for (auto& observer : observer_list_)
166 // This should be always true, but just in case as this is looked at 166 observer.OnArcSessionStopped(reason);
167 // inside RemoveArcData() at first. 167
168 VLOG(1) << "ARC had previously requested to remove user data."; 168 // Transition to the ARC data remove state.
169 DCHECK(arc_session_runner_->IsStopped()); 169 if (!profile_->GetPrefs()->GetBoolean(prefs::kArcDataRemoveRequested)) {
170 RemoveArcData(); 170 // TODO(crbug.com/665316): This is the workaround for the bug.
171 } else { 171 // If it is not necessary to remove the data, MaybeStartArcDataRemoval()
172 // To support special "Stop and enable ARC" procedure for enterprise, 172 // synchronously calls MaybeReenableArc(), which causes unexpected
173 // here call MaybeReenableArc() asyncronously. 173 // ARC session stop. (Please see the bug for details).
174 // TODO(hidehiko): Restructure the code. crbug.com/665316 174 SetState(State::REMOVING_DATA_DIR);
175 base::ThreadTaskRunnerHandle::Get()->PostTask( 175 base::ThreadTaskRunnerHandle::Get()->PostTask(
176 FROM_HERE, base::Bind(&ArcSessionManager::MaybeReenableArc, 176 FROM_HERE, base::Bind(&ArcSessionManager::MaybeReenableArc,
177 weak_ptr_factory_.GetWeakPtr())); 177 weak_ptr_factory_.GetWeakPtr()));
178 }
179
180 for (auto& observer : observer_list_)
181 observer.OnArcSessionStopped(reason);
182 }
183
184 void ArcSessionManager::RemoveArcData() {
185 // Ignore redundant data removal request.
186 if (state() == State::REMOVING_DATA_DIR)
187 return;
188
189 // OnArcDataRemoved resets this flag.
190 profile_->GetPrefs()->SetBoolean(prefs::kArcDataRemoveRequested, true);
191
192 if (!arc_session_runner_->IsStopped()) {
193 // Just set a flag. On session stopped, this will be re-called,
194 // then session manager should remove the data.
195 return; 178 return;
196 } 179 }
197 180
198 VLOG(1) << "Starting ARC data removal"; 181 MaybeStartArcDataRemoval();
199
200 // Remove Play user ID for Active Directory managed devices.
201 profile_->GetPrefs()->SetString(prefs::kArcActiveDirectoryPlayUserId,
202 std::string());
203
204 SetState(State::REMOVING_DATA_DIR);
205 chromeos::DBusThreadManager::Get()->GetSessionManagerClient()->RemoveArcData(
206 cryptohome::Identification(
207 multi_user_util::GetAccountIdFromProfile(profile_)),
208 base::Bind(&ArcSessionManager::OnArcDataRemoved,
209 weak_ptr_factory_.GetWeakPtr()));
210 }
211
212 void ArcSessionManager::OnArcDataRemoved(bool success) {
213 if (success)
214 VLOG(1) << "ARC data removal successful";
215 else
216 LOG(ERROR) << "Request for ARC user data removal failed.";
217
218 // TODO(khmel): Browser tests may shutdown profile by itself. Update browser
219 // tests and remove this check.
220 if (state() == State::NOT_INITIALIZED)
221 return;
222
223 for (auto& observer : observer_list_)
224 observer.OnArcDataRemoved();
225
226 profile_->GetPrefs()->SetBoolean(prefs::kArcDataRemoveRequested, false);
227 DCHECK_EQ(state(), State::REMOVING_DATA_DIR);
228 SetState(State::STOPPED);
229
230 MaybeReenableArc();
231 }
232
233 void ArcSessionManager::MaybeReenableArc() {
234 // Here check if |reenable_arc_| is marked or not.
235 // The only case this happens should be in the special case for enterprise
236 // "on managed lost" case. In that case, OnSessionStopped() should trigger
237 // the RemoveArcData(), then this.
238 // TODO(hidehiko): It looks necessary to reset |reenable_arc_| regardless of
239 // |enable_requested_|. Fix it.
240 if (!reenable_arc_ || !enable_requested_)
241 return;
242
243 // Restart ARC anyway. Let the enterprise reporting instance decide whether
244 // the ARC user data wipe is still required or not.
245 reenable_arc_ = false;
246 VLOG(1) << "Reenable ARC";
247 RequestEnableImpl();
248 } 182 }
249 183
250 void ArcSessionManager::OnProvisioningFinished(ProvisioningResult result) { 184 void ArcSessionManager::OnProvisioningFinished(ProvisioningResult result) {
251 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 185 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
252 186
253 // If the Mojo message to notify finishing the provisioning is already sent 187 // If the Mojo message to notify finishing the provisioning is already sent
254 // from the container, it will be processed even after requesting to stop the 188 // from the container, it will be processed even after requesting to stop the
255 // container. Ignore all |result|s arriving while ARC is disabled, in order to 189 // container. Ignore all |result|s arriving while ARC is disabled, in order to
256 // avoid popping up an error message triggered below. This code intentionally 190 // avoid popping up an error message triggered below. This code intentionally
257 // does not support the case of reenabling. 191 // does not support the case of reenabling.
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
384 318
385 if (result == ProvisioningResult::CLOUD_PROVISION_FLOW_FAILED || 319 if (result == ProvisioningResult::CLOUD_PROVISION_FLOW_FAILED ||
386 result == ProvisioningResult::CLOUD_PROVISION_FLOW_TIMEOUT || 320 result == ProvisioningResult::CLOUD_PROVISION_FLOW_TIMEOUT ||
387 result == ProvisioningResult::CLOUD_PROVISION_FLOW_INTERNAL_ERROR || 321 result == ProvisioningResult::CLOUD_PROVISION_FLOW_INTERNAL_ERROR ||
388 // OVERALL_SIGN_IN_TIMEOUT might be an indication that ARC believes it is 322 // OVERALL_SIGN_IN_TIMEOUT might be an indication that ARC believes it is
389 // fully setup, but Chrome does not. 323 // fully setup, but Chrome does not.
390 result == ProvisioningResult::OVERALL_SIGN_IN_TIMEOUT || 324 result == ProvisioningResult::OVERALL_SIGN_IN_TIMEOUT ||
391 // Just to be safe, remove data if we don't know the cause. 325 // Just to be safe, remove data if we don't know the cause.
392 result == ProvisioningResult::UNKNOWN_ERROR) { 326 result == ProvisioningResult::UNKNOWN_ERROR) {
393 VLOG(1) << "ARC provisioning failed permanently. Removing user data"; 327 VLOG(1) << "ARC provisioning failed permanently. Removing user data";
394 RemoveArcData(); 328 RequestArcDataRemoval();
395 } 329 }
396 330
397 // We'll delay shutting down the ARC instance in this case to allow people 331 // We'll delay shutting down the ARC instance in this case to allow people
398 // to send feedback. 332 // to send feedback.
399 if (support_host_) 333 if (support_host_)
400 support_host_->ShowError(error, true /* = show send feedback button */); 334 support_host_->ShowError(error, true /* = show send feedback button */);
401 } 335 }
402 336
403 void ArcSessionManager::SetState(State state) { 337 void ArcSessionManager::SetState(State state) {
404 state_ = state; 338 state_ = state;
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
441 SetState(State::STOPPED); 375 SetState(State::STOPPED);
442 376
443 context_ = base::MakeUnique<ArcAuthContext>(profile_); 377 context_ = base::MakeUnique<ArcAuthContext>(profile_);
444 378
445 if (!g_disable_ui_for_testing || 379 if (!g_disable_ui_for_testing ||
446 g_enable_check_android_management_for_testing) { 380 g_enable_check_android_management_for_testing) {
447 ArcAndroidManagementChecker::StartClient(); 381 ArcAndroidManagementChecker::StartClient();
448 } 382 }
449 383
450 // Chrome may be shut down before completing ARC data removal. 384 // Chrome may be shut down before completing ARC data removal.
451 // In such a case, start removing the data now. 385 // For such a case, start removing the data now, if necessary.
452 if (profile_->GetPrefs()->GetBoolean(prefs::kArcDataRemoveRequested)) { 386 MaybeStartArcDataRemoval();
453 VLOG(1) << "ARC data removal requested in previous session.";
454 RemoveArcData();
455 }
456 } 387 }
457 388
458 void ArcSessionManager::Shutdown() { 389 void ArcSessionManager::Shutdown() {
459 enable_requested_ = false; 390 enable_requested_ = false;
460 ShutdownSession(); 391 ShutdownSession();
461 if (support_host_) { 392 if (support_host_) {
462 support_host_->Close(); 393 support_host_->Close();
463 support_host_->RemoveObserver(this); 394 support_host_->RemoveObserver(this);
464 support_host_.reset(); 395 support_host_.reset();
465 } 396 }
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after
599 // OnBackgroundAndroidManagementChecked() synchronously (or 530 // OnBackgroundAndroidManagementChecked() synchronously (or
600 // asynchornously). In the callback, Google Play Store enabled preference 531 // asynchornously). In the callback, Google Play Store enabled preference
601 // can be set to false if managed, and it triggers RequestDisable() via 532 // can be set to false if managed, and it triggers RequestDisable() via
602 // ArcPlayStoreEnabledPreferenceHandler. 533 // ArcPlayStoreEnabledPreferenceHandler.
603 // Thus, StartArc() should be called so that disabling should work even 534 // Thus, StartArc() should be called so that disabling should work even
604 // if synchronous call case. 535 // if synchronous call case.
605 StartBackgroundAndroidManagementCheck(); 536 StartBackgroundAndroidManagementCheck();
606 return; 537 return;
607 } 538 }
608 539
609 StartTermsOfServiceNegotiation(); 540 MaybeStartTermsOfServiceNegotiation();
610 } 541 }
611 542
612 void ArcSessionManager::RequestDisable() { 543 void ArcSessionManager::RequestDisable() {
613 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 544 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
614 DCHECK(profile_); 545 DCHECK(profile_);
615 546
616 if (!enable_requested_) { 547 if (!enable_requested_) {
617 VLOG(1) << "ARC is already disabled. Do nothing."; 548 VLOG(1) << "ARC is already disabled. Do nothing.";
618 return; 549 return;
619 } 550 }
620 enable_requested_ = false; 551 enable_requested_ = false;
621 552
622 // Reset any pending request to re-enable ARC. 553 // Reset any pending request to re-enable ARC.
623 VLOG(1) << "ARC opt-out. Removing user data.";
624 reenable_arc_ = false; 554 reenable_arc_ = false;
625 StopArc(); 555 StopArc();
626 RemoveArcData(); 556 VLOG(1) << "ARC opt-out. Removing user data.";
557 RequestArcDataRemoval();
627 } 558 }
628 559
629 void ArcSessionManager::StartTermsOfServiceNegotiation() { 560 void ArcSessionManager::RequestArcDataRemoval() {
561 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
562 DCHECK(profile_);
563 // TODO(hidehiko): DCHECK the previous state. This is called for three cases;
564 // 1) Supporting managed user initial disabled case (Please see also
565 // ArcPlayStoreEnabledPreferenceHandler::Start() for details).
566 // 2) Supporting enterprise triggered data removal.
567 // 3) One called in OnProvisioningFinished().
568 // 4) On request disabling.
569 // After the state machine is fixed, 2) should be replaced by
570 // RequestDisable() immediately followed by RequestEnable().
571 // 3) and 4) are internal state transition. So, as for public interface, 1)
572 // should be the only use case, and the |state_| should be limited to
573 // STOPPED, then.
574 // TODO(hidehiko): Think a way to get rid of 1), too.
575
576 // Just remember the request in persistent data. The actual removal
577 // is done via MaybeStartArcDataRemoval(). On completion (in
578 // OnArcDataRemoved()), this flag should be reset.
579 profile_->GetPrefs()->SetBoolean(prefs::kArcDataRemoveRequested, true);
580
581 // To support 1) case above, maybe start data removal.
582 if (state_ == State::STOPPED && arc_session_runner_->IsStopped())
583 MaybeStartArcDataRemoval();
584 }
585
586 void ArcSessionManager::MaybeStartTermsOfServiceNegotiation() {
630 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 587 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
631 DCHECK(profile_); 588 DCHECK(profile_);
632 DCHECK(!terms_of_service_negotiator_); 589 DCHECK(!terms_of_service_negotiator_);
633 // In Kiosk-mode, Terms of Service negotiation should be skipped. 590 // In Kiosk-mode, Terms of Service negotiation should be skipped.
634 // See also RequestEnableImpl(). 591 // See also RequestEnableImpl().
635 DCHECK(!IsArcKioskMode()); 592 DCHECK(!IsArcKioskMode());
636 // If opt-in verification is disabled, Terms of Service negotiation should 593 // If opt-in verification is disabled, Terms of Service negotiation should
637 // be skipped, too. See also RequestEnableImpl(). 594 // be skipped, too. See also RequestEnableImpl().
638 DCHECK(!IsArcOptInVerificationDisabled()); 595 DCHECK(!IsArcOptInVerificationDisabled());
639 596
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after
843 void ArcSessionManager::StopArc() { 800 void ArcSessionManager::StopArc() {
844 if (state_ != State::STOPPED) { 801 if (state_ != State::STOPPED) {
845 profile_->GetPrefs()->SetBoolean(prefs::kArcSignedIn, false); 802 profile_->GetPrefs()->SetBoolean(prefs::kArcSignedIn, false);
846 profile_->GetPrefs()->SetBoolean(prefs::kArcTermsAccepted, false); 803 profile_->GetPrefs()->SetBoolean(prefs::kArcTermsAccepted, false);
847 } 804 }
848 ShutdownSession(); 805 ShutdownSession();
849 if (support_host_) 806 if (support_host_)
850 support_host_->Close(); 807 support_host_->Close();
851 } 808 }
852 809
810 void ArcSessionManager::MaybeStartArcDataRemoval() {
811 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
812 DCHECK(profile_);
813 // Data removal cannot run in parallel with ARC session.
814 DCHECK(arc_session_runner_->IsStopped());
815
816 // TODO(hidehiko): DCHECK the previous state, when the state machine is
817 // fixed.
818 SetState(State::REMOVING_DATA_DIR);
819
820 // TODO(hidehiko): Extract the implementation of data removal, so that
821 // shutdown can cancel the operation not to call OnArcDataRemoved callback.
822 if (!profile_->GetPrefs()->GetBoolean(prefs::kArcDataRemoveRequested)) {
823 // ARC data removal is not requested. Just move to the next state.
824 MaybeReenableArc();
825 return;
826 }
827
828 VLOG(1) << "Starting ARC data removal";
829
830 // Remove Play user ID for Active Directory managed devices.
831 profile_->GetPrefs()->SetString(prefs::kArcActiveDirectoryPlayUserId,
832 std::string());
833
834 chromeos::DBusThreadManager::Get()->GetSessionManagerClient()->RemoveArcData(
835 cryptohome::Identification(
836 multi_user_util::GetAccountIdFromProfile(profile_)),
837 base::Bind(&ArcSessionManager::OnArcDataRemoved,
838 weak_ptr_factory_.GetWeakPtr()));
839 }
840
841 void ArcSessionManager::OnArcDataRemoved(bool success) {
842 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
843
844 // TODO(khmel): Browser tests may shutdown profile by itself. Update browser
845 // tests and remove this check.
846 if (state() == State::NOT_INITIALIZED)
847 return;
848
849 DCHECK_EQ(state_, State::REMOVING_DATA_DIR);
850 DCHECK(profile_);
851 DCHECK(profile_->GetPrefs()->GetBoolean(prefs::kArcDataRemoveRequested));
852 if (success) {
853 VLOG(1) << "ARC data removal successful";
854 } else {
855 LOG(ERROR) << "Request for ARC user data removal failed. "
856 << "See session_manager logs for more details.";
857 }
858 profile_->GetPrefs()->SetBoolean(prefs::kArcDataRemoveRequested, false);
859
860 // Regardless of whether it is successfully done or not, notify observers.
861 for (auto& observer : observer_list_)
862 observer.OnArcDataRemoved();
863
864 MaybeReenableArc();
865 }
866
867 void ArcSessionManager::MaybeReenableArc() {
868 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
869 DCHECK_EQ(state_, State::REMOVING_DATA_DIR);
870 SetState(State::STOPPED);
871
872 // Here check if |reenable_arc_| is marked or not.
873 // TODO(hidehiko): Conceptually |reenable_arc_| should be always false
874 // if |enable_requested_| is false. Replace by DCHECK after state machine
875 // fix is done.
876 if (!reenable_arc_ || !enable_requested_) {
877 // Reset the flag, just in case. TODO(hidehiko): Remove this.
878 reenable_arc_ = false;
879 return;
880 }
881
882 // Restart ARC anyway. Let the enterprise reporting instance decide whether
883 // the ARC user data wipe is still required or not.
884 reenable_arc_ = false;
885 VLOG(1) << "Reenable ARC";
886 RequestEnableImpl();
887 }
888
853 void ArcSessionManager::OnWindowClosed() { 889 void ArcSessionManager::OnWindowClosed() {
854 DCHECK(support_host_); 890 DCHECK(support_host_);
855 if (terms_of_service_negotiator_) { 891 if (terms_of_service_negotiator_) {
856 // In this case, ArcTermsOfServiceNegotiator should handle the case. 892 // In this case, ArcTermsOfServiceNegotiator should handle the case.
857 // Do nothing. 893 // Do nothing.
858 return; 894 return;
859 } 895 }
860 CancelAuthCode(); 896 CancelAuthCode();
861 } 897 }
862 898
863 void ArcSessionManager::OnTermsAgreed(bool is_metrics_enabled, 899 void ArcSessionManager::OnTermsAgreed(bool is_metrics_enabled,
864 bool is_backup_and_restore_enabled, 900 bool is_backup_and_restore_enabled,
865 bool is_location_service_enabled) { 901 bool is_location_service_enabled) {
866 DCHECK(support_host_); 902 DCHECK(support_host_);
867 DCHECK(terms_of_service_negotiator_); 903 DCHECK(terms_of_service_negotiator_);
868 // This should be handled in ArcTermsOfServiceNegotiator. Do nothing here. 904 // This should be handled in ArcTermsOfServiceNegotiator. Do nothing here.
869 } 905 }
870 906
871 void ArcSessionManager::OnRetryClicked() { 907 void ArcSessionManager::OnRetryClicked() {
872 DCHECK(support_host_); 908 DCHECK(support_host_);
873 909
874 UpdateOptInActionUMA(OptInActionType::RETRY); 910 UpdateOptInActionUMA(OptInActionType::RETRY);
875 911
876 // TODO(hidehiko): Simplify the retry logic. 912 // TODO(hidehiko): Simplify the retry logic.
877 if (terms_of_service_negotiator_) { 913 if (terms_of_service_negotiator_) {
878 // Currently Terms of service is shown. ArcTermsOfServiceNegotiator should 914 // Currently Terms of service is shown. ArcTermsOfServiceNegotiator should
879 // handle this. 915 // handle this.
880 } else if (!profile_->GetPrefs()->GetBoolean(prefs::kArcTermsAccepted)) { 916 } else if (!profile_->GetPrefs()->GetBoolean(prefs::kArcTermsAccepted)) {
881 StartTermsOfServiceNegotiation(); 917 MaybeStartTermsOfServiceNegotiation();
882 } else if (support_host_->ui_page() == ArcSupportHost::UIPage::ERROR && 918 } else if (support_host_->ui_page() == ArcSupportHost::UIPage::ERROR &&
883 !arc_session_runner_->IsStopped()) { 919 !arc_session_runner_->IsStopped()) {
884 // ERROR_WITH_FEEDBACK is set in OnSignInFailed(). In the case, stopping 920 // ERROR_WITH_FEEDBACK is set in OnSignInFailed(). In the case, stopping
885 // ARC was postponed to contain its internal state into the report. 921 // ARC was postponed to contain its internal state into the report.
886 // Here, on retry, stop it, then restart. 922 // Here, on retry, stop it, then restart.
887 DCHECK_EQ(State::ACTIVE, state_); 923 DCHECK_EQ(State::ACTIVE, state_);
888 support_host_->ShowArcLoading(); 924 support_host_->ShowArcLoading();
889 ShutdownSession(); 925 ShutdownSession();
890 reenable_arc_ = true; 926 reenable_arc_ = true;
891 } else if (state_ == State::ACTIVE) { 927 } else if (state_ == State::ACTIVE) {
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
937 973
938 #undef MAP_STATE 974 #undef MAP_STATE
939 975
940 // Some compilers report an error even if all values of an enum-class are 976 // Some compilers report an error even if all values of an enum-class are
941 // covered exhaustively in a switch statement. 977 // covered exhaustively in a switch statement.
942 NOTREACHED() << "Invalid value " << static_cast<int>(state); 978 NOTREACHED() << "Invalid value " << static_cast<int>(state);
943 return os; 979 return os;
944 } 980 }
945 981
946 } // namespace arc 982 } // namespace arc
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/arc/arc_session_manager.h ('k') | chrome/browser/chromeos/arc/arc_session_manager_browsertest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698