// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/prefs/incognito_mode_prefs.h" #include "base/command_line.h" #include "base/logging.h" #include "base/metrics/histogram_macros.h" #include "base/prefs/pref_service.h" #include "base/threading/thread_restrictions.h" #include "base/time/time.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" #include "components/pref_registry/pref_registry_syncable.h" #include "content/public/browser/browser_thread.h" #if defined(OS_WIN) #include #include #include "base/bind.h" #include "base/bind_helpers.h" #include "base/memory/singleton.h" #include "base/win/scoped_comptr.h" #include "base/win/windows_version.h" #endif // OS_WIN #if defined(OS_ANDROID) #include "chrome/browser/android/chrome_application.h" #endif // OS_ANDROID using content::BrowserThread; #if defined(OS_WIN) namespace { // This singleton allows us to attempt to calculate the Platform Parental // Controls enabled value on a worker thread before the UI thread needs the // value. If the UI thread finishes sooner than we expect, that's no worse than // today where we block. class PlatformParentalControlsValue { public: static PlatformParentalControlsValue* GetInstance() { return Singleton::get(); } bool is_enabled() const { return is_enabled_; } private: friend struct DefaultSingletonTraits; // Histogram enum for tracking the thread that checked parental controls. enum class ThreadType { UI = 0, BLOCKING, COUNT, }; PlatformParentalControlsValue() : is_enabled_(IsParentalControlActivityLoggingOn()) {} ~PlatformParentalControlsValue() = default; // Returns true if Windows Parental control activity logging is enabled. This // feature is available on Windows 7 and beyond. This function should be // called on a COM Initialized thread and is potentially blocking. static bool IsParentalControlActivityLoggingOn() { // Since we can potentially block, make sure the thread is okay with this. base::ThreadRestrictions::AssertIOAllowed(); base::ThreadRestrictions::AssertWaitAllowed(); // Query this info on Windows 7 and above. if (base::win::GetVersion() < base::win::VERSION_WIN7) return false; ThreadType thread_type = ThreadType::BLOCKING; if (BrowserThread::IsThreadInitialized(BrowserThread::UI) && content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { thread_type = ThreadType::UI; } UMA_HISTOGRAM_ENUMERATION( "IncognitoModePrefs.WindowsParentalControlsInitThread", static_cast(thread_type), static_cast(ThreadType::COUNT)); base::Time begin_time = base::Time::Now(); bool result = IsParentalControlActivityLoggingOnImpl(); UMA_HISTOGRAM_TIMES("IncognitoModePrefs.WindowsParentalControlsInitTime", base::Time::Now() - begin_time); return result; } // Does the work of determining if Windows Parental control activity logging // is enabled. static bool IsParentalControlActivityLoggingOnImpl() { base::win::ScopedComPtr parent_controls; HRESULT hr = parent_controls.CreateInstance( __uuidof(WindowsParentalControls)); if (FAILED(hr)) return false; base::win::ScopedComPtr settings; hr = parent_controls->GetUserSettings(nullptr, settings.Receive()); if (FAILED(hr)) return false; unsigned long restrictions = 0; settings->GetRestrictions(&restrictions); return (restrictions & WPCFLAG_LOGGING_REQUIRED) == WPCFLAG_LOGGING_REQUIRED; } const bool is_enabled_; DISALLOW_COPY_AND_ASSIGN(PlatformParentalControlsValue); }; } // namespace #endif // OS_WIN // static bool IncognitoModePrefs::IntToAvailability(int in_value, Availability* out_value) { if (in_value < 0 || in_value >= AVAILABILITY_NUM_TYPES) { *out_value = ENABLED; return false; } *out_value = static_cast(in_value); return true; } // static IncognitoModePrefs::Availability IncognitoModePrefs::GetAvailability( const PrefService* pref_service) { DCHECK(pref_service); int pref_value = pref_service->GetInteger(prefs::kIncognitoModeAvailability); Availability result = IncognitoModePrefs::ENABLED; bool valid = IntToAvailability(pref_value, &result); DCHECK(valid); if (ArePlatformParentalControlsEnabled()) { if (result == IncognitoModePrefs::FORCED) LOG(ERROR) << "Ignoring FORCED incognito. Parental control logging on"; return IncognitoModePrefs::DISABLED; } return result; } // static void IncognitoModePrefs::SetAvailability(PrefService* prefs, const Availability availability) { prefs->SetInteger(prefs::kIncognitoModeAvailability, availability); } // static void IncognitoModePrefs::RegisterProfilePrefs( user_prefs::PrefRegistrySyncable* registry) { registry->RegisterIntegerPref(prefs::kIncognitoModeAvailability, IncognitoModePrefs::ENABLED); } // static bool IncognitoModePrefs::ShouldLaunchIncognito( const base::CommandLine& command_line, const PrefService* prefs) { Availability incognito_avail = GetAvailability(prefs); return incognito_avail != IncognitoModePrefs::DISABLED && (command_line.HasSwitch(switches::kIncognito) || incognito_avail == IncognitoModePrefs::FORCED); } // static bool IncognitoModePrefs::CanOpenBrowser(Profile* profile) { if (profile->IsGuestSession()) return true; switch (GetAvailability(profile->GetPrefs())) { case IncognitoModePrefs::ENABLED: return true; case IncognitoModePrefs::DISABLED: return !profile->IsOffTheRecord(); case IncognitoModePrefs::FORCED: return profile->IsOffTheRecord(); default: NOTREACHED(); return false; } } #if defined(OS_WIN) // static void IncognitoModePrefs::InitializePlatformParentalControls() { content::BrowserThread::PostBlockingPoolTask( FROM_HERE, base::Bind( base::IgnoreResult(&PlatformParentalControlsValue::GetInstance))); } #endif // static bool IncognitoModePrefs::ArePlatformParentalControlsEnabled() { #if defined(OS_WIN) return PlatformParentalControlsValue::GetInstance()->is_enabled(); #elif defined(OS_ANDROID) return chrome::android::ChromeApplication::AreParentalControlsEnabled(); #else return false; #endif }