| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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_auth_service.h" | 5 #include "chrome/browser/chromeos/arc/arc_auth_service.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" |
| 11 #include "base/auto_reset.h" | 11 #include "base/auto_reset.h" |
| 12 #include "base/bind.h" | 12 #include "base/bind.h" |
| 13 #include "base/command_line.h" | 13 #include "base/command_line.h" |
| 14 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "base/strings/string16.h" | 15 #include "base/strings/string16.h" |
| 16 #include "base/time/time.h" |
| 16 #include "chrome/browser/chromeos/arc/arc_android_management_checker.h" | 17 #include "chrome/browser/chromeos/arc/arc_android_management_checker.h" |
| 17 #include "chrome/browser/chromeos/arc/arc_auth_code_fetcher.h" | 18 #include "chrome/browser/chromeos/arc/arc_auth_code_fetcher.h" |
| 18 #include "chrome/browser/chromeos/arc/arc_auth_context.h" | 19 #include "chrome/browser/chromeos/arc/arc_auth_context.h" |
| 19 #include "chrome/browser/chromeos/arc/arc_auth_notification.h" | 20 #include "chrome/browser/chromeos/arc/arc_auth_notification.h" |
| 20 #include "chrome/browser/chromeos/arc/arc_optin_uma.h" | 21 #include "chrome/browser/chromeos/arc/arc_optin_uma.h" |
| 21 #include "chrome/browser/chromeos/arc/arc_support_host.h" | 22 #include "chrome/browser/chromeos/arc/arc_support_host.h" |
| 22 #include "chrome/browser/chromeos/profiles/profile_helper.h" | 23 #include "chrome/browser/chromeos/profiles/profile_helper.h" |
| 23 #include "chrome/browser/extensions/extension_util.h" | 24 #include "chrome/browser/extensions/extension_util.h" |
| 24 #include "chrome/browser/policy/profile_policy_connector.h" | 25 #include "chrome/browser/policy/profile_policy_connector.h" |
| 25 #include "chrome/browser/policy/profile_policy_connector_factory.h" | 26 #include "chrome/browser/policy/profile_policy_connector_factory.h" |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 58 // Skip creating UI in unit tests | 59 // Skip creating UI in unit tests |
| 59 bool g_disable_ui_for_testing = false; | 60 bool g_disable_ui_for_testing = false; |
| 60 | 61 |
| 61 // Use specified ash::ShelfDelegate for unit tests. | 62 // Use specified ash::ShelfDelegate for unit tests. |
| 62 ash::ShelfDelegate* g_shelf_delegate_for_testing = nullptr; | 63 ash::ShelfDelegate* g_shelf_delegate_for_testing = nullptr; |
| 63 | 64 |
| 64 // The Android management check is disabled by default, it's used only for | 65 // The Android management check is disabled by default, it's used only for |
| 65 // testing. | 66 // testing. |
| 66 bool g_enable_check_android_management_for_testing = false; | 67 bool g_enable_check_android_management_for_testing = false; |
| 67 | 68 |
| 69 // Maximum amount of time we'll wait for ARC to finish booting up. Once this |
| 70 // timeout expires, keep ARC running in case the user wants to file feedback, |
| 71 // but present the UI to try again. |
| 72 constexpr base::TimeDelta kArcSignInTimeout = base::TimeDelta::FromMinutes(5); |
| 73 |
| 68 const char kStateNotInitialized[] = "NOT_INITIALIZED"; | 74 const char kStateNotInitialized[] = "NOT_INITIALIZED"; |
| 69 const char kStateStopped[] = "STOPPED"; | 75 const char kStateStopped[] = "STOPPED"; |
| 70 const char kStateFetchingCode[] = "FETCHING_CODE"; | 76 const char kStateFetchingCode[] = "FETCHING_CODE"; |
| 71 const char kStateActive[] = "ACTIVE"; | 77 const char kStateActive[] = "ACTIVE"; |
| 72 | 78 |
| 73 bool IsAccountManaged(Profile* profile) { | 79 bool IsAccountManaged(Profile* profile) { |
| 74 return policy::ProfilePolicyConnectorFactory::GetForBrowserContext(profile) | 80 return policy::ProfilePolicyConnectorFactory::GetForBrowserContext(profile) |
| 75 ->IsManaged(); | 81 ->IsManaged(); |
| 76 } | 82 } |
| 77 | 83 |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 222 return true; | 228 return true; |
| 223 } | 229 } |
| 224 | 230 |
| 225 void ArcAuthService::OnInstanceReady() { | 231 void ArcAuthService::OnInstanceReady() { |
| 226 arc_bridge_service()->auth()->instance()->Init( | 232 arc_bridge_service()->auth()->instance()->Init( |
| 227 binding_.CreateInterfacePtrAndBind()); | 233 binding_.CreateInterfacePtrAndBind()); |
| 228 } | 234 } |
| 229 | 235 |
| 230 void ArcAuthService::OnBridgeStopped(ArcBridgeService::StopReason reason) { | 236 void ArcAuthService::OnBridgeStopped(ArcBridgeService::StopReason reason) { |
| 231 // TODO(crbug.com/625923): Use |reason| to report more detailed errors. | 237 // TODO(crbug.com/625923): Use |reason| to report more detailed errors. |
| 232 if (waiting_for_reply_) { | 238 if (arc_sign_in_timer_.IsRunning()) { |
| 233 // Using SERVICE_UNAVAILABLE instead of UNKNOWN_ERROR, since the latter | |
| 234 // causes this code to not try to stop ARC, so it would retry without the | |
| 235 // user noticing. | |
| 236 OnSignInFailedInternal(ProvisioningResult::ARC_STOPPED); | 239 OnSignInFailedInternal(ProvisioningResult::ARC_STOPPED); |
| 237 } | 240 } |
| 238 | 241 |
| 239 if (clear_required_) { | 242 if (clear_required_) { |
| 240 // This should be always true, but just in case as this is looked at | 243 // This should be always true, but just in case as this is looked at |
| 241 // inside RemoveArcData() at first. | 244 // inside RemoveArcData() at first. |
| 242 DCHECK(arc_bridge_service()->stopped()); | 245 DCHECK(arc_bridge_service()->stopped()); |
| 243 RemoveArcData(); | 246 RemoveArcData(); |
| 244 } else { | 247 } else { |
| 245 // To support special "Stop and enable ARC" procedure for enterprise, | 248 // To support special "Stop and enable ARC" procedure for enterprise, |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 310 initial_opt_in_ = false; | 313 initial_opt_in_ = false; |
| 311 auth_callback_ = callback; | 314 auth_callback_ = callback; |
| 312 StartUI(); | 315 StartUI(); |
| 313 } | 316 } |
| 314 | 317 |
| 315 void ArcAuthService::OnSignInComplete() { | 318 void ArcAuthService::OnSignInComplete() { |
| 316 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 319 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 317 DCHECK_EQ(state_, State::ACTIVE); | 320 DCHECK_EQ(state_, State::ACTIVE); |
| 318 DCHECK(!sign_in_time_.is_null()); | 321 DCHECK(!sign_in_time_.is_null()); |
| 319 | 322 |
| 320 waiting_for_reply_ = false; | 323 arc_sign_in_timer_.Stop(); |
| 321 | 324 |
| 322 if (!IsOptInVerificationDisabled() && | 325 if (!IsOptInVerificationDisabled() && |
| 323 !profile_->GetPrefs()->GetBoolean(prefs::kArcSignedIn)) { | 326 !profile_->GetPrefs()->GetBoolean(prefs::kArcSignedIn)) { |
| 324 playstore_launcher_.reset( | 327 playstore_launcher_.reset( |
| 325 new ArcAppLauncher(profile_, kPlayStoreAppId, true)); | 328 new ArcAppLauncher(profile_, kPlayStoreAppId, true)); |
| 326 } | 329 } |
| 327 | 330 |
| 328 profile_->GetPrefs()->SetBoolean(prefs::kArcSignedIn, true); | 331 profile_->GetPrefs()->SetBoolean(prefs::kArcSignedIn, true); |
| 329 CloseUI(); | 332 CloseUI(); |
| 330 UpdateProvisioningTiming(base::Time::Now() - sign_in_time_, true, | 333 UpdateProvisioningTiming(base::Time::Now() - sign_in_time_, true, |
| 331 IsAccountManaged(profile_)); | 334 IsAccountManaged(profile_)); |
| 332 UpdateProvisioningResultUMA(ProvisioningResult::SUCCESS); | 335 UpdateProvisioningResultUMA(ProvisioningResult::SUCCESS); |
| 333 | 336 |
| 334 FOR_EACH_OBSERVER(Observer, observer_list_, OnInitialStart()); | 337 FOR_EACH_OBSERVER(Observer, observer_list_, OnInitialStart()); |
| 335 } | 338 } |
| 336 | 339 |
| 337 void ArcAuthService::OnSignInFailed(arc::mojom::ArcSignInFailureReason reason) { | 340 void ArcAuthService::OnSignInFailed(arc::mojom::ArcSignInFailureReason reason) { |
| 338 OnSignInFailedInternal( | 341 OnSignInFailedInternal( |
| 339 ConvertArcSignInFailureReasonToProvisioningResult(reason)); | 342 ConvertArcSignInFailureReasonToProvisioningResult(reason)); |
| 340 } | 343 } |
| 341 | 344 |
| 342 void ArcAuthService::OnSignInFailedInternal(ProvisioningResult result) { | 345 void ArcAuthService::OnSignInFailedInternal(ProvisioningResult result) { |
| 343 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 346 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 344 DCHECK_EQ(state_, State::ACTIVE); | 347 DCHECK_EQ(state_, State::ACTIVE); |
| 345 DCHECK(!sign_in_time_.is_null()); | 348 DCHECK(!sign_in_time_.is_null()); |
| 346 | 349 |
| 347 waiting_for_reply_ = false; | 350 arc_sign_in_timer_.Stop(); |
| 348 | 351 |
| 349 UpdateProvisioningTiming(base::Time::Now() - sign_in_time_, false, | 352 UpdateProvisioningTiming(base::Time::Now() - sign_in_time_, false, |
| 350 IsAccountManaged(profile_)); | 353 IsAccountManaged(profile_)); |
| 351 UpdateOptInCancelUMA(OptInCancelReason::CLOUD_PROVISION_FLOW_FAIL); | 354 UpdateOptInCancelUMA(OptInCancelReason::CLOUD_PROVISION_FLOW_FAIL); |
| 352 UpdateProvisioningResultUMA(result); | 355 UpdateProvisioningResultUMA(result); |
| 353 | 356 |
| 354 int error_message_id; | 357 int error_message_id; |
| 355 switch (result) { | 358 switch (result) { |
| 356 case ProvisioningResult::GMS_NETWORK_ERROR: | 359 case ProvisioningResult::GMS_NETWORK_ERROR: |
| 357 error_message_id = IDS_ARC_SIGN_IN_NETWORK_ERROR; | 360 error_message_id = IDS_ARC_SIGN_IN_NETWORK_ERROR; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 384 if (profile_->GetPrefs()->HasPrefPath(prefs::kArcSignedIn)) | 387 if (profile_->GetPrefs()->HasPrefPath(prefs::kArcSignedIn)) |
| 385 profile_->GetPrefs()->SetBoolean(prefs::kArcSignedIn, false); | 388 profile_->GetPrefs()->SetBoolean(prefs::kArcSignedIn, false); |
| 386 ShutdownBridgeAndShowUI(UIPage::ERROR, | 389 ShutdownBridgeAndShowUI(UIPage::ERROR, |
| 387 l10n_util::GetStringUTF16(error_message_id)); | 390 l10n_util::GetStringUTF16(error_message_id)); |
| 388 return; | 391 return; |
| 389 } | 392 } |
| 390 | 393 |
| 391 if (result == ProvisioningResult::CLOUD_PROVISION_FLOW_FAILED || | 394 if (result == ProvisioningResult::CLOUD_PROVISION_FLOW_FAILED || |
| 392 result == ProvisioningResult::CLOUD_PROVISION_FLOW_TIMEOUT || | 395 result == ProvisioningResult::CLOUD_PROVISION_FLOW_TIMEOUT || |
| 393 result == ProvisioningResult::CLOUD_PROVISION_FLOW_INTERNAL_ERROR || | 396 result == ProvisioningResult::CLOUD_PROVISION_FLOW_INTERNAL_ERROR || |
| 394 result == ProvisioningResult::UNKNOWN_ERROR) | 397 // OVERALL_SIGN_IN_TIMEOUT might be an indication that ARC believes it is |
| 398 // fully setup, but Chrome does not. |
| 399 result == ProvisioningResult::OVERALL_SIGN_IN_TIMEOUT || |
| 400 // Just to be safe, remove data if we don't know the cause. |
| 401 result == ProvisioningResult::UNKNOWN_ERROR) { |
| 395 RemoveArcData(); | 402 RemoveArcData(); |
| 403 } |
| 396 | 404 |
| 397 // We'll delay shutting down the bridge in this case to allow people to send | 405 // We'll delay shutting down the bridge in this case to allow people to send |
| 398 // feedback. | 406 // feedback. |
| 399 ShowUI(UIPage::ERROR_WITH_FEEDBACK, | 407 ShowUI(UIPage::ERROR_WITH_FEEDBACK, |
| 400 l10n_util::GetStringUTF16(error_message_id)); | 408 l10n_util::GetStringUTF16(error_message_id)); |
| 401 } | 409 } |
| 402 | 410 |
| 403 void ArcAuthService::GetIsAccountManaged( | 411 void ArcAuthService::GetIsAccountManaged( |
| 404 const GetIsAccountManagedCallback& callback) { | 412 const GetIsAccountManagedCallback& callback) { |
| 405 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 413 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 589 CheckAndroidManagement(true); | 597 CheckAndroidManagement(true); |
| 590 } else { | 598 } else { |
| 591 StartArc(); | 599 StartArc(); |
| 592 } | 600 } |
| 593 } | 601 } |
| 594 | 602 |
| 595 UpdateEnabledStateUMA(true); | 603 UpdateEnabledStateUMA(true); |
| 596 } | 604 } |
| 597 | 605 |
| 598 void ArcAuthService::ShutdownBridge() { | 606 void ArcAuthService::ShutdownBridge() { |
| 607 arc_sign_in_timer_.Stop(); |
| 599 playstore_launcher_.reset(); | 608 playstore_launcher_.reset(); |
| 600 auth_callback_.Reset(); | 609 auth_callback_.Reset(); |
| 601 android_management_checker_.reset(); | 610 android_management_checker_.reset(); |
| 602 auth_code_fetcher_.reset(); | 611 auth_code_fetcher_.reset(); |
| 603 arc_bridge_service()->Shutdown(); | 612 arc_bridge_service()->Shutdown(); |
| 604 if (state_ != State::NOT_INITIALIZED) | 613 if (state_ != State::NOT_INITIALIZED) |
| 605 SetState(State::STOPPED); | 614 SetState(State::STOPPED); |
| 606 FOR_EACH_OBSERVER(Observer, observer_list_, OnShutdownBridge()); | 615 FOR_EACH_OBSERVER(Observer, observer_list_, OnShutdownBridge()); |
| 607 } | 616 } |
| 608 | 617 |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 668 return; | 677 return; |
| 669 } | 678 } |
| 670 | 679 |
| 671 State state = state_; | 680 State state = state_; |
| 672 if (state != State::FETCHING_CODE) { | 681 if (state != State::FETCHING_CODE) { |
| 673 ShutdownBridgeAndCloseUI(); | 682 ShutdownBridgeAndCloseUI(); |
| 674 return; | 683 return; |
| 675 } | 684 } |
| 676 | 685 |
| 677 sign_in_time_ = base::Time::Now(); | 686 sign_in_time_ = base::Time::Now(); |
| 687 VLOG(1) << "Starting ARC for first sign in."; |
| 678 | 688 |
| 679 SetUIPage(UIPage::START_PROGRESS, base::string16()); | 689 SetUIPage(UIPage::START_PROGRESS, base::string16()); |
| 680 ShutdownBridge(); | 690 ShutdownBridge(); |
| 681 auth_code_ = auth_code; | 691 auth_code_ = auth_code; |
| 682 waiting_for_reply_ = true; | 692 arc_sign_in_timer_.Start(FROM_HERE, kArcSignInTimeout, |
| 693 base::Bind(&ArcAuthService::OnArcSignInTimeout, |
| 694 weak_ptr_factory_.GetWeakPtr())); |
| 683 StartArc(); | 695 StartArc(); |
| 684 } | 696 } |
| 685 | 697 |
| 698 void ArcAuthService::OnArcSignInTimeout() { |
| 699 LOG(ERROR) << "Timed out waiting for first sign in."; |
| 700 OnSignInFailedInternal(ProvisioningResult::OVERALL_SIGN_IN_TIMEOUT); |
| 701 } |
| 702 |
| 686 void ArcAuthService::StartLso() { | 703 void ArcAuthService::StartLso() { |
| 687 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 704 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 688 | 705 |
| 689 // Update UMA only if error (with or without feedback) is currently shown. | 706 // Update UMA only if error (with or without feedback) is currently shown. |
| 690 if (ui_page_ == UIPage::ERROR) { | 707 if (ui_page_ == UIPage::ERROR) { |
| 691 UpdateOptInActionUMA(OptInActionType::RETRY); | 708 UpdateOptInActionUMA(OptInActionType::RETRY); |
| 692 } else if (ui_page_ == UIPage::ERROR_WITH_FEEDBACK) { | 709 } else if (ui_page_ == UIPage::ERROR_WITH_FEEDBACK) { |
| 693 UpdateOptInActionUMA(OptInActionType::RETRY); | 710 UpdateOptInActionUMA(OptInActionType::RETRY); |
| 694 ShutdownBridge(); | 711 ShutdownBridge(); |
| 695 } | 712 } |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 890 return os << kStateFetchingCode; | 907 return os << kStateFetchingCode; |
| 891 case ArcAuthService::State::ACTIVE: | 908 case ArcAuthService::State::ACTIVE: |
| 892 return os << kStateActive; | 909 return os << kStateActive; |
| 893 default: | 910 default: |
| 894 NOTREACHED(); | 911 NOTREACHED(); |
| 895 return os; | 912 return os; |
| 896 } | 913 } |
| 897 } | 914 } |
| 898 | 915 |
| 899 } // namespace arc | 916 } // namespace arc |
| OLD | NEW |