Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 144 // If ARC is being restarted, here do nothing, and just wait for its | 144 // If ARC is being restarted, here do nothing, and just wait for its |
| 145 // next run. | 145 // next run. |
| 146 VLOG(1) << "ARC session is stopped, but being restarted: " << reason; | 146 VLOG(1) << "ARC session is stopped, but being restarted: " << reason; |
| 147 return; | 147 return; |
| 148 } | 148 } |
| 149 | 149 |
| 150 // TODO(crbug.com/625923): Use |reason| to report more detailed errors. | 150 // TODO(crbug.com/625923): Use |reason| to report more detailed errors. |
| 151 if (arc_sign_in_timer_.IsRunning()) | 151 if (arc_sign_in_timer_.IsRunning()) |
| 152 OnProvisioningFinished(ProvisioningResult::ARC_STOPPED); | 152 OnProvisioningFinished(ProvisioningResult::ARC_STOPPED); |
| 153 | 153 |
| 154 if (profile_->GetPrefs()->GetBoolean(prefs::kArcDataRemoveRequested)) { | 154 for (auto& observer : observer_list_) |
| 155 // This should be always true, but just in case as this is looked at | 155 observer.OnArcSessionStopped(reason); |
| 156 // inside RemoveArcData() at first. | 156 |
| 157 VLOG(1) << "ARC had previously requested to remove user data."; | 157 // Transition to the ARC data remove state. |
| 158 DCHECK(arc_session_runner_->IsStopped()); | 158 if (!profile_->GetPrefs()->GetBoolean(prefs::kArcDataRemoveRequested)) { |
| 159 RemoveArcData(); | 159 // TODO(crbug.com/665316): This is the workaround for the bug. |
| 160 } else { | 160 // If it is not necessary to remove the data, StartArcDataRemoval() |
| 161 // To support special "Stop and enable ARC" procedure for enterprise, | 161 // synchronously calls OnArcDataRemoved(), which causes unexpected |
|
Yusuke Sato
2017/03/07 21:03:08
This line seems outdated now. StartArcDataRemoval
hidehiko
2017/03/09 09:25:51
Done.
| |
| 162 // here call MaybeReenableArc() asyncronously. | 162 // ARC session stop. (Please see the bug for details). |
| 163 // TODO(hidehiko): Restructure the code. crbug.com/665316 | 163 SetState(State::REMOVING_DATA_DIR); |
| 164 base::ThreadTaskRunnerHandle::Get()->PostTask( | 164 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 165 FROM_HERE, base::Bind(&ArcSessionManager::MaybeReenableArc, | 165 FROM_HERE, base::Bind(&ArcSessionManager::MaybeReenableArc, |
| 166 weak_ptr_factory_.GetWeakPtr())); | 166 weak_ptr_factory_.GetWeakPtr())); |
| 167 } | |
| 168 | |
| 169 for (auto& observer : observer_list_) | |
| 170 observer.OnArcSessionStopped(reason); | |
| 171 } | |
| 172 | |
| 173 void ArcSessionManager::RemoveArcData() { | |
| 174 // Ignore redundant data removal request. | |
| 175 if (state() == State::REMOVING_DATA_DIR) | |
| 176 return; | |
| 177 | |
| 178 // OnArcDataRemoved resets this flag. | |
| 179 profile_->GetPrefs()->SetBoolean(prefs::kArcDataRemoveRequested, true); | |
| 180 | |
| 181 if (!arc_session_runner_->IsStopped()) { | |
| 182 // Just set a flag. On session stopped, this will be re-called, | |
| 183 // then session manager should remove the data. | |
| 184 return; | 167 return; |
| 185 } | 168 } |
| 186 | 169 |
| 187 VLOG(1) << "Starting ARC data removal"; | 170 StartArcDataRemoval(); |
| 188 | |
| 189 // Remove Play user ID for Active Directory managed devices. | |
| 190 profile_->GetPrefs()->SetString(prefs::kArcActiveDirectoryPlayUserId, | |
| 191 std::string()); | |
| 192 | |
| 193 SetState(State::REMOVING_DATA_DIR); | |
| 194 chromeos::DBusThreadManager::Get()->GetSessionManagerClient()->RemoveArcData( | |
| 195 cryptohome::Identification( | |
| 196 multi_user_util::GetAccountIdFromProfile(profile_)), | |
| 197 base::Bind(&ArcSessionManager::OnArcDataRemoved, | |
| 198 weak_ptr_factory_.GetWeakPtr())); | |
| 199 } | |
| 200 | |
| 201 void ArcSessionManager::OnArcDataRemoved(bool success) { | |
| 202 if (success) | |
| 203 VLOG(1) << "ARC data removal successful"; | |
| 204 else | |
| 205 LOG(ERROR) << "Request for ARC user data removal failed."; | |
| 206 | |
| 207 // TODO(khmel): Browser tests may shutdown profile by itself. Update browser | |
| 208 // tests and remove this check. | |
| 209 if (state() == State::NOT_INITIALIZED) | |
| 210 return; | |
| 211 | |
| 212 for (auto& observer : observer_list_) | |
| 213 observer.OnArcDataRemoved(); | |
| 214 | |
| 215 profile_->GetPrefs()->SetBoolean(prefs::kArcDataRemoveRequested, false); | |
| 216 DCHECK_EQ(state(), State::REMOVING_DATA_DIR); | |
| 217 SetState(State::STOPPED); | |
| 218 | |
| 219 MaybeReenableArc(); | |
| 220 } | |
| 221 | |
| 222 void ArcSessionManager::MaybeReenableArc() { | |
| 223 // Here check if |reenable_arc_| is marked or not. | |
| 224 // The only case this happens should be in the special case for enterprise | |
| 225 // "on managed lost" case. In that case, OnSessionStopped() should trigger | |
| 226 // the RemoveArcData(), then this. | |
| 227 // TODO(hidehiko): It looks necessary to reset |reenable_arc_| regardless of | |
| 228 // |enable_requested_|. Fix it. | |
| 229 if (!reenable_arc_ || !enable_requested_) | |
| 230 return; | |
| 231 | |
| 232 // Restart ARC anyway. Let the enterprise reporting instance decide whether | |
| 233 // the ARC user data wipe is still required or not. | |
| 234 reenable_arc_ = false; | |
| 235 VLOG(1) << "Reenable ARC"; | |
| 236 RequestEnableImpl(); | |
| 237 } | 171 } |
| 238 | 172 |
| 239 void ArcSessionManager::OnProvisioningFinished(ProvisioningResult result) { | 173 void ArcSessionManager::OnProvisioningFinished(ProvisioningResult result) { |
| 240 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 174 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 241 | 175 |
| 242 // If the Mojo message to notify finishing the provisioning is already sent | 176 // If the Mojo message to notify finishing the provisioning is already sent |
| 243 // from the container, it will be processed even after requesting to stop the | 177 // from the container, it will be processed even after requesting to stop the |
| 244 // container. Ignore all |result|s arriving while ARC is disabled, in order to | 178 // container. Ignore all |result|s arriving while ARC is disabled, in order to |
| 245 // avoid popping up an error message triggered below. This code intentionally | 179 // avoid popping up an error message triggered below. This code intentionally |
| 246 // does not support the case of reenabling. | 180 // does not support the case of reenabling. |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 370 | 304 |
| 371 if (result == ProvisioningResult::CLOUD_PROVISION_FLOW_FAILED || | 305 if (result == ProvisioningResult::CLOUD_PROVISION_FLOW_FAILED || |
| 372 result == ProvisioningResult::CLOUD_PROVISION_FLOW_TIMEOUT || | 306 result == ProvisioningResult::CLOUD_PROVISION_FLOW_TIMEOUT || |
| 373 result == ProvisioningResult::CLOUD_PROVISION_FLOW_INTERNAL_ERROR || | 307 result == ProvisioningResult::CLOUD_PROVISION_FLOW_INTERNAL_ERROR || |
| 374 // OVERALL_SIGN_IN_TIMEOUT might be an indication that ARC believes it is | 308 // OVERALL_SIGN_IN_TIMEOUT might be an indication that ARC believes it is |
| 375 // fully setup, but Chrome does not. | 309 // fully setup, but Chrome does not. |
| 376 result == ProvisioningResult::OVERALL_SIGN_IN_TIMEOUT || | 310 result == ProvisioningResult::OVERALL_SIGN_IN_TIMEOUT || |
| 377 // Just to be safe, remove data if we don't know the cause. | 311 // Just to be safe, remove data if we don't know the cause. |
| 378 result == ProvisioningResult::UNKNOWN_ERROR) { | 312 result == ProvisioningResult::UNKNOWN_ERROR) { |
| 379 VLOG(1) << "ARC provisioning failed permanently. Removing user data"; | 313 VLOG(1) << "ARC provisioning failed permanently. Removing user data"; |
| 380 RemoveArcData(); | 314 RequestArcDataRemoval(); |
| 381 } | 315 } |
| 382 | 316 |
| 383 // We'll delay shutting down the ARC instance in this case to allow people | 317 // We'll delay shutting down the ARC instance in this case to allow people |
| 384 // to send feedback. | 318 // to send feedback. |
| 385 if (support_host_) | 319 if (support_host_) |
| 386 support_host_->ShowError(error, true /* = show send feedback button */); | 320 support_host_->ShowError(error, true /* = show send feedback button */); |
| 387 } | 321 } |
| 388 | 322 |
| 389 void ArcSessionManager::SetState(State state) { | 323 void ArcSessionManager::SetState(State state) { |
| 390 state_ = state; | 324 state_ = state; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 427 SetState(State::STOPPED); | 361 SetState(State::STOPPED); |
| 428 | 362 |
| 429 context_ = base::MakeUnique<ArcAuthContext>(profile_); | 363 context_ = base::MakeUnique<ArcAuthContext>(profile_); |
| 430 | 364 |
| 431 if (!g_disable_ui_for_testing || | 365 if (!g_disable_ui_for_testing || |
| 432 g_enable_check_android_management_for_testing) { | 366 g_enable_check_android_management_for_testing) { |
| 433 ArcAndroidManagementChecker::StartClient(); | 367 ArcAndroidManagementChecker::StartClient(); |
| 434 } | 368 } |
| 435 | 369 |
| 436 // Chrome may be shut down before completing ARC data removal. | 370 // Chrome may be shut down before completing ARC data removal. |
| 437 // In such a case, start removing the data now. | 371 // For such a case, start removing the data now, if necessary. |
| 438 if (profile_->GetPrefs()->GetBoolean(prefs::kArcDataRemoveRequested)) { | 372 StartArcDataRemoval(); |
| 439 VLOG(1) << "ARC data removal requested in previous session."; | |
| 440 RemoveArcData(); | |
| 441 } | |
| 442 } | 373 } |
| 443 | 374 |
| 444 void ArcSessionManager::Shutdown() { | 375 void ArcSessionManager::Shutdown() { |
| 445 enable_requested_ = false; | 376 enable_requested_ = false; |
| 446 ShutdownSession(); | 377 ShutdownSession(); |
| 447 if (support_host_) { | 378 if (support_host_) { |
| 448 support_host_->Close(); | 379 support_host_->Close(); |
| 449 support_host_->RemoveObserver(this); | 380 support_host_->RemoveObserver(this); |
| 450 support_host_.reset(); | 381 support_host_.reset(); |
| 451 } | 382 } |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 636 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 567 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 637 DCHECK(profile_); | 568 DCHECK(profile_); |
| 638 | 569 |
| 639 if (!enable_requested_) { | 570 if (!enable_requested_) { |
| 640 VLOG(1) << "ARC is already disabled. Do nothing."; | 571 VLOG(1) << "ARC is already disabled. Do nothing."; |
| 641 return; | 572 return; |
| 642 } | 573 } |
| 643 enable_requested_ = false; | 574 enable_requested_ = false; |
| 644 | 575 |
| 645 // Reset any pending request to re-enable ARC. | 576 // Reset any pending request to re-enable ARC. |
| 646 VLOG(1) << "ARC opt-out. Removing user data."; | |
| 647 reenable_arc_ = false; | 577 reenable_arc_ = false; |
| 648 StopArc(); | 578 StopArc(); |
| 649 RemoveArcData(); | 579 VLOG(1) << "ARC opt-out. Removing user data."; |
| 580 RequestArcDataRemoval(); | |
| 581 } | |
| 582 | |
| 583 void ArcSessionManager::RequestArcDataRemoval() { | |
| 584 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
| 585 DCHECK(profile_); | |
| 586 // TODO(hidehiko): DCHECK the previous state. This is called for three cases; | |
| 587 // 1) Supporting managed user initial disabled case (Please see also | |
| 588 // ArcPlayStoreEnabledPreferenceHandler::Start() for details). | |
| 589 // 2) Supporting enterprise triggered data removal. | |
| 590 // 3) One called in OnProvisioningFinished(). | |
| 591 // 4) On request disabling. | |
| 592 // After the state machine is fixed, 2) should be replaced by | |
| 593 // RequestDisable() immediately followed by RequestEnable(). | |
| 594 // 3) and 4) are internal state transition. So, as for public interface, 1) | |
| 595 // should be the only use case, and the |state_| should be limited to | |
| 596 // STOPPED, then. | |
| 597 // TODO(hidehiko): Think a way to get rid of 1), too. | |
| 598 | |
| 599 // Just remember the request in persistent data. The actual removal | |
| 600 // is done via StartArcDataRemoval(). On completion (in OnArcDataRemoved()), | |
| 601 // this flag should be reset. | |
| 602 profile_->GetPrefs()->SetBoolean(prefs::kArcDataRemoveRequested, true); | |
| 603 | |
| 604 // To support 1) case above, maybe start data removal. | |
| 605 if (state_ == State::STOPPED && arc_session_runner_->IsStopped()) | |
| 606 StartArcDataRemoval(); | |
| 650 } | 607 } |
| 651 | 608 |
| 652 void ArcSessionManager::StartTermsOfServiceNegotiation() { | 609 void ArcSessionManager::StartTermsOfServiceNegotiation() { |
| 653 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 610 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 654 DCHECK(!terms_of_service_negotiator_); | 611 DCHECK(!terms_of_service_negotiator_); |
| 655 | 612 |
| 656 if (!arc_session_runner_->IsStopped()) { | 613 if (!arc_session_runner_->IsStopped()) { |
| 657 // If the user attempts to re-enable ARC while the ARC instance is still | 614 // If the user attempts to re-enable ARC while the ARC instance is still |
| 658 // running the user should not be able to continue until the ARC instance | 615 // running the user should not be able to continue until the ARC instance |
| 659 // has stopped. | 616 // has stopped. |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 815 void ArcSessionManager::StopArc() { | 772 void ArcSessionManager::StopArc() { |
| 816 if (state_ != State::STOPPED) { | 773 if (state_ != State::STOPPED) { |
| 817 profile_->GetPrefs()->SetBoolean(prefs::kArcSignedIn, false); | 774 profile_->GetPrefs()->SetBoolean(prefs::kArcSignedIn, false); |
| 818 profile_->GetPrefs()->SetBoolean(prefs::kArcTermsAccepted, false); | 775 profile_->GetPrefs()->SetBoolean(prefs::kArcTermsAccepted, false); |
| 819 } | 776 } |
| 820 ShutdownSession(); | 777 ShutdownSession(); |
| 821 if (support_host_) | 778 if (support_host_) |
| 822 support_host_->Close(); | 779 support_host_->Close(); |
| 823 } | 780 } |
| 824 | 781 |
| 782 void ArcSessionManager::StartArcDataRemoval() { | |
| 783 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
| 784 DCHECK(profile_); | |
| 785 // Data removal cannot run, in parallel with ARC session. | |
|
Luis Héctor Chávez
2017/03/07 21:52:00
nit: remove comma.
hidehiko
2017/03/09 09:25:51
Done.
| |
| 786 DCHECK(arc_session_runner_->IsStopped()); | |
| 787 | |
| 788 // TODO(hidehiko): DCHECK the previous state, when the state machine is | |
| 789 // fixed. | |
| 790 SetState(State::REMOVING_DATA_DIR); | |
| 791 | |
| 792 // TODO(hidehiko): Extract the implementation of data removal, so that | |
| 793 // shutdown can cancel the operation not to call OnArcDataRemoved callback. | |
| 794 if (!profile_->GetPrefs()->GetBoolean(prefs::kArcDataRemoveRequested)) { | |
| 795 // ARC data removal is not requested. Just move to the next state. | |
| 796 MaybeReenableArc(); | |
| 797 return; | |
| 798 } | |
| 799 | |
| 800 VLOG(1) << "Starting ARC data removal"; | |
| 801 | |
| 802 // Remove Play user ID for Active Directory managed devices. | |
| 803 profile_->GetPrefs()->SetString(prefs::kArcActiveDirectoryPlayUserId, | |
| 804 std::string()); | |
| 805 | |
| 806 chromeos::DBusThreadManager::Get()->GetSessionManagerClient()->RemoveArcData( | |
| 807 cryptohome::Identification( | |
| 808 multi_user_util::GetAccountIdFromProfile(profile_)), | |
| 809 base::Bind(&ArcSessionManager::OnArcDataRemoved, | |
| 810 weak_ptr_factory_.GetWeakPtr())); | |
| 811 } | |
| 812 | |
| 813 void ArcSessionManager::OnArcDataRemoved(bool success) { | |
| 814 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
| 815 | |
| 816 // TODO(khmel): Browser tests may shutdown profile by itself. Update browser | |
| 817 // tests and remove this check. | |
| 818 if (state() == State::NOT_INITIALIZED) | |
| 819 return; | |
| 820 | |
| 821 DCHECK_EQ(state_, State::REMOVING_DATA_DIR); | |
| 822 DCHECK(profile_); | |
| 823 DCHECK(profile_->GetPrefs()->GetBoolean(prefs::kArcDataRemoveRequested)); | |
|
Yusuke Sato
2017/03/07 21:03:08
Thanks, the cb function is much easier to follow n
hidehiko
2017/03/09 09:25:50
Could you explain a bit more details about your qu
| |
| 824 if (success) | |
| 825 VLOG(1) << "ARC data removal successful"; | |
| 826 else | |
| 827 LOG(ERROR) << "Request for ARC user data removal failed."; | |
|
Yusuke Sato
2017/03/07 21:03:08
nit: What about adding 'See session_manager logs f
hidehiko
2017/03/09 09:25:51
Done.
| |
| 828 profile_->GetPrefs()->SetBoolean(prefs::kArcDataRemoveRequested, false); | |
| 829 | |
| 830 // Data removal runs (regardless of whether it is successfully done or | |
|
Luis Héctor Chávez
2017/03/07 21:52:00
This is not strictly true: there have been cases w
hidehiko
2017/03/09 09:25:51
I just wanted to say this is called regardless of
| |
| 831 // not), so notify observers. | |
| 832 for (auto& observer : observer_list_) | |
| 833 observer.OnArcDataRemoved(); | |
| 834 | |
| 835 MaybeReenableArc(); | |
| 836 } | |
| 837 | |
| 838 void ArcSessionManager::MaybeReenableArc() { | |
|
Yusuke Sato
2017/03/07 21:03:08
nit: why did you move this down? shouldn't we pres
hidehiko
2017/03/09 09:25:50
Yes, (and that's the order of the state transition
| |
| 839 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
| 840 DCHECK_EQ(state_, State::REMOVING_DATA_DIR); | |
| 841 SetState(State::STOPPED); | |
| 842 | |
| 843 // Here check if |reenable_arc_| is marked or not. | |
| 844 // TODO(hidehiko): Conceptually |reenable_arc_| should be always false | |
| 845 // if |enable_requested_| is false. Replace by DCHECK after state machine | |
| 846 // fix is done. | |
| 847 if (!reenable_arc_ || !enable_requested_) { | |
| 848 // Reset the flag, just in case. TODO(hidehiko): Remove this. | |
| 849 reenable_arc_ = false; | |
| 850 return; | |
| 851 } | |
| 852 | |
| 853 // Restart ARC anyway. Let the enterprise reporting instance decide whether | |
| 854 // the ARC user data wipe is still required or not. | |
| 855 reenable_arc_ = false; | |
| 856 VLOG(1) << "Reenable ARC"; | |
| 857 RequestEnableImpl(); | |
| 858 } | |
| 859 | |
| 825 void ArcSessionManager::OnWindowClosed() { | 860 void ArcSessionManager::OnWindowClosed() { |
| 826 DCHECK(support_host_); | 861 DCHECK(support_host_); |
| 827 if (terms_of_service_negotiator_) { | 862 if (terms_of_service_negotiator_) { |
| 828 // In this case, ArcTermsOfServiceNegotiator should handle the case. | 863 // In this case, ArcTermsOfServiceNegotiator should handle the case. |
| 829 // Do nothing. | 864 // Do nothing. |
| 830 return; | 865 return; |
| 831 } | 866 } |
| 832 CancelAuthCode(); | 867 CancelAuthCode(); |
| 833 } | 868 } |
| 834 | 869 |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 910 | 945 |
| 911 #undef MAP_STATE | 946 #undef MAP_STATE |
| 912 | 947 |
| 913 // Some compilers report an error even if all values of an enum-class are | 948 // Some compilers report an error even if all values of an enum-class are |
| 914 // covered exhaustively in a switch statement. | 949 // covered exhaustively in a switch statement. |
| 915 NOTREACHED() << "Invalid value " << static_cast<int>(state); | 950 NOTREACHED() << "Invalid value " << static_cast<int>(state); |
| 916 return os; | 951 return os; |
| 917 } | 952 } |
| 918 | 953 |
| 919 } // namespace arc | 954 } // namespace arc |
| OLD | NEW |