1 // Copyright 2013 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/ui/webui/options/create_profile_handler.h"
8 #include "base/command_line.h"
9 #include "base/files/file_path.h"
10 #include "base/metrics/histogram.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/value_conversions.h"
13 #include "base/values.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/managed_mode/managed_user_registration_utility.h"
16 #include "chrome/browser/managed_mode/managed_user_service.h"
17 #include "chrome/browser/managed_mode/managed_user_service_factory.h"
18 #include "chrome/browser/managed_mode/managed_user_sync_service.h"
19 #include "chrome/browser/managed_mode/managed_user_sync_service_factory.h"
20 #include "chrome/browser/profiles/profile_manager.h"
21 #include "chrome/browser/profiles/profile_metrics.h"
22 #include "chrome/browser/profiles/profiles_state.h"
23 #include "chrome/browser/sync/profile_sync_service.h"
24 #include "chrome/browser/sync/profile_sync_service_factory.h"
25 #include "chrome/browser/ui/webui/options/options_handlers_helper.h"
26 #include "chrome/common/chrome_switches.h"
27 #include "chrome/common/pref_names.h"
28 #include "grit/generated_resources.h"
29 #include "ui/base/l10n/l10n_util.h"
33 CreateProfileHandler::CreateProfileHandler()
34 : profile_creation_type_(NO_CREATION_IN_PROGRESS
),
35 weak_ptr_factory_(this) {
38 CreateProfileHandler::~CreateProfileHandler() {
39 CancelProfileRegistration(false);
42 void CreateProfileHandler::GetLocalizedValues(
43 base::DictionaryValue
* localized_strings
) {
46 void CreateProfileHandler::RegisterMessages() {
47 web_ui()->RegisterMessageCallback(
48 "cancelCreateProfile",
49 base::Bind(&CreateProfileHandler::HandleCancelProfileCreation
,
50 base::Unretained(this)));
51 web_ui()->RegisterMessageCallback(
53 base::Bind(&CreateProfileHandler::CreateProfile
,
54 base::Unretained(this)));
57 void CreateProfileHandler::CreateProfile(const base::ListValue
* args
) {
58 // This handler could have been called in managed mode, for example because
59 // the user fiddled with the web inspector. Silently return in this case.
60 Profile
* current_profile
= Profile::FromWebUI(web_ui());
61 if (current_profile
->IsManaged())
64 if (!profiles::IsMultipleProfilesEnabled())
67 // We can have only one in progress profile creation
68 // at any given moment, if new ones are initiated just
69 // ignore them until we are done with the old one.
70 if (profile_creation_type_
!= NO_CREATION_IN_PROGRESS
)
73 profile_creation_type_
= NON_SUPERVISED_PROFILE_CREATION
;
75 DCHECK(profile_path_being_created_
.empty());
76 profile_creation_start_time_
= base::TimeTicks::Now();
80 std::string managed_user_id
;
81 bool create_shortcut
= false;
82 bool managed_user
= false;
83 if (args
->GetString(0, &name
) && args
->GetString(1, &icon
)) {
84 if (args
->GetBoolean(2, &create_shortcut
)) {
85 bool success
= args
->GetBoolean(3, &managed_user
);
87 success
= args
->GetString(4, &managed_user_id
);
93 if (!IsValidExistingManagedUserId(managed_user_id
))
96 profile_creation_type_
= SUPERVISED_PROFILE_IMPORT
;
97 if (managed_user_id
.empty()) {
98 profile_creation_type_
= SUPERVISED_PROFILE_CREATION
;
100 ManagedUserRegistrationUtility::GenerateNewManagedUserId();
102 // If sync is not yet fully initialized, the creation may take extra time,
103 // so show a message. Import doesn't wait for an acknowledgement, so it
104 // won't have the same potential delay.
105 ProfileSyncService
* sync_service
=
106 ProfileSyncServiceFactory::GetInstance()->GetForProfile(
108 ProfileSyncService::SyncStatusSummary status
=
109 sync_service
->QuerySyncStatusSummary();
110 if (status
== ProfileSyncService::DATATYPES_NOT_INITIALIZED
) {
111 ShowProfileCreationWarning(l10n_util::GetStringUTF16(
112 IDS_PROFILES_CREATE_MANAGED_JUST_SIGNED_IN
));
117 ProfileMetrics::LogProfileAddNewUser(ProfileMetrics::ADD_NEW_USER_DIALOG
);
119 profile_path_being_created_
= ProfileManager::CreateMultiProfileAsync(
121 base::Bind(&CreateProfileHandler::OnProfileCreated
,
122 weak_ptr_factory_
.GetWeakPtr(),
124 helper::GetDesktopType(web_ui()),
129 void CreateProfileHandler::OnProfileCreated(
130 bool create_shortcut
,
131 chrome::HostDesktopType desktop_type
,
132 const std::string
& managed_user_id
,
134 Profile::CreateStatus status
) {
135 if (status
!= Profile::CREATE_STATUS_CREATED
)
136 RecordProfileCreationMetrics(status
);
139 case Profile::CREATE_STATUS_LOCAL_FAIL
: {
140 ShowProfileCreationError(profile
,
141 GetProfileCreationErrorMessage(LOCAL_ERROR
));
144 case Profile::CREATE_STATUS_CREATED
: {
145 // Do nothing for an intermediate status.
148 case Profile::CREATE_STATUS_INITIALIZED
: {
149 HandleProfileCreationSuccess(create_shortcut
, desktop_type
,
150 managed_user_id
, profile
);
153 // User-initiated cancellation is handled in CancelProfileRegistration and
154 // does not call this callback.
155 case Profile::CREATE_STATUS_CANCELED
:
156 // Managed user registration errors are handled in
157 // OnManagedUserRegistered().
158 case Profile::CREATE_STATUS_REMOTE_FAIL
:
159 case Profile::MAX_CREATE_STATUS
: {
166 void CreateProfileHandler::HandleProfileCreationSuccess(
167 bool create_shortcut
,
168 chrome::HostDesktopType desktop_type
,
169 const std::string
& managed_user_id
,
171 switch (profile_creation_type_
) {
172 case NON_SUPERVISED_PROFILE_CREATION
: {
173 DCHECK(managed_user_id
.empty());
174 CreateShortcutAndShowSuccess(create_shortcut
, desktop_type
, profile
);
177 case SUPERVISED_PROFILE_CREATION
:
178 case SUPERVISED_PROFILE_IMPORT
:
179 RegisterManagedUser(create_shortcut
, desktop_type
,
180 managed_user_id
, profile
);
182 case NO_CREATION_IN_PROGRESS
:
188 void CreateProfileHandler::RegisterManagedUser(
189 bool create_shortcut
,
190 chrome::HostDesktopType desktop_type
,
191 const std::string
& managed_user_id
,
192 Profile
* new_profile
) {
193 DCHECK_EQ(profile_path_being_created_
.value(),
194 new_profile
->GetPath().value());
196 ManagedUserService
* managed_user_service
=
197 ManagedUserServiceFactory::GetForProfile(new_profile
);
199 // Register the managed user using the profile of the custodian.
200 managed_user_registration_utility_
=
201 ManagedUserRegistrationUtility::Create(Profile::FromWebUI(web_ui()));
202 managed_user_service
->RegisterAndInitSync(
203 managed_user_registration_utility_
.get(),
204 Profile::FromWebUI(web_ui()),
206 base::Bind(&CreateProfileHandler::OnManagedUserRegistered
,
207 weak_ptr_factory_
.GetWeakPtr(),
213 void CreateProfileHandler::OnManagedUserRegistered(
214 bool create_shortcut
,
215 chrome::HostDesktopType desktop_type
,
217 const GoogleServiceAuthError
& error
) {
218 GoogleServiceAuthError::State state
= error
.state();
219 RecordSupervisedProfileCreationMetrics(state
);
220 if (state
== GoogleServiceAuthError::NONE
) {
221 CreateShortcutAndShowSuccess(create_shortcut
, desktop_type
, profile
);
225 base::string16 error_msg
;
226 if (state
== GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS
||
227 state
== GoogleServiceAuthError::USER_NOT_SIGNED_UP
||
228 state
== GoogleServiceAuthError::ACCOUNT_DELETED
||
229 state
== GoogleServiceAuthError::ACCOUNT_DISABLED
) {
230 error_msg
= GetProfileCreationErrorMessage(SIGNIN_ERROR
);
232 error_msg
= GetProfileCreationErrorMessage(REMOTE_ERROR
);
234 ShowProfileCreationError(profile
, error_msg
);
237 void CreateProfileHandler::CreateShortcutAndShowSuccess(
238 bool create_shortcut
,
239 chrome::HostDesktopType desktop_type
,
241 if (create_shortcut
) {
242 ProfileShortcutManager
* shortcut_manager
=
243 g_browser_process
->profile_manager()->profile_shortcut_manager();
245 if (shortcut_manager
)
246 shortcut_manager
->CreateProfileShortcut(profile
->GetPath());
249 DCHECK_EQ(profile_path_being_created_
.value(), profile
->GetPath().value());
250 profile_path_being_created_
.clear();
251 DCHECK_NE(NO_CREATION_IN_PROGRESS
, profile_creation_type_
);
252 base::DictionaryValue dict
;
253 dict
.SetString("name",
254 profile
->GetPrefs()->GetString(prefs::kProfileName
));
255 dict
.Set("filePath", base::CreateFilePathValue(profile
->GetPath()));
257 profile_creation_type_
== SUPERVISED_PROFILE_CREATION
||
258 profile_creation_type_
== SUPERVISED_PROFILE_IMPORT
;
259 dict
.SetBoolean("isManaged", is_managed
);
260 web_ui()->CallJavascriptFunction(
261 GetJavascriptMethodName(PROFILE_CREATION_SUCCESS
), dict
);
263 // If the new profile is a supervised user, instead of opening a new window
264 // right away, a confirmation overlay will be shown by JS from the creation
265 // dialog. If we are importing an existing supervised profile or creating a
266 // new non-supervised user profile we don't show any confirmation, so open
267 // the new window now.
268 if (profile_creation_type_
!= SUPERVISED_PROFILE_CREATION
) {
269 // Opening the new window must be the last action, after all callbacks
270 // have been run, to give them a chance to initialize the profile.
271 helper::OpenNewWindowForProfile(desktop_type
,
273 Profile::CREATE_STATUS_INITIALIZED
);
275 profile_creation_type_
= NO_CREATION_IN_PROGRESS
;
278 void CreateProfileHandler::ShowProfileCreationError(
280 const base::string16
& error
) {
281 DCHECK_NE(NO_CREATION_IN_PROGRESS
, profile_creation_type_
);
282 profile_creation_type_
= NO_CREATION_IN_PROGRESS
;
283 profile_path_being_created_
.clear();
284 web_ui()->CallJavascriptFunction(
285 GetJavascriptMethodName(PROFILE_CREATION_ERROR
),
286 base::StringValue(error
));
287 helper::DeleteProfileAtPath(profile
->GetPath(), web_ui());
290 void CreateProfileHandler::ShowProfileCreationWarning(
291 const base::string16
& warning
) {
292 DCHECK_EQ(SUPERVISED_PROFILE_CREATION
, profile_creation_type_
);
293 web_ui()->CallJavascriptFunction("BrowserOptions.showCreateProfileWarning",
294 base::StringValue(warning
));
297 void CreateProfileHandler::HandleCancelProfileCreation(
298 const base::ListValue
* args
) {
299 CancelProfileRegistration(true);
302 void CreateProfileHandler::CancelProfileRegistration(bool user_initiated
) {
303 if (profile_path_being_created_
.empty())
306 ProfileManager
* manager
= g_browser_process
->profile_manager();
307 Profile
* new_profile
= manager
->GetProfileByPath(profile_path_being_created_
);
311 // Non-managed user creation cannot be canceled. (Creating a non-managed
312 // profile shouldn't take significant time, and it can easily be deleted
314 if (!new_profile
->IsManaged())
317 if (user_initiated
) {
318 UMA_HISTOGRAM_MEDIUM_TIMES(
319 "Profile.CreateTimeCanceledNoTimeout",
320 base::TimeTicks::Now() - profile_creation_start_time_
);
321 RecordProfileCreationMetrics(Profile::CREATE_STATUS_CANCELED
);
324 DCHECK(managed_user_registration_utility_
.get());
325 managed_user_registration_utility_
.reset();
327 DCHECK_NE(NO_CREATION_IN_PROGRESS
, profile_creation_type_
);
328 profile_creation_type_
= NO_CREATION_IN_PROGRESS
;
330 // Cancelling registration means the callback passed into
331 // RegisterAndInitSync() won't be called, so the cleanup must be done here.
332 profile_path_being_created_
.clear();
333 helper::DeleteProfileAtPath(new_profile
->GetPath(), web_ui());
336 void CreateProfileHandler::RecordProfileCreationMetrics(
337 Profile::CreateStatus status
) {
338 UMA_HISTOGRAM_ENUMERATION("Profile.CreateResult",
340 Profile::MAX_CREATE_STATUS
);
341 UMA_HISTOGRAM_MEDIUM_TIMES(
342 "Profile.CreateTimeNoTimeout",
343 base::TimeTicks::Now() - profile_creation_start_time_
);
346 void CreateProfileHandler::RecordSupervisedProfileCreationMetrics(
347 GoogleServiceAuthError::State error_state
) {
348 if (profile_creation_type_
== SUPERVISED_PROFILE_CREATION
) {
349 UMA_HISTOGRAM_ENUMERATION("Profile.SupervisedProfileCreateError",
351 GoogleServiceAuthError::NUM_STATES
);
352 UMA_HISTOGRAM_MEDIUM_TIMES(
353 "Profile.SupervisedProfileTotalCreateTime",
354 base::TimeTicks::Now() - profile_creation_start_time_
);
356 DCHECK_EQ(SUPERVISED_PROFILE_IMPORT
, profile_creation_type_
);
357 UMA_HISTOGRAM_ENUMERATION("Profile.SupervisedProfileImportError",
359 GoogleServiceAuthError::NUM_STATES
);
360 UMA_HISTOGRAM_MEDIUM_TIMES(
361 "Profile.SupervisedProfileTotalImportTime",
362 base::TimeTicks::Now() - profile_creation_start_time_
);
366 base::string16
CreateProfileHandler::GetProfileCreationErrorMessage(
367 ProfileCreationErrorType error
) const {
372 profile_creation_type_
== SUPERVISED_PROFILE_IMPORT
?
373 IDS_MANAGED_USER_IMPORT_SIGN_IN_ERROR
:
374 IDS_PROFILES_CREATE_SIGN_IN_ERROR
;
378 profile_creation_type_
== SUPERVISED_PROFILE_IMPORT
?
379 IDS_MANAGED_USER_IMPORT_REMOTE_ERROR
:
380 IDS_PROFILES_CREATE_REMOTE_ERROR
;
384 profile_creation_type_
== SUPERVISED_PROFILE_IMPORT
?
385 IDS_MANAGED_USER_IMPORT_LOCAL_ERROR
:
386 IDS_PROFILES_CREATE_LOCAL_ERROR
;
390 return l10n_util::GetStringUTF16(message_id
);
393 std::string
CreateProfileHandler::GetJavascriptMethodName(
394 ProfileCreationStatus status
) const {
396 case PROFILE_CREATION_SUCCESS
:
397 return profile_creation_type_
== SUPERVISED_PROFILE_IMPORT
?
398 "BrowserOptions.showManagedUserImportSuccess" :
399 "BrowserOptions.showCreateProfileSuccess";
400 case PROFILE_CREATION_ERROR
:
401 return profile_creation_type_
== SUPERVISED_PROFILE_IMPORT
?
402 "BrowserOptions.showManagedUserImportError" :
403 "BrowserOptions.showCreateProfileError";
407 return std::string();
410 bool CreateProfileHandler::IsValidExistingManagedUserId(
411 const std::string
& existing_managed_user_id
) const {
412 if (existing_managed_user_id
.empty())
415 if (CommandLine::ForCurrentProcess()->HasSwitch(
416 switches::kDisableCreateExistingManagedUsers
)) {
420 Profile
* profile
= Profile::FromWebUI(web_ui());
421 const base::DictionaryValue
* dict
=
422 ManagedUserSyncServiceFactory::GetForProfile(profile
)->GetManagedUsers();
423 if (!dict
->HasKey(existing_managed_user_id
))
426 // Check if this managed user already exists on this machine.
427 const ProfileInfoCache
& cache
=
428 g_browser_process
->profile_manager()->GetProfileInfoCache();
429 for (size_t i
= 0; i
< cache
.GetNumberOfProfiles(); ++i
) {
430 if (existing_managed_user_id
== cache
.GetManagedUserIdOfProfileAtIndex(i
))
436 } // namespace options