• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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.
4 
5 #include <set>
6 
7 #include "chrome/browser/profiles/profile_manager.h"
8 
9 #include "base/command_line.h"
10 #include "base/file_util.h"
11 #include "base/path_service.h"
12 #include "base/string_util.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/ui/browser_list.h"
15 #include "chrome/browser/ui/browser_window.h"
16 #include "chrome/common/chrome_constants.h"
17 #include "chrome/common/chrome_paths.h"
18 #include "chrome/common/chrome_switches.h"
19 #include "chrome/common/logging_chrome.h"
20 #include "content/browser/browser_thread.h"
21 #include "content/common/notification_service.h"
22 #include "content/common/notification_type.h"
23 #include "grit/generated_resources.h"
24 #include "net/http/http_transaction_factory.h"
25 #include "net/url_request/url_request_context.h"
26 #include "net/url_request/url_request_context_getter.h"
27 #include "net/url_request/url_request_job.h"
28 #include "net/url_request/url_request_job_tracker.h"
29 
30 #if defined(OS_CHROMEOS)
31 #include "chrome/browser/chromeos/cros/cros_library.h"
32 #include "chrome/browser/chromeos/cros/cryptohome_library.h"
33 #endif
34 
35 namespace {
36 
SuspendURLRequestJobs()37 void SuspendURLRequestJobs() {
38   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
39   for (net::URLRequestJobTracker::JobIterator i =
40            net::g_url_request_job_tracker.begin();
41        i != net::g_url_request_job_tracker.end(); ++i)
42     (*i)->Kill();
43 }
44 
SuspendRequestContext(net::URLRequestContextGetter * request_context_getter)45 void SuspendRequestContext(
46     net::URLRequestContextGetter* request_context_getter) {
47   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
48 
49   scoped_refptr<net::URLRequestContext> request_context =
50       request_context_getter->GetURLRequestContext();
51 
52   request_context->http_transaction_factory()->Suspend(true);
53 }
54 
ResumeRequestContext(net::URLRequestContextGetter * request_context_getter)55 void ResumeRequestContext(
56     net::URLRequestContextGetter* request_context_getter) {
57   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
58 
59   scoped_refptr<net::URLRequestContext> request_context =
60       request_context_getter->GetURLRequestContext();
61   request_context->http_transaction_factory()->Suspend(false);
62 }
63 
64 }  // namespace
65 
66 // static
ShutdownSessionServices()67 void ProfileManager::ShutdownSessionServices() {
68   ProfileManager* pm = g_browser_process->profile_manager();
69   if (!pm)  // Is NULL when running unit tests.
70     return;
71   std::vector<Profile*> profiles(pm->GetLoadedProfiles());
72   for (size_t i = 0; i < profiles.size(); ++i)
73     profiles[i]->ShutdownSessionService();
74 }
75 
76 // static
GetDefaultProfile()77 Profile* ProfileManager::GetDefaultProfile() {
78   FilePath user_data_dir;
79   PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
80   ProfileManager* profile_manager = g_browser_process->profile_manager();
81   return profile_manager->GetDefaultProfile(user_data_dir);
82 }
83 
ProfileManager()84 ProfileManager::ProfileManager() : logged_in_(false) {
85   ui::SystemMonitor::Get()->AddObserver(this);
86 #if defined(OS_CHROMEOS)
87   registrar_.Add(
88       this,
89       NotificationType::LOGIN_USER_CHANGED,
90       NotificationService::AllSources());
91 #endif
92 }
93 
~ProfileManager()94 ProfileManager::~ProfileManager() {
95   ui::SystemMonitor* system_monitor = ui::SystemMonitor::Get();
96   if (system_monitor)
97     system_monitor->RemoveObserver(this);
98 }
99 
GetDefaultProfileDir(const FilePath & user_data_dir)100 FilePath ProfileManager::GetDefaultProfileDir(
101     const FilePath& user_data_dir) {
102   FilePath default_profile_dir(user_data_dir);
103   default_profile_dir =
104       default_profile_dir.AppendASCII(chrome::kNotSignedInProfile);
105   return default_profile_dir;
106 }
107 
GetProfilePrefsPath(const FilePath & profile_dir)108 FilePath ProfileManager::GetProfilePrefsPath(
109     const FilePath &profile_dir) {
110   FilePath default_prefs_path(profile_dir);
111   default_prefs_path = default_prefs_path.Append(chrome::kPreferencesFilename);
112   return default_prefs_path;
113 }
114 
GetCurrentProfileDir()115 FilePath ProfileManager::GetCurrentProfileDir() {
116   FilePath relative_profile_dir;
117 #if defined(OS_CHROMEOS)
118   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
119   if (logged_in_) {
120     FilePath profile_dir;
121     // If the user has logged in, pick up the new profile.
122     if (command_line.HasSwitch(switches::kLoginProfile)) {
123       profile_dir = command_line.GetSwitchValuePath(switches::kLoginProfile);
124     } else {
125       // We should never be logged in with no profile dir.
126       NOTREACHED();
127       return FilePath("");
128     }
129     relative_profile_dir = relative_profile_dir.Append(profile_dir);
130     return relative_profile_dir;
131   }
132 #endif
133   relative_profile_dir =
134       relative_profile_dir.AppendASCII(chrome::kNotSignedInProfile);
135   return relative_profile_dir;
136 }
137 
GetDefaultProfile(const FilePath & user_data_dir)138 Profile* ProfileManager::GetDefaultProfile(const FilePath& user_data_dir) {
139   FilePath default_profile_dir(user_data_dir);
140   default_profile_dir = default_profile_dir.Append(GetCurrentProfileDir());
141 #if defined(OS_CHROMEOS)
142   if (!logged_in_) {
143     Profile* profile;
144     const CommandLine& command_line = *CommandLine::ForCurrentProcess();
145 
146     // For cros, return the OTR profile so we never accidentally keep
147     // user data in an unencrypted profile. But doing this makes
148     // many of the browser and ui tests fail. We do return the OTR profile
149     // if the login-profile switch is passed so that we can test this.
150     // TODO(davemoore) Fix the tests so they allow OTR profiles.
151     if (!command_line.HasSwitch(switches::kTestType) ||
152         command_line.HasSwitch(switches::kLoginProfile)) {
153       // Don't init extensions for this profile
154       profile = GetProfile(default_profile_dir);
155       profile = profile->GetOffTheRecordProfile();
156     } else {
157       profile = GetProfile(default_profile_dir);
158     }
159     return profile;
160   }
161 #endif
162   return GetProfile(default_profile_dir);
163 }
164 
GetProfileWithId(ProfileId profile_id)165 Profile* ProfileManager::GetProfileWithId(ProfileId profile_id) {
166   DCHECK_NE(Profile::kInvalidProfileId, profile_id);
167   for (ProfilesInfoMap::iterator iter = profiles_info_.begin();
168        iter != profiles_info_.end(); ++iter) {
169     if (iter->second->created) {
170       Profile* candidate = iter->second->profile.get();
171       if (candidate->GetRuntimeId() == profile_id)
172         return candidate;
173       if (candidate->HasOffTheRecordProfile()) {
174         candidate = candidate->GetOffTheRecordProfile();
175         if (candidate->GetRuntimeId() == profile_id)
176           return candidate;
177       }
178     }
179   }
180   return NULL;
181 }
182 
IsValidProfile(Profile * profile)183 bool ProfileManager::IsValidProfile(Profile* profile) {
184   for (ProfilesInfoMap::iterator iter = profiles_info_.begin();
185        iter != profiles_info_.end(); ++iter) {
186     if (iter->second->created) {
187       Profile* candidate = iter->second->profile.get();
188       if (candidate == profile ||
189           (candidate->HasOffTheRecordProfile() &&
190            candidate->GetOffTheRecordProfile() == profile)) {
191         return true;
192       }
193     }
194   }
195   return false;
196 }
197 
GetLoadedProfiles() const198 std::vector<Profile*> ProfileManager::GetLoadedProfiles() const {
199   std::vector<Profile*> profiles;
200   for (ProfilesInfoMap::const_iterator iter = profiles_info_.begin();
201        iter != profiles_info_.end(); ++iter) {
202     if (iter->second->created)
203       profiles.push_back(iter->second->profile.get());
204   }
205   return profiles;
206 }
207 
GetProfile(const FilePath & profile_dir)208 Profile* ProfileManager::GetProfile(const FilePath& profile_dir) {
209   // If the profile is already loaded (e.g., chrome.exe launched twice), just
210   // return it.
211   Profile* profile = GetProfileByPath(profile_dir);
212   if (NULL != profile)
213     return profile;
214 
215   profile = Profile::CreateProfile(profile_dir);
216   DCHECK(profile);
217   if (profile) {
218     bool result = AddProfile(profile);
219     DCHECK(result);
220   }
221   return profile;
222 }
223 
CreateProfileAsync(const FilePath & user_data_dir,Observer * observer)224 void ProfileManager::CreateProfileAsync(const FilePath& user_data_dir,
225                                         Observer* observer) {
226   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
227   ProfilesInfoMap::iterator iter = profiles_info_.find(user_data_dir);
228   if (iter != profiles_info_.end()) {
229     ProfileInfo* info = iter->second.get();
230     if (info->created) {
231       // Profile has already been created. Call observer immediately.
232       observer->OnProfileCreated(info->profile.get());
233     } else {
234       // Profile is being created. Add observer to list.
235       info->observers.push_back(observer);
236     }
237   } else {
238     // Initiate asynchronous creation process.
239     ProfileInfo* info =
240         RegisterProfile(Profile::CreateProfileAsync(user_data_dir, this),
241                         false);
242     info->observers.push_back(observer);
243   }
244 }
245 
246 // static
CreateDefaultProfileAsync(Observer * observer)247 void ProfileManager::CreateDefaultProfileAsync(Observer* observer) {
248   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
249   ProfileManager* profile_manager = g_browser_process->profile_manager();
250 
251   FilePath default_profile_dir;
252   PathService::Get(chrome::DIR_USER_DATA, &default_profile_dir);
253   default_profile_dir = default_profile_dir.Append(
254       profile_manager->GetCurrentProfileDir());
255 
256   profile_manager->CreateProfileAsync(default_profile_dir,
257                                       observer);
258 }
259 
AddProfile(Profile * profile)260 bool ProfileManager::AddProfile(Profile* profile) {
261   DCHECK(profile);
262 
263   // Make sure that we're not loading a profile with the same ID as a profile
264   // that's already loaded.
265   if (GetProfileByPath(profile->GetPath())) {
266     NOTREACHED() << "Attempted to add profile with the same path (" <<
267                     profile->GetPath().value() <<
268                     ") as an already-loaded profile.";
269     return false;
270   }
271 
272   RegisterProfile(profile, true);
273   DoFinalInit(profile);
274   return true;
275 }
276 
RegisterProfile(Profile * profile,bool created)277 ProfileManager::ProfileInfo* ProfileManager::RegisterProfile(Profile* profile,
278                                                              bool created) {
279   ProfileInfo* info = new ProfileInfo(profile, created);
280   ProfilesInfoMap::iterator new_elem =
281       (profiles_info_.insert(std::make_pair(profile->GetPath(), info))).first;
282   return info;
283 }
284 
GetProfileByPath(const FilePath & path) const285 Profile* ProfileManager::GetProfileByPath(const FilePath& path) const {
286   ProfilesInfoMap::const_iterator iter = profiles_info_.find(path);
287   return (iter == profiles_info_.end()) ? NULL : iter->second->profile.get();
288 }
289 
OnSuspend()290 void ProfileManager::OnSuspend() {
291   DCHECK(CalledOnValidThread());
292 
293   bool posted = BrowserThread::PostTask(
294       BrowserThread::IO, FROM_HERE,
295       NewRunnableFunction(&SuspendURLRequestJobs));
296   DCHECK(posted);
297 
298   scoped_refptr<net::URLRequestContextGetter> request_context;
299   std::vector<Profile*> profiles(GetLoadedProfiles());
300   for (size_t i = 0; i < profiles.size(); ++i) {
301     request_context = profiles[i]->GetRequestContext();
302     posted = BrowserThread::PostTask(
303         BrowserThread::IO, FROM_HERE,
304         NewRunnableFunction(&SuspendRequestContext, request_context));
305     DCHECK(posted);
306     request_context = profiles[i]->GetRequestContextForMedia();
307     posted = BrowserThread::PostTask(
308         BrowserThread::IO, FROM_HERE,
309         NewRunnableFunction(&SuspendRequestContext, request_context));
310     DCHECK(posted);
311   }
312 }
313 
OnResume()314 void ProfileManager::OnResume() {
315   DCHECK(CalledOnValidThread());
316 
317   scoped_refptr<net::URLRequestContextGetter> request_context;
318   std::vector<Profile*> profiles(GetLoadedProfiles());
319   for (size_t i = 0; i < profiles.size(); ++i) {
320     request_context = profiles[i]->GetRequestContext();
321     bool posted = BrowserThread::PostTask(
322         BrowserThread::IO, FROM_HERE,
323         NewRunnableFunction(&ResumeRequestContext, request_context));
324     DCHECK(posted);
325     request_context = profiles[i]->GetRequestContextForMedia();
326     posted = BrowserThread::PostTask(
327         BrowserThread::IO, FROM_HERE,
328         NewRunnableFunction(&ResumeRequestContext, request_context));
329     DCHECK(posted);
330   }
331 }
332 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)333 void ProfileManager::Observe(
334     NotificationType type,
335     const NotificationSource& source,
336     const NotificationDetails& details) {
337 #if defined(OS_CHROMEOS)
338   if (type == NotificationType::LOGIN_USER_CHANGED) {
339     const CommandLine& command_line = *CommandLine::ForCurrentProcess();
340     if (!command_line.HasSwitch(switches::kTestType)) {
341       // This will fail when running on non cros os.
342       // TODO(davemoore) Need to mock this enough to enable testing.
343       CHECK(chromeos::CrosLibrary::Get()->EnsureLoaded());
344       // If we don't have a mounted profile directory we're in trouble.
345       // TODO(davemoore) Once we have better api this check should ensure that
346       // our profile directory is the one that's mounted, and that it's mounted
347       // as the current user.
348       CHECK(chromeos::CrosLibrary::Get()->GetCryptohomeLibrary()->IsMounted());
349     }
350     logged_in_ = true;
351   }
352 #endif
353 }
354 
DoFinalInit(Profile * profile)355 void ProfileManager::DoFinalInit(Profile* profile) {
356   const CommandLine& command_line = *CommandLine::ForCurrentProcess();
357   bool init_extensions = true;
358 #if defined(OS_CHROMEOS)
359   if (!logged_in_ &&
360       (!command_line.HasSwitch(switches::kTestType) ||
361         command_line.HasSwitch(switches::kLoginProfile))) {
362     init_extensions = false;
363   }
364 #endif
365   profile->InitExtensions(init_extensions);
366 
367   if (!command_line.HasSwitch(switches::kDisableWebResources))
368     profile->InitPromoResources();
369 }
370 
OnProfileCreated(Profile * profile,bool success)371 void ProfileManager::OnProfileCreated(Profile* profile, bool success) {
372   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
373 
374   ProfilesInfoMap::iterator iter = profiles_info_.find(profile->GetPath());
375   DCHECK(iter != profiles_info_.end());
376   ProfileInfo* info = iter->second.get();
377 
378   std::vector<Observer*> observers;
379   info->observers.swap(observers);
380 
381   if (success) {
382     DoFinalInit(profile);
383     info->created = true;
384 #if defined(OS_CHROMEOS)
385     const CommandLine& command_line = *CommandLine::ForCurrentProcess();
386     if (!logged_in_ &&
387         (!command_line.HasSwitch(switches::kTestType) ||
388          command_line.HasSwitch(switches::kLoginProfile))) {
389       profile = profile->GetOffTheRecordProfile();
390     }
391 #endif
392   } else {
393     profile = NULL;
394     profiles_info_.erase(iter);
395   }
396 
397   for (size_t i = 0; i < observers.size(); ++i) {
398     observers[i]->OnProfileCreated(profile);
399   }
400 }
401