off_the_record_profile_impl.cc revision 3551c9c881056c480085172ff9840cab31610854
1// Copyright (c) 2012 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 "chrome/browser/profiles/off_the_record_profile_impl.h"
6
7#include "base/bind.h"
8#include "base/command_line.h"
9#include "base/compiler_specific.h"
10#include "base/files/file_path.h"
11#include "base/memory/scoped_ptr.h"
12#include "base/path_service.h"
13#include "base/prefs/json_pref_store.h"
14#include "base/strings/string_number_conversions.h"
15#include "base/strings/string_util.h"
16#include "build/build_config.h"
17#include "chrome/browser/background/background_contents_service_factory.h"
18#include "chrome/browser/browser_process.h"
19#include "chrome/browser/content_settings/host_content_settings_map.h"
20#include "chrome/browser/download/chrome_download_manager_delegate.h"
21#include "chrome/browser/download/download_service.h"
22#include "chrome/browser/download/download_service_factory.h"
23#include "chrome/browser/extensions/api/web_request/web_request_api.h"
24#include "chrome/browser/extensions/extension_info_map.h"
25#include "chrome/browser/extensions/extension_service.h"
26#include "chrome/browser/extensions/extension_special_storage_policy.h"
27#include "chrome/browser/extensions/extension_system.h"
28#include "chrome/browser/geolocation/chrome_geolocation_permission_context.h"
29#include "chrome/browser/geolocation/chrome_geolocation_permission_context_factory.h"
30#include "chrome/browser/io_thread.h"
31#include "chrome/browser/media/chrome_midi_permission_context.h"
32#include "chrome/browser/media/chrome_midi_permission_context_factory.h"
33#include "chrome/browser/net/pref_proxy_config_tracker.h"
34#include "chrome/browser/net/proxy_service_factory.h"
35#include "chrome/browser/plugins/chrome_plugin_service_filter.h"
36#include "chrome/browser/plugins/plugin_prefs.h"
37#include "chrome/browser/prefs/incognito_mode_prefs.h"
38#include "chrome/browser/prefs/pref_service_syncable.h"
39#include "chrome/browser/themes/theme_service.h"
40#include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
41#include "chrome/common/chrome_constants.h"
42#include "chrome/common/chrome_paths.h"
43#include "chrome/common/chrome_switches.h"
44#include "chrome/common/extensions/extension.h"
45#include "chrome/common/pref_names.h"
46#include "chrome/common/render_messages.h"
47#include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
48#include "components/user_prefs/user_prefs.h"
49#include "content/public/browser/browser_thread.h"
50#include "content/public/browser/host_zoom_map.h"
51#include "content/public/browser/render_process_host.h"
52#include "content/public/browser/storage_partition.h"
53#include "content/public/browser/url_data_source.h"
54#include "content/public/browser/web_contents.h"
55#include "net/http/http_server_properties.h"
56#include "net/http/transport_security_state.h"
57#include "webkit/browser/database/database_tracker.h"
58
59#if defined(OS_ANDROID) || defined(OS_IOS)
60#include "chrome/browser/prefs/proxy_prefs.h"
61#include "chrome/browser/prefs/scoped_user_pref_update.h"
62#endif  // defined(OS_ANDROID) || defined(OS_IOS)
63
64#if defined(OS_CHROMEOS)
65#include "chrome/browser/chromeos/preferences.h"
66#include "chrome/browser/chromeos/profiles/profile_helper.h"
67#endif
68
69using content::BrowserThread;
70using content::DownloadManagerDelegate;
71using content::HostZoomMap;
72
73namespace {
74
75void NotifyOTRProfileCreatedOnIOThread(void* original_profile,
76                                       void* otr_profile) {
77  ExtensionWebRequestEventRouter::GetInstance()->OnOTRProfileCreated(
78      original_profile, otr_profile);
79}
80
81void NotifyOTRProfileDestroyedOnIOThread(void* original_profile,
82                                         void* otr_profile) {
83  ExtensionWebRequestEventRouter::GetInstance()->OnOTRProfileDestroyed(
84      original_profile, otr_profile);
85}
86
87}  // namespace
88
89OffTheRecordProfileImpl::OffTheRecordProfileImpl(Profile* real_profile)
90    : profile_(real_profile),
91      prefs_(PrefServiceSyncable::IncognitoFromProfile(real_profile)),
92      io_data_(this),
93      start_time_(Time::Now()),
94      zoom_callback_(base::Bind(&OffTheRecordProfileImpl::OnZoomLevelChanged,
95                                base::Unretained(this))) {
96  // Register on BrowserContext.
97  user_prefs::UserPrefs::Set(this, prefs_);
98}
99
100void OffTheRecordProfileImpl::Init() {
101  BrowserContextDependencyManager::GetInstance()->CreateBrowserContextServices(
102      this);
103
104  DCHECK_NE(IncognitoModePrefs::DISABLED,
105            IncognitoModePrefs::GetAvailability(profile_->GetPrefs()));
106
107#if defined(OS_ANDROID) || defined(OS_IOS)
108  UseSystemProxy();
109#endif  // defined(OS_ANDROID) || defined(OS_IOS)
110
111  // TODO(oshima): Remove the need to eagerly initialize the request context
112  // getter. chromeos::OnlineAttempt is illegally trying to access this
113  // Profile member from a thread other than the UI thread, so we need to
114  // prevent a race.
115#if defined(OS_CHROMEOS)
116  GetRequestContext();
117#endif  // defined(OS_CHROMEOS)
118
119  InitHostZoomMap();
120
121  // Make the chrome//extension-icon/ resource available.
122  extensions::ExtensionIconSource* icon_source =
123      new extensions::ExtensionIconSource(profile_);
124  content::URLDataSource::Add(this, icon_source);
125
126#if defined(ENABLE_PLUGINS)
127  ChromePluginServiceFilter::GetInstance()->RegisterResourceContext(
128      PluginPrefs::GetForProfile(this).get(),
129      io_data_.GetResourceContextNoInit());
130#endif
131
132  BrowserThread::PostTask(
133      BrowserThread::IO, FROM_HERE,
134      base::Bind(&NotifyOTRProfileCreatedOnIOThread, profile_, this));
135}
136
137OffTheRecordProfileImpl::~OffTheRecordProfileImpl() {
138  MaybeSendDestroyedNotification();
139
140  HostZoomMap::GetForBrowserContext(profile_)->RemoveZoomLevelChangedCallback(
141      zoom_callback_);
142
143#if defined(ENABLE_PLUGINS)
144  ChromePluginServiceFilter::GetInstance()->UnregisterResourceContext(
145    io_data_.GetResourceContextNoInit());
146#endif
147
148  BrowserContextDependencyManager::GetInstance()->DestroyBrowserContextServices(
149      this);
150
151  BrowserThread::PostTask(
152      BrowserThread::IO, FROM_HERE,
153      base::Bind(&NotifyOTRProfileDestroyedOnIOThread, profile_, this));
154
155  if (host_content_settings_map_.get())
156    host_content_settings_map_->ShutdownOnUIThread();
157
158  if (pref_proxy_config_tracker_)
159    pref_proxy_config_tracker_->DetachFromPrefService();
160
161  // Clears any data the network stack contains that may be related to the
162  // OTR session.
163  g_browser_process->io_thread()->ChangedToOnTheRecord();
164}
165
166void OffTheRecordProfileImpl::InitHostZoomMap() {
167  HostZoomMap* host_zoom_map = HostZoomMap::GetForBrowserContext(this);
168  HostZoomMap* parent_host_zoom_map =
169      HostZoomMap::GetForBrowserContext(profile_);
170  host_zoom_map->CopyFrom(parent_host_zoom_map);
171  // Observe parent's HZM change for propagating change of parent's
172  // change to this HZM.
173  parent_host_zoom_map->AddZoomLevelChangedCallback(zoom_callback_);
174}
175
176#if defined(OS_ANDROID) || defined(OS_IOS)
177void OffTheRecordProfileImpl::UseSystemProxy() {
178  // Force the use of the system-assigned proxy when off the record.
179  const char kProxyMode[] = "mode";
180  const char kProxyServer[] = "server";
181  const char kProxyBypassList[] = "bypass_list";
182  const char kProxyPacUrl[] = "pac_url";
183  DictionaryPrefUpdate update(prefs_, prefs::kProxy);
184  DictionaryValue* dict = update.Get();
185  dict->SetString(kProxyMode, ProxyModeToString(ProxyPrefs::MODE_SYSTEM));
186  dict->SetString(kProxyPacUrl, "");
187  dict->SetString(kProxyServer, "");
188  dict->SetString(kProxyBypassList, "");
189}
190#endif  // defined(OS_ANDROID) || defined(OS_IOS)
191
192std::string OffTheRecordProfileImpl::GetProfileName() {
193  // Incognito profile should not return the profile name.
194  return std::string();
195}
196
197base::FilePath OffTheRecordProfileImpl::GetPath() const {
198  return profile_->GetPath();
199}
200
201scoped_refptr<base::SequencedTaskRunner>
202OffTheRecordProfileImpl::GetIOTaskRunner() {
203  return profile_->GetIOTaskRunner();
204}
205
206bool OffTheRecordProfileImpl::IsOffTheRecord() const {
207  return true;
208}
209
210Profile* OffTheRecordProfileImpl::GetOffTheRecordProfile() {
211  return this;
212}
213
214void OffTheRecordProfileImpl::DestroyOffTheRecordProfile() {
215  // Suicide is bad!
216  NOTREACHED();
217}
218
219bool OffTheRecordProfileImpl::HasOffTheRecordProfile() {
220  return true;
221}
222
223Profile* OffTheRecordProfileImpl::GetOriginalProfile() {
224  return profile_;
225}
226
227ExtensionService* OffTheRecordProfileImpl::GetExtensionService() {
228  return extensions::ExtensionSystem::Get(this)->extension_service();
229}
230
231ExtensionSpecialStoragePolicy*
232    OffTheRecordProfileImpl::GetExtensionSpecialStoragePolicy() {
233  return GetOriginalProfile()->GetExtensionSpecialStoragePolicy();
234}
235
236bool OffTheRecordProfileImpl::IsManaged() {
237  return GetOriginalProfile()->IsManaged();
238}
239
240PrefService* OffTheRecordProfileImpl::GetPrefs() {
241  return prefs_;
242}
243
244PrefService* OffTheRecordProfileImpl::GetOffTheRecordPrefs() {
245  return prefs_;
246}
247
248DownloadManagerDelegate* OffTheRecordProfileImpl::GetDownloadManagerDelegate() {
249  return DownloadServiceFactory::GetForBrowserContext(this)->
250      GetDownloadManagerDelegate();
251}
252
253net::URLRequestContextGetter* OffTheRecordProfileImpl::GetRequestContext() {
254  return GetDefaultStoragePartition(this)->GetURLRequestContext();
255}
256
257net::URLRequestContextGetter* OffTheRecordProfileImpl::CreateRequestContext(
258    content::ProtocolHandlerMap* protocol_handlers) {
259  return io_data_.CreateMainRequestContextGetter(protocol_handlers).get();
260}
261
262net::URLRequestContextGetter*
263    OffTheRecordProfileImpl::GetRequestContextForRenderProcess(
264        int renderer_child_id) {
265  content::RenderProcessHost* rph = content::RenderProcessHost::FromID(
266      renderer_child_id);
267  return rph->GetStoragePartition()->GetURLRequestContext();
268}
269
270net::URLRequestContextGetter*
271    OffTheRecordProfileImpl::GetMediaRequestContext() {
272  // In OTR mode, media request context is the same as the original one.
273  return GetRequestContext();
274}
275
276net::URLRequestContextGetter*
277    OffTheRecordProfileImpl::GetMediaRequestContextForRenderProcess(
278        int renderer_child_id) {
279  // In OTR mode, media request context is the same as the original one.
280  return GetRequestContextForRenderProcess(renderer_child_id);
281}
282
283net::URLRequestContextGetter*
284OffTheRecordProfileImpl::GetMediaRequestContextForStoragePartition(
285    const base::FilePath& partition_path,
286    bool in_memory) {
287  return io_data_.GetIsolatedAppRequestContextGetter(partition_path, in_memory)
288      .get();
289}
290
291void OffTheRecordProfileImpl::RequestMIDISysExPermission(
292      int render_process_id,
293      int render_view_id,
294      const GURL& requesting_frame,
295      const MIDISysExPermissionCallback& callback) {
296  ChromeMIDIPermissionContext* context =
297      ChromeMIDIPermissionContextFactory::GetForProfile(this);
298  context->RequestMIDISysExPermission(render_process_id,
299                                      render_view_id,
300                                      requesting_frame,
301                                      callback);
302}
303
304net::URLRequestContextGetter*
305    OffTheRecordProfileImpl::GetRequestContextForExtensions() {
306  return io_data_.GetExtensionsRequestContextGetter().get();
307}
308
309net::URLRequestContextGetter*
310    OffTheRecordProfileImpl::CreateRequestContextForStoragePartition(
311        const base::FilePath& partition_path,
312        bool in_memory,
313        content::ProtocolHandlerMap* protocol_handlers) {
314  return io_data_.CreateIsolatedAppRequestContextGetter(
315                      partition_path, in_memory, protocol_handlers).get();
316}
317
318content::ResourceContext* OffTheRecordProfileImpl::GetResourceContext() {
319  return io_data_.GetResourceContext();
320}
321
322net::SSLConfigService* OffTheRecordProfileImpl::GetSSLConfigService() {
323  return profile_->GetSSLConfigService();
324}
325
326HostContentSettingsMap* OffTheRecordProfileImpl::GetHostContentSettingsMap() {
327  // Retrieve the host content settings map of the parent profile in order to
328  // ensure the preferences have been migrated.
329  profile_->GetHostContentSettingsMap();
330  if (!host_content_settings_map_.get()) {
331    host_content_settings_map_ = new HostContentSettingsMap(GetPrefs(), true);
332#if defined(ENABLE_EXTENSIONS)
333    ExtensionService* extension_service = GetExtensionService();
334    if (extension_service)
335      host_content_settings_map_->RegisterExtensionService(extension_service);
336#endif
337  }
338  return host_content_settings_map_.get();
339}
340
341content::GeolocationPermissionContext*
342    OffTheRecordProfileImpl::GetGeolocationPermissionContext() {
343  return ChromeGeolocationPermissionContextFactory::GetForProfile(this);
344}
345
346quota::SpecialStoragePolicy*
347    OffTheRecordProfileImpl::GetSpecialStoragePolicy() {
348  return GetExtensionSpecialStoragePolicy();
349}
350
351bool OffTheRecordProfileImpl::IsSameProfile(Profile* profile) {
352  return (profile == this) || (profile == profile_);
353}
354
355Time OffTheRecordProfileImpl::GetStartTime() const {
356  return start_time_;
357}
358
359history::TopSites* OffTheRecordProfileImpl::GetTopSitesWithoutCreating() {
360  return NULL;
361}
362
363history::TopSites* OffTheRecordProfileImpl::GetTopSites() {
364  return NULL;
365}
366
367void OffTheRecordProfileImpl::SetExitType(ExitType exit_type) {
368}
369
370base::FilePath OffTheRecordProfileImpl::last_selected_directory() {
371  const base::FilePath& directory = last_selected_directory_;
372  if (directory.empty()) {
373    return profile_->last_selected_directory();
374  }
375  return directory;
376}
377
378void OffTheRecordProfileImpl::set_last_selected_directory(
379    const base::FilePath& path) {
380  last_selected_directory_ = path;
381}
382
383bool OffTheRecordProfileImpl::WasCreatedByVersionOrLater(
384    const std::string& version) {
385  return profile_->WasCreatedByVersionOrLater(version);
386}
387
388Profile::ExitType OffTheRecordProfileImpl::GetLastSessionExitType() {
389  return profile_->GetLastSessionExitType();
390}
391
392#if defined(OS_CHROMEOS)
393void OffTheRecordProfileImpl::SetupChromeOSEnterpriseExtensionObserver() {
394  profile_->SetupChromeOSEnterpriseExtensionObserver();
395}
396
397void OffTheRecordProfileImpl::InitChromeOSPreferences() {
398  // The incognito profile shouldn't have Chrome OS's preferences.
399  // The preferences are associated with the regular user profile.
400}
401#endif  // defined(OS_CHROMEOS)
402
403#if defined(OS_CHROMEOS)
404void OffTheRecordProfileImpl::ChangeAppLocale(const std::string& locale,
405                                              AppLocaleChangedVia) {
406}
407
408void OffTheRecordProfileImpl::OnLogin() {
409}
410#endif  // defined(OS_CHROMEOS)
411
412PrefProxyConfigTracker* OffTheRecordProfileImpl::GetProxyConfigTracker() {
413  if (!pref_proxy_config_tracker_)
414    pref_proxy_config_tracker_.reset(CreateProxyConfigTracker());
415  return pref_proxy_config_tracker_.get();
416}
417
418chrome_browser_net::Predictor* OffTheRecordProfileImpl::GetNetworkPredictor() {
419  // We do not store information about websites visited in OTR profiles which
420  // is necessary for a Predictor, so we do not have a Predictor at all.
421  return NULL;
422}
423
424void OffTheRecordProfileImpl::ClearNetworkingHistorySince(
425    base::Time time,
426    const base::Closure& completion) {
427  // Nothing to do here, our transport security state is read-only.
428  // Still, fire the callback to indicate we have finished, otherwise the
429  // BrowsingDataRemover will never be destroyed and the dialog will never be
430  // closed. We must do this asynchronously in order to avoid reentrancy issues.
431  if (!completion.is_null()) {
432    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, completion);
433  }
434}
435
436GURL OffTheRecordProfileImpl::GetHomePage() {
437  return profile_->GetHomePage();
438}
439
440#if defined(OS_CHROMEOS)
441// Special case of the OffTheRecordProfileImpl which is used while Guest
442// session in CrOS.
443class GuestSessionProfile : public OffTheRecordProfileImpl {
444 public:
445  explicit GuestSessionProfile(Profile* real_profile)
446      : OffTheRecordProfileImpl(real_profile) {
447  }
448
449  virtual void InitChromeOSPreferences() OVERRIDE {
450    chromeos_preferences_.reset(new chromeos::Preferences());
451    chromeos_preferences_->Init(static_cast<PrefServiceSyncable*>(GetPrefs()));
452  }
453
454 private:
455  // The guest user should be able to customize Chrome OS preferences.
456  scoped_ptr<chromeos::Preferences> chromeos_preferences_;
457};
458#endif
459
460Profile* Profile::CreateOffTheRecordProfile() {
461  OffTheRecordProfileImpl* profile = NULL;
462#if defined(OS_CHROMEOS)
463  if (IsGuestSession())
464    profile = new GuestSessionProfile(this);
465#endif
466  if (!profile)
467    profile = new OffTheRecordProfileImpl(this);
468  profile->Init();
469  return profile;
470}
471
472void OffTheRecordProfileImpl::OnZoomLevelChanged(
473    const HostZoomMap::ZoomLevelChange& change) {
474  HostZoomMap* host_zoom_map = HostZoomMap::GetForBrowserContext(this);
475  switch (change.mode) {
476    case HostZoomMap::ZOOM_CHANGED_TEMPORARY_ZOOM:
477       return;
478    case HostZoomMap::ZOOM_CHANGED_FOR_HOST:
479       host_zoom_map->SetZoomLevelForHost(change.host, change.zoom_level);
480       return;
481    case HostZoomMap::ZOOM_CHANGED_FOR_SCHEME_AND_HOST:
482       host_zoom_map->SetZoomLevelForHostAndScheme(change.scheme,
483           change.host,
484           change.zoom_level);
485       return;
486  }
487}
488
489PrefProxyConfigTracker* OffTheRecordProfileImpl::CreateProxyConfigTracker() {
490#if defined(OS_CHROMEOS)
491  if (chromeos::ProfileHelper::IsSigninProfile(this)) {
492    return ProxyServiceFactory::CreatePrefProxyConfigTrackerOfLocalState(
493        g_browser_process->local_state());
494  }
495#endif  // defined(OS_CHROMEOS)
496  return ProxyServiceFactory::CreatePrefProxyConfigTrackerOfProfile(
497      GetPrefs(), g_browser_process->local_state());
498}
499