Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / supervised_user / child_accounts / child_account_service.cc
blobf7a813c1ba60883bc2143437ea9ed7d963b2d53b
1 // Copyright 2014 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.
5 #include "chrome/browser/supervised_user/child_accounts/child_account_service.h"
7 #include "base/callback.h"
8 #include "base/command_line.h"
9 #include "base/metrics/field_trial.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/values.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/browser/signin/account_tracker_service_factory.h"
14 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
15 #include "chrome/browser/signin/signin_manager_factory.h"
16 #include "chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary.h"
17 #include "chrome/browser/supervised_user/supervised_user_constants.h"
18 #include "chrome/browser/supervised_user/supervised_user_service.h"
19 #include "chrome/browser/supervised_user/supervised_user_service_factory.h"
20 #include "chrome/browser/supervised_user/supervised_user_settings_service.h"
21 #include "chrome/browser/supervised_user/supervised_user_settings_service_factory.h"
22 #include "chrome/browser/sync/profile_sync_service.h"
23 #include "chrome/browser/sync/profile_sync_service_factory.h"
24 #include "chrome/common/chrome_switches.h"
25 #include "chrome/common/pref_names.h"
26 #include "components/pref_registry/pref_registry_syncable.h"
27 #include "components/signin/core/browser/profile_oauth2_token_service.h"
28 #include "components/signin/core/browser/signin_manager.h"
30 #if defined(OS_ANDROID)
31 #include "base/android/jni_android.h"
32 #include "chrome/browser/supervised_user/child_accounts/child_account_service_android.h"
33 #endif
35 #if defined(OS_CHROMEOS)
36 #include "chrome/browser/chromeos/profiles/profile_helper.h"
37 #include "components/user_manager/user_manager.h"
38 #endif
40 const char kChildAccountDetectionFieldTrialName[] = "ChildAccountDetection";
42 // Normally, re-check the family info once per day.
43 const int kUpdateIntervalSeconds = 60 * 60 * 24;
45 // In case of an error while getting the family info, retry with exponential
46 // backoff.
47 const net::BackoffEntry::Policy kBackoffPolicy = {
48 // Number of initial errors (in sequence) to ignore before applying
49 // exponential back-off rules.
52 // Initial delay for exponential backoff in ms.
53 2000,
55 // Factor by which the waiting time will be multiplied.
58 // Fuzzing percentage. ex: 10% will spread requests randomly
59 // between 90%-100% of the calculated time.
60 0.2, // 20%
62 // Maximum amount of time we are willing to delay our request in ms.
63 1000 * 60 * 60 * 4, // 4 hours.
65 // Time to keep an entry from being discarded even when it
66 // has no significant state, -1 to never discard.
67 -1,
69 // Don't use initial delay unless the last request was an error.
70 false,
73 ChildAccountService::ChildAccountService(Profile* profile)
74 : profile_(profile), active_(false),
75 family_fetch_backoff_(&kBackoffPolicy),
76 weak_ptr_factory_(this) {}
78 ChildAccountService::~ChildAccountService() {}
80 // static
81 bool ChildAccountService::IsChildAccountDetectionEnabled() {
82 // Note: It's important to query the field trial state first, to ensure that
83 // UMA reports the correct group.
84 const std::string group_name =
85 base::FieldTrialList::FindFullName(kChildAccountDetectionFieldTrialName);
87 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
88 if (command_line->HasSwitch(switches::kDisableChildAccountDetection))
89 return false;
90 if (command_line->HasSwitch(switches::kEnableChildAccountDetection))
91 return true;
93 if (group_name == "Disabled")
94 return false;
95 return true;
98 void ChildAccountService::RegisterProfilePrefs(
99 user_prefs::PrefRegistrySyncable* registry) {
100 registry->RegisterBooleanPref(prefs::kChildAccountStatusKnown, false);
103 void ChildAccountService::SetIsChildAccount(bool is_child_account) {
104 PropagateChildStatusToUser(is_child_account);
105 if (profile_->IsChild() != is_child_account) {
106 if (is_child_account) {
107 profile_->GetPrefs()->SetString(prefs::kSupervisedUserId,
108 supervised_users::kChildAccountSUID);
109 } else {
110 profile_->GetPrefs()->ClearPref(prefs::kSupervisedUserId);
112 ClearFirstCustodianPrefs();
113 ClearSecondCustodianPrefs();
116 profile_->GetPrefs()->SetBoolean(prefs::kChildAccountStatusKnown, true);
118 for (const auto& callback : status_received_callback_list_)
119 callback.Run();
120 status_received_callback_list_.clear();
123 void ChildAccountService::Init() {
124 SupervisedUserServiceFactory::GetForProfile(profile_)->SetDelegate(this);
125 AccountTrackerServiceFactory::GetForProfile(profile_)->AddObserver(this);
127 #if defined(OS_ANDROID)
128 bool is_child_account = false;
129 if (GetJavaChildAccountStatus(&is_child_account))
130 SetIsChildAccount(is_child_account);
131 #endif
133 PropagateChildStatusToUser(profile_->IsChild());
135 // If we're already signed in, check the account immediately just to be sure.
136 // (We might have missed an update before registering as an observer.)
137 SigninManagerBase* signin = SigninManagerFactory::GetForProfile(profile_);
138 if (signin->IsAuthenticated()) {
139 OnAccountUpdated(
140 AccountTrackerServiceFactory::GetForProfile(profile_)->GetAccountInfo(
141 signin->GetAuthenticatedAccountId()));
145 bool ChildAccountService::IsChildAccountStatusKnown() {
146 return profile_->GetPrefs()->GetBoolean(prefs::kChildAccountStatusKnown);
149 void ChildAccountService::Shutdown() {
150 family_fetcher_.reset();
151 AccountTrackerServiceFactory::GetForProfile(profile_)->RemoveObserver(this);
152 SupervisedUserServiceFactory::GetForProfile(profile_)->SetDelegate(nullptr);
153 DCHECK(!active_);
156 void ChildAccountService::AddChildStatusReceivedCallback(
157 const base::Closure& callback) {
158 if (IsChildAccountStatusKnown())
159 callback.Run();
160 else
161 status_received_callback_list_.push_back(callback);
164 bool ChildAccountService::SetActive(bool active) {
165 if (!profile_->IsChild() && !active_)
166 return false;
167 if (active_ == active)
168 return true;
169 active_ = active;
171 if (active_) {
172 // In contrast to legacy SUs, child account SUs must sign in.
173 scoped_ptr<base::Value> allow_signin(new base::FundamentalValue(true));
174 SupervisedUserSettingsService* settings_service =
175 SupervisedUserSettingsServiceFactory::GetForProfile(profile_);
176 settings_service->SetLocalSetting(supervised_users::kSigninAllowed,
177 allow_signin.Pass());
178 #if !defined(OS_CHROMEOS)
179 // This is also used by user policies (UserPolicySigninService), but since
180 // child accounts can not also be Dasher accounts, there shouldn't be any
181 // problems.
182 SigninManagerFactory::GetForProfile(profile_)->ProhibitSignout(true);
183 #endif
185 // TODO(treib): Maybe store the last update time in a pref, so we don't
186 // have to re-fetch on every start.
187 StartFetchingFamilyInfo();
189 SupervisedUserService* service =
190 SupervisedUserServiceFactory::GetForProfile(profile_);
191 service->AddPermissionRequestCreator(
192 PermissionRequestCreatorApiary::CreateWithProfile(profile_));
193 } else {
194 SupervisedUserSettingsService* settings_service =
195 SupervisedUserSettingsServiceFactory::GetForProfile(profile_);
196 settings_service->SetLocalSetting(supervised_users::kSigninAllowed,
197 scoped_ptr<base::Value>());
198 #if !defined(OS_CHROMEOS)
199 SigninManagerFactory::GetForProfile(profile_)->ProhibitSignout(false);
200 #endif
202 CancelFetchingFamilyInfo();
205 // Trigger a sync reconfig to enable/disable the right SU data types.
206 // The logic to do this lives in the SupervisedUserSyncDataTypeController.
207 ProfileSyncService* sync_service =
208 ProfileSyncServiceFactory::GetForProfile(profile_);
209 if (sync_service->HasSyncSetupCompleted())
210 sync_service->ReconfigureDatatypeManager();
212 return true;
215 void ChildAccountService::OnAccountUpdated(
216 const AccountTrackerService::AccountInfo& info) {
217 std::string auth_account_id = SigninManagerFactory::GetForProfile(profile_)
218 ->GetAuthenticatedAccountId();
219 if (!info.IsValid() || info.account_id != auth_account_id)
220 return;
222 if (!IsChildAccountDetectionEnabled()) {
223 SetIsChildAccount(false);
224 return;
227 SetIsChildAccount(info.is_child_account);
230 void ChildAccountService::OnGetFamilyMembersSuccess(
231 const std::vector<FamilyInfoFetcher::FamilyMember>& members) {
232 bool hoh_found = false;
233 bool parent_found = false;
234 for (const FamilyInfoFetcher::FamilyMember& member : members) {
235 if (member.role == FamilyInfoFetcher::HEAD_OF_HOUSEHOLD) {
236 hoh_found = true;
237 SetFirstCustodianPrefs(member);
238 } else if (member.role == FamilyInfoFetcher::PARENT) {
239 parent_found = true;
240 SetSecondCustodianPrefs(member);
242 if (hoh_found && parent_found)
243 break;
245 if (!hoh_found) {
246 DLOG(WARNING) << "GetFamilyMembers didn't return a HOH?!";
247 ClearFirstCustodianPrefs();
249 if (!parent_found)
250 ClearSecondCustodianPrefs();
251 family_fetcher_.reset();
253 family_fetch_backoff_.InformOfRequest(true);
255 ScheduleNextFamilyInfoUpdate(
256 base::TimeDelta::FromSeconds(kUpdateIntervalSeconds));
259 void ChildAccountService::OnFailure(FamilyInfoFetcher::ErrorCode error) {
260 DLOG(WARNING) << "GetFamilyMembers failed with code " << error;
261 family_fetch_backoff_.InformOfRequest(false);
262 ScheduleNextFamilyInfoUpdate(family_fetch_backoff_.GetTimeUntilRelease());
265 void ChildAccountService::StartFetchingFamilyInfo() {
266 family_fetcher_.reset(new FamilyInfoFetcher(
267 this,
268 SigninManagerFactory::GetForProfile(profile_)
269 ->GetAuthenticatedAccountId(),
270 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_),
271 profile_->GetRequestContext()));
272 family_fetcher_->StartGetFamilyMembers();
275 void ChildAccountService::CancelFetchingFamilyInfo() {
276 family_fetcher_.reset();
277 family_fetch_timer_.Stop();
280 void ChildAccountService::ScheduleNextFamilyInfoUpdate(base::TimeDelta delay) {
281 family_fetch_timer_.Start(
282 FROM_HERE, delay, this, &ChildAccountService::StartFetchingFamilyInfo);
285 void ChildAccountService::PropagateChildStatusToUser(bool is_child) {
286 #if defined(OS_CHROMEOS)
287 user_manager::User* user =
288 chromeos::ProfileHelper::Get()->GetUserByProfile(profile_);
289 if (user) {
290 user_manager::UserManager::Get()->ChangeUserChildStatus(user, is_child);
291 } else {
292 LOG(WARNING) <<
293 "User instance wasn't found while setting child account flag.";
295 #endif
298 void ChildAccountService::SetFirstCustodianPrefs(
299 const FamilyInfoFetcher::FamilyMember& custodian) {
300 profile_->GetPrefs()->SetString(prefs::kSupervisedUserCustodianName,
301 custodian.display_name);
302 profile_->GetPrefs()->SetString(prefs::kSupervisedUserCustodianEmail,
303 custodian.email);
304 profile_->GetPrefs()->SetString(prefs::kSupervisedUserCustodianProfileURL,
305 custodian.profile_url);
306 profile_->GetPrefs()->SetString(
307 prefs::kSupervisedUserCustodianProfileImageURL,
308 custodian.profile_image_url);
311 void ChildAccountService::SetSecondCustodianPrefs(
312 const FamilyInfoFetcher::FamilyMember& custodian) {
313 profile_->GetPrefs()->SetString(prefs::kSupervisedUserSecondCustodianName,
314 custodian.display_name);
315 profile_->GetPrefs()->SetString(prefs::kSupervisedUserSecondCustodianEmail,
316 custodian.email);
317 profile_->GetPrefs()->SetString(
318 prefs::kSupervisedUserSecondCustodianProfileURL,
319 custodian.profile_url);
320 profile_->GetPrefs()->SetString(
321 prefs::kSupervisedUserSecondCustodianProfileImageURL,
322 custodian.profile_image_url);
325 void ChildAccountService::ClearFirstCustodianPrefs() {
326 profile_->GetPrefs()->ClearPref(prefs::kSupervisedUserCustodianName);
327 profile_->GetPrefs()->ClearPref(prefs::kSupervisedUserCustodianEmail);
328 profile_->GetPrefs()->ClearPref(prefs::kSupervisedUserCustodianProfileURL);
329 profile_->GetPrefs()->ClearPref(
330 prefs::kSupervisedUserCustodianProfileImageURL);
333 void ChildAccountService::ClearSecondCustodianPrefs() {
334 profile_->GetPrefs()->ClearPref(prefs::kSupervisedUserSecondCustodianName);
335 profile_->GetPrefs()->ClearPref(prefs::kSupervisedUserSecondCustodianEmail);
336 profile_->GetPrefs()->ClearPref(
337 prefs::kSupervisedUserSecondCustodianProfileURL);
338 profile_->GetPrefs()->ClearPref(
339 prefs::kSupervisedUserSecondCustodianProfileImageURL);