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"
35 #if defined(OS_CHROMEOS)
36 #include "chrome/browser/chromeos/profiles/profile_helper.h"
37 #include "components/user_manager/user_manager.h"
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
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.
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.
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.
69 // Don't use initial delay unless the last request was an error.
73 ChildAccountService::ChildAccountService(Profile
* profile
)
74 : profile_(profile
), active_(false),
75 family_fetch_backoff_(&kBackoffPolicy
),
76 weak_ptr_factory_(this) {}
78 ChildAccountService::~ChildAccountService() {}
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
))
90 if (command_line
->HasSwitch(switches::kEnableChildAccountDetection
))
93 if (group_name
== "Disabled")
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
);
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_
)
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
);
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()) {
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);
156 void ChildAccountService::AddChildStatusReceivedCallback(
157 const base::Closure
& callback
) {
158 if (IsChildAccountStatusKnown())
161 status_received_callback_list_
.push_back(callback
);
164 bool ChildAccountService::SetActive(bool active
) {
165 if (!profile_
->IsChild() && !active_
)
167 if (active_
== 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
182 SigninManagerFactory::GetForProfile(profile_
)->ProhibitSignout(true);
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_
));
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);
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();
215 void ChildAccountService::OnAccountUpdated(const AccountInfo
& info
) {
216 std::string auth_account_id
= SigninManagerFactory::GetForProfile(profile_
)
217 ->GetAuthenticatedAccountId();
218 if (!info
.IsValid() || info
.account_id
!= auth_account_id
)
221 if (!IsChildAccountDetectionEnabled()) {
222 SetIsChildAccount(false);
226 SetIsChildAccount(info
.is_child_account
);
229 void ChildAccountService::OnGetFamilyMembersSuccess(
230 const std::vector
<FamilyInfoFetcher::FamilyMember
>& members
) {
231 bool hoh_found
= false;
232 bool parent_found
= false;
233 for (const FamilyInfoFetcher::FamilyMember
& member
: members
) {
234 if (member
.role
== FamilyInfoFetcher::HEAD_OF_HOUSEHOLD
) {
236 SetFirstCustodianPrefs(member
);
237 } else if (member
.role
== FamilyInfoFetcher::PARENT
) {
239 SetSecondCustodianPrefs(member
);
241 if (hoh_found
&& parent_found
)
245 DLOG(WARNING
) << "GetFamilyMembers didn't return a HOH?!";
246 ClearFirstCustodianPrefs();
249 ClearSecondCustodianPrefs();
250 family_fetcher_
.reset();
252 family_fetch_backoff_
.InformOfRequest(true);
254 ScheduleNextFamilyInfoUpdate(
255 base::TimeDelta::FromSeconds(kUpdateIntervalSeconds
));
258 void ChildAccountService::OnFailure(FamilyInfoFetcher::ErrorCode error
) {
259 DLOG(WARNING
) << "GetFamilyMembers failed with code " << error
;
260 family_fetch_backoff_
.InformOfRequest(false);
261 ScheduleNextFamilyInfoUpdate(family_fetch_backoff_
.GetTimeUntilRelease());
264 void ChildAccountService::StartFetchingFamilyInfo() {
265 family_fetcher_
.reset(new FamilyInfoFetcher(
267 SigninManagerFactory::GetForProfile(profile_
)
268 ->GetAuthenticatedAccountId(),
269 ProfileOAuth2TokenServiceFactory::GetForProfile(profile_
),
270 profile_
->GetRequestContext()));
271 family_fetcher_
->StartGetFamilyMembers();
274 void ChildAccountService::CancelFetchingFamilyInfo() {
275 family_fetcher_
.reset();
276 family_fetch_timer_
.Stop();
279 void ChildAccountService::ScheduleNextFamilyInfoUpdate(base::TimeDelta delay
) {
280 family_fetch_timer_
.Start(
281 FROM_HERE
, delay
, this, &ChildAccountService::StartFetchingFamilyInfo
);
284 void ChildAccountService::PropagateChildStatusToUser(bool is_child
) {
285 #if defined(OS_CHROMEOS)
286 user_manager::User
* user
=
287 chromeos::ProfileHelper::Get()->GetUserByProfile(profile_
);
289 user_manager::UserManager::Get()->ChangeUserChildStatus(user
, is_child
);
292 "User instance wasn't found while setting child account flag.";
297 void ChildAccountService::SetFirstCustodianPrefs(
298 const FamilyInfoFetcher::FamilyMember
& custodian
) {
299 profile_
->GetPrefs()->SetString(prefs::kSupervisedUserCustodianName
,
300 custodian
.display_name
);
301 profile_
->GetPrefs()->SetString(prefs::kSupervisedUserCustodianEmail
,
303 profile_
->GetPrefs()->SetString(prefs::kSupervisedUserCustodianProfileURL
,
304 custodian
.profile_url
);
305 profile_
->GetPrefs()->SetString(
306 prefs::kSupervisedUserCustodianProfileImageURL
,
307 custodian
.profile_image_url
);
310 void ChildAccountService::SetSecondCustodianPrefs(
311 const FamilyInfoFetcher::FamilyMember
& custodian
) {
312 profile_
->GetPrefs()->SetString(prefs::kSupervisedUserSecondCustodianName
,
313 custodian
.display_name
);
314 profile_
->GetPrefs()->SetString(prefs::kSupervisedUserSecondCustodianEmail
,
316 profile_
->GetPrefs()->SetString(
317 prefs::kSupervisedUserSecondCustodianProfileURL
,
318 custodian
.profile_url
);
319 profile_
->GetPrefs()->SetString(
320 prefs::kSupervisedUserSecondCustodianProfileImageURL
,
321 custodian
.profile_image_url
);
324 void ChildAccountService::ClearFirstCustodianPrefs() {
325 profile_
->GetPrefs()->ClearPref(prefs::kSupervisedUserCustodianName
);
326 profile_
->GetPrefs()->ClearPref(prefs::kSupervisedUserCustodianEmail
);
327 profile_
->GetPrefs()->ClearPref(prefs::kSupervisedUserCustodianProfileURL
);
328 profile_
->GetPrefs()->ClearPref(
329 prefs::kSupervisedUserCustodianProfileImageURL
);
332 void ChildAccountService::ClearSecondCustodianPrefs() {
333 profile_
->GetPrefs()->ClearPref(prefs::kSupervisedUserSecondCustodianName
);
334 profile_
->GetPrefs()->ClearPref(prefs::kSupervisedUserSecondCustodianEmail
);
335 profile_
->GetPrefs()->ClearPref(
336 prefs::kSupervisedUserSecondCustodianProfileURL
);
337 profile_
->GetPrefs()->ClearPref(
338 prefs::kSupervisedUserSecondCustodianProfileImageURL
);