blob: 224dd8d4114a19e6012413429b1ce3a0f55a6b72 [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// Copyright (c) 2006-2008 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.
initial.commit09911bf2008-07-26 23:55:294
5#include "chrome/browser/profile.h"
6
7#include "base/command_line.h"
[email protected]04fba9a92008-10-28 17:25:258#include "base/file_path.h"
initial.commit09911bf2008-07-26 23:55:299#include "base/file_util.h"
initial.commit09911bf2008-07-26 23:55:2910#include "base/path_service.h"
11#include "base/scoped_ptr.h"
12#include "base/string_util.h"
[email protected]a9afddb2009-02-12 17:49:4213#include "chrome/browser/bookmarks/bookmark_model.h"
initial.commit09911bf2008-07-26 23:55:2914#include "chrome/browser/browser_list.h"
15#include "chrome/browser/browser_process.h"
[email protected]b7f05882009-02-22 01:21:5616#include "chrome/browser/download/download_manager.h"
[email protected]bb28e062009-02-27 17:19:1817#include "chrome/browser/extensions/extension_error_reporter.h"
[email protected]6014d672008-12-05 00:38:2518#include "chrome/browser/extensions/extensions_service.h"
[email protected]0938d3c2009-01-09 20:37:3519#include "chrome/browser/extensions/user_script_master.h"
[email protected]a9afddb2009-02-12 17:49:4220#include "chrome/browser/history/history.h"
[email protected]6ab9b202008-12-23 22:34:5021#include "chrome/browser/net/chrome_url_request_context.h"
initial.commit09911bf2008-07-26 23:55:2922#include "chrome/browser/profile_manager.h"
[email protected]8c8657d62009-01-16 18:31:2623#include "chrome/browser/renderer_host/render_process_host.h"
[email protected]f63ae312009-02-04 17:58:4624#include "chrome/browser/search_engines/template_url_model.h"
[email protected]34cc84f2009-02-13 10:04:3525#include "chrome/browser/ssl/ssl_host_state.h"
[email protected]85e921fb82009-02-11 23:19:4426#include "chrome/browser/sessions/session_service.h"
[email protected]bd580a252009-02-12 01:16:3027#include "chrome/browser/sessions/tab_restore_service.h"
[email protected]f0a644292009-02-25 23:32:4728#include "chrome/browser/spellchecker.h"
initial.commit09911bf2008-07-26 23:55:2929#include "chrome/browser/visitedlink_master.h"
30#include "chrome/browser/webdata/web_data_service.h"
31#include "chrome/common/chrome_constants.h"
32#include "chrome/common/chrome_paths.h"
33#include "chrome/common/chrome_switches.h"
initial.commit09911bf2008-07-26 23:55:2934#include "chrome/common/notification_service.h"
35#include "chrome/common/pref_names.h"
[email protected]f7011fcb2009-01-28 21:54:3236#include "chrome/common/render_messages.h"
[email protected]f90f5c512009-02-18 19:10:5837#include "grit/locale_settings.h"
initial.commit09911bf2008-07-26 23:55:2938
[email protected]f7011fcb2009-01-28 21:54:3239#if defined(OS_POSIX)
40// TODO(port): get rid of this include. It's used just to provide declarations
41// and stub definitions for classes we encouter during the porting effort.
42#include "chrome/common/temp_scaffolding_stubs.h"
43#endif
44
45// TODO(port): Get rid of this section and finish porting.
46#if defined(OS_WIN)
[email protected]f7011fcb2009-01-28 21:54:3247#include "chrome/browser/search_engines/template_url_fetcher.h"
[email protected]f7011fcb2009-01-28 21:54:3248#endif
49
[email protected]e1acf6f2008-10-27 20:43:3350using base::Time;
51using base::TimeDelta;
52
initial.commit09911bf2008-07-26 23:55:2953// Delay, in milliseconds, before we explicitly create the SessionService.
54static const int kCreateSessionServiceDelayMS = 500;
55
56// A pointer to the request context for the default profile. See comments on
57// Profile::GetDefaultRequestContext.
58URLRequestContext* Profile::default_request_context_;
59
[email protected]34cc84f2009-02-13 10:04:3560// static
initial.commit09911bf2008-07-26 23:55:2961void Profile::RegisterUserPrefs(PrefService* prefs) {
[email protected]430d3f72008-10-27 17:56:5562 prefs->RegisterBooleanPref(prefs::kSearchSuggestEnabled, true);
initial.commit09911bf2008-07-26 23:55:2963 prefs->RegisterBooleanPref(prefs::kSessionExitedCleanly, true);
64 prefs->RegisterBooleanPref(prefs::kSafeBrowsingEnabled, true);
[email protected]74c8b422009-03-11 00:34:1265 // TODO(estade): IDS_SPELLCHECK_DICTIONARY should be an ASCII string.
[email protected]f7011fcb2009-01-28 21:54:3266#if defined(OS_MACOSX)
67 // MASSIVE HACK!!! We don't have localization working yet. Undo this once we
68 // do. TODO(port): take this out
69 prefs->RegisterStringPref(prefs::kSpellCheckDictionary,
70 L"IDS_SPELLCHECK_DICTIONARY");
71#elif defined(OS_WIN) || defined(OS_LINUX)
[email protected]e7244d82008-10-29 18:13:2672 prefs->RegisterLocalizedStringPref(prefs::kSpellCheckDictionary,
73 IDS_SPELLCHECK_DICTIONARY);
[email protected]f7011fcb2009-01-28 21:54:3274#endif
[email protected]e7244d82008-10-29 18:13:2675 prefs->RegisterBooleanPref(prefs::kEnableSpellCheck, true);
[email protected]f93fe782009-02-19 01:26:1376 prefs->RegisterBooleanPref(prefs::kEnableUserScripts, false);
77 prefs->RegisterBooleanPref(prefs::kEnableExtensions, false);
initial.commit09911bf2008-07-26 23:55:2978}
79
[email protected]34cc84f2009-02-13 10:04:3580// static
[email protected]f7011fcb2009-01-28 21:54:3281Profile* Profile::CreateProfile(const FilePath& path) {
initial.commit09911bf2008-07-26 23:55:2982 return new ProfileImpl(path);
83}
84
[email protected]34cc84f2009-02-13 10:04:3585// static
initial.commit09911bf2008-07-26 23:55:2986URLRequestContext* Profile::GetDefaultRequestContext() {
87 return default_request_context_;
88}
89
90
initial.commit09911bf2008-07-26 23:55:2991////////////////////////////////////////////////////////////////////////////////
92//
93// OffTheRecordProfileImpl is a profile subclass that wraps an existing profile
94// to make it suitable for the off the record mode.
95//
96////////////////////////////////////////////////////////////////////////////////
97class OffTheRecordProfileImpl : public Profile,
98 public NotificationObserver {
99 public:
100 explicit OffTheRecordProfileImpl(Profile* real_profile)
101 : profile_(real_profile),
[email protected]363347b2009-03-13 20:06:57102 media_request_context_(NULL),
initial.commit09911bf2008-07-26 23:55:29103 start_time_(Time::Now()) {
[email protected]6ab9b202008-12-23 22:34:50104 request_context_ = ChromeURLRequestContext::CreateOffTheRecord(this);
initial.commit09911bf2008-07-26 23:55:29105 request_context_->AddRef();
106 // Register for browser close notifications so we can detect when the last
107 // off-the-record window is closed, in which case we can clean our states
108 // (cookies, downloads...).
109 NotificationService::current()->AddObserver(
[email protected]bfd04a62009-02-01 18:16:56110 this,
111 NotificationType::BROWSER_CLOSED,
112 NotificationService::AllSources());
initial.commit09911bf2008-07-26 23:55:29113 }
114
115 virtual ~OffTheRecordProfileImpl() {
116 if (request_context_) {
[email protected]6ab9b202008-12-23 22:34:50117 request_context_->CleanupOnUIThread();
118
initial.commit09911bf2008-07-26 23:55:29119 // Clean up request context on IO thread.
120 g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE,
[email protected]6ab9b202008-12-23 22:34:50121 NewRunnableMethod(request_context_,
122 &base::RefCountedThreadSafe<URLRequestContext>::Release));
initial.commit09911bf2008-07-26 23:55:29123 request_context_ = NULL;
124 }
125 NotificationService::current()->RemoveObserver(
[email protected]bfd04a62009-02-01 18:16:56126 this,
127 NotificationType::BROWSER_CLOSED,
128 NotificationService::AllSources());
initial.commit09911bf2008-07-26 23:55:29129 }
130
[email protected]f7011fcb2009-01-28 21:54:32131 virtual FilePath GetPath() { return profile_->GetPath(); }
initial.commit09911bf2008-07-26 23:55:29132
133 virtual bool IsOffTheRecord() {
134 return true;
135 }
136
137 virtual Profile* GetOffTheRecordProfile() {
138 return this;
139 }
140
141 virtual Profile* GetOriginalProfile() {
142 return profile_;
143 }
144
145 virtual VisitedLinkMaster* GetVisitedLinkMaster() {
[email protected]7fb6c862009-03-13 02:51:49146 // We don't provide access to the VisitedLinkMaster when we're OffTheRecord
147 // because we don't want to leak the sites that the user has visited before.
148 return NULL;
initial.commit09911bf2008-07-26 23:55:29149 }
150
[email protected]6014d672008-12-05 00:38:25151 virtual ExtensionsService* GetExtensionsService() {
152 return profile_->GetExtensionsService();
153 }
154
[email protected]0938d3c2009-01-09 20:37:35155 virtual UserScriptMaster* GetUserScriptMaster() {
156 return profile_->GetUserScriptMaster();
[email protected]04fba9a92008-10-28 17:25:25157 }
158
[email protected]34cc84f2009-02-13 10:04:35159 virtual SSLHostState* GetSSLHostState() {
160 if (!ssl_host_state_.get())
161 ssl_host_state_.reset(new SSLHostState());
162
163 DCHECK(ssl_host_state_->CalledOnValidThread());
164 return ssl_host_state_.get();
165 }
166
initial.commit09911bf2008-07-26 23:55:29167 virtual HistoryService* GetHistoryService(ServiceAccessType sat) {
168 if (sat == EXPLICIT_ACCESS) {
169 return profile_->GetHistoryService(sat);
170 } else {
171 NOTREACHED() << "This profile is OffTheRecord";
172 return NULL;
173 }
174 }
175
initial.commit09911bf2008-07-26 23:55:29176 virtual WebDataService* GetWebDataService(ServiceAccessType sat) {
177 if (sat == EXPLICIT_ACCESS) {
178 return profile_->GetWebDataService(sat);
179 } else {
180 NOTREACHED() << "This profile is OffTheRecord";
181 return NULL;
182 }
183 }
184
185 virtual PrefService* GetPrefs() {
186 return profile_->GetPrefs();
187 }
188
189 virtual TemplateURLModel* GetTemplateURLModel() {
190 return profile_->GetTemplateURLModel();
191 }
192
193 virtual TemplateURLFetcher* GetTemplateURLFetcher() {
194 return profile_->GetTemplateURLFetcher();
195 }
196
197 virtual DownloadManager* GetDownloadManager() {
198 if (!download_manager_.get()) {
199 scoped_refptr<DownloadManager> dlm(new DownloadManager);
200 dlm->Init(this);
201 download_manager_.swap(dlm);
202 }
203 return download_manager_.get();
204 }
205
206 virtual bool HasCreatedDownloadManager() const {
207 return (download_manager_.get() != NULL);
208 }
209
210 virtual URLRequestContext* GetRequestContext() {
211 return request_context_;
212 }
213
[email protected]e7f29642009-03-02 22:53:18214 virtual URLRequestContext* GetRequestContextForMedia() {
215 if (!media_request_context_) {
216 FilePath cache_path = GetPath();
[email protected]e3edeba2009-03-23 18:57:14217
218 // Override the cache location if specified by the user.
219 const std::wstring user_cache_dir(
220 CommandLine::ForCurrentProcess()->GetSwitchValue(
221 switches::kDiskCacheDir));
222 if (!user_cache_dir.empty()) {
223 cache_path = FilePath::FromWStringHack(user_cache_dir);
224 }
225
[email protected]e7f29642009-03-02 22:53:18226 cache_path.Append(chrome::kOffTheRecordMediaCacheDirname);
227 media_request_context_ =
228 ChromeURLRequestContext::CreateOffTheRecordForMedia(
229 this, cache_path);
230 media_request_context_->AddRef();
231
232 DCHECK(media_request_context_->cookie_store());
233 }
234 return media_request_context_;
235 }
236
initial.commit09911bf2008-07-26 23:55:29237 virtual SessionService* GetSessionService() {
238 // Don't save any sessions when off the record.
239 return NULL;
240 }
241
242 virtual void ShutdownSessionService() {
243 // We don't allow a session service, nothing to do.
244 }
245
246 virtual bool HasSessionService() const {
247 // We never have a session service.
248 return false;
249 }
250
251 virtual std::wstring GetName() {
252 return profile_->GetName();
253 }
254
255 virtual void SetName(const std::wstring& name) {
256 profile_->SetName(name);
257 }
258
259 virtual std::wstring GetID() {
260 return profile_->GetID();
261 }
262
263 virtual void SetID(const std::wstring& id) {
264 profile_->SetID(id);
265 }
266
initial.commit09911bf2008-07-26 23:55:29267 virtual bool DidLastSessionExitCleanly() {
268 return profile_->DidLastSessionExitCleanly();
269 }
270
[email protected]d8e41ed2008-09-11 15:22:32271 virtual BookmarkModel* GetBookmarkModel() {
272 return profile_->GetBookmarkModel();
initial.commit09911bf2008-07-26 23:55:29273 }
274
[email protected]3a453fa2008-08-15 18:46:34275#ifdef CHROME_PERSONALIZATION
[email protected]57d3d0a2008-09-24 00:50:07276 virtual ProfilePersonalization* GetProfilePersonalization() {
[email protected]3a453fa2008-08-15 18:46:34277 return profile_->GetProfilePersonalization();
278 }
279#endif
280
initial.commit09911bf2008-07-26 23:55:29281 virtual bool IsSameProfile(Profile* profile) {
282 if (profile == static_cast<Profile*>(this))
283 return true;
284 return profile == profile_;
285 }
286
287 virtual Time GetStartTime() const {
288 return start_time_;
289 }
290
291 virtual TabRestoreService* GetTabRestoreService() {
292 return NULL;
293 }
294
[email protected]e7244d82008-10-29 18:13:26295 virtual void ResetTabRestoreService() {
[email protected]20930852008-10-15 19:30:41296 }
297
[email protected]e7244d82008-10-29 18:13:26298 virtual void ReinitializeSpellChecker() {
299 profile_->ReinitializeSpellChecker();
initial.commit09911bf2008-07-26 23:55:29300 }
301
302 virtual SpellChecker* GetSpellChecker() {
303 return profile_->GetSpellChecker();
304 }
305
306 virtual void MarkAsCleanShutdown() {
307 }
308
[email protected]bdbc87c2009-01-25 05:08:54309 virtual void InitExtensions() {
310 NOTREACHED();
311 }
312
initial.commit09911bf2008-07-26 23:55:29313 virtual void ExitedOffTheRecordMode() {
314 // Drop our download manager so we forget about all the downloads made
315 // in off-the-record mode.
316 download_manager_ = NULL;
317 }
318
319 virtual void Observe(NotificationType type,
320 const NotificationSource& source,
321 const NotificationDetails& details) {
[email protected]bfd04a62009-02-01 18:16:56322 DCHECK_EQ(NotificationType::BROWSER_CLOSED, type.value);
initial.commit09911bf2008-07-26 23:55:29323 // We are only interested in OTR browser closing.
324 if (Source<Browser>(source)->profile() != this)
325 return;
326
327 // Let's check if we still have an Off The Record window opened.
328 // Note that we check against 1 as this notification is sent before the
329 // browser window is actually removed from the list.
330 if (BrowserList::GetBrowserCount(this) <= 1)
331 ExitedOffTheRecordMode();
332 }
333
334 private:
335 // The real underlying profile.
336 Profile* profile_;
337
[email protected]6ab9b202008-12-23 22:34:50338 // The context to use for requests made from this OTR session.
339 ChromeURLRequestContext* request_context_;
initial.commit09911bf2008-07-26 23:55:29340
[email protected]e7f29642009-03-02 22:53:18341 // The context for requests for media resources.
342 ChromeURLRequestContext* media_request_context_;
343
initial.commit09911bf2008-07-26 23:55:29344 // The download manager that only stores downloaded items in memory.
345 scoped_refptr<DownloadManager> download_manager_;
346
[email protected]34cc84f2009-02-13 10:04:35347 // We don't want SSLHostState from the OTR profile to leak back to the main
348 // profile because then the main profile would learn some of the host names
349 // the user visited while OTR.
350 scoped_ptr<SSLHostState> ssl_host_state_;
351
initial.commit09911bf2008-07-26 23:55:29352 // Time we were started.
353 Time start_time_;
354
355 DISALLOW_EVIL_CONSTRUCTORS(OffTheRecordProfileImpl);
356};
357
[email protected]f7011fcb2009-01-28 21:54:32358ProfileImpl::ProfileImpl(const FilePath& path)
initial.commit09911bf2008-07-26 23:55:29359 : path_(path),
360 off_the_record_(false),
[email protected]3a453fa2008-08-15 18:46:34361#ifdef CHROME_PERSONALIZATION
362 personalization_(NULL),
363#endif
[email protected]f7011fcb2009-01-28 21:54:32364 request_context_(NULL),
[email protected]363347b2009-03-13 20:06:57365 media_request_context_(NULL),
[email protected]f7011fcb2009-01-28 21:54:32366 history_service_created_(false),
367 created_web_data_service_(false),
368 created_download_manager_(false),
369 start_time_(Time::Now()),
370 spellchecker_(NULL),
initial.commit09911bf2008-07-26 23:55:29371 shutdown_session_service_(false) {
372 DCHECK(!path.empty()) << "Using an empty path will attempt to write " <<
373 "profile files to the root directory!";
[email protected]2d316662008-09-03 18:18:14374 create_session_service_timer_.Start(
375 TimeDelta::FromMilliseconds(kCreateSessionServiceDelayMS), this,
376 &ProfileImpl::EnsureSessionServiceCreated);
[email protected]bdbc87c2009-01-25 05:08:54377
[email protected]e7244d82008-10-29 18:13:26378 PrefService* prefs = GetPrefs();
379 prefs->AddPrefObserver(prefs::kSpellCheckDictionary, this);
380 prefs->AddPrefObserver(prefs::kEnableSpellCheck, this);
initial.commit09911bf2008-07-26 23:55:29381}
382
[email protected]bdbc87c2009-01-25 05:08:54383void ProfileImpl::InitExtensions() {
[email protected]8c756ac2009-01-30 23:36:41384 if (user_script_master_ || extensions_service_)
385 return; // Already initialized.
386
[email protected]bdbc87c2009-01-25 05:08:54387 const CommandLine* command_line = CommandLine::ForCurrentProcess();
[email protected]f93fe782009-02-19 01:26:13388 PrefService* prefs = GetPrefs();
[email protected]bdbc87c2009-01-25 05:08:54389 bool user_scripts_enabled =
[email protected]f0a51fb52009-03-05 12:46:38390 command_line->HasSwitch(switches::kEnableUserScripts) ||
[email protected]f93fe782009-02-19 01:26:13391 prefs->GetBoolean(prefs::kEnableUserScripts);
[email protected]a9afddb2009-02-12 17:49:42392 bool extensions_enabled =
[email protected]f0a51fb52009-03-05 12:46:38393 command_line->HasSwitch(switches::kEnableExtensions) ||
[email protected]f93fe782009-02-19 01:26:13394 prefs->GetBoolean(prefs::kEnableExtensions);
[email protected]bdbc87c2009-01-25 05:08:54395
[email protected]f7011fcb2009-01-28 21:54:32396 FilePath script_dir;
[email protected]bdbc87c2009-01-25 05:08:54397 if (user_scripts_enabled) {
[email protected]0cd957b2009-03-06 20:13:23398 if (command_line->HasSwitch(switches::kUserScriptsDir)) {
399 std::wstring path_string =
400 command_line->GetSwitchValue(switches::kUserScriptsDir);
401 script_dir = FilePath::FromWStringHack(path_string);
402 } else {
403 script_dir = GetPath();
404 script_dir = script_dir.Append(chrome::kUserScriptsDirname);
405 }
[email protected]bdbc87c2009-01-25 05:08:54406 }
407
[email protected]bb28e062009-02-27 17:19:18408 ExtensionErrorReporter::Init(true); // allow noisy errors.
[email protected]bdbc87c2009-01-25 05:08:54409 user_script_master_ = new UserScriptMaster(
[email protected]f7011fcb2009-01-28 21:54:32410 g_browser_process->file_thread()->message_loop(), script_dir);
[email protected]81e63782009-02-27 19:35:09411 extensions_service_ = new ExtensionsService(this, user_script_master_.get());
[email protected]bdbc87c2009-01-25 05:08:54412
413 // If we have extensions, the extension service will kick off the first scan
414 // after extensions are loaded. Otherwise, we need to do that now.
415 if (extensions_enabled)
416 extensions_service_->Init();
417 else if (user_scripts_enabled)
418 user_script_master_->StartScan();
419}
420
initial.commit09911bf2008-07-26 23:55:29421ProfileImpl::~ProfileImpl() {
[email protected]169627b2008-12-06 19:30:19422 tab_restore_service_ = NULL;
initial.commit09911bf2008-07-26 23:55:29423
424 StopCreateSessionServiceTimer();
425 // TemplateURLModel schedules a task on the WebDataService from its
426 // destructor. Delete it first to ensure the task gets scheduled before we
427 // shut down the database.
428 template_url_model_.reset();
429
430 // The download manager queries the history system and should be deleted
431 // before the history is shutdown so it can properly cancel all requests.
432 download_manager_ = NULL;
433
[email protected]e7244d82008-10-29 18:13:26434 // Remove pref observers.
435 PrefService* prefs = GetPrefs();
436 prefs->RemovePrefObserver(prefs::kSpellCheckDictionary, this);
437 prefs->RemovePrefObserver(prefs::kEnableSpellCheck, this);
438
[email protected]3a453fa2008-08-15 18:46:34439#ifdef CHROME_PERSONALIZATION
[email protected]57d3d0a2008-09-24 00:50:07440 personalization_.reset();
[email protected]3a453fa2008-08-15 18:46:34441#endif
442
initial.commit09911bf2008-07-26 23:55:29443 // Both HistoryService and WebDataService maintain threads for background
444 // processing. Its possible each thread still has tasks on it that have
445 // increased the ref count of the service. In such a situation, when we
446 // decrement the refcount, it won't be 0, and the threads/databases aren't
447 // properly shut down. By explicitly calling Cleanup/Shutdown we ensure the
448 // databases are properly closed.
449 if (web_data_service_.get())
450 web_data_service_->Shutdown();
451
452 if (history_service_.get())
453 history_service_->Cleanup();
454
455 // The I/O thread may be NULL during testing.
[email protected]ab820df2008-08-26 05:55:10456 base::Thread* io_thread = g_browser_process->io_thread();
initial.commit09911bf2008-07-26 23:55:29457
458 if (spellchecker_) {
459 // The spellchecker must be deleted on the I/O thread. During testing, we
460 // don't have an I/O thread.
461 if (io_thread)
462 io_thread->message_loop()->ReleaseSoon(FROM_HERE, spellchecker_);
463 else
464 spellchecker_->Release();
465 }
466
467 if (request_context_) {
[email protected]6ab9b202008-12-23 22:34:50468 request_context_->CleanupOnUIThread();
469
470 if (default_request_context_ == request_context_)
471 default_request_context_ = NULL;
472
initial.commit09911bf2008-07-26 23:55:29473 // Clean up request context on IO thread.
[email protected]6ab9b202008-12-23 22:34:50474 g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE,
475 NewRunnableMethod(request_context_,
476 &base::RefCountedThreadSafe<URLRequestContext>::Release));
initial.commit09911bf2008-07-26 23:55:29477 request_context_ = NULL;
478 }
479
[email protected]d8e41ed2008-09-11 15:22:32480 // HistoryService may call into the BookmarkModel, as such we need to
481 // delete HistoryService before the BookmarkModel. The destructor for
[email protected]90ef13132008-08-27 03:27:46482 // HistoryService will join with HistoryService's backend thread so that
483 // by the time the destructor has finished we're sure it will no longer call
[email protected]d8e41ed2008-09-11 15:22:32484 // into the BookmarkModel.
[email protected]90ef13132008-08-27 03:27:46485 history_service_ = NULL;
486 bookmark_bar_model_.reset();
487
initial.commit09911bf2008-07-26 23:55:29488 MarkAsCleanShutdown();
489}
490
[email protected]f7011fcb2009-01-28 21:54:32491FilePath ProfileImpl::GetPath() {
initial.commit09911bf2008-07-26 23:55:29492 return path_;
493}
494
495bool ProfileImpl::IsOffTheRecord() {
496 return false;
497}
498
499Profile* ProfileImpl::GetOffTheRecordProfile() {
500 if (!off_the_record_profile_.get()) {
501 scoped_ptr<OffTheRecordProfileImpl> p(new OffTheRecordProfileImpl(this));
502 off_the_record_profile_.swap(p);
503 }
504 return off_the_record_profile_.get();
505}
506
507Profile* ProfileImpl::GetOriginalProfile() {
508 return this;
509}
510
[email protected]176aa482008-11-14 03:25:15511static void BroadcastNewHistoryTable(base::SharedMemory* table_memory) {
initial.commit09911bf2008-07-26 23:55:29512 if (!table_memory)
513 return;
514
515 // send to all RenderProcessHosts
516 for (RenderProcessHost::iterator i = RenderProcessHost::begin();
517 i != RenderProcessHost::end(); i++) {
518 if (!i->second->channel())
519 continue;
520
[email protected]176aa482008-11-14 03:25:15521 base::SharedMemoryHandle new_table;
[email protected]f7011fcb2009-01-28 21:54:32522 base::ProcessHandle process = i->second->process().handle();
initial.commit09911bf2008-07-26 23:55:29523 if (!process) {
524 // process can be null if it's started with the --single-process flag.
[email protected]f7011fcb2009-01-28 21:54:32525 process = base::Process::Current().handle();
initial.commit09911bf2008-07-26 23:55:29526 }
527
528 table_memory->ShareToProcess(process, &new_table);
529 IPC::Message* msg = new ViewMsg_VisitedLink_NewTable(new_table);
530 i->second->channel()->Send(msg);
531 }
532}
533
534VisitedLinkMaster* ProfileImpl::GetVisitedLinkMaster() {
535 if (!visited_link_master_.get()) {
536 scoped_ptr<VisitedLinkMaster> visited_links(
537 new VisitedLinkMaster(g_browser_process->file_thread(),
538 BroadcastNewHistoryTable, this));
539 if (!visited_links->Init())
540 return NULL;
541 visited_link_master_.swap(visited_links);
542 }
543
544 return visited_link_master_.get();
545}
546
[email protected]6014d672008-12-05 00:38:25547ExtensionsService* ProfileImpl::GetExtensionsService() {
548 return extensions_service_.get();
549}
550
[email protected]0938d3c2009-01-09 20:37:35551UserScriptMaster* ProfileImpl::GetUserScriptMaster() {
[email protected]0938d3c2009-01-09 20:37:35552 return user_script_master_.get();
[email protected]04fba9a92008-10-28 17:25:25553}
554
[email protected]34cc84f2009-02-13 10:04:35555SSLHostState* ProfileImpl::GetSSLHostState() {
556 if (!ssl_host_state_.get())
557 ssl_host_state_.reset(new SSLHostState());
558
559 DCHECK(ssl_host_state_->CalledOnValidThread());
560 return ssl_host_state_.get();
561}
562
initial.commit09911bf2008-07-26 23:55:29563PrefService* ProfileImpl::GetPrefs() {
564 if (!prefs_.get()) {
[email protected]b9636002009-03-04 00:05:25565 prefs_.reset(new PrefService(GetPrefFilePath()));
initial.commit09911bf2008-07-26 23:55:29566
567 // The Profile class and ProfileManager class may read some prefs so
568 // register known prefs as soon as possible.
569 Profile::RegisterUserPrefs(prefs_.get());
570 ProfileManager::RegisterUserPrefs(prefs_.get());
571
572 // The last session exited cleanly if there is no pref for
573 // kSessionExitedCleanly or the value for kSessionExitedCleanly is true.
574 last_session_exited_cleanly_ =
575 prefs_->GetBoolean(prefs::kSessionExitedCleanly);
576 // Mark the session as open.
577 prefs_->SetBoolean(prefs::kSessionExitedCleanly, false);
578 // Make sure we save to disk that the session has opened.
579 prefs_->ScheduleSavePersistentPrefs(g_browser_process->file_thread());
580 }
581
582 return prefs_.get();
583}
584
[email protected]f7011fcb2009-01-28 21:54:32585FilePath ProfileImpl::GetPrefFilePath() {
586 FilePath pref_file_path = path_;
587 pref_file_path = pref_file_path.Append(chrome::kPreferencesFilename);
initial.commit09911bf2008-07-26 23:55:29588 return pref_file_path;
589}
590
591URLRequestContext* ProfileImpl::GetRequestContext() {
592 if (!request_context_) {
[email protected]f7011fcb2009-01-28 21:54:32593 FilePath cookie_path = GetPath();
594 cookie_path = cookie_path.Append(chrome::kCookieFilename);
595 FilePath cache_path = GetPath();
[email protected]2b2830a2009-02-07 01:58:42596
597 // Override the cache location if specified by the user.
598 const std::wstring user_cache_dir(
599 CommandLine::ForCurrentProcess()->GetSwitchValue(
600 switches::kDiskCacheDir));
601 if (!user_cache_dir.empty()) {
602 cache_path = FilePath::FromWStringHack(user_cache_dir);
603 }
604
[email protected]f7011fcb2009-01-28 21:54:32605 cache_path = cache_path.Append(chrome::kCacheDirname);
[email protected]6ab9b202008-12-23 22:34:50606 request_context_ = ChromeURLRequestContext::CreateOriginal(
607 this, cookie_path, cache_path);
initial.commit09911bf2008-07-26 23:55:29608 request_context_->AddRef();
609
[email protected]6ab9b202008-12-23 22:34:50610 // The first request context is always a normal (non-OTR) request context.
611 // Even when Chromium is started in OTR mode, a normal profile is always
612 // created first.
613 if (!default_request_context_) {
614 default_request_context_ = request_context_;
615 NotificationService::current()->Notify(
[email protected]bfd04a62009-02-01 18:16:56616 NotificationType::DEFAULT_REQUEST_CONTEXT_AVAILABLE,
[email protected]6ab9b202008-12-23 22:34:50617 NotificationService::AllSources(), NotificationService::NoDetails());
618 }
619
initial.commit09911bf2008-07-26 23:55:29620 DCHECK(request_context_->cookie_store());
621 }
622
623 return request_context_;
624}
625
[email protected]e7f29642009-03-02 22:53:18626URLRequestContext* ProfileImpl::GetRequestContextForMedia() {
627 if (!media_request_context_) {
628 FilePath cache_path = GetPath();
[email protected]e3edeba2009-03-23 18:57:14629
630 // Override the cache location if specified by the user.
631 const std::wstring user_cache_dir(
632 CommandLine::ForCurrentProcess()->GetSwitchValue(
633 switches::kDiskCacheDir));
634 if (!user_cache_dir.empty()) {
635 cache_path = FilePath::FromWStringHack(user_cache_dir);
636 }
637
[email protected]e7f29642009-03-02 22:53:18638 cache_path.Append(chrome::kMediaCacheDirname);
639 media_request_context_ = ChromeURLRequestContext::CreateOriginalForMedia(
640 this, cache_path);
641 media_request_context_->AddRef();
642
643 DCHECK(media_request_context_->cookie_store());
644 }
645
646 return media_request_context_;
647}
648
initial.commit09911bf2008-07-26 23:55:29649HistoryService* ProfileImpl::GetHistoryService(ServiceAccessType sat) {
650 if (!history_service_created_) {
[email protected]90ef13132008-08-27 03:27:46651 history_service_created_ = true;
initial.commit09911bf2008-07-26 23:55:29652 scoped_refptr<HistoryService> history(new HistoryService(this));
[email protected]d8e41ed2008-09-11 15:22:32653 if (!history->Init(GetPath(), GetBookmarkModel()))
initial.commit09911bf2008-07-26 23:55:29654 return NULL;
655 history_service_.swap(history);
initial.commit09911bf2008-07-26 23:55:29656
657 // Send out the notification that the history service was created.
658 NotificationService::current()->
[email protected]bfd04a62009-02-01 18:16:56659 Notify(NotificationType::HISTORY_CREATED, Source<Profile>(this),
initial.commit09911bf2008-07-26 23:55:29660 Details<HistoryService>(history_service_.get()));
661 }
662 return history_service_.get();
663}
664
initial.commit09911bf2008-07-26 23:55:29665TemplateURLModel* ProfileImpl::GetTemplateURLModel() {
666 if (!template_url_model_.get())
667 template_url_model_.reset(new TemplateURLModel(this));
668 return template_url_model_.get();
669}
670
671TemplateURLFetcher* ProfileImpl::GetTemplateURLFetcher() {
672 if (!template_url_fetcher_.get())
673 template_url_fetcher_.reset(new TemplateURLFetcher(this));
674 return template_url_fetcher_.get();
675}
676
677WebDataService* ProfileImpl::GetWebDataService(ServiceAccessType sat) {
678 if (!created_web_data_service_)
679 CreateWebDataService();
680 return web_data_service_.get();
681}
682
683void ProfileImpl::CreateWebDataService() {
684 DCHECK(!created_web_data_service_ && web_data_service_.get() == NULL);
685 created_web_data_service_ = true;
686 scoped_refptr<WebDataService> wds(new WebDataService());
687 if (!wds->Init(GetPath()))
688 return;
689 web_data_service_.swap(wds);
690}
691
692DownloadManager* ProfileImpl::GetDownloadManager() {
693 if (!created_download_manager_) {
694 scoped_refptr<DownloadManager> dlm(new DownloadManager);
695 dlm->Init(this);
696 created_download_manager_ = true;
697 download_manager_.swap(dlm);
698 }
699 return download_manager_.get();
700}
701
702bool ProfileImpl::HasCreatedDownloadManager() const {
703 return created_download_manager_;
704}
705
706SessionService* ProfileImpl::GetSessionService() {
707 if (!session_service_.get() && !shutdown_session_service_) {
708 session_service_ = new SessionService(this);
709 session_service_->ResetFromCurrentBrowsers();
710 }
711 return session_service_.get();
712}
713
714void ProfileImpl::ShutdownSessionService() {
715 if (shutdown_session_service_)
716 return;
717
718 // We're about to exit, force creation of the session service if it hasn't
719 // been created yet. We do this to ensure session state matches the point in
720 // time the user exited.
721 GetSessionService();
722 shutdown_session_service_ = true;
723 session_service_ = NULL;
724}
725
726bool ProfileImpl::HasSessionService() const {
727 return (session_service_.get() != NULL);
728}
729
730std::wstring ProfileImpl::GetName() {
731 return GetPrefs()->GetString(prefs::kProfileName);
732}
733void ProfileImpl::SetName(const std::wstring& name) {
734 GetPrefs()->SetString(prefs::kProfileName, name);
735}
736
737std::wstring ProfileImpl::GetID() {
738 return GetPrefs()->GetString(prefs::kProfileID);
739}
740void ProfileImpl::SetID(const std::wstring& id) {
741 GetPrefs()->SetString(prefs::kProfileID, id);
742}
743
initial.commit09911bf2008-07-26 23:55:29744bool ProfileImpl::DidLastSessionExitCleanly() {
745 // last_session_exited_cleanly_ is set when the preferences are loaded. Force
746 // it to be set by asking for the prefs.
747 GetPrefs();
748 return last_session_exited_cleanly_;
749}
750
[email protected]d8e41ed2008-09-11 15:22:32751BookmarkModel* ProfileImpl::GetBookmarkModel() {
[email protected]90ef13132008-08-27 03:27:46752 if (!bookmark_bar_model_.get()) {
[email protected]d8e41ed2008-09-11 15:22:32753 bookmark_bar_model_.reset(new BookmarkModel(this));
[email protected]90ef13132008-08-27 03:27:46754 bookmark_bar_model_->Load();
755 }
initial.commit09911bf2008-07-26 23:55:29756 return bookmark_bar_model_.get();
757}
758
759bool ProfileImpl::IsSameProfile(Profile* profile) {
760 if (profile == static_cast<Profile*>(this))
761 return true;
762 OffTheRecordProfileImpl* otr_profile = off_the_record_profile_.get();
763 return otr_profile && profile == static_cast<Profile*>(otr_profile);
764}
765
766Time ProfileImpl::GetStartTime() const {
767 return start_time_;
768}
769
770TabRestoreService* ProfileImpl::GetTabRestoreService() {
771 if (!tab_restore_service_.get())
[email protected]169627b2008-12-06 19:30:19772 tab_restore_service_ = new TabRestoreService(this);
initial.commit09911bf2008-07-26 23:55:29773 return tab_restore_service_.get();
774}
775
776void ProfileImpl::ResetTabRestoreService() {
[email protected]169627b2008-12-06 19:30:19777 tab_restore_service_ = NULL;
initial.commit09911bf2008-07-26 23:55:29778}
779
[email protected]a9afddb2009-02-12 17:49:42780// To be run in the IO thread to notify all resource message filters that the
[email protected]20930852008-10-15 19:30:41781// spellchecker has changed.
782class NotifySpellcheckerChangeTask : public Task {
783 public:
784 NotifySpellcheckerChangeTask(
[email protected]e7244d82008-10-29 18:13:26785 Profile* profile,
786 const SpellcheckerReinitializedDetails& spellchecker)
[email protected]20930852008-10-15 19:30:41787 : profile_(profile),
788 spellchecker_(spellchecker) {
789 }
790
791 private:
792 void Run(void) {
793 NotificationService::current()->Notify(
[email protected]bfd04a62009-02-01 18:16:56794 NotificationType::SPELLCHECKER_REINITIALIZED,
[email protected]20930852008-10-15 19:30:41795 Source<Profile>(profile_),
796 Details<SpellcheckerReinitializedDetails>(&spellchecker_));
797 }
798
799 Profile* profile_;
800 SpellcheckerReinitializedDetails spellchecker_;
801};
802
[email protected]e7244d82008-10-29 18:13:26803void ProfileImpl::InitializeSpellChecker(bool need_to_broadcast) {
[email protected]20930852008-10-15 19:30:41804 // The I/O thread may be NULL during testing.
805 base::Thread* io_thread = g_browser_process->io_thread();
806 if (spellchecker_) {
807 // The spellchecker must be deleted on the I/O thread.
808 // A dummy variable to aid in logical clarity.
809 SpellChecker* last_spellchecker = spellchecker_;
810
811 if (io_thread)
812 io_thread->message_loop()->ReleaseSoon(FROM_HERE, last_spellchecker);
813 else // during testing, we don't have an I/O thread
814 last_spellchecker->Release();
[email protected]20930852008-10-15 19:30:41815 }
816
[email protected]20930852008-10-15 19:30:41817 // Retrieve the (perhaps updated recently) dictionary name from preferences.
818 PrefService* prefs = GetPrefs();
[email protected]e7244d82008-10-29 18:13:26819 bool enable_spellcheck = prefs->GetBoolean(prefs::kEnableSpellCheck);
[email protected]20930852008-10-15 19:30:41820
[email protected]e7244d82008-10-29 18:13:26821 if (enable_spellcheck) {
[email protected]bd17b702009-02-25 20:44:08822 FilePath dict_dir;
[email protected]e7244d82008-10-29 18:13:26823 PathService::Get(chrome::DIR_APP_DICTIONARIES, &dict_dir);
[email protected]a9afddb2009-02-12 17:49:42824 // Note that, as the object pointed to by previously by spellchecker_
[email protected]e7244d82008-10-29 18:13:26825 // is being deleted in the io thread, the spellchecker_ can be made to point
826 // to a new object (RE-initialized) in parallel in this UI thread.
[email protected]4b4d1adc2008-12-10 22:28:58827 spellchecker_ = new SpellChecker(dict_dir,
[email protected]74c8b422009-03-11 00:34:12828 WideToASCII(prefs->GetString(prefs::kSpellCheckDictionary)),
829 GetRequestContext(),
[email protected]bd17b702009-02-25 20:44:08830 FilePath());
[email protected]e7244d82008-10-29 18:13:26831 spellchecker_->AddRef(); // Manual refcounting.
832 } else {
833 spellchecker_ = NULL;
834 }
[email protected]20930852008-10-15 19:30:41835
836 if (need_to_broadcast && io_thread) { // Notify resource message filters.
837 SpellcheckerReinitializedDetails scoped_spellchecker;
838 scoped_spellchecker.spellchecker = spellchecker_;
[email protected]e7244d82008-10-29 18:13:26839 if (io_thread) {
840 io_thread->message_loop()->PostTask(
[email protected]a9afddb2009-02-12 17:49:42841 FROM_HERE,
[email protected]e7244d82008-10-29 18:13:26842 new NotifySpellcheckerChangeTask(this, scoped_spellchecker));
843 }
[email protected]20930852008-10-15 19:30:41844 }
845}
846
[email protected]e7244d82008-10-29 18:13:26847void ProfileImpl::ReinitializeSpellChecker() {
848 InitializeSpellChecker(true);
849}
850
initial.commit09911bf2008-07-26 23:55:29851SpellChecker* ProfileImpl::GetSpellChecker() {
852 if (!spellchecker_) {
[email protected]20930852008-10-15 19:30:41853 // This is where spellchecker gets initialized. Note that this is being
854 // initialized in the ui_thread. However, this is not a problem as long as
855 // it is *used* in the io thread.
[email protected]34cc84f2009-02-13 10:04:35856 // TODO(sidchat): One day, change everything so that spellchecker gets
[email protected]20930852008-10-15 19:30:41857 // initialized in the IO thread itself.
[email protected]e7244d82008-10-29 18:13:26858 InitializeSpellChecker(false);
initial.commit09911bf2008-07-26 23:55:29859 }
[email protected]20930852008-10-15 19:30:41860
initial.commit09911bf2008-07-26 23:55:29861 return spellchecker_;
862}
863
864void ProfileImpl::MarkAsCleanShutdown() {
865 if (prefs_.get()) {
866 // The session cleanly exited, set kSessionExitedCleanly appropriately.
867 prefs_->SetBoolean(prefs::kSessionExitedCleanly, true);
868
869 // NOTE: If you change what thread this writes on, be sure and update
870 // ChromeFrame::EndSession().
871 prefs_->SavePersistentPrefs(g_browser_process->file_thread());
872 }
873}
874
[email protected]e7244d82008-10-29 18:13:26875void ProfileImpl::Observe(NotificationType type,
876 const NotificationSource& source,
877 const NotificationDetails& details) {
[email protected]bfd04a62009-02-01 18:16:56878 if (NotificationType::PREF_CHANGED == type) {
[email protected]e7244d82008-10-29 18:13:26879 std::wstring* pref_name_in = Details<std::wstring>(details).ptr();
880 PrefService* prefs = Source<PrefService>(source).ptr();
881 DCHECK(pref_name_in && prefs);
882 if (*pref_name_in == prefs::kSpellCheckDictionary ||
883 *pref_name_in == prefs::kEnableSpellCheck) {
884 InitializeSpellChecker(true);
885 }
886 }
887}
888
initial.commit09911bf2008-07-26 23:55:29889void ProfileImpl::StopCreateSessionServiceTimer() {
[email protected]2d316662008-09-03 18:18:14890 create_session_service_timer_.Stop();
initial.commit09911bf2008-07-26 23:55:29891}
[email protected]3a453fa2008-08-15 18:46:34892
893#ifdef CHROME_PERSONALIZATION
[email protected]57d3d0a2008-09-24 00:50:07894ProfilePersonalization* ProfileImpl::GetProfilePersonalization() {
[email protected]bb95ef9e2009-03-05 23:20:29895 DCHECK(!Personalization::IsP13NDisabled());
[email protected]828e46f2009-02-27 02:43:51896 if (!personalization_.get())
897 personalization_.reset(
898 Personalization::CreateProfilePersonalization(this));
[email protected]57d3d0a2008-09-24 00:50:07899 return personalization_.get();
[email protected]3a453fa2008-08-15 18:46:34900}
license.botbf09a502008-08-24 00:55:55901#endif