Home | History | Annotate | Download | only in profiles
      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 
     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 
     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 
     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
     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
     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 
     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 
     94 ProfileManager::~ProfileManager() {
     95   ui::SystemMonitor* system_monitor = ui::SystemMonitor::Get();
     96   if (system_monitor)
     97     system_monitor->RemoveObserver(this);
     98 }
     99 
    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 
    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 
    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 
    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 
    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 
    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 
    198 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 
    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 
    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
    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 
    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 
    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 
    285 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 
    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 
    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 
    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 
    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 
    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