1 // Copyright (c) 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/chromeos/profiles/profile_helper.h"
7 #include "base/barrier_closure.h"
8 #include "base/callback.h"
9 #include "base/command_line.h"
10 #include "chrome/browser/browser_process.h"
11 #include "chrome/browser/browsing_data/browsing_data_helper.h"
12 #include "chrome/browser/chromeos/login/helper.h"
13 #include "chrome/browser/chromeos/login/signin/oauth2_login_manager_factory.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/profiles/profile_manager.h"
16 #include "chrome/browser/profiles/profiles_state.h"
17 #include "chrome/common/chrome_constants.h"
18 #include "chrome/common/chrome_switches.h"
19 #include "chromeos/chromeos_switches.h"
20 #include "components/guest_view/browser/guest_view_manager.h"
21 #include "components/user_manager/user.h"
22 #include "components/user_manager/user_manager.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "content/public/browser/storage_partition.h"
25 #include "content/public/browser/web_contents.h"
26 #include "extensions/browser/guest_view/web_view/web_view_guest.h"
32 // As defined in /chromeos/dbus/cryptohome_client.cc.
33 static const char kUserIdHashSuffix
[] = "-hash";
35 bool ShouldAddProfileDirPrefix(const std::string
& user_id_hash
) {
36 // Do not add profile dir prefix for legacy profile dir and test
37 // user profile. The reason of not adding prefix for test user profile
38 // is to keep the promise that TestingProfile::kTestUserProfileDir and
39 // chrome::kTestUserProfileDir are always in sync. Otherwise,
40 // TestingProfile::kTestUserProfileDir needs to be dynamically calculated
41 // based on whether multi profile is enabled or not.
42 return user_id_hash
!= chrome::kLegacyProfileDir
&&
43 user_id_hash
!= chrome::kTestUserProfileDir
;
46 class UsernameHashMatcher
{
48 explicit UsernameHashMatcher(const std::string
& h
) : username_hash(h
) {}
49 bool operator()(const user_manager::User
* user
) const {
50 return user
->username_hash() == username_hash
;
54 const std::string
& username_hash
;
57 } // anonymous namespace
60 bool ProfileHelper::enable_profile_to_user_testing
= false;
61 bool ProfileHelper::always_return_primary_user_for_testing
= false;
63 ////////////////////////////////////////////////////////////////////////////////
64 // ProfileHelper, public
66 ProfileHelper::ProfileHelper()
67 : browsing_data_remover_(nullptr), weak_factory_(this) {
70 ProfileHelper::~ProfileHelper() {
71 // Checking whether UserManager is initialized covers case
72 // when ScopedTestUserManager is used.
73 if (user_manager::UserManager::IsInitialized())
74 user_manager::UserManager::Get()->RemoveSessionStateObserver(this);
76 if (browsing_data_remover_
) {
77 browsing_data_remover_
->RemoveObserver(this);
78 // BrowsingDataRemover deletes itself.
79 browsing_data_remover_
= nullptr;
84 ProfileHelper
* ProfileHelper::Get() {
85 return g_browser_process
->platform_part()->profile_helper();
89 Profile
* ProfileHelper::GetProfileByUserIdHash(
90 const std::string
& user_id_hash
) {
91 ProfileManager
* profile_manager
= g_browser_process
->profile_manager();
92 return profile_manager
->GetProfile(GetProfilePathByUserIdHash(user_id_hash
));
96 base::FilePath
ProfileHelper::GetProfilePathByUserIdHash(
97 const std::string
& user_id_hash
) {
98 // Fails for KioskTest.InstallAndLaunchApp test - crbug.com/238985
99 // Will probably fail for Guest session / restart after a crash -
101 // TODO(nkostylev): Remove this check once these bugs are fixed.
102 DCHECK(!user_id_hash
.empty());
103 ProfileManager
* profile_manager
= g_browser_process
->profile_manager();
104 base::FilePath profile_path
= profile_manager
->user_data_dir();
106 return profile_path
.Append(GetUserProfileDir(user_id_hash
));
110 base::FilePath
ProfileHelper::GetSigninProfileDir() {
111 ProfileManager
* profile_manager
= g_browser_process
->profile_manager();
112 base::FilePath user_data_dir
= profile_manager
->user_data_dir();
113 return user_data_dir
.AppendASCII(chrome::kInitialProfile
);
117 Profile
* ProfileHelper::GetSigninProfile() {
118 ProfileManager
* profile_manager
= g_browser_process
->profile_manager();
119 return profile_manager
->GetProfile(GetSigninProfileDir())->
120 GetOffTheRecordProfile();
124 std::string
ProfileHelper::GetUserIdHashFromProfile(const Profile
* profile
) {
126 return std::string();
128 std::string profile_dir
= profile
->GetPath().BaseName().value();
130 // Don't strip prefix if the dir is not supposed to be prefixed.
131 if (!ShouldAddProfileDirPrefix(profile_dir
))
134 // Check that profile directory starts with the correct prefix.
135 std::string
prefix(chrome::kProfileDirPrefix
);
136 if (profile_dir
.find(prefix
) != 0) {
137 // This happens when creating a TestingProfile in browser tests.
138 return std::string();
141 return profile_dir
.substr(prefix
.length(),
142 profile_dir
.length() - prefix
.length());
146 base::FilePath
ProfileHelper::GetUserProfileDir(
147 const std::string
& user_id_hash
) {
148 CHECK(!user_id_hash
.empty());
149 return ShouldAddProfileDirPrefix(user_id_hash
)
150 ? base::FilePath(chrome::kProfileDirPrefix
+ user_id_hash
)
151 : base::FilePath(user_id_hash
);
155 bool ProfileHelper::IsSigninProfile(const Profile
* profile
) {
157 profile
->GetPath().BaseName().value() == chrome::kInitialProfile
;
161 bool ProfileHelper::IsOwnerProfile(Profile
* profile
) {
162 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
163 chromeos::switches::kStubCrosSettings
)) {
169 const user_manager::User
* user
=
170 ProfileHelper::Get()->GetUserByProfile(profile
);
173 return user
->email() == user_manager::UserManager::Get()->GetOwnerEmail();
177 bool ProfileHelper::IsPrimaryProfile(const Profile
* profile
) {
180 const user_manager::User
* user
=
181 ProfileHelper::Get()->GetUserByProfile(profile
);
184 return user
== user_manager::UserManager::Get()->GetPrimaryUser();
187 void ProfileHelper::ProfileStartup(Profile
* profile
, bool process_startup
) {
188 // Initialize Chrome OS preferences like touch pad sensitivity. For the
189 // preferences to work in the guest mode, the initialization has to be
190 // done after |profile| is switched to the incognito profile (which
191 // is actually GuestSessionProfile in the guest mode). See the
192 // GetOffTheRecordProfile() call above.
193 profile
->InitChromeOSPreferences();
195 // Add observer so we can see when the first profile's session restore is
196 // completed. After that, we won't need the default profile anymore.
197 if (!IsSigninProfile(profile
) &&
198 user_manager::UserManager::Get()->IsLoggedInAsUserWithGaiaAccount() &&
199 !user_manager::UserManager::Get()->IsLoggedInAsStub()) {
200 chromeos::OAuth2LoginManager
* login_manager
=
201 chromeos::OAuth2LoginManagerFactory::GetInstance()->GetForProfile(
204 login_manager
->AddObserver(this);
208 base::FilePath
ProfileHelper::GetActiveUserProfileDir() {
209 return ProfileHelper::GetUserProfileDir(active_user_id_hash_
);
212 void ProfileHelper::Initialize() {
213 user_manager::UserManager::Get()->AddSessionStateObserver(this);
216 void ProfileHelper::ClearSigninProfile(const base::Closure
& on_clear_callback
) {
217 on_clear_callbacks_
.push_back(on_clear_callback
);
219 // Profile is already clearing.
220 if (on_clear_callbacks_
.size() > 1)
223 on_clear_profile_stage_finished_
=
224 base::BarrierClosure(2, base::Bind(&ProfileHelper::OnSigninProfileCleared
,
225 weak_factory_
.GetWeakPtr()));
227 ProfileManager
* profile_manager
= g_browser_process
->profile_manager();
228 // Check if signin profile was loaded.
229 if (profile_manager
->GetProfileByPath(GetSigninProfileDir())) {
230 LOG_ASSERT(!browsing_data_remover_
);
231 browsing_data_remover_
=
232 BrowsingDataRemover::CreateForUnboundedRange(GetSigninProfile());
233 browsing_data_remover_
->AddObserver(this);
234 browsing_data_remover_
->Remove(BrowsingDataRemover::REMOVE_SITE_DATA
,
235 BrowsingDataHelper::ALL
);
237 on_clear_profile_stage_finished_
.Run();
240 if (content::StoragePartition
* partition
= login::GetSigninPartition()) {
241 partition
->ClearData(
242 content::StoragePartition::REMOVE_DATA_MASK_ALL
,
243 content::StoragePartition::QUOTA_MANAGED_STORAGE_MASK_ALL
, GURL(),
244 content::StoragePartition::OriginMatcherFunction(), base::Time(),
245 base::Time::Now(), on_clear_profile_stage_finished_
);
247 on_clear_profile_stage_finished_
.Run();
251 Profile
* ProfileHelper::GetProfileByUser(const user_manager::User
* user
) {
252 // This map is non-empty only in tests.
253 if (!user_to_profile_for_testing_
.empty()) {
254 std::map
<const user_manager::User
*, Profile
*>::const_iterator it
=
255 user_to_profile_for_testing_
.find(user
);
256 return it
== user_to_profile_for_testing_
.end() ? NULL
: it
->second
;
259 if (!user
->is_profile_created())
262 ProfileHelper::GetProfileByUserIdHash(user
->username_hash());
264 // GetActiveUserProfile() or GetProfileByUserIdHash() returns a new instance
265 // of ProfileImpl(), but actually its OffTheRecordProfile() should be used.
266 if (user_manager::UserManager::Get()->IsLoggedInAsGuest())
267 profile
= profile
->GetOffTheRecordProfile();
272 Profile
* ProfileHelper::GetProfileByUserUnsafe(const user_manager::User
* user
) {
273 // This map is non-empty only in tests.
274 if (!user_to_profile_for_testing_
.empty()) {
275 std::map
<const user_manager::User
*, Profile
*>::const_iterator it
=
276 user_to_profile_for_testing_
.find(user
);
277 return it
== user_to_profile_for_testing_
.end() ? NULL
: it
->second
;
280 Profile
* profile
= NULL
;
281 if (user
->is_profile_created()) {
282 profile
= ProfileHelper::GetProfileByUserIdHash(user
->username_hash());
284 LOG(ERROR
) << "ProfileHelper::GetProfileByUserUnsafe is called when "
285 "|user|'s profile is not created. It probably means that "
286 "something is wrong with a calling code. Please report in "
287 "http://crbug.com/361528 if you see this message. user_id: "
289 profile
= ProfileManager::GetActiveUserProfile();
292 // GetActiveUserProfile() or GetProfileByUserIdHash() returns a new instance
293 // of ProfileImpl(), but actually its OffTheRecordProfile() should be used.
294 if (profile
&& user_manager::UserManager::Get()->IsLoggedInAsGuest())
295 profile
= profile
->GetOffTheRecordProfile();
299 const user_manager::User
* ProfileHelper::GetUserByProfile(
300 const Profile
* profile
) const {
301 // This map is non-empty only in tests.
302 if (enable_profile_to_user_testing
|| !user_list_for_testing_
.empty()) {
303 if (always_return_primary_user_for_testing
)
304 return user_manager::UserManager::Get()->GetPrimaryUser();
306 const std::string
& user_name
= profile
->GetProfileUserName();
307 for (user_manager::UserList::const_iterator it
=
308 user_list_for_testing_
.begin();
309 it
!= user_list_for_testing_
.end();
311 if ((*it
)->email() == user_name
)
315 // In case of test setup we should always default to primary user.
316 return user_manager::UserManager::Get()->GetPrimaryUser();
319 DCHECK(!content::BrowserThread::IsThreadInitialized(
320 content::BrowserThread::UI
) ||
321 content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
322 if (ProfileHelper::IsSigninProfile(profile
))
325 user_manager::UserManager
* user_manager
= user_manager::UserManager::Get();
327 // Special case for non-CrOS tests that do create several profiles
328 // and don't really care about mapping to the real user.
329 // Without multi-profiles on Chrome OS such tests always got active_user_.
330 // Now these tests will specify special flag to continue working.
331 // In future those tests can get a proper CrOS configuration i.e. register
332 // and login several users if they want to work with an additional profile.
333 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
334 switches::kIgnoreUserProfileMappingForTests
)) {
335 return user_manager
->GetActiveUser();
338 const std::string username_hash
=
339 ProfileHelper::GetUserIdHashFromProfile(profile
);
340 const user_manager::UserList
& users
= user_manager
->GetUsers();
341 const user_manager::UserList::const_iterator pos
= std::find_if(
342 users
.begin(), users
.end(), UsernameHashMatcher(username_hash
));
343 if (pos
!= users
.end())
346 // Many tests do not have their users registered with UserManager and
347 // runs here. If |active_user_| matches |profile|, returns it.
348 const user_manager::User
* active_user
= user_manager
->GetActiveUser();
349 return active_user
&&
350 ProfileHelper::GetProfilePathByUserIdHash(
351 active_user
->username_hash()) == profile
->GetPath()
356 user_manager::User
* ProfileHelper::GetUserByProfile(Profile
* profile
) const {
357 return const_cast<user_manager::User
*>(
358 GetUserByProfile(static_cast<const Profile
*>(profile
)));
361 void ProfileHelper::OnSigninProfileCleared() {
362 std::vector
<base::Closure
> callbacks
;
363 callbacks
.swap(on_clear_callbacks_
);
364 for (const base::Closure
& callback
: callbacks
) {
365 if (!callback
.is_null())
370 ////////////////////////////////////////////////////////////////////////////////
371 // ProfileHelper, BrowsingDataRemover::Observer implementation:
373 void ProfileHelper::OnBrowsingDataRemoverDone() {
374 LOG_ASSERT(browsing_data_remover_
);
375 browsing_data_remover_
->RemoveObserver(this);
376 // BrowsingDataRemover deletes itself.
377 browsing_data_remover_
= nullptr;
379 on_clear_profile_stage_finished_
.Run();
382 ////////////////////////////////////////////////////////////////////////////////
383 // ProfileHelper, OAuth2LoginManager::Observer implementation:
385 void ProfileHelper::OnSessionRestoreStateChanged(
386 Profile
* user_profile
,
387 OAuth2LoginManager::SessionRestoreState state
) {
388 if (state
== OAuth2LoginManager::SESSION_RESTORE_DONE
||
389 state
== OAuth2LoginManager::SESSION_RESTORE_FAILED
||
390 state
== OAuth2LoginManager::SESSION_RESTORE_CONNECTION_FAILED
) {
391 chromeos::OAuth2LoginManager
* login_manager
=
392 chromeos::OAuth2LoginManagerFactory::GetInstance()->
393 GetForProfile(user_profile
);
394 login_manager
->RemoveObserver(this);
395 ClearSigninProfile(base::Closure());
399 ////////////////////////////////////////////////////////////////////////////////
400 // ProfileHelper, UserManager::UserSessionStateObserver implementation:
402 void ProfileHelper::ActiveUserHashChanged(const std::string
& hash
) {
403 active_user_id_hash_
= hash
;
406 void ProfileHelper::SetProfileToUserMappingForTesting(
407 user_manager::User
* user
) {
408 user_list_for_testing_
.push_back(user
);
412 void ProfileHelper::SetProfileToUserForTestingEnabled(bool enabled
) {
413 enable_profile_to_user_testing
= enabled
;
417 void ProfileHelper::SetAlwaysReturnPrimaryUserForTesting(bool value
) {
418 always_return_primary_user_for_testing
= true;
419 ProfileHelper::SetProfileToUserForTestingEnabled(true);
422 void ProfileHelper::SetUserToProfileMappingForTesting(
423 const user_manager::User
* user
,
425 user_to_profile_for_testing_
[user
] = profile
;
429 std::string
ProfileHelper::GetUserIdHashByUserIdForTesting(
430 const std::string
& user_id
) {
431 return user_id
+ kUserIdHashSuffix
;
434 } // namespace chromeos