diff --git a/base/BUILD.gn b/base/BUILD.gn index 98bacb75d01cd..523211053f966 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn @@ -146,11 +146,6 @@ if (is_win) { ldflags = [ # Linking with shcore.lib causes the shcore api forwarder dll to load. "/DELAYLOAD:api-ms-win-shcore-scaling-l1-1-1.dll", - - # Linking with OneCore.lib causes the next three dlls to load. - "/DELAYLOAD:api-ms-win-core-realtime-l1-1-1.dll", - "/DELAYLOAD:api-ms-win-power-base-l1-1-0.dll", - "/DELAYLOAD:api-ms-win-power-setting-l1-1-0.dll", "/DELAYLOAD:cfgmgr32.dll", "/DELAYLOAD:powrprof.dll", "/DELAYLOAD:setupapi.dll", @@ -1954,7 +1949,6 @@ component("base") { libs += [ "cfgmgr32.lib", "ntdll.lib", - "onecore.lib", "powrprof.lib", "propsys.lib", "setupapi.lib", diff --git a/base/allocator/partition_allocator/page_allocator_internals_win.h b/base/allocator/partition_allocator/page_allocator_internals_win.h index ec70187f36595..6e2b8676c0aec 100644 --- a/base/allocator/partition_allocator/page_allocator_internals_win.h +++ b/base/allocator/partition_allocator/page_allocator_internals_win.h @@ -5,6 +5,8 @@ #ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_INTERNALS_WIN_H_ #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_PAGE_ALLOCATOR_INTERNALS_WIN_H_ +#include + #include #include "base/allocator/partition_allocator/oom.h" @@ -16,6 +18,17 @@ namespace partition_alloc::internal { +namespace { + +// On Windows, discarded pages are not returned to the system immediately and +// not guaranteed to be zeroed when returned to the application. +using DiscardVirtualMemoryFunction = DWORD(WINAPI*)(PVOID virtualAddress, + SIZE_T size); +DiscardVirtualMemoryFunction s_discard_virtual_memory = + reinterpret_cast(-1); + +} // namespace + // |VirtualAlloc| will fail if allocation at the hint address is blocked. constexpr bool kHintIsAdvisory = false; std::atomic s_allocPageErrorCode{ERROR_SUCCESS}; @@ -224,12 +237,27 @@ bool TryRecommitSystemPagesInternal( } void DiscardSystemPagesInternal(uintptr_t address, size_t length) { + if (s_discard_virtual_memory == + reinterpret_cast(-1)) { + // DiscardVirtualMemory's minimum supported client is Windows 8.1 Update. + // So skip GetProcAddress("DiscardVirtualMemory") if windows version is + // smaller than Windows 8.1. + if (IsWindows8Point1OrGreater()) { + s_discard_virtual_memory = + reinterpret_cast(GetProcAddress( + GetModuleHandle(L"Kernel32.dll"), "DiscardVirtualMemory")); + } else { + s_discard_virtual_memory = nullptr; + } + } + void* ptr = reinterpret_cast(address); // Use DiscardVirtualMemory when available because it releases faster than // MEM_RESET. - DWORD ret = DiscardVirtualMemory(ptr, length); - // DiscardVirtualMemory is buggy in Win10 SP0, so fall back to MEM_RESET on - // failure. + DWORD ret = 1; + if (s_discard_virtual_memory) { + ret = s_discard_virtual_memory(ptr, length); + } if (ret) { PA_CHECK(VirtualAllocWithRetry(ptr, length, MEM_RESET, PAGE_READWRITE)); } diff --git a/base/files/file_util_win.cc b/base/files/file_util_win.cc index d7b5fb20aeb34..490d00454b657 100644 --- a/base/files/file_util_win.cc +++ b/base/files/file_util_win.cc @@ -1104,11 +1104,37 @@ bool SetNonBlocking(int fd) { return false; } +namespace { + +// ::PrefetchVirtualMemory() is only available on Windows 8 and above. Chrome +// supports Windows 7, so we need to check for the function's presence +// dynamically. +using PrefetchVirtualMemoryPtr = decltype(&::PrefetchVirtualMemory); + +// Returns null if ::PrefetchVirtualMemory() is not available. +PrefetchVirtualMemoryPtr GetPrefetchVirtualMemoryPtr() { + HMODULE kernel32_dll = ::GetModuleHandleA("kernel32.dll"); + return reinterpret_cast( + GetProcAddress(kernel32_dll, "PrefetchVirtualMemory")); +} + +} // namespace + bool PreReadFile(const FilePath& file_path, bool is_executable, int64_t max_bytes) { DCHECK_GE(max_bytes, 0); + // On Win8 and higher use ::PrefetchVirtualMemory(). This is better than a + // simple data file read, more from a RAM perspective than CPU. This is + // because reading the file as data results in double mapping to + // Image/executable pages for all pages of code executed. + static PrefetchVirtualMemoryPtr prefetch_virtual_memory = + GetPrefetchVirtualMemoryPtr(); + + if (prefetch_virtual_memory == nullptr) + return internal::PreReadFileSlow(file_path, max_bytes); + if (max_bytes == 0) { // ::PrefetchVirtualMemory() fails when asked to read zero bytes. // base::MemoryMappedFile::Initialize() fails on an empty file. @@ -1131,7 +1157,7 @@ bool PreReadFile(const FilePath& file_path, // simple data file read, more from a RAM perspective than CPU. This is // because reading the file as data results in double mapping to // Image/executable pages for all pages of code executed. - if (!::PrefetchVirtualMemory(::GetCurrentProcess(), + if (!prefetch_virtual_memory(::GetCurrentProcess(), /*NumberOfEntries=*/1, &address_range, /*Flags=*/0)) { return internal::PreReadFileSlow(file_path, max_bytes); diff --git a/base/memory/discardable_shared_memory.cc b/base/memory/discardable_shared_memory.cc index 23c95bad719c7..62a0b3c1f1d17 100644 --- a/base/memory/discardable_shared_memory.cc +++ b/base/memory/discardable_shared_memory.cc @@ -422,11 +422,23 @@ bool DiscardableSharedMemory::Purge(Time current_time) { #elif BUILDFLAG(IS_WIN) // On Windows, discarded pages are not returned to the system immediately and // not guaranteed to be zeroed when returned to the application. + using DiscardVirtualMemoryFunction = + DWORD(WINAPI*)(PVOID virtualAddress, SIZE_T size); + static DiscardVirtualMemoryFunction discard_virtual_memory = + reinterpret_cast(GetProcAddress( + GetModuleHandle(L"Kernel32.dll"), "DiscardVirtualMemory")); + char* address = static_cast(shared_memory_mapping_.memory()) + AlignToPageSize(sizeof(SharedState)); size_t length = AlignToPageSize(mapped_size_); - DWORD ret = DiscardVirtualMemory(address, length); + // Use DiscardVirtualMemory when available because it releases faster than + // MEM_RESET. + DWORD ret = ERROR_NOT_SUPPORTED; + if (discard_virtual_memory) { + ret = discard_virtual_memory(address, length); + } + // DiscardVirtualMemory is buggy in Win10 SP0, so fall back to MEM_RESET on // failure. if (ret != ERROR_SUCCESS) { diff --git a/base/memory/platform_shared_memory_region_win.cc b/base/memory/platform_shared_memory_region_win.cc index e387015249731..233ba25da5efe 100644 --- a/base/memory/platform_shared_memory_region_win.cc +++ b/base/memory/platform_shared_memory_region_win.cc @@ -14,7 +14,12 @@ #include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/process/process_handle.h" +#include "base/rand_util.h" #include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversions.h" +#include "base/win/windows_version.h" + namespace base::subtle { @@ -73,6 +78,7 @@ HANDLE CreateFileMappingWithReducedPermissions(SECURITY_ATTRIBUTES* sa, HANDLE h = CreateFileMapping(INVALID_HANDLE_VALUE, sa, PAGE_READWRITE, 0, static_cast(rounded_size), name); if (!h) { + LOG(ERROR) << "CreateFileMappingW failed with error " << GetLastError() << "."; return nullptr; } @@ -211,6 +217,17 @@ PlatformSharedMemoryRegion PlatformSharedMemoryRegion::Create(Mode mode, } std::u16string name; + if (win::GetVersion() < win::Version::WIN8_1) { + // Windows < 8.1 ignores DACLs on certain unnamed objects (like shared + // sections). So, we generate a random name when we need to enforce + // read-only. + uint64_t rand_values[4]; + RandBytes(&rand_values, sizeof(rand_values)); + name = ASCIIToUTF16(StringPrintf("CrSharedMem_%016llx%016llx%016llx%016llx", + rand_values[0], rand_values[1], + rand_values[2], rand_values[3])); + DCHECK(!name.empty()); + } SECURITY_ATTRIBUTES sa = {sizeof(sa), &sd, FALSE}; // Ask for the file mapping with reduced permisions to avoid passing the // access control permissions granted by default into unpriviledged process. diff --git a/base/power_monitor/power_monitor_device_source_win.cc b/base/power_monitor/power_monitor_device_source_win.cc index 4e7b6563bc229..3925a372ed509 100644 --- a/base/power_monitor/power_monitor_device_source_win.cc +++ b/base/power_monitor/power_monitor_device_source_win.cc @@ -32,8 +32,9 @@ void ProcessWmPowerBroadcastMessage(WPARAM event_id) { power_event = PowerMonitorSource::POWER_STATE_EVENT; break; case PBT_APMRESUMEAUTOMATIC: // Resume from suspend. - // We don't notify for PBT_APMRESUMESUSPEND - // because, if it occurs, it is always sent as a + //case PBT_APMRESUMESUSPEND: // User-initiated resume from suspend. + // We don't notify for this latter event + // because if it occurs it is always sent as a // second event after PBT_APMRESUMEAUTOMATIC. power_event = PowerMonitorSource::RESUME_EVENT; break; @@ -55,6 +56,28 @@ void ProcessWmPowerBroadcastMessage(WPARAM event_id) { ProcessPowerEventHelper(power_event); } +HPOWERNOTIFY RegisterSuspendResumeNotification(HANDLE hRecipient, DWORD Flags) { + const auto register_suspend_resume_notification_ptr = + reinterpret_cast( + ::GetProcAddress(::GetModuleHandle(L"user32.dll"), + "RegisterSuspendResumeNotification")); + if (!register_suspend_resume_notification_ptr) + return nullptr; + + return register_suspend_resume_notification_ptr(hRecipient, Flags); +} + +BOOL UnregisterSuspendResumeNotification(HPOWERNOTIFY Handle) { + const auto unregister_suspend_resume_notification_ptr = + reinterpret_cast( + ::GetProcAddress(::GetModuleHandle(L"user32.dll"), + "UnregisterSuspendResumeNotification")); + if (!unregister_suspend_resume_notification_ptr) + return FALSE; + + return unregister_suspend_resume_notification_ptr(Handle); +} + } // namespace void PowerMonitorDeviceSource::PlatformInit() { @@ -79,7 +102,7 @@ void PowerMonitorDeviceSource::PlatformDestroy() { // battery power. Returns true if running on battery. bool PowerMonitorDeviceSource::IsOnBatteryPower() { SYSTEM_POWER_STATUS status; - if (!::GetSystemPowerStatus(&status)) { + if (!GetSystemPowerStatus(&status)) { DPLOG(ERROR) << "GetSystemPowerStatus failed"; return false; } @@ -92,7 +115,8 @@ int PowerMonitorDeviceSource::GetInitialSpeedLimit() { return PowerThermalObserver::kSpeedLimitMax; } -PowerMonitorDeviceSource::PowerMessageWindow::PowerMessageWindow() { +PowerMonitorDeviceSource::PowerMessageWindow::PowerMessageWindow() + : instance_(NULL), message_hwnd_(NULL) { if (!CurrentUIThread::IsSet()) { // Creating this window in (e.g.) a renderer inhibits shutdown on Windows. // See http://crbug.com/230122. TODO(vandebo): http://crbug.com/236031 @@ -105,18 +129,21 @@ PowerMonitorDeviceSource::PowerMessageWindow::PowerMessageWindow() { kWindowClassName, &base::win::WrappedWindowProc< PowerMonitorDeviceSource::PowerMessageWindow::WndProcThunk>, - 0, 0, 0, nullptr, nullptr, nullptr, nullptr, nullptr, &window_class); + 0, 0, 0, NULL, NULL, NULL, NULL, NULL, + &window_class); instance_ = window_class.hInstance; - ATOM clazz = ::RegisterClassEx(&window_class); + ATOM clazz = RegisterClassEx(&window_class); DCHECK(clazz); message_hwnd_ = - ::CreateWindowEx(WS_EX_NOACTIVATE, kWindowClassName, nullptr, WS_POPUP, 0, - 0, 0, 0, nullptr, nullptr, instance_, nullptr); + CreateWindowEx(WS_EX_NOACTIVATE, kWindowClassName, NULL, WS_POPUP, 0, 0, + 0, 0, NULL, NULL, instance_, NULL); if (message_hwnd_) { - // On machines with modern standby calling RegisterSuspendResumeNotification - // is required in order to get the PBT_APMSUSPEND message. - power_notify_handle_ = ::RegisterSuspendResumeNotification( + // On machines with modern standby and Win8+, calling + // RegisterSuspendResumeNotification is required in order to get the + // PBT_APMSUSPEND message. The notification is no longer automatically + // fired. + power_notify_handle_ = base::RegisterSuspendResumeNotification( message_hwnd_, DEVICE_NOTIFY_WINDOW_HANDLE); } } @@ -124,10 +151,10 @@ PowerMonitorDeviceSource::PowerMessageWindow::PowerMessageWindow() { PowerMonitorDeviceSource::PowerMessageWindow::~PowerMessageWindow() { if (message_hwnd_) { if (power_notify_handle_) - ::UnregisterSuspendResumeNotification(power_notify_handle_); + base::UnregisterSuspendResumeNotification(power_notify_handle_); - ::DestroyWindow(message_hwnd_); - ::UnregisterClass(kWindowClassName, instance_); + DestroyWindow(message_hwnd_); + UnregisterClass(kWindowClassName, instance_); } } diff --git a/base/process/process_util_unittest.cc b/base/process/process_util_unittest.cc index 152af82815bfb..f0ed5c311e830 100644 --- a/base/process/process_util_unittest.cc +++ b/base/process/process_util_unittest.cc @@ -821,11 +821,19 @@ TEST_F(ProcessUtilTest, LaunchAsUser) { } MULTIPROCESS_TEST_MAIN(ChildVerifiesCetDisabled) { - // Policy not defined for Win < Win10 20H1 but that's ok. + auto get_process_mitigation_policy = + reinterpret_cast(::GetProcAddress( + ::GetModuleHandleW(L"kernel32.dll"), "GetProcessMitigationPolicy")); + + // Not available for Win7 but this process should still work. + if (!get_process_mitigation_policy) + return kSuccess; + + // Policy not defined for Win < Win10 20H1 but that's also ok. PROCESS_MITIGATION_USER_SHADOW_STACK_POLICY policy = {}; - if (GetProcessMitigationPolicy(GetCurrentProcess(), - ProcessUserShadowStackPolicy, &policy, - sizeof(policy))) { + if (get_process_mitigation_policy(GetCurrentProcess(), + ProcessUserShadowStackPolicy, &policy, + sizeof(policy))) { if (policy.EnableUserShadowStack) return 1; } diff --git a/base/process/process_win.cc b/base/process/process_win.cc index b5e8cc5aefeea..67594ef57684e 100644 --- a/base/process/process_win.cc +++ b/base/process/process_win.cc @@ -262,33 +262,10 @@ bool Process::SetProcessBackgrounded(bool value) { // priority inversion, and having a process put itself in background mode is // broken in Windows 11 22H2. So, it is no longer supported. See // https://crbug.com/1396155 for details. + // NOTE: NtSetInformationProcess call (SetProcessInformation really) using ProcessPowerThrottling class removed because it is useless before Windows 10. DCHECK(!is_current()); const DWORD priority = value ? IDLE_PRIORITY_CLASS : NORMAL_PRIORITY_CLASS; - if (base::win::OSInfo::GetInstance()->version() >= - base::win::Version::WIN11 && - FeatureList::IsEnabled(kUseEcoQoSForBackgroundProcess)) { - PROCESS_POWER_THROTTLING_STATE power_throttling; - RtlZeroMemory(&power_throttling, sizeof(power_throttling)); - power_throttling.Version = PROCESS_POWER_THROTTLING_CURRENT_VERSION; - - if (value) { - // Sets Eco QoS level. - power_throttling.ControlMask = PROCESS_POWER_THROTTLING_EXECUTION_SPEED; - power_throttling.StateMask = PROCESS_POWER_THROTTLING_EXECUTION_SPEED; - } else { - // Uses system default. - power_throttling.ControlMask = 0; - power_throttling.StateMask = 0; - } - bool ret = - ::SetProcessInformation(Handle(), ProcessPowerThrottling, - &power_throttling, sizeof(power_throttling)); - if (ret == 0) { - DPLOG(ERROR) << "Setting process QoS policy fails"; - } - } - return (::SetPriorityClass(Handle(), priority) != 0); } diff --git a/base/time/time_win.cc b/base/time/time_win.cc index c6540592a5c18..f453dc2ed20cf 100644 --- a/base/time/time_win.cc +++ b/base/time/time_win.cc @@ -646,11 +646,11 @@ TimeTicks::Clock TimeTicks::GetClock() { namespace subtle { LiveTicks LiveTicksNowIgnoringOverride() { - ULONGLONG unbiased_interrupt_time; - QueryUnbiasedInterruptTimePrecise(&unbiased_interrupt_time); + LARGE_INTEGER unbiased_interrupt_time; + QueryPerformanceCounter(&unbiased_interrupt_time); // QueryUnbiasedInterruptTimePrecise gets the interrupt time in system time // units of 100 nanoseconds. - return LiveTicks() + Nanoseconds(unbiased_interrupt_time * 100); + return LiveTicks() + Nanoseconds(unbiased_interrupt_time.QuadPart * 100); } } // namespace subtle diff --git a/base/trace_event/trace_logging_minimal_win.cc b/base/trace_event/trace_logging_minimal_win.cc index 5fb2a8c3bbc7b..4527a414a7d43 100644 --- a/base/trace_event/trace_logging_minimal_win.cc +++ b/base/trace_event/trace_logging_minimal_win.cc @@ -10,6 +10,61 @@ #include "base/logging.h" #include "base/numerics/checked_math.h" +/* +EventSetInformation configuration macros: + +TraceLogging works best if the EventSetInformation API can be used to notify +ETW that the provider uses TraceLogging event encoding. + +The EventSetInformation API is available on Windows 8 and later. (It is also +available on fully-patched Windows 7, but not on Windows 7 RTM). + +The TLM_HAVE_EVENT_SET_INFORMATION and TLM_EVENT_SET_INFORMATION macros can +be set before compiling this file to control how the TlmProvider class deals +with the EventSetInformation API. + +If these macros are not set, the default behavior is to check the WINVER +macro at compile time: + +- If WINVER is set to Windows 7 or before, TlmProvider will use GetProcAddress + to locate EventSetInformation, and then invoke it if present. This is less + efficient, but works on older versions of Windows. +- If WINVER is set to Windows 8 or later, TlmProvider will directly invoke + EventSetInformation. This is more efficient, but the resulting application + will only work correctly on newer versions of Windows. + +If you need to run on Windows 7 RTM, but for some reason need to set WINVER to +Windows 8 or higher, you can override the default behavior by defining +TLM_HAVE_EVENT_SET_INFORMATION=2 when compiling this file. + +Details: +- The TLM_EVENT_SET_INFORMATION macro can be set the name of a replacement + function that TlmProvider should use instead of EventSetInformation. +- The TLM_HAVE_EVENT_SET_INFORMATION macro can be set to 0 (disable the use of + EventSetInformation), 1 (directly invoke EventSetInformation), or 2 (try to + locate EventSetInformation via GetProcAddress, and invoke if found). +*/ + +// This code needs to run on Windows 7 and this is magic which +// removes static linking to EventSetInformation +#define TLM_HAVE_EVENT_SET_INFORMATION 2 + +#ifndef TLM_EVENT_SET_INFORMATION +#define TLM_EVENT_SET_INFORMATION EventSetInformation +#ifndef TLM_HAVE_EVENT_SET_INFORMATION +#if WINVER < 0x0602 || !defined(EVENT_FILTER_TYPE_SCHEMATIZED) +// Find "EventSetInformation" via GetModuleHandleExW+GetProcAddress +#define TLM_HAVE_EVENT_SET_INFORMATION 2 +#else +// Directly invoke TLM_EVENT_SET_INFORMATION(...) +#define TLM_HAVE_EVENT_SET_INFORMATION 1 +#endif +#endif +#elif !defined(TLM_HAVE_EVENT_SET_INFORMATION) +// Directly invoke TLM_EVENT_SET_INFORMATION(...) +#define TLM_HAVE_EVENT_SET_INFORMATION 1 +#endif + TlmProvider::~TlmProvider() { Unregister(); } @@ -20,7 +75,7 @@ TlmProvider::TlmProvider(const char* provider_name, void* enable_callback_context) noexcept { ULONG status = Register(provider_name, provider_guid, enable_callback, enable_callback_context); - LOG_IF(ERROR, status != ERROR_SUCCESS) << "Provider resistration failure"; + LOG_IF(ERROR, status != ERROR_SUCCESS) << "Provider registration failure"; } // Appends a nul-terminated string to a metadata block. @@ -79,9 +134,42 @@ ULONG TlmProvider::Register(const char* provider_name, if (status != ERROR_SUCCESS) return status; +#if TLM_HAVE_EVENT_SET_INFORMATION == 1 + // Best-effort, ignore failure. - return ::EventSetInformation(reg_handle_, EventProviderSetTraits, - provider_metadata_, provider_metadata_size_); + status = + TLM_EVENT_SET_INFORMATION(reg_handle_, EventProviderSetTraits, + provider_metadata_, provider_metadata_size_); + +#elif TLM_HAVE_EVENT_SET_INFORMATION == 2 + + HMODULE eventing_lib; + if (GetModuleHandleExW(0, L"api-ms-win-eventing-provider-l1-1-0.dll", + &eventing_lib) || + GetModuleHandleExW(0, L"advapi32.dll", &eventing_lib)) { + typedef ULONG(WINAPI * PFEventSetInformation)( + REGHANDLE reg_handle, EVENT_INFO_CLASS information_class, + PVOID event_information, ULONG information_length); + PFEventSetInformation event_set_information_ptr = + reinterpret_cast( + GetProcAddress(eventing_lib, "EventSetInformation")); + if (event_set_information_ptr) { + // Best-effort, ignore failure. + status = event_set_information_ptr(reg_handle_, EventProviderSetTraits, + provider_metadata_, + provider_metadata_size_); + } + + FreeLibrary(eventing_lib); + } + +#else // TLM_HAVE_EVENT_SET_INFORMATION == 0 + + // Make no attempt to invoke EventSetInformation. + +#endif // TLM_HAVE_EVENT_SET_INFORMATION + + return status; } bool TlmProvider::IsEnabled() const noexcept { diff --git a/base/win/cet_shadow_stack_unittest.cc b/base/win/cet_shadow_stack_unittest.cc index 8c58163cfbf44..cb73ea9e8e388 100644 --- a/base/win/cet_shadow_stack_unittest.cc +++ b/base/win/cet_shadow_stack_unittest.cc @@ -19,10 +19,14 @@ bool IsHardwareEnforcedShadowStacksEnabled() { if (base::win::GetVersion() < base::win::Version::WIN10_20H1) return false; + auto get_process_mitigation_policy = + reinterpret_cast(::GetProcAddress( + ::GetModuleHandleA("kernel32.dll"), "GetProcessMitigationPolicy")); + PROCESS_MITIGATION_USER_SHADOW_STACK_POLICY uss_policy; - if (!::GetProcessMitigationPolicy(GetCurrentProcess(), - ProcessUserShadowStackPolicy, &uss_policy, - sizeof(uss_policy))) { + if (!get_process_mitigation_policy(GetCurrentProcess(), + ProcessUserShadowStackPolicy, &uss_policy, + sizeof(uss_policy))) { return false; } diff --git a/base/win/core_winrt_util.cc b/base/win/core_winrt_util.cc index 25f5885bf2f40..3508cfe474bfd 100644 --- a/base/win/core_winrt_util.cc +++ b/base/win/core_winrt_util.cc @@ -3,17 +3,54 @@ // found in the LICENSE file. #include "base/win/core_winrt_util.h" +#include "base/threading/scoped_thread_priority.h" namespace base::win { +FARPROC LoadComBaseFunction(const char* function_name) { + static HMODULE const handle = []() { + // Mitigate the issues caused by loading DLLs on a background thread + // (http://crbug/973868). + SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY(); + return ::LoadLibraryEx(L"combase.dll", nullptr, + LOAD_LIBRARY_SEARCH_SYSTEM32); + }(); + return handle ? ::GetProcAddress(handle, function_name) : nullptr; +} + +decltype(&::RoActivateInstance) GetRoActivateInstanceFunction() { + static decltype(&::RoActivateInstance) const function = + reinterpret_cast( + LoadComBaseFunction("RoActivateInstance")); + return function; +} + +decltype(&::RoGetActivationFactory) GetRoGetActivationFactoryFunction() { + static decltype(&::RoGetActivationFactory) const function = + reinterpret_cast( + LoadComBaseFunction("RoGetActivationFactory")); + return function; +} + +bool ResolveCoreWinRTDelayload() { + // TODO(finnur): Add AssertIOAllowed once crbug.com/770193 is fixed. + return GetRoActivateInstanceFunction() && GetRoGetActivationFactoryFunction(); +} + HRESULT RoGetActivationFactory(HSTRING class_id, const IID& iid, void** out_factory) { - return ::RoGetActivationFactory(class_id, iid, out_factory); + auto get_factory_func = GetRoGetActivationFactoryFunction(); + if (!get_factory_func) + return E_FAIL; + return get_factory_func(class_id, iid, out_factory); } HRESULT RoActivateInstance(HSTRING class_id, IInspectable** instance) { - return ::RoActivateInstance(class_id, instance); + auto activate_instance_func = GetRoActivateInstanceFunction(); + if (!activate_instance_func) + return E_FAIL; + return activate_instance_func(class_id, instance); } } // namespace base::win diff --git a/base/win/core_winrt_util.h b/base/win/core_winrt_util.h index 3a6e0c9f3774c..c4a802c85d6ed 100644 --- a/base/win/core_winrt_util.h +++ b/base/win/core_winrt_util.h @@ -15,6 +15,8 @@ namespace base::win { +BASE_EXPORT bool ResolveCoreWinRTDelayload(); + // The following stubs are provided for when component build is enabled, in // order to avoid the propagation of delay-loading CoreWinRT to other modules. diff --git a/base/win/hstring_reference.cc b/base/win/hstring_reference.cc index b254fc64310a1..8e4506d08a188 100644 --- a/base/win/hstring_reference.cc +++ b/base/win/hstring_reference.cc @@ -12,18 +12,51 @@ #include "base/check_op.h" #include "base/numerics/safe_conversions.h" -namespace base::win { +namespace base { +namespace { + +bool g_winrt_string_loaded = false; + +decltype(&::WindowsCreateStringReference) GetWindowsCreateStringReference() { + static auto const create_string_reference_func = + []() -> decltype(&::WindowsCreateStringReference) { + const HMODULE handle = + ::LoadLibraryEx(L"combase.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); + if (handle) { + return reinterpret_cast( + ::GetProcAddress(handle, "WindowsCreateStringReference")); + } + return nullptr; + }(); + return create_string_reference_func; +} + +} // namespace + +namespace win { + +// static +bool HStringReference::ResolveCoreWinRTStringDelayload() { + g_winrt_string_loaded = GetWindowsCreateStringReference() != nullptr; + return g_winrt_string_loaded; +} HStringReference::HStringReference(const wchar_t* str, size_t length) { + DCHECK(g_winrt_string_loaded); // String must be null terminated for WindowsCreateStringReference. // nullptr str is OK so long as the length is 0. DCHECK(str ? str[length] == L'\0' : length == 0); - const HRESULT hr = ::WindowsCreateStringReference( + // If you nullptr crash here, you've failed to call + // ResolveCoreWinRTStringDelayLoad and check its return value. + const HRESULT hr = GetWindowsCreateStringReference()( str, checked_cast(length), &hstring_header_, &hstring_); + // All failure modes of WindowsCreateStringReference are handled gracefully + // but this class. DCHECK_EQ(hr, S_OK); } HStringReference::HStringReference(const wchar_t* str) : HStringReference(str, str ? wcslen(str) : 0) {} -} // namespace base::win +} // namespace win +} // namespace base diff --git a/base/win/hstring_reference.h b/base/win/hstring_reference.h index 3cde4acef6f2e..2366a681e72c0 100644 --- a/base/win/hstring_reference.h +++ b/base/win/hstring_reference.h @@ -9,7 +9,8 @@ #include "base/base_export.h" -namespace base::win { +namespace base { +namespace win { // HStringReference is an HSTRING representation of a null terminated // string backed by memory that outlives the HStringReference instance. @@ -17,12 +18,31 @@ namespace base::win { // If you need an HSTRING class that manages its own memory, you should // use ScopedHString instead. // +// Note that HStringReference requires certain functions that are only +// available on Windows 8 and later, and that these functions need to be +// delayloaded to avoid breaking Chrome on Windows 7. +// +// Callers MUST check the return value of ResolveCoreWinRTStringDelayLoad() +// *before* using HStringReference. +// +// One-time Initialization for HStringReference: +// +// const bool success = HStringReference::ResolveCoreWinRTStringDelayload(); +// if (success) { +// // HStringReference can be used. +// } else { +// // Handle error. +// } +// // Example use: // // HStringReference string(L"abc"); // class BASE_EXPORT HStringReference { public: + // Loads all required HSTRING functions, available from Win8 and onwards. + static bool ResolveCoreWinRTStringDelayload(); + HStringReference(const wchar_t* str, size_t len); explicit HStringReference(const wchar_t* str); @@ -47,6 +67,7 @@ class BASE_EXPORT HStringReference { HSTRING_HEADER hstring_header_; }; -} // namespace base::win +} // namespace win +} // namespace base #endif // BASE_WIN_HSTRING_REFERENCE_H_ diff --git a/base/win/hstring_reference_unittest.cc b/base/win/hstring_reference_unittest.cc index 64fa91320a040..5761ea461574a 100644 --- a/base/win/hstring_reference_unittest.cc +++ b/base/win/hstring_reference_unittest.cc @@ -26,6 +26,8 @@ void VerifyHSTRINGEquals(HSTRING hstring, const wchar_t* test_string) { } // namespace TEST(HStringReferenceTest, Init) { + EXPECT_TRUE(HStringReference::ResolveCoreWinRTStringDelayload()); + const HStringReference string(kTestString); EXPECT_NE(string.Get(), nullptr); VerifyHSTRINGEquals(string.Get(), kTestString); diff --git a/base/win/scoped_hstring.cc b/base/win/scoped_hstring.cc index 042768f2b249e..6a8b7eff01b90 100644 --- a/base/win/scoped_hstring.cc +++ b/base/win/scoped_hstring.cc @@ -18,24 +18,88 @@ namespace base { +namespace { + +static bool g_load_succeeded = false; + +FARPROC LoadComBaseFunction(const char* function_name) { + static HMODULE const handle = + ::LoadLibraryEx(L"combase.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); + return handle ? ::GetProcAddress(handle, function_name) : nullptr; +} + +decltype(&::WindowsCreateString) GetWindowsCreateString() { + static decltype(&::WindowsCreateString) const function = + reinterpret_cast( + LoadComBaseFunction("WindowsCreateString")); + return function; +} + +decltype(&::WindowsDeleteString) GetWindowsDeleteString() { + static decltype(&::WindowsDeleteString) const function = + reinterpret_cast( + LoadComBaseFunction("WindowsDeleteString")); + return function; +} + +decltype(&::WindowsGetStringRawBuffer) GetWindowsGetStringRawBuffer() { + static decltype(&::WindowsGetStringRawBuffer) const function = + reinterpret_cast( + LoadComBaseFunction("WindowsGetStringRawBuffer")); + return function; +} + +HRESULT WindowsCreateString(const wchar_t* src, + uint32_t len, + HSTRING* out_hstr) { + decltype(&::WindowsCreateString) create_string_func = + GetWindowsCreateString(); + if (!create_string_func) + return E_FAIL; + return create_string_func(src, len, out_hstr); +} + +HRESULT WindowsDeleteString(HSTRING hstr) { + decltype(&::WindowsDeleteString) delete_string_func = + GetWindowsDeleteString(); + if (!delete_string_func) + return E_FAIL; + return delete_string_func(hstr); +} + +const wchar_t* WindowsGetStringRawBuffer(HSTRING hstr, uint32_t* out_len) { + decltype(&::WindowsGetStringRawBuffer) get_string_raw_buffer_func = + GetWindowsGetStringRawBuffer(); + if (!get_string_raw_buffer_func) { + *out_len = 0; + return nullptr; + } + return get_string_raw_buffer_func(hstr, out_len); +} + +} // namespace + namespace internal { // static void ScopedHStringTraits::Free(HSTRING hstr) { - ::WindowsDeleteString(hstr); + base::WindowsDeleteString(hstr); } } // namespace internal namespace win { -ScopedHString::ScopedHString(HSTRING hstr) : ScopedGeneric(hstr) {} +ScopedHString::ScopedHString(HSTRING hstr) : ScopedGeneric(hstr) { + DCHECK(g_load_succeeded); +} // static ScopedHString ScopedHString::Create(WStringPiece str) { + DCHECK(g_load_succeeded); HSTRING hstr; - HRESULT hr = ::WindowsCreateString(str.data(), - checked_cast(str.length()), &hstr); + HRESULT hr = base::WindowsCreateString( + str.data(), checked_cast(str.length()), &hstr); if (SUCCEEDED(hr)) return ScopedHString(hstr); @@ -57,9 +121,21 @@ ScopedHString ScopedHString::Create(StringPiece str) { } // static +bool ScopedHString::ResolveCoreWinRTStringDelayload() { + // TODO(finnur): Add AssertIOAllowed once crbug.com/770193 is fixed. + + static const bool load_succeeded = []() { + bool success = GetWindowsCreateString() && GetWindowsDeleteString() && + GetWindowsGetStringRawBuffer(); + g_load_succeeded = success; + return success; + }(); + return load_succeeded; +} + WStringPiece ScopedHString::Get() const { UINT32 length = 0; - const wchar_t* buffer = ::WindowsGetStringRawBuffer(get(), &length); + const wchar_t* buffer = base::WindowsGetStringRawBuffer(get(), &length); return WStringPiece(buffer, length); } diff --git a/base/win/scoped_hstring.h b/base/win/scoped_hstring.h index 95bc98bc2cf09..4ba6e23d08272 100644 --- a/base/win/scoped_hstring.h +++ b/base/win/scoped_hstring.h @@ -27,7 +27,21 @@ struct BASE_EXPORT ScopedHStringTraits { namespace win { -// ScopedHString is a wrapper around an HSTRING. +// ScopedHString is a wrapper around an HSTRING. Note that it requires certain +// functions that are only available on Windows 8 and later, and that these +// functions need to be delayloaded to avoid breaking Chrome on Windows 7. +// +// Callers MUST check the return value of ResolveCoreWinRTStringDelayLoad() +// *before* using ScopedHString. +// +// One-time Initialization for ScopedHString: +// +// bool success = ScopedHString::ResolveCoreWinRTStringDelayload(); +// if (success) { +// // ScopeHString can be used. +// } else { +// // Handle error. +// } // // Example use: // @@ -48,6 +62,9 @@ class BASE_EXPORT ScopedHString static ScopedHString Create(WStringPiece str); static ScopedHString Create(StringPiece str); + // Loads all required HSTRING functions, available from Win8 and onwards. + [[nodiscard]] static bool ResolveCoreWinRTStringDelayload(); + // Returns a view into the memory buffer managed by the instance. The returned // StringPiece is only valid during the lifetime of this ScopedHString // instance. diff --git a/base/win/win_util.cc b/base/win/win_util.cc index 0d81e7c0a268e..61880ddc38aa1 100644 --- a/base/win/win_util.cc +++ b/base/win/win_util.cc @@ -101,6 +101,34 @@ POWER_PLATFORM_ROLE GetPlatformRole() { return PowerDeterminePlatformRoleEx(POWER_PLATFORM_ROLE_V2); } +// Because we used to support versions earlier than 8.1, we dynamically load +// this function from user32.dll, so it won't fail to load in runtime. +// TODO(https://crbug.com/1408307): Call SetProcessDpiAwareness directly. +bool SetProcessDpiAwarenessWrapper(PROCESS_DPI_AWARENESS value) { + if (!IsUser32AndGdi32Available()) + return false; + + static const auto set_process_dpi_awareness_func = + reinterpret_cast( + GetUser32FunctionPointer("SetProcessDpiAwarenessInternal")); + if (set_process_dpi_awareness_func) { + HRESULT hr = set_process_dpi_awareness_func(value); + if (SUCCEEDED(hr)) + return true; + DLOG_IF(ERROR, hr == E_ACCESSDENIED) + << "Access denied error from SetProcessDpiAwarenessInternal. " + "Function called twice, or manifest was used."; + NOTREACHED() + << "SetProcessDpiAwarenessInternal failed with unexpected error: " + << hr; + return false; + } + + NOTREACHED() << "SetProcessDpiAwarenessInternal " + "should be available on all platforms >= Windows 8.1"; + return false; +} + // Enable V2 per-monitor high-DPI support for the process. This will cause // Windows to scale dialogs, comctl32 controls, context menus, and non-client // area owned by this process on a per-monitor basis. If per-monitor V2 is not @@ -238,10 +266,16 @@ bool IsWindows10OrGreaterTabletMode(HWND hwnd) { IsDeviceUsedAsATablet(/*reason=*/nullptr); } + if (!ResolveCoreWinRTDelayload() || + !ScopedHString::ResolveCoreWinRTStringDelayload()) { + return false; + } + + ScopedHString view_settings_guid = ScopedHString::Create( RuntimeClass_Windows_UI_ViewManagement_UIViewSettings); Microsoft::WRL::ComPtr view_settings_interop; - HRESULT hr = ::RoGetActivationFactory(view_settings_guid.get(), + HRESULT hr = win::RoGetActivationFactory(view_settings_guid.get(), IID_PPV_ARGS(&view_settings_interop)); if (FAILED(hr)) return false; @@ -606,8 +640,15 @@ bool IsJoinedToAzureAD() { bool IsUser32AndGdi32Available() { static auto is_user32_and_gdi32_available = []() { // If win32k syscalls aren't disabled, then user32 and gdi32 are available. + auto get_process_mitigation_policy = + reinterpret_cast(::GetProcAddress( + ::GetModuleHandleA("kernel32.dll"), "GetProcessMitigationPolicy")); + + if(!get_process_mitigation_policy) + return true; + PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY policy = {}; - if (::GetProcessMitigationPolicy(GetCurrentProcess(), + if (get_process_mitigation_policy(GetCurrentProcess(), ProcessSystemCallDisablePolicy, &policy, sizeof(policy))) { return policy.DisallowWin32kSystemCalls == 0; @@ -682,7 +723,7 @@ void EnableHighDPISupport() { // Fall back to per-monitor DPI for older versions of Win10. PROCESS_DPI_AWARENESS process_dpi_awareness = PROCESS_PER_MONITOR_DPI_AWARE; - if (!::SetProcessDpiAwareness(process_dpi_awareness)) { + if (!SetProcessDpiAwarenessWrapper(process_dpi_awareness)) { // For windows versions where SetProcessDpiAwareness fails, try its // predecessor. BOOL result = ::SetProcessDPIAware(); diff --git a/base/win/winrt_storage_util_unittest.cc b/base/win/winrt_storage_util_unittest.cc index 5c54819e4b85a..8f3f64f29011a 100644 --- a/base/win/winrt_storage_util_unittest.cc +++ b/base/win/winrt_storage_util_unittest.cc @@ -21,6 +21,10 @@ namespace win { TEST(WinrtStorageUtilTest, CreateBufferFromData) { ScopedCOMInitializer com_initializer(ScopedCOMInitializer::kMTA); + if (!ResolveCoreWinRTDelayload()) { + return; + } + const std::vector data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; Microsoft::WRL::ComPtr buffer; ASSERT_HRESULT_SUCCEEDED( diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd index 44ea93c98f87a..6944cb37210b7 100644 --- a/chrome/app/chromium_strings.grd +++ b/chrome/app/chromium_strings.grd @@ -278,7 +278,7 @@ If you update this file, be sure also to update google_chrome_strings.grd. --> - Chromium + Supermium - Chromium + Supermium - + - + - + - Chromium is a web browser that runs webpages and applications with lightning speed. It's fast, stable, and easy to use. Browse the web more safely with malware and phishing protection built into Chromium. + Supermium is a web browser that runs webpages and applications with lightning speed. It's fast, stable, and easy to use. Browse the web more safely with malware and phishing protection built into Supermium. - Welcome to Chromium; new browser window opened + Welcome to Supermium; new browser window opened - Welcome to Chromium + Welcome to Supermium @@ -331,8 +331,8 @@ If you update this file, be sure also to update google_chrome_strings.grd. --> ChromiumOS - - Chromium Enterprise logo + + Supermium Enterprise logo @@ -346,34 +346,34 @@ If you update this file, be sure also to update google_chrome_strings.grd. --> - Task Manager - Chromium + Task Manager - Supermium - Help make Chromium better by sending crash reports and $1usage statistics to Google + Help make Supermium better by sending crash reports and $1usage statistics to Google - $1Google - Chromium + $1Google - Supermium - Chromium - $1Google + Supermium - $1Google - $1Google - Network Sign-in - Chromium + $1Google - Network Sign-in - Supermium - Chromium - Network Sign-in - $1Google + Supermium - Network Sign-in - $1Google @@ -385,16 +385,16 @@ If you update this file, be sure also to update google_chrome_strings.grd. --> - $1Google - Chromium + $1Google - Supermium - $1Google - Chromium Beta + $1Google - Supermium Beta - $1Google - Chromium Dev + $1Google - Supermium Dev - $1Google - Chromium Canary + $1Google - Supermium Canary @@ -407,106 +407,106 @@ If you update this file, be sure also to update google_chrome_strings.grd. --> - The Chromium Authors + The Supermium Authors - Copyright {0,date,y}2016 The Chromium Authors. All rights reserved. + Copyright {0,date,y}2016 The Supermium Authors. All rights reserved. - + ChromiumOS is made possible by additional <a target="_blank" href="$1">open source software</a>. - + ChromiumOS is made possible by additional <a target="_blank" href="$1">open source software</a>, as is <a target="_blank" href="$2">Linux development environment</a>. - Not used in Chromium. Placeholder to keep resource maps in sync. + Not used in Supermium. Placeholder to keep resource maps in sync. - Not used in Chromium. Placeholder to keep resource maps in sync. + Not used in Supermium. Placeholder to keep resource maps in sync. - To get future Chromium updates, you'll need macOS 10.15 or later. This computer is using macOS 10.13. + To get future Supermium updates, you'll need macOS 10.15 or later. This computer is using macOS 10.13. - To get future Chromium updates, you'll need macOS 10.15 or later. This computer is using macOS 10.14. + To get future Supermium updates, you'll need macOS 10.15 or later. This computer is using macOS 10.14. - Chromium may not function correctly because it is no longer supported on Windows XP or Windows Vista + Supermium may not function correctly because it is no longer supported on Windows XP or Windows Vista - To get future Chromium updates, you'll need Windows 10 or later. This computer is using Windows 7. + To get future Supermium updates, you'll need Windows 10 or later. This computer is using Windows 7. - To get future Chromium updates, you'll need Windows 10 or later. This computer is using Windows 8. + To get future Supermium updates, you'll need Windows 10 or later. This computer is using Windows 8. - To get future Chromium updates, you'll need Windows 10 or later. This computer is using Windows 8.1. + To get future Supermium updates, you'll need Windows 10 or later. This computer is using Windows 8.1. - Chromium may not function correctly because it is no longer supported on this Linux distribution + Supermium may not function correctly because it is no longer supported on this Linux distribution - Chromium + Supermium - Chromium is unresponsive. Relaunch now? + Supermium is unresponsive. Relaunch now? - To send a number from here to your Android phone, sign in to Chromium on both devices. + To send a number from here to your Android phone, sign in to Supermium on both devices. - To send a number from $1www.google.com to your Android phone, sign in to Chromium on both devices. + To send a number from $1www.google.com to your Android phone, sign in to Supermium on both devices. - Make sure you are signed in to Chromium on your $1Pixel XL and then try sending again. + Make sure you are signed in to Supermium on your $1Pixel XL and then try sending again. - Please close all Chromium windows and try again. + Please close all Supermium windows and try again. - Are you sure you want to uninstall Chromium? + Are you sure you want to uninstall Supermium? - - Uninstall Chromium + + Uninstall Supermium - Make Chromium the default browser + Make Supermium the default browser - Let Chromium Run in the Background + Let Supermium Run in the Background - Let Chromium run in the background + Let Supermium run in the background -Chromium cannot read and write to its data directory: +Supermium cannot read and write to its data directory: $1C:\Documents and Settings\devint\Local Settings\Application Data\Google\Chrome @@ -516,9 +516,9 @@ Chromium cannot read and write to its data directory: -Your profile can not be used because it is from a newer version of Chromium. +Your profile can not be used because it is from a newer version of Supermium. -Some features may be unavailable. Please specify a different profile directory or use a newer version of Chromium. +Some features may be unavailable. Please specify a different profile directory or use a newer version of Supermium. Your preferences can not be read. @@ -528,35 +528,35 @@ Some features may be unavailable and changes to preferences won't be saved. Your preferences file is corrupt or invalid. -Chromium is unable to recover your settings. +Supermium is unable to recover your settings. -If you want to use this account one-time only, you can use <a id="guestModeLink" href="#">Guest mode</a> in Chromium browser. If you want to add an account for someone else, <a target="_blank" id="newPersonLink" href="$1https://google.com/">add a new person</a> to your $2Chromebook. +If you want to use this account one-time only, you can use <a id="guestModeLink" href="#">Guest mode</a> in Supermium browser. If you want to add an account for someone else, <a target="_blank" id="newPersonLink" href="$1https://google.com/">add a new person</a> to your $2Chromebook. Permissions you've already given to websites and apps may apply to this account. You can manage your Google Accounts in <a id="osSettingsLink" href="$3https://google.com/">Settings</a>. - Chromium + Supermium - Whoa! Chromium has crashed. Relaunch now? + Whoa! Supermium has crashed. Relaunch now? - Chromium will save this password in your Google Account. You won’t have to remember it. + Supermium will save this password in your Google Account. You won’t have to remember it. - Chromium lets you know if your passwords are ever compromised + Supermium lets you know if your passwords are ever compromised - Chromium + Supermium Password Manager @@ -569,252 +569,252 @@ Permissions you've already given to websites and apps may apply to this account. - Chromium is trying to $1show passwords + Supermium is trying to $1show passwords - Chromium is trying to show passwords. Type your Windows password to allow this. + Supermium is trying to show passwords. Type your Windows password to allow this. - Chromium is trying to copy passwords. Type your Windows password to allow this. + Supermium is trying to copy passwords. Type your Windows password to allow this. - Chromium is trying to edit passwords. Type your Windows password to allow this. + Supermium is trying to edit passwords. Type your Windows password to allow this. - Chromium wants to export your passwords. Type your Windows password to allow this. + Supermium wants to export your passwords. Type your Windows password to allow this. - Chromium is trying to replace existing passwords. Type your Windows password to allow this. + Supermium is trying to replace existing passwords. Type your Windows password to allow this. - This computer already has a more recent version of Chromium. If the software is not working, please uninstall Chromium and try again. + This computer already has a more recent version of Supermium. If the software is not working, please uninstall Supermium and try again. - Installation failed due to unspecified error. If Chromium is currently running, please close it and try again. + Installation failed due to unspecified error. If Supermium is currently running, please close it and try again. - Can not install the same Chromium version that is currently running. Please close Chromium and try again. + Can not install the same Supermium version that is currently running. Please close Supermium and try again. - Installation failed due to unspecified error. Please download Chromium again. + Installation failed due to unspecified error. Please download Supermium again. - Chromium requires Windows 10 or higher. + Supermium requires Windows 10 or higher. - An operating system error occurred during installation. Please download Chromium again. + An operating system error occurred during installation. Please download Supermium again. - Another operation on Chromium is in progress. Please try again later. + Another operation on Supermium is in progress. Please try again later. The installer couldn't create a temporary directory. Please check for free disk space and permission to install software. - The installer failed to uncompress archive. Please download Chromium again. + The installer failed to uncompress archive. Please download Supermium again. - The installer archive is corrupted or invalid. Please download Chromium again. + The installer archive is corrupted or invalid. Please download Supermium again. You do not have appropriate rights for system-level install. Try running the installer again as Administrator. - Chromium is already installed for all users on your computer. + Supermium is already installed for all users on your computer. - + Access the Internet Also delete your browsing data? - + Change default browser to: Uninstall - - Chromium isn't your default browser + + Supermium isn't your default browser - There is a new version of Chromium available. + There is a new version of Supermium available. - There's a new version of Chromium available, and it's faster than ever. + There's a new version of Supermium available, and it's faster than ever. - There's a new, safer version of Chromium available. + There's a new, safer version of Supermium available. - Chromium has been updated, but you haven't used it for at least 30 days. + Supermium has been updated, but you haven't used it for at least 30 days. - Chromium lets you click a phone number on the web and call it with Skype! + Supermium lets you click a phone number on the web and call it with Skype! - Chromium blocked this file because this type of file is dangerous + Supermium blocked this file because this type of file is dangerous - Chromium blocked this file because it is dangerous + Supermium blocked this file because it is dangerous - Extensions, apps, and themes from unknown sources can harm your device. Chromium recommends only installing them from the $1Chrome Web Store + Extensions, apps, and themes from unknown sources can harm your device. Supermium recommends only installing them from the $1Chrome Web Store - Chromium blocked this file because it has malware + Supermium blocked this file because it has malware - Chromium recommends scanning this file because it may be dangerous + Supermium recommends scanning this file because it may be dangerous - Chromium blocked this archive file because it may hide malware + Supermium blocked this archive file because it may hide malware - Adding to Chromium... + Adding to Supermium... - $1bla.exe may be dangerous, so Chromium has blocked it. + $1bla.exe may be dangerous, so Supermium has blocked it. - This file is dangerous, so Chromium has blocked it. + This file is dangerous, so Supermium has blocked it. - $1malware.exe is dangerous, so Chromium has blocked it. + $1malware.exe is dangerous, so Supermium has blocked it. - This file is dangerous, so Chromium has blocked it. + This file is dangerous, so Supermium has blocked it. - This file may be dangerous, so Chromium has blocked it. + This file may be dangerous, so Supermium has blocked it. - Chromium recommends scanning this file because it may be dangerous. + Supermium recommends scanning this file because it may be dangerous. - Exit Chromium anyway? + Exit Supermium anyway? - Quit Chromium anyway? + Quit Supermium anyway? - Chromium is in background mode. + Supermium is in background mode. - Google API keys are missing. Some functionality of Chromium will be disabled. + Google API keys are missing. Some functionality of Supermium will be disabled. - $1Gmail Checker has been added to Chromium + $1Gmail Checker has been added to Supermium - Also clear data from Chromium ($1www.google.com) + Also clear data from Supermium ($1www.google.com) - Chromium found that "$1Gmail Checker" contains malware + Supermium found that "$1Gmail Checker" contains malware - Chromium found that these items contain malware: + Supermium found that these items contain malware: - This extension contains malware and is unsafe. Remove it from Chromium so it can no longer see and change your data on sites you visit, including your personal info. + This extension contains malware and is unsafe. Remove it from Supermium so it can no longer see and change your data on sites you visit, including your personal info. - This extension violates the Chrome Web Store policy, and might be unsafe. Remove it from Chromium so it can no longer see and change your data on sites you visit, including your personal info. + This extension violates the Chrome Web Store policy, and might be unsafe. Remove it from Supermium so it can no longer see and change your data on sites you visit, including your personal info. - This extension was unpublished by its developer, and might be unsafe. Remove it from Chromium so it can no longer see and change your data on sites you visit, including your personal info. + This extension was unpublished by its developer, and might be unsafe. Remove it from Supermium so it can no longer see and change your data on sites you visit, including your personal info. - Allow extension to show access requests in the Chromium toolbar + Allow extension to show access requests in the Supermium toolbar - - Warning: Chromium cannot prevent extensions from recording your browsing history. To disable this extension in Incognito mode, unselect this option. + + Warning: Supermium cannot prevent extensions from recording your browsing history. To disable this extension in Incognito mode, unselect this option. - Remove from Chromium + Remove from Supermium - In Chromium + In Supermium - To make Chromium safer, we disabled some extensions that aren't listed in the $1Chrome Web Store and may have been added without your knowledge. + To make Supermium safer, we disabled some extensions that aren't listed in the $1Chrome Web Store and may have been added without your knowledge. - To make Chromium safer, we disabled the following extension that isn't listed in the $1Chrome Web Store and may have been added without your knowledge. + To make Supermium safer, we disabled the following extension that isn't listed in the $1Chrome Web Store and may have been added without your knowledge. - Customize and control Chromium + Customize and control Supermium - Customize and control Chromium. Update is available. + Customize and control Supermium. Update is available. - Customize and control Chromium. Something needs your attention - click for details. + Customize and control Supermium. Something needs your attention - click for details. - &Open in Chromium + &Open in Supermium @@ -826,12 +826,12 @@ Permissions you've already given to websites and apps may apply to this account. - About &Chromium + About &Supermium - Relaunch to Update &Chromium + Relaunch to Update &Supermium @@ -843,17 +843,17 @@ Permissions you've already given to websites and apps may apply to this account. - About &Chromium + About &Supermium - Relaunch to update &Chromium + Relaunch to update &Supermium - About &Chromium + About &Supermium Relaunch to update &ChromiumOS @@ -862,19 +862,19 @@ Permissions you've already given to websites and apps may apply to this account. - Not used in Chromium. Placeholder to keep resource maps in sync. + Not used in Supermium. Placeholder to keep resource maps in sync. - Chromium + Supermium - Chromium Helper + Supermium Helper - Chromium Helper + Supermium Helper @@ -884,34 +884,34 @@ Permissions you've already given to websites and apps may apply to this account. - Chromium + Supermium - Sync and personalize Chromium across your devices + Sync and personalize Supermium across your devices - You were signed in to Chromium as $1foo@gmail.com. Please use the same account to sign in again. + You were signed in to Supermium as $1foo@gmail.com. Please use the same account to sign in again. - Someone previously signed in to Chromium on this computer as $1user@example.com. Please create a new Chromium user to keep your information separate. + Someone previously signed in to Supermium on this computer as $1user@example.com. Please create a new Supermium user to keep your information separate. - Link your Chromium data to this account? + Link your Supermium data to this account? - You are signing in with a managed account and giving its administrator control over your Chromium profile. Your Chromium data, such as your apps, bookmarks, history, passwords, and other settings will become permanently tied to $1pat@example.com. You will be able to delete this data via the Google Accounts Dashboard, but you will not be able to associate this data with another account. $2Learn more + You are signing in with a managed account and giving its administrator control over your Supermium profile. Your Supermium data, such as your apps, bookmarks, history, passwords, and other settings will become permanently tied to $1pat@example.com. You will be able to delete this data via the Google Accounts Dashboard, but you will not be able to associate this data with another account. $2Learn more - You are signing in with a managed account and giving its administrator control over your Chromium profile. Your Chromium data, such as your apps, bookmarks, history, passwords, and other settings will become permanently tied to $1pat@example.com. You will be able to delete this data via the Google Accounts Dashboard, but you will not be able to associate this data with another account. You can optionally create a new profile to keep your existing Chromium data separate. $2Learn more + You are signing in with a managed account and giving its administrator control over your Supermium profile. Your Supermium data, such as your apps, bookmarks, history, passwords, and other settings will become permanently tied to $1pat@example.com. You will be able to delete this data via the Google Accounts Dashboard, but you will not be able to associate this data with another account. You can optionally create a new profile to keep your existing Supermium data separate. $2Learn more Add Work Profile to this browser @@ -923,11 +923,11 @@ Permissions you've already given to websites and apps may apply to this account. This work profile is completely separate from your personal profile. - Any Chromium data that is generated during the use of this profile (such as the creation of bookmarks, history, passwords, and other settings) can be removed by the work profile administrator. $1Learn more + Any Supermium data that is generated during the use of this profile (such as the creation of bookmarks, history, passwords, and other settings) can be removed by the work profile administrator. $1Learn more - You're signed in to Chromium! + You're signed in to Supermium! You're signed in as $1foo@gmail.com. Now you can access your bookmarks, history, and other settings on all your signed in devices. @@ -937,57 +937,57 @@ Permissions you've already given to websites and apps may apply to this account. - Your system administrator has configured Chromium to open an alternative browser to access $1example.com. + Your system administrator has configured Supermium to open an alternative browser to access $1example.com. - Your system administrator has configured Chromium to open $2Internet Explorer to access $1example.com. + Your system administrator has configured Supermium to open $2Internet Explorer to access $1example.com. - - Customize Chromium + + Customize Supermium - $1foo@gmail.com was previously using Chromium + $1foo@gmail.com was previously using Supermium - Continue in a new Chromium profile? + Continue in a new Supermium profile? - Switch to existing Chromium profile? + Switch to existing Supermium profile? - A Chromium profile with this account already exists + A Supermium profile with this account already exists - $1Elisa is already signed in to this Chromium profile. To keep your browsing separate, Chromium can create your own profile for you. + $1Elisa is already signed in to this Supermium profile. To keep your browsing separate, Supermium can create your own profile for you. - $1Elisa is already signed in to this Chromium profile. This will create a new Chromium profile for $2foo@gmail.com + $1Elisa is already signed in to this Supermium profile. This will create a new Supermium profile for $2foo@gmail.com - This will create a new Chromium profile for $1foo@gmail.com + This will create a new Supermium profile for $1foo@gmail.com - Another account is already signed in. To keep your browsing separate, Chromium can create your own profile for you. + Another account is already signed in. To keep your browsing separate, Supermium can create your own profile for you. - Customize your new Chromium profile + Customize your new Supermium profile - Customize your Chromium profile + Customize your Supermium profile @@ -995,8 +995,8 @@ Permissions you've already given to websites and apps may apply to this account. Note: these strings should only be used by Google Chrome, but omitting them brings up a hash collision error. --> - - There's harmful software on your computer. Chromium can remove it, restore your settings, and disable extensions to make your browser work normally again. + + There's harmful software on your computer. Supermium can remove it, restore your settings, and disable extensions to make your browser work normally again. @@ -1019,21 +1019,21 @@ Permissions you've already given to websites and apps may apply to this account. - Remove from Chromium... + Remove from Supermium... - - Chromium Apps + + Supermium Apps - Chromium Apps + Supermium Apps - + - + @@ -1046,42 +1046,42 @@ Permissions you've already given to websites and apps may apply to this account. - Chromium is using your camera and microphone. + Supermium is using your camera and microphone. - Chromium is using your microphone. + Supermium is using your microphone. - Chromium is using your camera. + Supermium is using your camera. {NUM_DEVICES, plural, - =0 {A Chromium extension was accessing HID devices} - =1 {A Chromium extension is accessing 1 HID device} - other {A Chromium extension is accessing # HID devices}} + =0 {A Supermium extension was accessing HID devices} + =1 {A Supermium extension is accessing 1 HID device} + other {A Supermium extension is accessing # HID devices}} {NUM_DEVICES, plural, - =0 {Chromium extensions were accessing HID devices} - =1 {Chromium extensions are accessing HID devices} - other {Chromium extensions are accessing # HID devices}} + =0 {Supermium extensions were accessing HID devices} + =1 {Supermium extensions are accessing HID devices} + other {Supermium extensions are accessing # HID devices}} - The profile appears to be in use by another Chromium process ($112345) on another computer ($2example.com). Chromium has locked the profile so that it doesn't get corrupted. If you are sure no other processes are using this profile, you can unlock the profile and relaunch Chromium. + The profile appears to be in use by another Supermium process ($112345) on another computer ($2example.com). Supermium has locked the profile so that it doesn't get corrupted. If you are sure no other processes are using this profile, you can unlock the profile and relaunch Supermium. - Set Chromium as your default browser + Set Supermium as your default browser @@ -1089,40 +1089,40 @@ Permissions you've already given to websites and apps may apply to this account. - This person's browsing data will be deleted from this device. To recover the data, sign in to Chromium as $2foo@example.com. + This person's browsing data will be deleted from this device. To recover the data, sign in to Supermium as $2foo@example.com. - Chromium just got better + Supermium just got better - Now it's easier to use Chromium with your Google Account and on shared computers. + Now it's easier to use Supermium with your Google Account and on shared computers. - This is your Chromium + This is your Supermium - Your web, bookmarks, and other Chromium stuff live here. + Your web, bookmarks, and other Supermium stuff live here. - Guests can use Chromium without leaving anything behind. + Guests can use Supermium without leaving anything behind. - If you share a computer, friends and family can browse separately and set up Chromium just the way they want. + If you share a computer, friends and family can browse separately and set up Supermium just the way they want. - Click your name to open Chromium and start browsing. + Click your name to open Supermium and start browsing. - Add yourself to Chromium + Add yourself to Supermium - Click the Chromium menu + Click the Supermium menu Click “Password Manager” @@ -1137,72 +1137,72 @@ Permissions you've already given to websites and apps may apply to this account. - This extension has changed what page is shown when you start Chromium. + This extension has changed what page is shown when you start Supermium. - The extension "$1AdBlock" has changed what page is shown when you start Chromium. + The extension "$1AdBlock" has changed what page is shown when you start Supermium. - ''' It also controls what page is shown when you start Chromium. ''' + ''' It also controls what page is shown when you start Supermium. ''' - ''' It also controls what page is shown when you start Chromium or click the Home button. ''' + ''' It also controls what page is shown when you start Supermium or click the Home button. ''' - ''' It also controls what page is shown when you start Chromium or search from the Omnibox. ''' + ''' It also controls what page is shown when you start Supermium or search from the Omnibox. ''' - Discover great apps, games, extensions and themes for Chromium. + Discover great apps, games, extensions and themes for Supermium. - Chromium (mDNS-In) + Supermium (mDNS-In) - + - + - + - Inbound rule for Chromium to allow mDNS traffic. + Inbound rule for Supermium to allow mDNS traffic. - + - + - + - - If an image doesn’t have a useful description, Chromium will try to provide one for you. To create descriptions, images are sent to Google. You can turn this off in settings at any time. + + If an image doesn’t have a useful description, Supermium will try to provide one for you. To create descriptions, images are sent to Google. You can turn this off in settings at any time. - - If an image doesn’t have a useful description, Chromium will try to provide one for you. To create descriptions, images are sent to Google. + + If an image doesn’t have a useful description, Supermium will try to provide one for you. To create descriptions, images are sent to Google. This uses the same spell checker that's used in Google search. Text you type in the browser is sent to Google. You can always change this behavior in settings. - Open link in new Chromium &tab + Open link in new Supermium &tab - Open link in Chromium inco&gnito window + Open link in Supermium inco&gnito window - Open Link in New Chromium &tab + Open Link in New Supermium &tab - Open Link in Chromium Inco&gnito Window + Open Link in Supermium Inco&gnito Window @@ -1210,13 +1210,13 @@ Permissions you've already given to websites and apps may apply to this account. - Relaunch Chromium + Relaunch Supermium {COUNT, plural, - =0 {A new update for Chromium is available and will be applied as soon as you relaunch.} - =1 {A new update for Chromium is available and will be applied as soon as you relaunch. Your Incognito window won't reopen.} - other {A new update for Chromium is available and will be applied as soon as you relaunch. Your # Incognito windows won't reopen.}} + =0 {A new update for Supermium is available and will be applied as soon as you relaunch.} + =1 {A new update for Supermium is available and will be applied as soon as you relaunch. Your Incognito window won't reopen.} + other {A new update for Supermium is available and will be applied as soon as you relaunch. Your # Incognito windows won't reopen.}} Relaunch @@ -1236,61 +1236,61 @@ Permissions you've already given to websites and apps may apply to this account. - Not used in Chromium. Placeholder to keep resource maps in sync. + Not used in Supermium. Placeholder to keep resource maps in sync. - Not used in Chromium. Placeholder to keep resource maps in sync. + Not used in Supermium. Placeholder to keep resource maps in sync. - Reinstall Chromium + Reinstall Supermium - Chromium is Out of Date + Supermium is Out of Date - Chromium is out of date + Supermium is out of date - Can't update Chromium + Can't update Supermium - Chromium couldn't update to the latest version, so you're missing out on new features and security fixes. + Supermium couldn't update to the latest version, so you're missing out on new features and security fixes. - Update Chromium + Update Supermium - Update Chromium to start sync + Update Supermium to start sync - Update Chromium + Update Supermium - Chromium is out of date + Supermium is out of date - Update Chromium + Update Supermium - Update Chromium + Update Supermium @@ -1298,72 +1298,72 @@ Permissions you've already given to websites and apps may apply to this account. - - Chromium will restart in $11 minute, 7 seconds + + Supermium will restart in $11 minute, 7 seconds - - Please restart Chromium now + + Please restart Supermium now - - A special security update for Chromium was just applied. Restart now and we'll restore your tabs. + + A special security update for Supermium was just applied. Restart now and we'll restore your tabs. - Chromium Tab + Supermium Tab - Chromium needs permission to access your camera to create a 3D map of your surroundings + Supermium needs permission to access your camera to create a 3D map of your surroundings - Chromium needs permission to access your camera for this site + Supermium needs permission to access your camera for this site - Chromium needs permission to access your microphone for this site + Supermium needs permission to access your microphone for this site - Chromium needs permission to access your camera and microphone for this site + Supermium needs permission to access your camera and microphone for this site - Chromium needs access to your location to share your location with this site + Supermium needs access to your location to share your location with this site - Chromium needs storage access to download files + Supermium needs storage access to download files - Chromium needs camera permission to create a 3D map of your surroundings + Supermium needs camera permission to create a 3D map of your surroundings - Chromium needs camera permission for this site + Supermium needs camera permission for this site - Chromium needs microphone permission for this site + Supermium needs microphone permission for this site - Chromium needs camera and microphone permissions for this site + Supermium needs camera and microphone permissions for this site - Chromium needs location permission for this site + Supermium needs location permission for this site - Chromium needs storage access permission to download files + Supermium needs storage access permission to download files - Once Chromium has access, websites will be able to ask you for access. + Once Supermium has access, websites will be able to ask you for access. - Please wait while Chromium installs the latest system updates. + Please wait while Supermium installs the latest system updates. ChromiumOS terms @@ -1372,15 +1372,15 @@ Permissions you've already given to websites and apps may apply to this account. - - Welcome to Chromium + + Welcome to Supermium - Go to Chromium notification settings + Go to Supermium notification settings @@ -1388,116 +1388,116 @@ Permissions you've already given to websites and apps may apply to this account. {0, plural, - =0 {A Chromium update is available} - =1 {A Chromium update is available} - other {A Chromium update has been available for # days}} + =0 {A Supermium update is available} + =1 {A Supermium update is available} + other {A Supermium update has been available for # days}} {COUNT, plural, - =0 {Your administrator asks that you relaunch Chromium to apply this update} - =1 {Your administrator asks that you relaunch Chromium to apply this update. Your Incognito window won't reopen.} - other {Your administrator asks that you relaunch Chromium to apply this update. Your # Incognito windows won't reopen.}} + =0 {Your administrator asks that you relaunch Supermium to apply this update} + =1 {Your administrator asks that you relaunch Supermium to apply this update. Your Incognito window won't reopen.} + other {Your administrator asks that you relaunch Supermium to apply this update. Your # Incognito windows won't reopen.}} {0, plural, - =1 {Relaunch Chromium within a day} - other {Relaunch Chromium within # days}} + =1 {Relaunch Supermium within a day} + other {Relaunch Supermium within # days}} {0, plural, - =1 {Chromium will relaunch in an hour} - other {Chromium will relaunch in # hours}} + =1 {Supermium will relaunch in an hour} + other {Supermium will relaunch in # hours}} {0, plural, - =1 {Chromium will relaunch in 1 minute} - other {Chromium will relaunch in # minutes}} + =1 {Supermium will relaunch in 1 minute} + other {Supermium will relaunch in # minutes}} {0, plural, - =0 {Chromium will relaunch now} - =1 {Chromium will relaunch in 1 second} - other {Chromium will relaunch in # seconds}} + =0 {Supermium will relaunch now} + =1 {Supermium will relaunch in 1 second} + other {Supermium will relaunch in # seconds}} {COUNT, plural, - =0 {Your administrator requires that you relaunch Chromium to apply an update} - =1 {Your administrator requires that you relaunch Chromium to apply an update. Your Incognito window won't reopen.} - other {Your administrator requires that you relaunch Chromium to apply an update. Your # Incognito windows won't reopen.}} + =0 {Your administrator requires that you relaunch Supermium to apply an update} + =1 {Your administrator requires that you relaunch Supermium to apply an update. Your Incognito window won't reopen.} + other {Your administrator requires that you relaunch Supermium to apply an update. Your # Incognito windows won't reopen.}} - + - - Launching Chromium... + + Launching Supermium... - - Couldn't launch Chromium. Try again. + + Couldn't launch Supermium. Try again. - - Relaunch Chromium + + Relaunch Supermium - Share a Chromium tab + Share a Supermium tab - Chromium was automatically closed + Supermium was automatically closed - - Your organization closes Chromium when it isn't used for $130 minutes. Browsing data was deleted. This could include history, autofill, and downloads. + + Your organization closes Supermium when it isn't used for $130 minutes. Browsing data was deleted. This could include history, autofill, and downloads. - - Your organization deletes Chromium data when it isn't used for $130 minutes. This could include history, autofill, and downloads. + + Your organization deletes Supermium data when it isn't used for $130 minutes. This could include history, autofill, and downloads. - - Your organization closes Chromium when it isn't used for $130 minutes. + + Your organization closes Supermium when it isn't used for $130 minutes. - Chromium will soon close + Supermium will soon close - Chromium will soon delete browsing data + Supermium will soon delete browsing data - Chromium will soon close and delete data + Supermium will soon close and delete data - + {COUNT, plural, - =1 {Your organization automatically closes Chromium when it isn't used for 1 minute.} - other {Your organization automatically closes Chromium when it isn't used for # minutes.}} + =1 {Your organization automatically closes Supermium when it isn't used for 1 minute.} + other {Your organization automatically closes Supermium when it isn't used for # minutes.}} - + {COUNT, plural, - =1 {Your organization automatically deletes browsing data when Chromium isn't used for 1 minute. This could include history, autofill, and downloads. Your tabs will stay open.} - other {Your organization automatically deletes browsing data when Chromium isn't used for # minutes. This could include history, autofill, and downloads. Your tabs will stay open.}} + =1 {Your organization automatically deletes browsing data when Supermium isn't used for 1 minute. This could include history, autofill, and downloads. Your tabs will stay open.} + other {Your organization automatically deletes browsing data when Supermium isn't used for # minutes. This could include history, autofill, and downloads. Your tabs will stay open.}} - + {COUNT, plural, - =1 {Your organization automatically closes Chromium when it isn't used for 1 minute. Browsing data is deleted. This could include history, autofill, and downloads.} - other {Your organization automatically closes Chromium when it isn't used for # minutes. Browsing data is deleted. This could include history, autofill, and downloads.}} + =1 {Your organization automatically closes Supermium when it isn't used for 1 minute. Browsing data is deleted. This could include history, autofill, and downloads.} + other {Your organization automatically closes Supermium when it isn't used for # minutes. Browsing data is deleted. This could include history, autofill, and downloads.}} - Continue using Chromium + Continue using Supermium - Help us improve Chromium + Help us improve Supermium - Your parent has turned off "Permissions for sites, apps and extensions" for Chromium. Adding this $1extension is not allowed. + Your parent has turned off "Permissions for sites, apps and extensions" for Supermium. Adding this $1extension is not allowed. - Your parent has turned off "Permissions for sites, apps and extensions" for Chromium. Enabling this $1extension is not allowed. + Your parent has turned off "Permissions for sites, apps and extensions" for Supermium. Enabling this $1extension is not allowed. @@ -1505,90 +1505,90 @@ Permissions you've already given to websites and apps may apply to this account. - With Chromium profiles you can separate all of your Chromium stuff. This makes it easier to split between work and fun. + With Supermium profiles you can separate all of your Supermium stuff. This makes it easier to split between work and fun. - To access your Chromium browser stuff across all your devices, sign in, then turn on sync + To access your Supermium browser stuff across all your devices, sign in, then turn on sync - Sign in to Chromium + Sign in to Supermium - Sign in to Chromium. If you want to sign in an account one-time only, you can <a id="guestModeLink" href="#">use the device as guest</a>. + Sign in to Supermium. If you want to sign in an account one-time only, you can <a id="guestModeLink" href="#">use the device as guest</a>. - Welcome to Chromium profiles + Welcome to Supermium profiles - - Who's using Chromium? + + Who's using Supermium? - With Chromium profiles you can separate all your Chromium stuff. Create profiles for friends and family, or split between work and fun. + With Supermium profiles you can separate all your Supermium stuff. Create profiles for friends and family, or split between work and fun. - To access your Chromium stuff across all your devices, sign in, then turn on sync. + To access your Supermium stuff across all your devices, sign in, then turn on sync. - Set up your new Chromium profile + Set up your new Supermium profile - Customize your Chromium profile + Customize your Supermium profile - Each profile holds its own Chromium info like bookmarks, history, passwords, and more + Each profile holds its own Supermium info like bookmarks, history, passwords, and more - If you share a device, friends and family can browse separately and set up Chromium just the way they want + If you share a device, friends and family can browse separately and set up Supermium just the way they want - Switch to existing Chromium profile? + Switch to existing Supermium profile? - A Chromium profile with this account already exists on this device + A Supermium profile with this account already exists on this device - - Welcome to Chromium, $1Jane + + Welcome to Supermium, $1Jane - - Welcome to Chromium + + Welcome to Supermium - - Get your Chromium browser stuff from $1Jane.Doe@gmail.com + + Get your Supermium browser stuff from $1Jane.Doe@gmail.com - Your account is managed by $1example.com. Your administrator can see and edit this Chromium browser profile and its data like bookmarks, history, and passwords. + Your account is managed by $1example.com. Your administrator can see and edit this Supermium browser profile and its data like bookmarks, history, and passwords. - Sign in to Chromium + desc="This string appears as a heading on a full-page screen that asks the user to sign in to Supermium with their Google Account. It appears when the user launches Supermium for the first time. When they sign in, they can personalize and customize Supermium and remember their settings in their Google Account. The tone should be inviting and alluring."> + Sign in to Supermium - Make Chromium your own + desc="This string appears as a heading on a full-page screen that asks the user to sign in to Supermium with their Google Account. It appears when the user launches Supermium for the first time. When they sign in, they can personalize and customize Supermium and remember their settings in their Google Account. The tone should be inviting and alluring."> + Make Supermium your own - Do more with Chromium + desc="This string appears as a heading on a full-page screen that tells users the benefits of signing in to Supermium. It appears when the user launches Supermium for the first time. When they sign in, they can personalize and customize Supermium and remember their settings in their Google Account. The tone should be inviting and alluring."> + Do more with Supermium - You can switch between Chromium profiles here + You can switch between Supermium profiles here - $1CTRL+SHIFT+M can switch between Chromium profiles + $1CTRL+SHIFT+M can switch between Supermium profiles - You can switch to see passwords from another Chromium profile + You can switch to see passwords from another Supermium profile @@ -1601,20 +1601,20 @@ Permissions you've already given to websites and apps may apply to this account. - Your changes will take effect the next time you relaunch Chromium. + Your changes will take effect the next time you relaunch Supermium. - Chromium needs Bluetooth access to continue pairing. $1Open Preferences + Supermium needs Bluetooth access to continue pairing. $1Open Preferences - Get Chromium's strongest security + Get Supermium's strongest security - Get Chromium's strongest security + Get Supermium's strongest security Enhanced protection does more to block phishing and malware @@ -1628,49 +1628,49 @@ Permissions you've already given to websites and apps may apply to this account. - Chromium is exploring new features that allow sites to deliver the same browsing experience using less of your info + Supermium is exploring new features that allow sites to deliver the same browsing experience using less of your info - You can see and remove topics of interest sites use to show you ads. Chromium estimates your interests based on your recent browsing history. + You can see and remove topics of interest sites use to show you ads. Supermium estimates your interests based on your recent browsing history. - Learn more about ad personalization in Chromium + Learn more about ad personalization in Supermium - - Your interests as estimated by Chromium + + Your interests as estimated by Supermium - - <b>What data is used:</b> Your browsing history, a record of sites you’ve visited using Chromium on this device. + + <b>What data is used:</b> Your browsing history, a record of sites you’ve visited using Supermium on this device. - - <b>How we use this data:</b> Chromium can estimate your interests. Later, a site you visit can ask Chromium to see your interests in order to personalize the ads you see. + + <b>How we use this data:</b> Supermium can estimate your interests. Later, a site you visit can ask Supermium to see your interests in order to personalize the ads you see. - - <b>How you can manage your data:</b> To protect your privacy, we auto-delete your interests that are older than 4 weeks. As you keep browsing, an interest might appear on the list again. Or you can remove interests you don’t want Chromium to consider. + + <b>How you can manage your data:</b> To protect your privacy, we auto-delete your interests that are older than 4 weeks. As you keep browsing, an interest might appear on the list again. Or you can remove interests you don’t want Supermium to consider. - - <b>What data is used:</b> Your browsing history, a record of sites you’ve visited using Chromium on this device. + + <b>What data is used:</b> Your browsing history, a record of sites you’ve visited using Supermium on this device. - <b>How we use this data:</b> Sites can store information with Chromium about your interests. For example, if you visit a site to buy shoes for a marathon, the site might define your interest as running marathons. Later, if you visit a different site to register for a race, that site can show you an ad for running shoes based on your interests. + <b>How we use this data:</b> Sites can store information with Supermium about your interests. For example, if you visit a site to buy shoes for a marathon, the site might define your interest as running marathons. Later, if you visit a different site to register for a race, that site can show you an ad for running shoes based on your interests. - You can change your mind at any time in Chromium settings. The trials run alongside the current way ads get served, so you won’t see changes right away. + You can change your mind at any time in Supermium settings. The trials run alongside the current way ads get served, so you won’t see changes right away. - Chromium is exploring new features that allow sites to deliver the same browsing experience using less of your info + Supermium is exploring new features that allow sites to deliver the same browsing experience using less of your info - During the trials, you can see and remove topics of interest sites use to show you ads. Chromium estimates your interests based on your recent browsing history. + During the trials, you can see and remove topics of interest sites use to show you ads. Supermium estimates your interests based on your recent browsing history. - You can learn more about these features in Chromium settings. + You can learn more about these features in Supermium settings. - Chromium + Supermium No update is available. @@ -1679,7 +1679,7 @@ Permissions you've already given to websites and apps may apply to this account. Installation failed. Please try again. - $1Chromium Installer + $1Supermium Installer Close @@ -1718,13 +1718,13 @@ Permissions you've already given to websites and apps may apply to this account. Canceling... - Thanks for installing. You must restart your browser before using $1Chromium. + Thanks for installing. You must restart your browser before using $1Supermium. - Thanks for installing. You must restart all your browsers before using $1Chromium. + Thanks for installing. You must restart all your browsers before using $1Supermium. - Thanks for installing. You must restart your computer before using $1Chromium. + Thanks for installing. You must restart your computer before using $1Supermium. Close @@ -1761,16 +1761,16 @@ Permissions you've already given to websites and apps may apply to this account. - Memory Saver Made Chromium Faster + Memory Saver Made Supermium Faster - Memory Saver made Chromium faster + Memory Saver made Supermium faster - While this tab was inactive, memory was freed up to keep Chromium fast. You can choose to always exclude this site from being inactive. + While this tab was inactive, memory was freed up to keep Supermium fast. You can choose to always exclude this site from being inactive. @@ -1778,15 +1778,15 @@ Permissions you've already given to websites and apps may apply to this account. - Make Chromium Faster + Make Supermium Faster - Make Chromium faster + Make Supermium faster - + \ No newline at end of file diff --git a/chrome/app/settings_chromium_strings.grdp b/chrome/app/settings_chromium_strings.grdp index 9a595a5b491fa..a323050c49dcc 100644 --- a/chrome/app/settings_chromium_strings.grdp +++ b/chrome/app/settings_chromium_strings.grdp @@ -1,10 +1,10 @@ - + - Relaunch Chromium? + Relaunch Supermium? @@ -19,25 +19,25 @@ - About Chromium + About Supermium - Get help with Chromium + Get help with Supermium - - Updating Chromium + + Updating Supermium - - Updating Chromium ($190%) + + Updating Supermium ($190%) - - Nearly up to date! Relaunch Chromium to finish updating. + + Nearly up to date! Relaunch Supermium to finish updating. - - Chromium is up to date + + Supermium is up to date @@ -53,52 +53,52 @@ - - Google Pay (copied to Chromium) + + Google Pay (copied to Supermium) - Chromium can't check your passwords. Try checking your internet connection. + Supermium can't check your passwords. Try checking your internet connection. - Chromium can check your passwords when you sign in with your Google Account + Supermium can check your passwords when you sign in with your Google Account - No saved passwords. Chromium can check your passwords when you save them. + No saved passwords. Supermium can check your passwords when you save them. - Chromium can't check your passwords. Try again after 24 hours or <a href="$1" target="_blank">check passwords in your Google Account</a>. + Supermium can't check your passwords. Try again after 24 hours or <a href="$1" target="_blank">check passwords in your Google Account</a>. - Chromium can't check your passwords. Try again after 24 hours. + Supermium can't check your passwords. Try again after 24 hours. - Chromium can't check your passwords. Try again later. + Supermium can't check your passwords. Try again later. - Chromium will notify you when you sign in with a compromised password + Supermium will notify you when you sign in with a compromised password - To check if your passwords are safe from data breaches and other security issues, <a target='_blank' href='$1'>sign in to Chromium</a>. + To check if your passwords are safe from data breaches and other security issues, <a target='_blank' href='$1'>sign in to Supermium</a>. - To check if your other passwords are safe from data breaches and other security issues, <a target='_blank' href='$1'>sign in to Chromium</a>. + To check if your other passwords are safe from data breaches and other security issues, <a target='_blank' href='$1'>sign in to Supermium</a>. - Weak passwords are easy to guess. Let Chromium <a target='_blank' href='$1'>create and remember strong passwords for you</a>. + Weak passwords are easy to guess. Let Supermium <a target='_blank' href='$1'>create and remember strong passwords for you</a>. - - If so, please edit your saved password in Chromium so it matches your new password. + + If so, please edit your saved password in Supermium so it matches your new password. - Chromium is your default browser + Supermium is your default browser - Make Chromium the default browser + Make Supermium the default browser - Chromium cannot determine or set the default browser + Supermium cannot determine or set the default browser @@ -108,7 +108,7 @@ - This is a secondary installation of Chromium, and cannot be made your default browser. + This is a secondary installation of Supermium, and cannot be made your default browser. @@ -116,218 +116,218 @@ - To fix spelling errors, Chromium sends the text you type in text fields to Google + To fix spelling errors, Supermium sends the text you type in text fields to Google - To apply your changes, relaunch Chromium + To apply your changes, relaunch Supermium - Allow Chromium sign-in + Allow Supermium sign-in - By turning this off, you can sign in to Google sites like Gmail without signing in to Chromium + By turning this off, you can sign in to Google sites like Gmail without signing in to Supermium - Open PDFs in Chromium + Open PDFs in Supermium - When on, you'll also be signed out of Chromium + When on, you'll also be signed out of Supermium - Sites will probably work as you expect but won't remember you after you close all Chromium windows + Sites will probably work as you expect but won't remember you after you close all Supermium windows - Always clear site data from your device when you close Chromium + Always clear site data from your device when you close Supermium - Review key privacy and security controls in Chromium + Review key privacy and security controls in Supermium - Checks URLs with a list of unsafe sites stored in Chromium + Checks URLs with a list of unsafe sites stored in Supermium - If a site tries to steal your password, or when you download a harmful file, Chromium may also send URLs, including bits of page content, to Safe Browsing + If a site tries to steal your password, or when you download a harmful file, Supermium may also send URLs, including bits of page content, to Safe Browsing - Chromium is exploring new features that allow sites to deliver the same browsing experience using less of your data + Supermium is exploring new features that allow sites to deliver the same browsing experience using less of your data - Choose whether to include Chromium history for more personalized experiences in Google services + Choose whether to include Supermium history for more personalized experiences in Google services - If you also share Chromium usage reports, those reports include the URLs you visit + If you also share Supermium usage reports, those reports include the URLs you visit - Your interests as estimated by Chromium + Your interests as estimated by Supermium - Your browsing history, a record of sites you've visited using Chromium on this device. + Your browsing history, a record of sites you've visited using Supermium on this device. - Chromium can estimate your interests. Later, a site you visit can ask Chromium to see your interests in order to personalize the ads you see. + Supermium can estimate your interests. Later, a site you visit can ask Supermium to see your interests in order to personalize the ads you see. - To protect your privacy, we auto-delete your interests that are older than 4 weeks. As you keep browsing, an interest might appear on the list again. Or you can remove interests you don't want Chromium to consider. + To protect your privacy, we auto-delete your interests that are older than 4 weeks. As you keep browsing, an interest might appear on the list again. Or you can remove interests you don't want Supermium to consider. - Your browsing history, a record of sites you've visited using Chromium on this device. + Your browsing history, a record of sites you've visited using Supermium on this device. - Sites can store information with Chromium about your interests. For example, if you visit a site to buy shoes for a marathon, the site might define your interest as running marathons. Later, if you visit a different site to register for a race, that site can show you an ad for running shoes based on your interests. + Sites can store information with Supermium about your interests. For example, if you visit a site to buy shoes for a marathon, the site might define your interest as running marathons. Later, if you visit a different site to register for a race, that site can show you an ad for running shoes based on your interests. - Your browsing history affects the ads you see and the interests as estimated below. To protect your privacy, Chromium auto-deletes your interests on a rolling basis each month. Interests can refresh unless you remove them. + Your browsing history affects the ads you see and the interests as estimated below. To protect your privacy, Supermium auto-deletes your interests on a rolling basis each month. Interests can refresh unless you remove them. - When trials are on and if Chromium has randomly placed you in an active trial, your browsing history affects the ads you see and the interests as estimated below. To protect your privacy, Chromium deletes your interests on a rolling basis each month. + When trials are on and if Supermium has randomly placed you in an active trial, your browsing history affects the ads you see and the interests as estimated below. To protect your privacy, Supermium deletes your interests on a rolling basis each month. - If Chromium has randomly placed you in an active trial, your browsing history affects the ads you see and the interests as estimated below. To protect your privacy, Chromium deletes your interests on a rolling basis each month. Interests refresh unless you remove them. + If Supermium has randomly placed you in an active trial, your browsing history affects the ads you see and the interests as estimated below. To protect your privacy, Supermium deletes your interests on a rolling basis each month. Interests refresh unless you remove them. - Your interests as estimated by Chromium + Your interests as estimated by Supermium - Chromium can estimate your interests based on your browsing history from the last few weeks. This info stays on your device. + Supermium can estimate your interests based on your browsing history from the last few weeks. This info stays on your device. - Later, a site you visit can ask Chromium to see your interests in order to personalize the ads you see. Chromium can share up to 3 interests. + Later, a site you visit can ask Supermium to see your interests in order to personalize the ads you see. Supermium can share up to 3 interests. - To protect your privacy, we auto-delete your interests that are older than 4 weeks. As you keep browsing, an interest might appear on the list again. And if Chromium gets it wrong or you don't want to see certain ads, you can remove an interest. + To protect your privacy, we auto-delete your interests that are older than 4 weeks. As you keep browsing, an interest might appear on the list again. And if Supermium gets it wrong or you don't want to see certain ads, you can remove an interest. - It's common for sites you visit to remember things you're interested in, to personalize your experience. Sites can also store information with Chromium about your interests. + It's common for sites you visit to remember things you're interested in, to personalize your experience. Sites can also store information with Supermium about your interests. - Ad measurement allows sites you visit to request information from Chromium that helps the site measure the performance of their ads. Ad measurement restricts cross-site tracking by transferring as little information as possible between sites. + Ad measurement allows sites you visit to request information from Supermium that helps the site measure the performance of their ads. Ad measurement restricts cross-site tracking by transferring as little information as possible between sites. - When trials are on, Ad measurement allows sites you visit to request information from Chromium that helps the site measure the performance of their ads. Ad measurement restricts cross-site tracking by transferring as little information as possible between sites. + When trials are on, Ad measurement allows sites you visit to request information from Supermium that helps the site measure the performance of their ads. Ad measurement restricts cross-site tracking by transferring as little information as possible between sites. - Chromium can help keep you safe from data breaches, bad extensions, and more + Supermium can help keep you safe from data breaches, bad extensions, and more - - Chromium can't check for updates. Try checking your internet connection. + + Supermium can't check for updates. Try checking your internet connection. - - Chromium didn't update, something went wrong. <a target="_blank" href="$1">Fix Chromium update problems and failed updates.</a> + + Supermium didn't update, something went wrong. <a target="_blank" href="$1">Fix Supermium update problems and failed updates.</a> - - Chromium version $115.0.865.0 is installed + + Supermium version $115.0.865.0 is installed - Chromium can't check your passwords because you're not signed in + Supermium can't check your passwords because you're not signed in - Safe Browsing is off. Chromium recommends turning it on. + Safe Browsing is off. Supermium recommends turning it on. - Keeps you safe on Chromium and may be used to improve your security in other Google apps when you are signed in + Keeps you safe on Supermium and may be used to improve your security in other Google apps when you are signed in - Checks URLs with a list of unsafe sites stored in Chromium. If a site tries to steal your password, or when you download a harmful file, Chromium may also send URLs, including bits of page content, to Safe Browsing. + Checks URLs with a list of unsafe sites stored in Supermium. If a site tries to steal your password, or when you download a harmful file, Supermium may also send URLs, including bits of page content, to Safe Browsing. - This will delete 1 item from this device. To retrieve your data later, sign in to Chromium as $1foo@example.com. + This will delete 1 item from this device. To retrieve your data later, sign in to Supermium as $1foo@example.com. - This will delete $166 items from this device. To retrieve your data later, sign in to Chromium as $2foo@example.com. + This will delete $166 items from this device. To retrieve your data later, sign in to Supermium as $2foo@example.com. - This will delete your browsing data from this device. To retrieve your data later, sign in to Chromium as $1foo@example.com. + This will delete your browsing data from this device. To retrieve your data later, sign in to Supermium as $1foo@example.com. - Customize your Chromium profile + Customize your Supermium profile - Name your Chromium profile + Name your Supermium profile - - Sync and personalize Chromium across your devices + + Sync and personalize Supermium across your devices - You can manage your signed-in Google Accounts. Your Google Accounts are used for Chromium browser, Play Store, Gmail, and more. If you want to add an account for someone else, like a family member, add a new person to your $1Chromebook instead. <a>Learn more</a> + You can manage your signed-in Google Accounts. Your Google Accounts are used for Supermium browser, Play Store, Gmail, and more. If you want to add an account for someone else, like a family member, add a new person to your $1Chromebook instead. <a>Learn more</a> - For added security, Chromium will encrypt your data. + For added security, Supermium will encrypt your data. - Sign out of Chromium? + Sign out of Supermium? - When you type in the address bar or search box, Chromium sends what you type to your default search engine to get better suggestions. This is off in Incognito. + When you type in the address bar or search box, Supermium sends what you type to your default search engine to get better suggestions. This is off in Incognito. - When you type in the address bar or search box, Chromium sends what you type to Google Drive to get item suggestions. This is off in Incognito. + When you type in the address bar or search box, Supermium sends what you type to Google Drive to get item suggestions. This is off in Incognito. - - Sign in to sync and personalize Chromium across your devices + + Sign in to sync and personalize Supermium across your devices - When on, Chromium frees up memory from inactive tabs. This gives active tabs and other apps more computer resources and keeps Chromium fast. Your inactive tabs automatically become active again when you go back to them. + When on, Supermium frees up memory from inactive tabs. This gives active tabs and other apps more computer resources and keeps Supermium fast. Your inactive tabs automatically become active again when you go back to them. - When on, Chromium conserves battery power by limiting background activity and visual effects, such as smooth scrolling and video frame rates. + When on, Supermium conserves battery power by limiting background activity and visual effects, such as smooth scrolling and video frame rates. - This language is used to display the Chromium UI + This language is used to display the Supermium UI - Display Chromium in this language + Display Supermium in this language - Continue running background apps when Chromium is closed + Continue running background apps when Supermium is closed - Help make Chromium better by reporting the <a is="action-link" target="_blank">current settings</a> + Help make Supermium better by reporting the <a is="action-link" target="_blank">current settings</a> - Certificates managed by Chromium + Certificates managed by Supermium - Information about how Chromium manages its root certificates + Information about how Supermium manages its root certificates - + \ No newline at end of file diff --git a/chrome/app/theme/chromium/BRANDING b/chrome/app/theme/chromium/BRANDING index f8363d5b294fe..2c43477b3f324 100644 --- a/chrome/app/theme/chromium/BRANDING +++ b/chrome/app/theme/chromium/BRANDING @@ -1,10 +1,10 @@ -COMPANY_FULLNAME=The Chromium Authors -COMPANY_SHORTNAME=The Chromium Authors -PRODUCT_FULLNAME=Chromium -PRODUCT_SHORTNAME=Chromium -PRODUCT_INSTALLER_FULLNAME=Chromium Installer -PRODUCT_INSTALLER_SHORTNAME=Chromium Installer -COPYRIGHT=Copyright @LASTCHANGE_YEAR@ The Chromium Authors. All rights reserved. +COMPANY_FULLNAME=win32 +COMPANY_SHORTNAME=win32 +PRODUCT_FULLNAME=Supermium +PRODUCT_SHORTNAME=Supermium +PRODUCT_INSTALLER_FULLNAME=Supermium Installer +PRODUCT_INSTALLER_SHORTNAME=Supermium Installer +COPYRIGHT=Copyright @LASTCHANGE_YEAR@ Shane Fournier. All rights reserved. MAC_BUNDLE_ID=org.chromium.Chromium MAC_CREATOR_CODE=Cr24 MAC_TEAM_ID= diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index 5c5154be22b2a..e2ce0038d2bc7 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc @@ -4380,6 +4380,13 @@ std::string ChromeContentBrowserClient::GetDefaultDownloadName() { return l10n_util::GetStringUTF8(IDS_DEFAULT_DOWNLOAD_FILENAME); } +base::FilePath ChromeContentBrowserClient::GetFontLookupTableCacheDir() { + base::FilePath user_data_dir; + base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); + DCHECK(!user_data_dir.empty()); + return user_data_dir.Append(FILE_PATH_LITERAL("FontLookupTableCache")); +} + base::FilePath ChromeContentBrowserClient::GetShaderDiskCacheDirectory() { base::FilePath user_data_dir; base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h index 88b50cb7b7b62..e7a28398d5c06 100644 --- a/chrome/browser/chrome_content_browser_client.h +++ b/chrome/browser/chrome_content_browser_client.h @@ -421,6 +421,7 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient { void BrowserURLHandlerCreated(content::BrowserURLHandler* handler) override; base::FilePath GetDefaultDownloadDirectory() override; std::string GetDefaultDownloadName() override; + base::FilePath GetFontLookupTableCacheDir() override; base::FilePath GetShaderDiskCacheDirectory() override; base::FilePath GetGrShaderDiskCacheDirectory() override; base::FilePath GetGraphiteDawnDiskCacheDirectory() override; diff --git a/chrome/browser/device_reauth/win/authenticator_win.cc b/chrome/browser/device_reauth/win/authenticator_win.cc index 672c1e936d8a6..3a2f414b06f67 100644 --- a/chrome/browser/device_reauth/win/authenticator_win.cc +++ b/chrome/browser/device_reauth/win/authenticator_win.cc @@ -45,6 +45,11 @@ using ABI::Windows::Security::Credentials::UI:: UserConsentVerifierAvailability_NotConfiguredForUser; using Microsoft::WRL::ComPtr; +bool ResolveCoreWinRT() { + return base::win::ResolveCoreWinRTDelayload() && + base::win::ScopedHString::ResolveCoreWinRTStringDelayload(); +} + BiometricAuthenticationStatusWin ConvertUserConsentVerifierAvailability( UserConsentVerifierAvailability availability) { switch (availability) { @@ -93,6 +98,11 @@ void GetBiometricAvailabilityFromWindows( // (http://crbug/973868). SCOPED_MAY_LOAD_LIBRARY_AT_BACKGROUND_PRIORITY(); + if (!ResolveCoreWinRT()) { + ReportCantCheckAvailability(thread, std::move(callback)); + return; + } + ComPtr factory; HRESULT hr = base::win::GetActivationFactory< IUserConsentVerifierStatics, diff --git a/chrome/browser/enterprise/platform_auth/cloud_ap_provider_win.cc b/chrome/browser/enterprise/platform_auth/cloud_ap_provider_win.cc index cfe13c30f9758..204edde196be8 100644 --- a/chrome/browser/enterprise/platform_auth/cloud_ap_provider_win.cc +++ b/chrome/browser/enterprise/platform_auth/cloud_ap_provider_win.cc @@ -88,6 +88,11 @@ class WebAccountSupportFinder DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); base::win::AssertComApartmentType(base::win::ComApartmentType::MTA); + if (!base::win::ResolveCoreWinRTDelayload()) + return; // Unsupported. + if (!base::win::ScopedHString::ResolveCoreWinRTStringDelayload()) + return; // Unsupported. + // Get the `WebAuthenticationCoreManager`. ComPtr auth_manager; HRESULT hresult = base::win::GetActivationFactory< diff --git a/chrome/browser/notifications/notification_platform_bridge_win.cc b/chrome/browser/notifications/notification_platform_bridge_win.cc index 5bb38415f8739..872790bfc060d 100644 --- a/chrome/browser/notifications/notification_platform_bridge_win.cc +++ b/chrome/browser/notifications/notification_platform_bridge_win.cc @@ -702,7 +702,7 @@ class NotificationPlatformBridgeWinImpl InstallUtil::IsStartMenuShortcutWithActivatorGuidInstalled(); int status = static_cast(SetReadyCallbackStatus::kSuccess); - bool enabled = activator_registered && shortcut_installed; + bool enabled = base::win::ResolveCoreWinRTDelayload() && ScopedHString::ResolveCoreWinRTStringDelayload() && activator_registered && shortcut_installed; if (!enabled) { if (!shortcut_installed) { @@ -713,6 +713,8 @@ class NotificationPlatformBridgeWinImpl status |= static_cast( SetReadyCallbackStatus::kComServerMisconfiguration); } + if (!(base::win::ResolveCoreWinRTDelayload() && ScopedHString::ResolveCoreWinRTStringDelayload())) + status |= static_cast(SetReadyCallbackStatus::kComNotInitialized); } LogSetReadyCallbackStatus(static_cast(status)); diff --git a/chrome/browser/notifications/win/notification_metrics.h b/chrome/browser/notifications/win/notification_metrics.h index 8dfbaea83d66c..aab0938792430 100644 --- a/chrome/browser/notifications/win/notification_metrics.h +++ b/chrome/browser/notifications/win/notification_metrics.h @@ -137,8 +137,8 @@ enum class SetReadyCallbackStatus { kSuccess = 0, kShortcutMisconfiguration = 1 << 0, kComServerMisconfiguration = 1 << 1, - kComNotInitializedObsolete = 1 << 2, // No longer possible w/ Win10+ only. - kMaxValue = kComNotInitializedObsolete, + kComNotInitialized = 1 << 2, + kMaxValue = kComNotInitialized, }; // These values are persisted to logs. Entries should not be renumbered and diff --git a/chrome/browser/obsolete_system/obsolete_system_win.cc b/chrome/browser/obsolete_system/obsolete_system_win.cc index eb373d6316c13..9e36da7040451 100644 --- a/chrome/browser/obsolete_system/obsolete_system_win.cc +++ b/chrome/browser/obsolete_system/obsolete_system_win.cc @@ -22,16 +22,12 @@ base::win::Version GetRealOSVersion() { return base::win::OSInfo::Kernel32Version(); } -bool IsObsoleteOsVersion() { - return GetRealOSVersion() < base::win::Version::WIN10; -} - } // namespace namespace ObsoleteSystem { bool IsObsoleteNowOrSoon() { - return IsObsoleteOsVersion(); + return false; } std::u16string LocalizedObsoleteString() { @@ -52,7 +48,7 @@ bool IsEndOfTheLine() { // M109 was the last milestone to support Win 7/8/8.1, the last deprecated // Windows version. Future deprecations should update this to the last // milestone that supports the soon-to-be-deprecated Windows version. - return CHROME_VERSION_MAJOR >= 109; + return false; } const char* GetLinkURL() { diff --git a/chrome/browser/webshare/win/fake_storage_file_statics.cc b/chrome/browser/webshare/win/fake_storage_file_statics.cc index 6308ccec3a576..f17033b2d1ec7 100644 --- a/chrome/browser/webshare/win/fake_storage_file_statics.cc +++ b/chrome/browser/webshare/win/fake_storage_file_statics.cc @@ -9,7 +9,6 @@ #include #include -#include #include #include "base/functional/bind.h" @@ -279,6 +278,13 @@ IFACEMETHODIMP FakeStorageFileStatics::CreateStreamedFileAsync( IStreamedFileDataRequestedHandler* data_requested, IRandomAccessStreamReference* thumbnail, IAsyncOperation** operation) { + + if (!base::win::ScopedHString::ResolveCoreWinRTStringDelayload()) { + ADD_FAILURE() << "Attempted to use FakeStorageFileStatics in an " + "environment that doesn't support ScopedHStrings."; + return E_UNEXPECTED; + } + auto fake_iasync_operation = Make>(); HRESULT hr = fake_iasync_operation->QueryInterface(IID_PPV_ARGS(operation)); diff --git a/chrome/browser/webshare/win/share_operation.cc b/chrome/browser/webshare/win/share_operation.cc index 5f7e0771fbce3..2fa7f7b461645 100644 --- a/chrome/browser/webshare/win/share_operation.cc +++ b/chrome/browser/webshare/win/share_operation.cc @@ -369,6 +369,13 @@ void ShareOperation::Run(blink::mojom::ShareService::ShareCallback callback) { DCHECK(!callback_); callback_ = std::move(callback); + // Ensure that the required WinRT functionality is available/loaded. + if (!base::win::ResolveCoreWinRTDelayload() || + !base::win::ScopedHString::ResolveCoreWinRTStringDelayload()) { + Complete(blink::mojom::ShareError::INTERNAL_ERROR); + return; + } + // If the corresponding web_contents have already been cleaned up, cancel // the operation. if (!web_contents_) { diff --git a/chrome/browser/webshare/win/show_share_ui_for_window_operation.cc b/chrome/browser/webshare/win/show_share_ui_for_window_operation.cc index 15f2def437648..021f9f2b55471 100644 --- a/chrome/browser/webshare/win/show_share_ui_for_window_operation.cc +++ b/chrome/browser/webshare/win/show_share_ui_for_window_operation.cc @@ -40,6 +40,12 @@ HRESULT GetDataTransferManagerHandles( HWND hwnd, IDataTransferManagerInterop** data_transfer_manager_interop, IDataTransferManager** data_transfer_manager) { + + if (!base::win::ResolveCoreWinRTDelayload() || + !base::win::ScopedHString::ResolveCoreWinRTStringDelayload()) { + return E_FAIL; + } + // IDataTransferManagerInterop is semi-hidden behind a CloakedIid // structure on the DataTransferManager, excluding it from things // used by RoGetActivationFactory like GetIids(). Because of this, diff --git a/chrome/browser/win/titlebar_config.cc b/chrome/browser/win/titlebar_config.cc index 92d0e8165a264..d0b41c4ea5441 100644 --- a/chrome/browser/win/titlebar_config.cc +++ b/chrome/browser/win/titlebar_config.cc @@ -4,21 +4,48 @@ #include "chrome/browser/win/titlebar_config.h" +#include +#include "base/command_line.h" #include "base/win/windows_version.h" #include "chrome/browser/themes/theme_service.h" #include "chrome/browser/themes/theme_service_factory.h" #include "chrome/browser/ui/views/frame/browser_view.h" +#include "chrome/common/chrome_switches.h" #include "ui/color/win/accent_color_observer.h" #include "ui/native_theme/native_theme.h" -// Allows the titlebar to be drawn by the system using the Mica material -// on Windows 11, version 22H2 and above. -BASE_FEATURE(kWindows11MicaTitlebar, - "Windows11MicaTitlebar", - base::FEATURE_DISABLED_BY_DEFAULT); +bool ShouldCustomDrawSystemTitlebar() { + // Some extra code added here because those with pre-win8 and no DWM will have to fallback on the custom titlebar. + BOOL result = FALSE; + + typedef HRESULT(WINAPI* DwmIsCompositionEnabledFunc)(BOOL* enabled); + DwmIsCompositionEnabledFunc func_ = nullptr; + + HMODULE dwmapi_library_ = LoadLibraryW(L"dwmapi.dll"); + if (dwmapi_library_) { + func_ = reinterpret_cast( + GetProcAddress(dwmapi_library_, "DwmIsCompositionEnabled")); + } + else + return true; + + if (func_) { + func_(&result); + } + else + return true; + // Cache flag lookup. + static const bool custom_titlebar_disabled = + base::CommandLine::InitializedForCurrentProcess() && + base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableWindows10CustomTitlebar); + + return (!custom_titlebar_disabled && + base::win::GetVersion() >= base::win::Version::WIN10) || !result; +} bool ShouldBrowserCustomDrawTitlebar(BrowserView* browser_view) { - return !ShouldDefaultThemeUseMicaTitlebar() || + return ShouldCustomDrawSystemTitlebar() || !ThemeServiceFactory::GetForProfile(browser_view->GetProfile()) ->UsingSystemTheme() || (!browser_view->browser()->is_type_normal() && @@ -26,6 +53,7 @@ bool ShouldBrowserCustomDrawTitlebar(BrowserView* browser_view) { !browser_view->browser()->is_type_devtools()); } + bool ShouldDefaultThemeUseMicaTitlebar() { return SystemTitlebarCanUseMicaMaterial() && !ui::AccentColorObserver::Get()->accent_color().has_value() && @@ -34,6 +62,13 @@ bool ShouldDefaultThemeUseMicaTitlebar() { } bool SystemTitlebarCanUseMicaMaterial() { - return base::win::GetVersion() >= base::win::Version::WIN11_22H2 && - base::FeatureList::IsEnabled(kWindows11MicaTitlebar); + return false; } + +bool ShouldBrowserUseMicaTitlebar(class BrowserView *) { + return false; +} + +bool SystemTitlebarSupportsDarkMode() { + return base::win::GetVersion() >= base::win::Version::WIN11; +} \ No newline at end of file diff --git a/chrome/chrome_elf/chrome_elf_security.cc b/chrome/chrome_elf/chrome_elf_security.cc index ea44babfb52ea..045b3a6221712 100644 --- a/chrome/chrome_elf/chrome_elf_security.cc +++ b/chrome/chrome_elf/chrome_elf_security.cc @@ -82,6 +82,7 @@ class ExtensionPointDisableSet { } // namespace void EarlyBrowserSecurity() { + typedef decltype(SetProcessMitigationPolicy)* SetProcessMitigationPolicyFunc; // This function is called from within DllMain. // Don't do anything naughty while we have the loader lock. NTSTATUS ret_val = STATUS_SUCCESS; @@ -105,12 +106,20 @@ void EarlyBrowserSecurity() { nt::CloseRegKey(handle); - // Disable extension points (legacy hooking) in this process. - PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY policy = {}; - policy.DisableExtensionPoints = true; - SetProcessMitigationPolicy(ProcessExtensionPointDisablePolicy, &policy, - sizeof(policy)); - ExtensionPointDisableSet::GetInstance()->SetExtensionPointDisabled(true); + if (::IsWindows8OrGreater()) { + SetProcessMitigationPolicyFunc set_process_mitigation_policy = + reinterpret_cast(::GetProcAddress( + ::GetModuleHandleW(L"kernel32.dll"), "SetProcessMitigationPolicy")); + if (set_process_mitigation_policy) { + // Disable extension points in this process. + // (Legacy hooking.) + PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY policy = {}; + policy.DisableExtensionPoints = true; + set_process_mitigation_policy(ProcessExtensionPointDisablePolicy, &policy, + sizeof(policy)); + ExtensionPointDisableSet::GetInstance()->SetExtensionPointDisabled(true); + } + } return; } diff --git a/chrome/chrome_elf/chrome_elf_util_unittest.cc b/chrome/chrome_elf/chrome_elf_util_unittest.cc index 5ee09effb6e03..3af5789ad6185 100644 --- a/chrome/chrome_elf/chrome_elf_util_unittest.cc +++ b/chrome/chrome_elf/chrome_elf_util_unittest.cc @@ -4,6 +4,8 @@ #include +#include // windows.h must be before. + #include #include "base/test/test_reg_util_win.h" @@ -37,14 +39,28 @@ bool SetExtensionPointEnabledFlag(bool creation) { } bool IsSecuritySet() { - // Check that extension points are disabled. (Legacy hooking.) - PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY policy = {}; - if (!::GetProcessMitigationPolicy(::GetCurrentProcess(), - ProcessExtensionPointDisablePolicy, &policy, - sizeof(policy))) { - return false; + typedef decltype(GetProcessMitigationPolicy)* GetProcessMitigationPolicyFunc; + + // Check the settings from EarlyBrowserSecurity(). + if (::IsWindows8OrGreater()) { + GetProcessMitigationPolicyFunc get_process_mitigation_policy = + reinterpret_cast(::GetProcAddress( + ::GetModuleHandleW(L"kernel32.dll"), "GetProcessMitigationPolicy")); + if (!get_process_mitigation_policy) + return false; + + // Check that extension points are disabled. + // (Legacy hooking.) + PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY policy = {}; + if (!get_process_mitigation_policy(::GetCurrentProcess(), + ProcessExtensionPointDisablePolicy, + &policy, sizeof(policy))) + return false; + + return policy.DisableExtensionPoints; } - return policy.DisableExtensionPoints; + + return true; } void RegRedirect(nt::ROOT_KEY key, @@ -70,6 +86,9 @@ void CancelRegRedirect(nt::ROOT_KEY key) { } TEST(ChromeElfUtilTest, ValidateExtensionPointCallComesFromDLL) { + + if (!::IsWindows8OrGreater()) + return; // We should validate the exe version isn't used for this test elf_security::ValidateExeForTesting(true); @@ -78,6 +97,8 @@ TEST(ChromeElfUtilTest, ValidateExtensionPointCallComesFromDLL) { } TEST(ChromeElfUtilTest, BrowserProcessSecurityTest) { + if (!::IsWindows8OrGreater()) + return; // Set up registry override for this test. registry_util::RegistryOverrideManager override_manager; ASSERT_NO_FATAL_FAILURE(RegRedirect(nt::HKCU, &override_manager)); diff --git a/chrome/installer/setup/install.cc b/chrome/installer/setup/install.cc index 4ab0037456c8c..f459966796cf0 100644 --- a/chrome/installer/setup/install.cc +++ b/chrome/installer/setup/install.cc @@ -27,6 +27,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/time/time.h" #include "base/win/shortcut.h" +#include "base/win/windows_version.h" #include "chrome/install_static/install_details.h" #include "chrome/install_static/install_util.h" #include "chrome/installer/setup/install_params.h" @@ -134,6 +135,7 @@ void ExecuteAndLogShortcutOperation( // For Start Menu shortcut creation on versions of Win10 that support // pinning, record whether or not the installer pinned Chrome. if (location == ShellUtil::SHORTCUT_LOCATION_START_MENU_ROOT && + base::win::GetVersion() >= base::win::Version::WIN10 && CanPinShortcutToTaskbar()) { SetInstallerPinnedChromeToTaskbar(properties.pin_to_taskbar && pinned); } diff --git a/chrome/installer/util/install_util.cc b/chrome/installer/util/install_util.cc index 5efc79e743383..1bf0bf47f68e4 100644 --- a/chrome/installer/util/install_util.cc +++ b/chrome/installer/util/install_util.cc @@ -242,10 +242,10 @@ base::Version InstallUtil::GetCriticalUpdateVersion() { } bool InstallUtil::IsOSSupported() { - // We do not support anything prior to Windows 10. + // We do not support anything prior to Windows Vista. VLOG(1) << base::SysInfo::OperatingSystemName() << ' ' << base::SysInfo::OperatingSystemVersion(); - return base::win::GetVersion() >= base::win::Version::WIN10; + return base::win::GetVersion() >= base::win::Version::VISTA; } void InstallUtil::AddInstallerResultItems(bool system_install, diff --git a/chrome/installer/util/shell_util.cc b/chrome/installer/util/shell_util.cc index d32b663370c0a..f2d16697a2c9b 100644 --- a/chrome/installer/util/shell_util.cc +++ b/chrome/installer/util/shell_util.cc @@ -298,12 +298,13 @@ void GetProgIdEntries(const ShellUtil::ApplicationInfo& app_info, entries->back()->set_removal_flag(RegistryEntry::RemovalFlag::VALUE); } - // The following entries are required but do not depend on the DelegateExecute - // verb handler being set. - if (!app_info.app_id.empty()) { - entries->push_back(std::make_unique( - prog_id_path, ShellUtil::kRegAppUserModelId, app_info.app_id)); - } + // The following entries are required as of Windows 8, but do not + // depend on the DelegateExecute verb handler being set. + if (base::win::GetVersion() >= base::win::Version::WIN8) { + if (!app_info.app_id.empty()) { + entries->push_back(std::make_unique( + prog_id_path, ShellUtil::kRegAppUserModelId, app_info.app_id)); + } // Add \Software\Classes\\Application entries std::wstring application_path(prog_id_path + ShellUtil::kRegApplication); @@ -333,6 +334,7 @@ void GetProgIdEntries(const ShellUtil::ApplicationInfo& app_info, app_info.publisher_name)); } } +} // This method returns a list of all the registry entries that are needed to // register this installation's ProgId and AppId. These entries need to be @@ -747,11 +749,12 @@ bool QuickIsChromeRegisteredForMode( } reg_key += ShellUtil::kRegShellOpen; - // ProgId and shell integration registrations are allowed to reside in HKCU - // for user-level installs, and values there have priority over values in - // HKLM. + // ProgId registrations are allowed to reside in HKCU for user-level installs + // (and values there have priority over values in HKLM). The same is true for + // shell integration entries as of Windows 8. if (confirmation_level == CONFIRM_PROGID_REGISTRATION || - confirmation_level == CONFIRM_SHELL_REGISTRATION) { + (confirmation_level == CONFIRM_SHELL_REGISTRATION && + base::win::GetVersion() >= base::win::Version::WIN8)) { const RegKey key_hkcu(HKEY_CURRENT_USER, reg_key.c_str(), KEY_QUERY_VALUE); std::wstring hkcu_value; // If |reg_key| is present in HKCU, assert that it points to |chrome_exe|. @@ -826,7 +829,9 @@ bool GetInstallationSpecificSuffix(const base::FilePath& chrome_exe, // be placed for this install. As of Windows 8 everything can go in HKCU for // per-user installs. HKEY DetermineRegistrationRoot(bool is_per_user) { - return is_per_user ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE; + return is_per_user && base::win::GetVersion() >= base::win::Version::WIN8 + ? HKEY_CURRENT_USER + : HKEY_LOCAL_MACHINE; } // Associates Chrome with supported protocols and file associations. This should @@ -1045,6 +1050,7 @@ ShellUtil::DefaultState ProbeProtocolHandlers(const base::FilePath& chrome_exe, // Returns true on success. bool GetAppShortcutsFolder(ShellUtil::ShellChange level, base::FilePath* path) { DCHECK(path); + DCHECK_GE(base::win::GetVersion(), base::win::Version::WIN8); base::FilePath folder; if (!base::PathService::Get(base::DIR_APP_SHORTCUTS, &folder)) { @@ -1426,6 +1432,7 @@ bool RegisterChromeBrowserImpl(const base::FilePath& chrome_exe, bool RegisterApplicationForProtocols(const std::vector& protocols, const std::wstring& prog_id, const base::FilePath& chrome_exe) { + DCHECK_GT(base::win::GetVersion(), base::win::Version::WIN7); std::vector> entries; ShellUtil::ApplicationInfo app_info = ShellUtil::GetApplicationInfoForProgId(prog_id); @@ -1788,10 +1795,12 @@ bool ShellUtil::ShortcutLocationIsSupported(ShortcutLocation location) { case SHORTCUT_LOCATION_START_MENU_ROOT: // Falls through. case SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED: // Falls through. case SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR: // Falls through. - case SHORTCUT_LOCATION_STARTUP: // Falls through. - case SHORTCUT_LOCATION_TASKBAR_PINS: // Falls through. - case SHORTCUT_LOCATION_APP_SHORTCUTS: + case SHORTCUT_LOCATION_STARTUP: return true; + case SHORTCUT_LOCATION_TASKBAR_PINS: + return base::win::GetVersion() >= base::win::Version::WIN7; + case SHORTCUT_LOCATION_APP_SHORTCUTS: + return base::win::GetVersion() >= base::win::Version::WIN8; default: NOTREACHED(); return false; @@ -2812,16 +2821,19 @@ bool ShellUtil::AddAppProtocolAssociations( if (!AddRegistryEntries(HKEY_CURRENT_USER, entries)) success = false; - // Removing the existing user choice for a given protocol forces Windows to - // present a disambiguation dialog the next time this protocol is invoked - // from the OS. - std::unique_ptr entry = GetProtocolUserChoiceEntry(protocol); - if (!installer::DeleteRegistryValue(HKEY_CURRENT_USER, entry->key_path(), - WorkItem::kWow64Default, kRegProgId)) { - success = false; + // On Windows 10, removing the existing user choice for a given protocol + // forces Windows to present a disambiguation dialog the next time this + // protocol is invoked from the OS. + if (base::win::GetVersion() >= base::win::Version::WIN10) { + std::unique_ptr entry = + GetProtocolUserChoiceEntry(protocol); + if (!installer::DeleteRegistryValue(HKEY_CURRENT_USER, entry->key_path(), + WorkItem::kWow64Default, + kRegProgId)) { + success = false; + } } } - return success; } diff --git a/chrome/services/util_win/processor_metrics.cc b/chrome/services/util_win/processor_metrics.cc index 4852a753e5edf..8d58fc54c7add 100644 --- a/chrome/services/util_win/processor_metrics.cc +++ b/chrome/services/util_win/processor_metrics.cc @@ -108,17 +108,21 @@ void RecordCetAvailability() { ::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), "IsUserCetAvailableInEnvironment")); + auto get_process_mitigation_policy = + reinterpret_cast(::GetProcAddress( + ::GetModuleHandleW(L"kernel32.dll"), "GetProcessMitigationPolicy")); + if (is_user_cet_available_in_environment) { available = is_user_cet_available_in_environment( USER_CET_ENVIRONMENT_WIN32_PROCESS); } base::UmaHistogramBoolean("Windows.CetAvailable", available); - if (available) { + if (available && get_process_mitigation_policy) { PROCESS_MITIGATION_USER_SHADOW_STACK_POLICY policy = {0}; - if (::GetProcessMitigationPolicy(GetCurrentProcess(), - ProcessUserShadowStackPolicy, &policy, - sizeof(policy))) { + if (get_process_mitigation_policy(GetCurrentProcess(), + ProcessUserShadowStackPolicy, &policy, + sizeof(policy))) { base::UmaHistogramBoolean("Windows.CetEnabled", policy.EnableUserShadowStack); } diff --git a/chrome/updater/net/network_fetcher_win.cc b/chrome/updater/net/network_fetcher_win.cc index e28cbd8a7d622..9f24a413ca90a 100644 --- a/chrome/updater/net/network_fetcher_win.cc +++ b/chrome/updater/net/network_fetcher_win.cc @@ -19,8 +19,10 @@ #include "base/memory/scoped_refptr.h" #include "base/sequence_checker.h" #include "base/strings/sys_string_conversions.h" +#include "base/win/windows_version.h" #include "chrome/updater/policy/service.h" #include "chrome/updater/util/win_util.h" +#include "chrome/updater/win/scoped_impersonation.h" #include "chrome/updater/win/user_info.h" #include "components/update_client/network.h" #include "components/winhttp/network_fetcher.h" @@ -31,6 +33,56 @@ namespace updater { namespace { + + std::wstring FromCharOrEmpty(const wchar_t* str) { + return str ? std::wstring(str) : std::wstring(); +} + +// Wrapper for WINHTTP_CURRENT_USER_IE_PROXY_CONFIG structure. +// According to MSDN, callers must free strings with GlobalFree. +class ScopedIeProxyConfig { + public: + ScopedIeProxyConfig(); + ScopedIeProxyConfig(const ScopedIeProxyConfig&) = delete; + ScopedIeProxyConfig& operator=(const ScopedIeProxyConfig&) = delete; + ~ScopedIeProxyConfig(); + + WINHTTP_CURRENT_USER_IE_PROXY_CONFIG* receive() { return &ie_proxy_config_; } + + bool auto_detect() const { return ie_proxy_config_.fAutoDetect; } + std::wstring auto_config_url() const { + return FromCharOrEmpty(ie_proxy_config_.lpszAutoConfigUrl); + } + std::wstring proxy() const { + return FromCharOrEmpty(ie_proxy_config_.lpszProxy); + } + std::wstring proxy_bypass() const { + return FromCharOrEmpty(ie_proxy_config_.lpszProxyBypass); + } + + private: + WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ie_proxy_config_ = {}; +}; + +ScopedIeProxyConfig::ScopedIeProxyConfig() { + ie_proxy_config_.fAutoDetect = false; + ie_proxy_config_.lpszAutoConfigUrl = nullptr; + ie_proxy_config_.lpszProxy = nullptr; + ie_proxy_config_.lpszProxyBypass = nullptr; +} + +ScopedIeProxyConfig::~ScopedIeProxyConfig() { + if (ie_proxy_config_.lpszAutoConfigUrl) + ::GlobalFree(ie_proxy_config_.lpszAutoConfigUrl); + + if (ie_proxy_config_.lpszProxy) + ::GlobalFree(ie_proxy_config_.lpszProxy); + + if (ie_proxy_config_.lpszProxyBypass) + ::GlobalFree(ie_proxy_config_.lpszProxyBypass); +} + + // Factory method for the proxy configuration strategy. scoped_refptr GetProxyConfiguration( @@ -48,7 +100,32 @@ scoped_refptr GetProxyConfiguration( VLOG(1) << "Using the system configuration for proxy."; - return base::MakeRefCounted(); + const base::win::OSInfo* os_info = base::win::OSInfo::GetInstance(); + const bool supports_automatic_proxy = + os_info->version() >= base::win::Version::WIN8_1; + if (supports_automatic_proxy) { + return base::MakeRefCounted(); + } + + ScopedImpersonation impersonate_user; + if (IsLocalSystemUser()) { + VLOG(2) << "Running as SYSTEM, impersonate the current user."; + base::win::ScopedHandle user_token = GetUserTokenFromCurrentSessionId(); + if (user_token.IsValid()) { + impersonate_user.Impersonate(user_token.Get()); + } + } + + ScopedIeProxyConfig ie_proxy_config; + if (::WinHttpGetIEProxyConfigForCurrentUser(ie_proxy_config.receive())) { + return base::MakeRefCounted(winhttp::ProxyInfo{ + ie_proxy_config.auto_detect(), ie_proxy_config.auto_config_url(), + ie_proxy_config.proxy(), ie_proxy_config.proxy_bypass()}); + } else { + PLOG(ERROR) << "Failed to get proxy for current user"; + } + + return base::MakeRefCounted(); } class NetworkFetcher : public update_client::NetworkFetcher { diff --git a/chrome/updater/win/installer/installer.cc b/chrome/updater/win/installer/installer.cc index 15958e1ae1334..189955f527ae9 100644 --- a/chrome/updater/win/installer/installer.cc +++ b/chrome/updater/win/installer/installer.cc @@ -343,7 +343,7 @@ ProcessExitResult InstallerMain(HMODULE module) { CHECK(EnableSecureDllLoading()); EnableProcessHeapMetadataProtection(); - if (base::win::GetVersion() < base::win::Version::WIN10) { + if (base::win::GetVersion() < base::win::Version::VISTA) { return ProcessExitResult(UNSUPPORTED_WINDOWS_VERSION); } diff --git a/components/metrics/motherboard.cc b/components/metrics/motherboard.cc index 4b2270d10a86d..e97bde5ddf5d1 100644 --- a/components/metrics/motherboard.cc +++ b/components/metrics/motherboard.cc @@ -16,6 +16,7 @@ #if BUILDFLAG(IS_WIN) #include +#include "base/scoped_native_library.h" #include "base/strings/utf_string_conversions.h" #include "base/threading/scoped_blocking_call.h" #include "base/win/scoped_bstr.h" @@ -142,7 +143,19 @@ void ReadWin32Bios(const ComPtr& services, void ReadFirmwareType(absl::optional* bios_type) { FIRMWARE_TYPE firmware_type = FirmwareTypeUnknown; - if (::GetFirmwareType(&firmware_type)) { + // NOTE: GetFirmwareType API only exists on >= Win8. Dynamically + // get function handle. + using GetFirmwareTypeFunction = decltype(&GetFirmwareType); + base::ScopedNativeLibrary dll(base::FilePath(L"kernel32.dll")); + if (!dll.is_valid()) + return; + GetFirmwareTypeFunction get_firmware_type_function = + reinterpret_cast( + dll.GetFunctionPointer("GetFirmwareType")); + if (!get_firmware_type_function) + return; + + if (get_firmware_type_function(&firmware_type)) { if (firmware_type == FirmwareTypeBios) { *bios_type = Motherboard::BiosType::kLegacy; } else if (firmware_type == FirmwareTypeUefi) { diff --git a/components/system_media_controls/win/system_media_controls_win.cc b/components/system_media_controls/win/system_media_controls_win.cc index 8e6430f0832db..9291a58c2c003 100644 --- a/components/system_media_controls/win/system_media_controls_win.cc +++ b/components/system_media_controls/win/system_media_controls_win.cc @@ -9,11 +9,6 @@ #include #include -#include -#include -#include -#include - #include "base/strings/string_piece.h" #include "base/strings/utf_string_conversions.h" #include "base/win/core_winrt_util.h" @@ -91,6 +86,11 @@ bool SystemMediaControlsWin::Initialize() { attempted_to_initialize_ = true; + if (!base::win::ResolveCoreWinRTDelayload() || + !base::win::ScopedHString::ResolveCoreWinRTStringDelayload()) { + return false; + } + Microsoft::WRL::ComPtr interop; HRESULT hr = base::win::GetActivationFactory< ISystemMediaTransportControlsInterop, diff --git a/content/app/initialize_mojo_core.cc b/content/app/initialize_mojo_core.cc index 6600e576a857f..6259f4a0754e9 100644 --- a/content/app/initialize_mojo_core.cc +++ b/content/app/initialize_mojo_core.cc @@ -20,6 +20,10 @@ #include "mojo/public/cpp/system/dynamic_library_support.h" #include "sandbox/policy/sandbox_type.h" +#if BUILDFLAG(IS_WIN) +#include "base/win/windows_version.h" +#endif + namespace content { void InitializeMojoCore() { @@ -52,9 +56,16 @@ void InitializeMojoCore() { config.force_direct_shared_memory_allocation = true; } else { #if BUILDFLAG(IS_WIN) - // On Windows it's not necessary to broker shared memory allocation, as - // even sandboxed processes can allocate their own without trouble. - config.force_direct_shared_memory_allocation = true; + if (base::win::GetVersion() >= base::win::Version::WIN8_1) { + // On Windows 8.1 and later it's not necessary to broker shared memory + // allocation, as even sandboxed processes can allocate their own without + // trouble. + config.force_direct_shared_memory_allocation = true; + } +#elif BUILDFLAG(IS_ANDROID) + // On Android we run a Finch experiment testing direct memory allocation. + config.force_direct_shared_memory_allocation = base::FeatureList::IsEnabled( + mojo::core::kMojoDirectSharedMemoryAndroid); #endif } diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index 7e10fac2d7dc5..03e40eb6b7c51 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn @@ -2812,6 +2812,8 @@ source_set("browser") { "renderer_host/direct_manipulation_helper_win.h", "renderer_host/dwrite_font_file_util_win.cc", "renderer_host/dwrite_font_file_util_win.h", + "renderer_host/dwrite_font_lookup_table_builder_win.cc", + "renderer_host/dwrite_font_lookup_table_builder_win.h", "renderer_host/dwrite_font_proxy_impl_win.cc", "renderer_host/dwrite_font_proxy_impl_win.h", "renderer_host/dwrite_font_uma_logging_win.cc", diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc index 7dd6f38e441f0..25ddec3a52850 100644 --- a/content/browser/browser_main_loop.cc +++ b/content/browser/browser_main_loop.cc @@ -191,6 +191,7 @@ #include #include "base/threading/platform_thread_win.h" +#include "content/browser/renderer_host/dwrite_font_lookup_table_builder_win.h" #include "net/base/winsock_init.h" #include "sandbox/policy/win/sandbox_win.h" #include "sandbox/win/src/sandbox.h" @@ -994,6 +995,16 @@ int BrowserMainLoop::PreMainMessageLoopRun() { variations::MaybeScheduleFakeCrash(); +#if BUILDFLAG(IS_WIN) + // ShellBrowserMainParts initializes a ShellBrowserContext with a profile + // directory only in PreMainMessageLoopRun(). DWriteFontLookupTableBuilder + // needs to access this directory, hence triggering after this stage has run. + if (base::FeatureList::IsEnabled(features::kFontSrcLocalMatching)) { + content::DWriteFontLookupTableBuilder::GetInstance() + ->SchedulePrepareFontUniqueNameTableIfNeeded(); + } +#endif // BUILDFLAG(IS_WIN) + // Unretained(this) is safe as the main message loop expected to run it is // stopped before ~BrowserMainLoop (in the event the message loop doesn't // reach idle before that point). diff --git a/content/browser/installedapp/installed_app_provider_impl_win.cc b/content/browser/installedapp/installed_app_provider_impl_win.cc index e02f9dc5251cc..fa217674fd620 100644 --- a/content/browser/installedapp/installed_app_provider_impl_win.cc +++ b/content/browser/installedapp/installed_app_provider_impl_win.cc @@ -112,6 +112,13 @@ void FilterInstalledAppsForWin( std::vector related_apps, blink::mojom::InstalledAppProvider::FilterInstalledAppsCallback callback, const GURL frame_url) { + + if (!base::win::ScopedHString::ResolveCoreWinRTStringDelayload() || + !base::win::ResolveCoreWinRTDelayload()) { + std::move(callback).Run(std::vector()); + return; + } + ComPtr launcher_statics; HRESULT hr = base::win::RoActivateInstance( base::win::ScopedHString::Create(RuntimeClass_Windows_System_Launcher) diff --git a/content/browser/ppapi_plugin_sandboxed_process_launcher_delegate.cc b/content/browser/ppapi_plugin_sandboxed_process_launcher_delegate.cc index b141cfe3cc2e6..711838407f765 100644 --- a/content/browser/ppapi_plugin_sandboxed_process_launcher_delegate.cc +++ b/content/browser/ppapi_plugin_sandboxed_process_launcher_delegate.cc @@ -12,6 +12,7 @@ #include "sandbox/policy/mojom/sandbox.mojom.h" #if BUILDFLAG(IS_WIN) +#include "base/win/windows_version.h" #include "sandbox/policy/win/sandbox_win.h" #include "sandbox/win/src/process_mitigations.h" #include "sandbox/win/src/sandbox_policy.h" @@ -34,8 +35,10 @@ bool PpapiPluginSandboxedProcessLauncherDelegate::InitializeConfig( // create the server side of Chrome pipes. sandbox::ResultCode result; #if !defined(NACL_WIN64) + // We don't support PPAPI win32k lockdown prior to Windows 10. + if (base::win::GetVersion() >= base::win::Version::WIN10) { result = sandbox::policy::SandboxWin::AddWin32kLockdownPolicy(config); - if (result != sandbox::SBOX_ALL_OK) { + if (result != sandbox::SBOX_ALL_OK) return false; } #endif // !defined(NACL_WIN64) diff --git a/content/browser/renderer_host/direct_manipulation_helper_win.cc b/content/browser/renderer_host/direct_manipulation_helper_win.cc index b04194c32a4d1..b5ad20605fbd8 100644 --- a/content/browser/renderer_host/direct_manipulation_helper_win.cc +++ b/content/browser/renderer_host/direct_manipulation_helper_win.cc @@ -10,6 +10,7 @@ #include "base/logging.h" #include "base/memory/ptr_util.h" #include "base/win/win_util.h" +#include "base/win/windows_version.h" #include "ui/base/ui_base_features.h" #include "ui/base/win/window_event_target.h" #include "ui/compositor/compositor.h" @@ -27,6 +28,10 @@ DirectManipulationHelper::CreateInstance(HWND window, if (!::IsWindow(window) || !compositor || !event_target) return nullptr; + // DM_POINTERHITTEST supported since Win10. + if (base::win::GetVersion() < base::win::Version::WIN10) + return nullptr; + std::unique_ptr instance = base::WrapUnique(new DirectManipulationHelper(window, compositor)); @@ -41,6 +46,9 @@ std::unique_ptr DirectManipulationHelper::CreateInstanceForTesting( ui::WindowEventTarget* event_target, Microsoft::WRL::ComPtr viewport) { + // DM_POINTERHITTEST supported since Win10. + if (base::win::GetVersion() < base::win::Version::WIN10) + return nullptr; std::unique_ptr instance = base::WrapUnique(new DirectManipulationHelper(0, nullptr)); diff --git a/content/browser/renderer_host/dwrite_font_lookup_table_builder_win.cc b/content/browser/renderer_host/dwrite_font_lookup_table_builder_win.cc new file mode 100644 index 0000000000000..891840540bb13 --- /dev/null +++ b/content/browser/renderer_host/dwrite_font_lookup_table_builder_win.cc @@ -0,0 +1,772 @@ +// Copyright 2019 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/renderer_host/dwrite_font_lookup_table_builder_win.h" + +#include +#include + +#include +#include + +#include "base/file_version_info.h" +#include "base/files/file.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/hash/hash.h" +#include "base/i18n/case_conversion.h" +#include "base/metrics/histogram_functions.h" +#include "base/metrics/histogram_macros.h" +#include "base/no_destructor.h" +#include "base/path_service.h" +#include "base/stl_util.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/utf_string_conversions.h" +#include "base/task/sequenced_task_runner.h" +#include "base/task/task_traits.h" +#include "base/task/thread_pool.h" +#include "base/threading/scoped_blocking_call.h" +#include "base/threading/thread_restrictions.h" +#include "base/trace_event/trace_event.h" +#include "base/types/optional_util.h" +#include "base/version.h" +#include "base/win/registry.h" +#include "content/browser/renderer_host/dwrite_font_file_util_win.h" +#include "content/browser/renderer_host/dwrite_font_proxy_impl_win.h" +#include "content/browser/renderer_host/dwrite_font_uma_logging_win.h" +#include "content/public/browser/content_browser_client.h" +#include "content/public/common/content_client.h" +#include "content/public/common/content_features.h" +#include "third_party/blink/public/common/font_unique_name_lookup/font_table_matcher.h" +#include "third_party/blink/public/common/font_unique_name_lookup/font_table_persistence.h" +#include "third_party/blink/public/common/font_unique_name_lookup/icu_fold_case_util.h" +#include "ui/gfx/win/direct_write.h" + +namespace content { + +namespace { + +const base::FilePath::CharType kProtobufFilename[] = + FILE_PATH_LITERAL("font_unique_name_table.pb"); + +// Timeout after which font scanning and metadata extraction is stopped and the +// local lookup table is cleared. Font scanning and lookup table construction is +// only needed pre Windows 10. If the timeout is hit, no local font matching +// will be performed on this particular pre Win 10 system. +constexpr base::TimeDelta kFontIndexingTimeoutDefault = base::Minutes(5); + +// In timeout test case, slow down indexing of one font file to this percentage +// of the timeout value. Assuming that at least two fonts are indexed, the +// timeout should be usually hit during indexing the second font. +constexpr float kIndexingSlowDownForTestingPercentage = 0.75; + +// Additional local custom interface specific HRESULT codes (also added to +// enums.xml) to mark font scanning implementation specific error situations, as +// part of reporting them in a UMA metric. +constexpr HRESULT kErrorFontScanningTimedOut = + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xD101); +constexpr HRESULT kErrorExtractingLocalizedStringsFailed = + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xD102); +constexpr HRESULT kErrorNoFullNameOrPostScriptName = + MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xD103); + +bool ExtractCaseFoldedLocalizedStrings( + IDWriteLocalizedStrings* dwrite_localized_strings, + std::vector* localized_strings) { + uint32_t strings_count = dwrite_localized_strings->GetCount(); + + if (!strings_count) + return false; + + localized_strings->reserve(localized_strings->size() + strings_count); + for (UINT32 j = 0; j < strings_count; ++j) { + UINT32 length; + HRESULT hr = dwrite_localized_strings->GetStringLength(j, &length); + if (FAILED(hr)) + continue; + std::wstring localized_name; + localized_name.resize(length + 1); + hr = dwrite_localized_strings->GetString(j, &localized_name[0], length + 1); + if (FAILED(hr)) { + continue; + } + localized_name.resize(length); + // The documentation for the API call does not specify an encoding but the + // results are wchar_t and FireFox considers them UTF-16, as seen here: + // https://dxr.mozilla.org/mozilla-central/source/gfx/thebes/gfxDWriteFontList.cpp#90 + // so we'll assume that. + localized_strings->push_back(base::UTF16ToUTF8( + base::i18n::FoldCase(base::WideToUTF16(localized_name)))); + } + return true; +} + +bool EnsureCacheDirectory(base::FilePath cache_directory) { + // If the directory does not exist already, ensure that the parent directory + // exists, which is usually the User Data directory. If it exists, we can try + // creating the cache directory. + return !cache_directory.empty() && + (base::DirectoryExists(cache_directory) || + (base::DirectoryExists(cache_directory.DirName()) && + CreateDirectory(cache_directory))); +} + +} // namespace + +DWriteFontLookupTableBuilder::FontFileWithUniqueNames::FontFileWithUniqueNames( + blink::FontUniqueNameTable_UniqueFont&& font, + std::vector&& names) + : font_entry(std::move(font)), extracted_names(std::move(names)) {} + +DWriteFontLookupTableBuilder::FontFileWithUniqueNames:: + ~FontFileWithUniqueNames() = default; + +DWriteFontLookupTableBuilder::FontFileWithUniqueNames::FontFileWithUniqueNames( + DWriteFontLookupTableBuilder::FontFileWithUniqueNames&& other) = default; + +DWriteFontLookupTableBuilder::FamilyResult::FamilyResult() = default; +DWriteFontLookupTableBuilder::FamilyResult::FamilyResult(FamilyResult&& other) = + default; +DWriteFontLookupTableBuilder::FamilyResult::~FamilyResult() = default; + +DWriteFontLookupTableBuilder::DWriteFontLookupTableBuilder() + : font_indexing_timeout_(kFontIndexingTimeoutDefault) { + InitializeCacheDirectoryFromProfile(); +} + +void DWriteFontLookupTableBuilder::InitializeCacheDirectoryFromProfile() { + // Unit tests that do not launch a full browser environment usually don't need + // testing of src:local()-style font matching. Check that an environment is + // present here and configcure the cache directory based on that. If none is + // configured, catch this in DuplicateMemoryRegion(), i.e. when a client + // tries to use this API. + cache_directory_ = + GetContentClient() && GetContentClient()->browser() + ? GetContentClient()->browser()->GetFontLookupTableCacheDir() + : base::FilePath(); +} + +DWriteFontLookupTableBuilder::~DWriteFontLookupTableBuilder() = default; + +base::ReadOnlySharedMemoryRegion +DWriteFontLookupTableBuilder::DuplicateMemoryRegion() { + DCHECK(!TableCacheFilePath().empty()) + << "Ensure that a cache_directory_ is set (see " + "InitializeCacheDirectoryFromProfile())"; + DCHECK(FontUniqueNameTableReady()); + return font_table_memory_.region.Duplicate(); +} + +bool DWriteFontLookupTableBuilder::IsFontUniqueNameTableValid() { + return font_table_memory_.IsValid() && font_table_memory_.mapping.size(); +} + +void DWriteFontLookupTableBuilder::InitializeDirectWrite() { + if (direct_write_initialized_) + return; + direct_write_initialized_ = true; + + Microsoft::WRL::ComPtr factory; + gfx::win::CreateDWriteFactory(&factory); + if (factory == nullptr) { + // We won't be able to load fonts, but we should still return messages so + // renderers don't hang if they for some reason send us a font message. + return; + } + + // QueryInterface for IDwriteFactory3, needed for MatchUniqueFont on Windows + // 10. May fail on older versions, in which case, unique font matching must be + // done through indexing system fonts using DWriteFontLookupTableBuilder. + factory.As(&factory3_); + + HRESULT hr = factory->GetSystemFontCollection(&collection_); + DCHECK(SUCCEEDED(hr)); + + if (!collection_) { + base::UmaHistogramSparse( + "DirectWrite.Fonts.Proxy.GetSystemFontCollectionResult", hr); + LogMessageFilterError(MessageFilterError::ERROR_NO_COLLECTION); + return; + } +} + +std::string DWriteFontLookupTableBuilder::ComputePersistenceHash( + const std::string& browser_version) { + // Build a hash from DWrite product version, browser major version and font + // names and file paths as stored in the registry. The browser major version + // is included to ensure that the cache is rebuild at least once for every + // Chrome milestone release. DWrite DLL version is included to ensure that any + // change in DWrite behavior after an update does not interfere with the + // information we have in the cache. The font registry keys and values are + // used to detect changes in installed fonts. + + std::unique_ptr dwrite_version_info = + FileVersionInfo::CreateFileVersionInfo( + base::FilePath(FILE_PATH_LITERAL("DWrite.dll"))); + + DCHECK(dwrite_version_info); + + std::string dwrite_version = + base::UTF16ToUTF8(dwrite_version_info->product_version()); + + std::string to_hash = dwrite_version; + + const wchar_t kFonts[] = + L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"; + base::win::RegistryValueIterator it(HKEY_LOCAL_MACHINE, kFonts); + for (; it.Valid(); ++it) { + to_hash.append(base::WideToUTF8(it.Name())); + to_hash.append(base::WideToUTF8(it.Value())); + } + + base::Version full_version = base::Version(browser_version); + + // Version can be an empty string on trybots. + if (full_version.IsValid()) { + to_hash.append(base::NumberToString(full_version.components()[0])); + } + + uint32_t fonts_changed_hash = base::PersistentHash(to_hash); + return std::to_string(fonts_changed_hash); +} + +void DWriteFontLookupTableBuilder::SetCacheDirectoryForTesting( + base::FilePath cache_directory) { + cache_directory_ = cache_directory; +} + +void DWriteFontLookupTableBuilder::SetCachingEnabledForTesting( + bool caching_enabled) { + caching_enabled_ = caching_enabled; +} + +bool DWriteFontLookupTableBuilder::HasDWriteUniqueFontLookups() { + InitializeDirectWrite(); + return factory3_; +} + +void DWriteFontLookupTableBuilder::OverrideDWriteVersionChecksForTesting() { + InitializeDirectWrite(); + factory3_.Reset(); +} + +base::TimeDelta DWriteFontLookupTableBuilder::IndexingTimeout() { + return font_indexing_timeout_; +} + +void DWriteFontLookupTableBuilder::PostCallbacks() { + callbacks_task_runner_->StartWithTaskRunner( + base::ThreadPool::CreateSequencedTaskRunner({ +#if DCHECK_IS_ON() + // Needed for DCHECK in DuplicateMemoryRegion() which performs file + // operations to detect cache directory. + base::MayBlock(), +#endif + base::TaskPriority::USER_VISIBLE, + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN + })); +} + +base::FilePath DWriteFontLookupTableBuilder::TableCacheFilePath() { + if (!EnsureCacheDirectory(cache_directory_)) + return base::FilePath(); + return cache_directory_.Append(kProtobufFilename); +} + +bool DWriteFontLookupTableBuilder::PersistToFile() { + DCHECK(caching_enabled_); + + if (!IsFontUniqueNameTableValid()) + return false; + + return blink::font_table_persistence::PersistToFile(font_table_memory_, + TableCacheFilePath()); +} + +bool DWriteFontLookupTableBuilder::LoadFromFile() { + DCHECK(caching_enabled_); + DCHECK(!IsFontUniqueNameTableValid()); + + return blink::font_table_persistence::LoadFromFile(TableCacheFilePath(), + &font_table_memory_); +} + +DWriteFontLookupTableBuilder::CallbackOnTaskRunner::CallbackOnTaskRunner( + scoped_refptr runner, + blink::mojom::DWriteFontProxy::GetUniqueNameLookupTableCallback callback) + : task_runner(std::move(runner)), mojo_callback(std::move(callback)) {} + +DWriteFontLookupTableBuilder::CallbackOnTaskRunner::CallbackOnTaskRunner( + CallbackOnTaskRunner&& other) = default; + +DWriteFontLookupTableBuilder::CallbackOnTaskRunner::~CallbackOnTaskRunner() = + default; + +void DWriteFontLookupTableBuilder::QueueShareMemoryRegionWhenReady( + scoped_refptr task_runner, + blink::mojom::DWriteFontProxy::GetUniqueNameLookupTableCallback callback) { + TRACE_EVENT0("dwrite,fonts", + "DWriteFontLookupTableBuilder::QueueShareMemoryRegionWhenReady"); + DCHECK(!HasDWriteUniqueFontLookups()); + + // base::Unretained(this) acceptable as bound argument here since + // DWriteFontLookupTableBuilder is a singleton instance. + callbacks_task_runner_->PostTask( + FROM_HERE, + base::BindOnce( + &DWriteFontLookupTableBuilder::RunPendingCallback, + base::Unretained(this), + CallbackOnTaskRunner(std::move(task_runner), std::move(callback)))); +} + +bool DWriteFontLookupTableBuilder::FontUniqueNameTableReady() { + TRACE_EVENT0("dwrite,fonts", + "DWriteFontLookupTableBuilder::FontUniqueNameTableReady"); + DCHECK(base::FeatureList::IsEnabled(features::kFontSrcLocalMatching)); + DCHECK(!HasDWriteUniqueFontLookups()); + return font_table_built_.IsSet() && IsFontUniqueNameTableValid(); +} + +void DWriteFontLookupTableBuilder:: + SchedulePrepareFontUniqueNameTableIfNeeded() { + DCHECK(base::FeatureList::IsEnabled(features::kFontSrcLocalMatching)); + + { + base::ScopedBlockingCall scoped_blocking_call( + FROM_HERE, base::BlockingType::MAY_BLOCK); + InitializeDirectWrite(); + } + + // Nothing to do if we have API to directly lookup local fonts by unique name + // (as on Windows 10, IDWriteFactory3 available). + if (HasDWriteUniqueFontLookups()) + return; + + // Do not schedule indexing if we do not have a profile or temporary directory + // to store the cached table. This prevents repetitive and redundant scanning + // when the ContentBrowserClient did not provide a cache directory, as is the + // case in content_unittests. + if (TableCacheFilePath().empty()) + return; + + start_time_table_ready_ = base::TimeTicks::Now(); + scanning_error_reasons_.clear(); + + scoped_refptr results_collection_task_runner = + base::ThreadPool::CreateSequencedTaskRunner( + {base::MayBlock(), base::TaskPriority::BEST_EFFORT, + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}); + + std::string browser_version = + GetContentClient()->browser()->GetUserAgentMetadata().full_version; + results_collection_task_runner->PostTask( + FROM_HERE, + base::BindOnce(&DWriteFontLookupTableBuilder::PrepareFontUniqueNameTable, + base::Unretained(this), browser_version)); +} + +void DWriteFontLookupTableBuilder::PrepareFontUniqueNameTable( + const std::string& browser_version) { + TRACE_EVENT0("dwrite,fonts", + "DWriteFontLookupTableBuilder::PrepareFontUniqueNameTable"); + DCHECK(!HasDWriteUniqueFontLookups()); + // The table must only be built once. + DCHECK(!font_table_built_.IsSet()); + + if (caching_enabled_ && LoadFromFile()) { + blink::FontUniqueNameTable font_table; + const bool update_needed = + !IsFontUniqueNameTableValid() || + !font_table.ParseFromArray(font_table_memory_.mapping.memory(), + font_table_memory_.mapping.size()) || + font_table.stored_for_platform_version_identifier() != + ComputePersistenceHash(browser_version); + + UMA_HISTOGRAM_BOOLEAN("DirectWrite.Fonts.Proxy.LookupTableDiskCacheHit", + !update_needed); + if (!update_needed) { + base::TimeDelta duration = + base::TimeTicks::Now() - start_time_table_ready_; + UMA_HISTOGRAM_MEDIUM_TIMES("DirectWrite.Fonts.Proxy.LookupTableReadyTime", + duration); + font_table_built_.Set(); + PostCallbacks(); + return; + } + } + + start_time_table_build_ = base::TimeTicks::Now(); + font_unique_name_table_ = std::make_unique(); + + // The |stored_for_platform_version_identifier| proto field is used for + // persisting the table to disk and identifying whether an update to the + // table is needed when loading it back. + font_unique_name_table_->set_stored_for_platform_version_identifier( + ComputePersistenceHash(browser_version)); + + { + base::ScopedBlockingCall scoped_blocking_call( + FROM_HERE, base::BlockingType::MAY_BLOCK); + + outstanding_family_results_ = collection_->GetFontFamilyCount(); + family_results_empty_ = 0; + family_results_non_empty_ = 0; + UMA_HISTOGRAM_CUSTOM_COUNTS( + "DirectWrite.Fonts.Proxy.FamilyCountIndexingStart", + outstanding_family_results_, 1, 5000, 50); + } + for (UINT32 family_index = 0; family_index < outstanding_family_results_; + ++family_index) { + // Specify base::ThreadPolicy::MUST_USE_FOREGROUND because in + // https://crbug.com/960263 we observed a priority inversion when running + // DWrite worker tasks in the background. + base::ThreadPool::PostTaskAndReplyWithResult( + FROM_HERE, + {base::MayBlock(), base::TaskPriority::BEST_EFFORT, + base::ThreadPolicy::MUST_USE_FOREGROUND, + base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, + base::BindOnce( + &ExtractPathAndNamesFromFamily, collection_, family_index, + start_time_table_build_, slow_down_mode_for_testing_, + OptionalToPtr(hang_event_for_testing_), IndexingTimeout()), + base::BindOnce(&DWriteFontLookupTableBuilder:: + AppendFamilyResultAndFinalizeIfNeeded, + base::Unretained(this))); + } + // Post a task to catch timeouts should one of the + // tasks will eventually not reply. + timeout_callback_.Reset(base::BindOnce( + &DWriteFontLookupTableBuilder::OnTimeout, base::Unretained(this))); + base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask( + FROM_HERE, timeout_callback_.callback(), IndexingTimeout()); +} + +// static +DWriteFontLookupTableBuilder::FamilyResult +DWriteFontLookupTableBuilder::ExtractPathAndNamesFromFamily( + Microsoft::WRL::ComPtr collection, + uint32_t family_index, + base::TimeTicks start_time, + SlowDownMode slow_down_mode_for_testing, + base::WaitableEvent* hang_event_for_testing, + base::TimeDelta indexing_timeout) { + TRACE_EVENT0("dwrite,fonts", + "DWriteFontLookupTableBuilder::ExtractPathAndNamesFromFamily"); + + static base::NoDestructor windows_fonts_path( + GetWindowsFontsPath()); + + DWriteFontLookupTableBuilder::FamilyResult family_result; + + if (base::TimeTicks::Now() - start_time > indexing_timeout) { + family_result.exit_hresult = kErrorFontScanningTimedOut; + return family_result; + } + + Microsoft::WRL::ComPtr family; + HRESULT hr = collection->GetFontFamily(family_index, &family); + if (FAILED(hr)) { + family_result.exit_hresult = hr; + return family_result; + } + UINT32 font_count = family->GetFontCount(); + + HRESULT last_hresult_continue_reason = S_OK; + for (UINT32 font_index = 0; font_index < font_count; ++font_index) { + if (base::TimeTicks::Now() - start_time > indexing_timeout) { + family_result.exit_hresult = kErrorFontScanningTimedOut; + return family_result; + } + + Microsoft::WRL::ComPtr font; + { + base::ScopedBlockingCall scoped_blocking_call( + FROM_HERE, base::BlockingType::MAY_BLOCK); + hr = family->GetFont(font_index, &font); + } + if (FAILED(hr)) { + family_result.exit_hresult = hr; + return family_result; + } + + if (font->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE) + continue; + + std::set path_set; + std::set custom_font_path_set; + uint32_t ttc_index = 0; + { + base::ScopedBlockingCall scoped_blocking_call( + FROM_HERE, base::BlockingType::MAY_BLOCK); + hr = AddFilesForFont(font.Get(), *windows_fonts_path, &path_set); + if (FAILED(hr)) { + // It's possible to not be able to retrieve a font file for a font that + // is in the system font collection, see https://crbug.com/922183. If we + // were not able to retrieve a file for a registered font, we do not + // need to add it to the map. + last_hresult_continue_reason = hr; + continue; + } + } + + // After having received clarification from Microsoft, the API is designed + // for allowing multiple files to be returned, if MS was to support a file + // format like Type1 fonts with this API, but for now only ever returns 1 + // font file as only TrueType / OpenType fonts are supported. + DCHECK_EQ(path_set.size() + custom_font_path_set.size(), 1u); + // If this font is placed in a custom font path location, we pass it to + // Blink, and we'll track with UMA there if such a font path is matched + // and used. If this happens more than very rarely, we will need to add an + // out-of-process loading mechanism for loading those uniquely matched + // font files. + base::FilePath file_path(path_set.size() ? *path_set.begin() + : *custom_font_path_set.begin()); + DCHECK(!file_path.empty()); + + // Build entry for being added to the table in separate call. + blink::FontUniqueNameTable_UniqueFont unique_font; + unique_font.set_file_path(file_path.AsUTF8Unsafe()); + unique_font.set_ttc_index(ttc_index); + + std::vector extracted_names; + auto extract_names = + [&extracted_names, + &font](DWRITE_INFORMATIONAL_STRING_ID font_info_string_id) -> HRESULT { + // Now get names, and make them point to the added font. + Microsoft::WRL::ComPtr font_id_keyed_names; + BOOL has_id_keyed_names; + { + base::ScopedBlockingCall scoped_blocking_call( + FROM_HERE, base::BlockingType::MAY_BLOCK); + HRESULT hr = font->GetInformationalStrings( + font_info_string_id, &font_id_keyed_names, &has_id_keyed_names); + if (FAILED(hr)) + return hr; + if (!has_id_keyed_names) + return kErrorNoFullNameOrPostScriptName; + } + + return ExtractCaseFoldedLocalizedStrings(font_id_keyed_names.Get(), + &extracted_names) + ? S_OK + : kErrorExtractingLocalizedStringsFailed; + }; + + hr = extract_names(DWRITE_INFORMATIONAL_STRING_POSTSCRIPT_NAME); + hr = FAILED(hr) ? hr : extract_names(DWRITE_INFORMATIONAL_STRING_FULL_NAME); + + if (UNLIKELY(slow_down_mode_for_testing == SlowDownMode::kDelayEachTask)) { + base::PlatformThread::Sleep(indexing_timeout * + kIndexingSlowDownForTestingPercentage); + } else if (UNLIKELY(slow_down_mode_for_testing == + SlowDownMode::kHangOneTask) && + family_index == 0) { + base::ScopedAllowBaseSyncPrimitivesForTesting scoped_allow_sync_; + DCHECK(hang_event_for_testing); + hang_event_for_testing->Wait(); + } + + if (extracted_names.empty()) { + last_hresult_continue_reason = hr; + continue; + } + + family_result.exit_hresult = S_OK; + family_result.font_files_with_names.push_back( + DWriteFontLookupTableBuilder::FontFileWithUniqueNames( + std::move(unique_font), std::move(extracted_names))); + } + + if (family_result.font_files_with_names.empty()) { + family_result.exit_hresult = last_hresult_continue_reason; + } + + return family_result; +} + +void DWriteFontLookupTableBuilder::AppendFamilyResultAndFinalizeIfNeeded( + const FamilyResult& family_result) { + TRACE_EVENT0( + "dwrite,fonts", + "DWriteFontLookupTableBuilder::AppendFamilyResultAndFinalizeIfNeeded"); + + outstanding_family_results_--; + + // If this task's response came late and OnTimeout was called, we + // do not need the results anymore and the table was already finalized. + if (font_table_built_.IsSet()) + return; + + if (!family_result.font_files_with_names.size()) + family_results_empty_++; + else + family_results_non_empty_++; + + if (FAILED(family_result.exit_hresult)) + scanning_error_reasons_[family_result.exit_hresult]++; + + for (const FontFileWithUniqueNames& font_of_family : + family_result.font_files_with_names) { + blink::FontUniqueNameTable_UniqueFont* added_unique_font = + font_unique_name_table_->add_fonts(); + + *added_unique_font = font_of_family.font_entry; + + int added_font_index = font_unique_name_table_->fonts_size() - 1; + + for (auto& font_name : font_of_family.extracted_names) { + blink::FontUniqueNameTable_UniqueNameToFontMapping* added_mapping = + font_unique_name_table_->add_name_map(); + DCHECK(added_mapping); + added_mapping->set_font_name(font_name); + added_mapping->set_font_index(added_font_index); + } + } + + if (!outstanding_family_results_) { + FinalizeFontTable(); + } +} + +void DWriteFontLookupTableBuilder::RunPendingCallback( + CallbackOnTaskRunner pending_callback) { + DCHECK(callbacks_task_runner_->RunsTasksInCurrentSequence()); + pending_callback.task_runner->PostTask( + FROM_HERE, base::BindOnce(std::move(pending_callback.mojo_callback), + DuplicateMemoryRegion())); +} + +void DWriteFontLookupTableBuilder::FinalizeFontTable() { + TRACE_EVENT0("dwrite,fonts", + "DWriteFontLookupTableBuilder::FinalizeFontTable"); + DCHECK(!font_table_built_.IsSet()); + + timeout_callback_.Cancel(); + + // Make sure that whatever happens in the remainder of this function the + // FontUniqueNameTable object gets released by moving it to a local variable. + std::unique_ptr font_unique_name_table( + std::move(font_unique_name_table_)); + + bool timed_out = false; + if (base::TimeTicks::Now() - start_time_table_build_ > IndexingTimeout()) { + font_unique_name_table->clear_fonts(); + font_unique_name_table->clear_name_map(); + timed_out = true; + } + UMA_HISTOGRAM_BOOLEAN("DirectWrite.Fonts.Proxy.TableBuildTimedOut", + timed_out); + + int empty_family_results_percentage = + round(((family_results_empty_ * 1.0f) / + (family_results_empty_ + family_results_non_empty_)) * + 100.0); + UMA_HISTOGRAM_PERCENTAGE("DirectWrite.Fonts.Proxy.EmptyFamilyResultsRatio", + empty_family_results_percentage); + + if (empty_family_results_percentage > 0) { + auto most_frequent_hresult_element = std::max_element( + std::begin(scanning_error_reasons_), std::end(scanning_error_reasons_), + [](const decltype(scanning_error_reasons_)::value_type& a, + decltype(scanning_error_reasons_)::value_type& b) { + return a.second < b.second; + }); + base::UmaHistogramSparse( + "DirectWrite.Fonts.Proxy.MostFrequentScanningFailure", + most_frequent_hresult_element->first); + } + + unsigned num_font_files = font_unique_name_table->fonts_size(); + + blink::FontTableMatcher::SortUniqueNameTableForSearch( + font_unique_name_table.get()); + + font_table_memory_ = base::ReadOnlySharedMemoryRegion::Create( + font_unique_name_table->ByteSizeLong()); + + if (!IsFontUniqueNameTableValid() || + !font_unique_name_table->SerializeToArray( + font_table_memory_.mapping.memory(), + font_table_memory_.mapping.size())) { + font_table_memory_ = base::MappedReadOnlyRegion(); + } + + if (caching_enabled_) { + bool persist_succeeded = PersistToFile(); + UMA_HISTOGRAM_BOOLEAN("DirectWrite.Fonts.Proxy.LookupTablePersistSuccess", + persist_succeeded); + } + + font_table_built_.Set(); + PostCallbacks(); + + if (!IsFontUniqueNameTableValid()) + return; + + base::TimeDelta duration = base::TimeTicks::Now() - start_time_table_build_; + UMA_HISTOGRAM_MEDIUM_TIMES("DirectWrite.Fonts.Proxy.LookupTableBuildTime", + duration); + + duration = base::TimeTicks::Now() - start_time_table_ready_; + UMA_HISTOGRAM_MEDIUM_TIMES("DirectWrite.Fonts.Proxy.LookupTableReadyTime", + duration); + + // The size is usually tens of kilobytes, ~50kb on a standard Windows 10 + // installation, 1MB should be a more than high enough upper limit. + UMA_HISTOGRAM_CUSTOM_COUNTS("DirectWrite.Fonts.Proxy.LookupTableSize", + font_table_memory_.mapping.size() / 1024, 1, 1000, + 50); + + UMA_HISTOGRAM_CUSTOM_COUNTS("DirectWrite.Fonts.Proxy.NumFontFiles", + num_font_files, 1, 5000, 50); + + UMA_HISTOGRAM_CUSTOM_COUNTS("DirectWrite.Fonts.Proxy.IndexingSpeed", + num_font_files / duration.InSecondsF(), 1, 10000, + 50); +} + +void DWriteFontLookupTableBuilder::OnTimeout() { + DCHECK(!font_table_built_.IsSet()); + FinalizeFontTable(); +} + +void DWriteFontLookupTableBuilder::SetSlowDownIndexingForTestingWithTimeout( + SlowDownMode slow_down_mode, + base::TimeDelta new_timeout) { + slow_down_mode_for_testing_ = slow_down_mode; + font_indexing_timeout_ = new_timeout; + if (slow_down_mode == SlowDownMode::kHangOneTask) + hang_event_for_testing_.emplace(); +} + +void DWriteFontLookupTableBuilder::ResetLookupTableForTesting() { + slow_down_mode_for_testing_ = SlowDownMode::kNoSlowdown; + font_indexing_timeout_ = kFontIndexingTimeoutDefault; + callbacks_task_runner_ = + base::MakeRefCounted(); + font_table_memory_ = base::MappedReadOnlyRegion(); + caching_enabled_ = true; + font_table_built_.UnsafeResetForTesting(); +} + +void DWriteFontLookupTableBuilder::ResetStateForTesting() { + ResetLookupTableForTesting(); + // Recreate fFactory3 if available, to reset + // OverrideDWriteVersionChecksForTesting(). + direct_write_initialized_ = false; + InitializeDirectWrite(); + InitializeCacheDirectoryFromProfile(); +} + +void DWriteFontLookupTableBuilder::ResumeFromHangForTesting() { + hang_event_for_testing_->Signal(); +} + +// static +DWriteFontLookupTableBuilder* DWriteFontLookupTableBuilder::GetInstance() { + static base::NoDestructor instance; + return instance.get(); +} + +} // namespace content \ No newline at end of file diff --git a/content/browser/renderer_host/dwrite_font_lookup_table_builder_win.h b/content/browser/renderer_host/dwrite_font_lookup_table_builder_win.h new file mode 100644 index 0000000000000..cee91dd4e059b --- /dev/null +++ b/content/browser/renderer_host/dwrite_font_lookup_table_builder_win.h @@ -0,0 +1,255 @@ +// Copyright 2019 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_RENDERER_HOST_DWRITE_FONT_LOOKUP_TABLE_BUILDER_WIN_H_ +#define CONTENT_BROWSER_RENDERER_HOST_DWRITE_FONT_LOOKUP_TABLE_BUILDER_WIN_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include "base/cancelable_callback.h" +#include "base/files/file_path.h" +#include "base/memory/read_only_shared_memory_region.h" +#include "base/memory/singleton.h" +#include "base/no_destructor.h" +#include "base/synchronization/atomic_flag.h" +#include "base/synchronization/waitable_event.h" +#include "base/task/deferred_sequenced_task_runner.h" +#include "base/time/time.h" +#include "content/common/content_export.h" +#include "third_party/abseil-cpp/absl/types/optional.h" +#include "third_party/blink/public/common/font_unique_name_lookup/font_unique_name_table.pb.h" +#include "third_party/blink/public/mojom/dwrite_font_proxy/dwrite_font_proxy.mojom.h" + +namespace content { + +// Singleton class which encapsulates building the font unique name table lookup +// once, then serving the built table as a ReadOnlySharedMemoryRegion. Receives +// requests for accessing this table from DWriteFontProxyImpl after Mojo IPC +// calls from the renderer. A method ScheduleBuildFontUniqueNameTable() is +// provided to schedule building the font unique name lookup +// structure. EnsureFontUniqueNameTable() can be called on any thread to wait +// for the lookup table to be ready. After that, DuplicateMemoryRegion() can be +// used to retrieve the lookup structure. Thread-safe when used as described +// below. +class CONTENT_EXPORT DWriteFontLookupTableBuilder { + public: + static DWriteFontLookupTableBuilder* GetInstance(); + + DWriteFontLookupTableBuilder(const DWriteFontLookupTableBuilder&) = delete; + DWriteFontLookupTableBuilder& operator=(const DWriteFontLookupTableBuilder&) = + delete; + + // Retrieve the prepared memory region if it is available. + // EnsureFontUniqueNameTable() must be checked before. + base::ReadOnlySharedMemoryRegion DuplicateMemoryRegion(); + + // Enqueue a request to get notified about the availability of the shared + // memory region holding the unique font lookup table. + // https://crbug.com/967316 shows that we do have a higher number of + // DWriteFontProxyImpl instances, potentially running on different + // TaskRunners. Capture each relevant task runner with a call to this method. + void QueueShareMemoryRegionWhenReady( + scoped_refptr task_runner, + blink::mojom::DWriteFontProxy::GetUniqueNameLookupTableCallback callback); + + // Returns whether the indexing has completed and the shared memory region is + // immediately ready without any sync operations. + bool FontUniqueNameTableReady(); + + // If needed, i.e. if we're on pre-Windows 10, posts a task to load from cache + // or build (if cache not available) the unique name table index, should only + // be called once at browser startup, after that, + // QueueShareMemoryRegionWhenReady() to trigger the mojo callbacks when the + // table is ready. + void SchedulePrepareFontUniqueNameTableIfNeeded(); + + enum class SlowDownMode { kDelayEachTask, kHangOneTask, kNoSlowdown }; + + // Slow down each family indexing step for testing the internal timeout, + // either with a single hung task or by delaying each indexing step. At the + // same time, configure a new timeout value for testing, overriding the + // default timeout. + void SetSlowDownIndexingForTestingWithTimeout(SlowDownMode slowdown_mode, + base::TimeDelta new_timeout); + + // Reset timeout overrides and empty table. Needed to trigger rebuilding the + // lookup table, when testing using slowed-down indexing. Otherwise, the test + // methods would use the already cached lookup table. + void ResetLookupTableForTesting(); + + // Resets other overrides such as the DWrite version check override and cache + // directory back to its default values. + void ResetStateForTesting(); + + // Signals hang_event_for_testing_ which is used in testing hanging one of the + // font name retrieval tasks. + void ResumeFromHangForTesting(); + + // Computes a hash to determine whether cache contents needed to be updated, + // consisting of font names and their file paths read from the registry (not + // from disk), The DWrite.dll's product version and the Chrome version, as a + // safety mechanism to refresh the cache for every release. Exposed as a + // public method to be able to run the hash function in a test. + // `browser_version` is used in the hash. + std::string ComputePersistenceHash(const std::string& browser_version); + + // Configures the cache directory in which to store the serialized font table + // lookup structure. Use only in testing. Normally the directory name is + // retrieved from ContentBrowserClient. + void SetCacheDirectoryForTesting(base::FilePath cache_directory); + + // Configures whether the cache should be used. Needed for testing to test + // repeated rebuilding of the font table lookup structure. + void SetCachingEnabledForTesting(bool caching_enabled); + + // Disable DCHECKs that ensure DWriteFontLookupTableBuilder is only + // run pre Windows 10, used for testing only to allow running the tests on + // Windows 10. + void OverrideDWriteVersionChecksForTesting(); + + private: + friend class base::NoDestructor; + + struct FontFileWithUniqueNames { + FontFileWithUniqueNames(blink::FontUniqueNameTable_UniqueFont&& font, + std::vector&& names); + ~FontFileWithUniqueNames(); + FontFileWithUniqueNames( + DWriteFontLookupTableBuilder::FontFileWithUniqueNames&& other); + FontFileWithUniqueNames(const FontFileWithUniqueNames&) = delete; + FontFileWithUniqueNames& operator=(const FontFileWithUniqueNames&) = delete; + + blink::FontUniqueNameTable_UniqueFont font_entry; + std::vector extracted_names; + }; + + struct FamilyResult { + FamilyResult(); + + FamilyResult(const FamilyResult&) = delete; + FamilyResult& operator=(const FamilyResult&) = delete; + + FamilyResult(FamilyResult&& other); + + ~FamilyResult(); + + std::vector font_files_with_names; + HRESULT exit_hresult{S_OK}; + }; + + // Try to find a serialized lookup table from the cache directory specified at + // construction and load it into memory. + bool LoadFromFile(); + + // Serialize the current lookup table into a file in the cache directory + // specified at construction time. + bool PersistToFile(); + + // Initialize the cache directory from the user profile directory if + // DWriteFontLookupTableBuilder is executed in an environment where the + // profile is accessible. + void InitializeCacheDirectoryFromProfile(); + + // Load from cache or construct the font unique name lookup table. If the + // cache is up to date, do not schedule a run to scan all Windows-enumerated + // fonts. `browser_version` is used in the hashing algorithm for the cache + // key. + void PrepareFontUniqueNameTable(const std::string& browser_version); + + // Helper function to perform DWrite operations to retrieve path names, full + // font name and PostScript name for a font specified by collection + family + // index. + static FamilyResult ExtractPathAndNamesFromFamily( + Microsoft::WRL::ComPtr collection, + uint32_t family_index, + base::TimeTicks start_time, + SlowDownMode slow_down_mode, + base::WaitableEvent* hang_event_for_testing, + base::TimeDelta indexing_timeout); + + // Callback from scheduled tasks to add the retrieved font names to the + // protobuf. + void AppendFamilyResultAndFinalizeIfNeeded(const FamilyResult& family_result); + + // Sort the results that were collected into the protobuf structure and + // signal that font unique name lookup table construction is complete. + // Serializes the constructed protobuf to disk. + void FinalizeFontTable(); + + void OnTimeout(); + + bool IsFontUniqueNameTableValid(); + + void InitializeDirectWrite(); + + base::FilePath TableCacheFilePath(); + + // Returns true if IDWriteFactory3 is available, which means that we can + // access IDWriteFontSet API which provides direct lookup by PostScript name + // and full font name, in which case we do not need to build this table. + bool HasDWriteUniqueFontLookups(); + + base::TimeDelta IndexingTimeout(); + + void PostCallbacks(); + + DWriteFontLookupTableBuilder(); + ~DWriteFontLookupTableBuilder(); + + // Protobuf structure temporarily used and shared during table construction. + std::unique_ptr font_unique_name_table_; + + struct CallbackOnTaskRunner { + CallbackOnTaskRunner( + scoped_refptr, + blink::mojom::DWriteFontProxy::GetUniqueNameLookupTableCallback); + CallbackOnTaskRunner(CallbackOnTaskRunner&&); + ~CallbackOnTaskRunner(); + scoped_refptr task_runner; + blink::mojom::DWriteFontProxy::GetUniqueNameLookupTableCallback + mojo_callback; + }; + + // Task method to bind the CallbackOnTaskRunner for delayed execution when + // building the font table is completed. + void RunPendingCallback(CallbackOnTaskRunner pending_callback); + + base::MappedReadOnlyRegion font_table_memory_; + base::AtomicFlag font_table_built_; + + bool direct_write_initialized_ = false; + base::TimeDelta font_indexing_timeout_; + Microsoft::WRL::ComPtr collection_; + Microsoft::WRL::ComPtr factory2_; + Microsoft::WRL::ComPtr factory3_; + SlowDownMode slow_down_mode_for_testing_ = SlowDownMode::kNoSlowdown; + uint32_t outstanding_family_results_ = 0; + uint32_t family_results_non_empty_ = 0; + uint32_t family_results_empty_ = 0; + base::TimeTicks start_time_table_ready_; + base::TimeTicks start_time_table_build_; + base::FilePath cache_directory_; + + bool caching_enabled_ = true; + absl::optional hang_event_for_testing_; + base::CancelableOnceCallback timeout_callback_; + + // All responses are serialized through this DeferredSequencedTaskRunner. It + // is started when the table is ready and guarantees that requests made before + // the table was ready are replied to first. + scoped_refptr callbacks_task_runner_ = + base::MakeRefCounted(); + + std::map scanning_error_reasons_; +}; + +} // namespace content + +#endif // CONTENT_BROWSER_RENDERER_HOST_DWRITE_FONT_LOOKUP_TABLE_BUILDER_WIN_H_ \ No newline at end of file diff --git a/content/browser/renderer_host/dwrite_font_proxy_impl_win.cc b/content/browser/renderer_host/dwrite_font_proxy_impl_win.cc index f69f1e36a612e..a3aae215aae4e 100644 --- a/content/browser/renderer_host/dwrite_font_proxy_impl_win.cc +++ b/content/browser/renderer_host/dwrite_font_proxy_impl_win.cc @@ -465,6 +465,21 @@ void DWriteFontProxyImpl::MapCharacters( DCHECK_GT(result->mapped_length, 0u); } +void DWriteFontProxyImpl::GetUniqueNameLookupTableIfAvailable( + GetUniqueNameLookupTableIfAvailableCallback callback) { + DCHECK(base::FeatureList::IsEnabled(features::kFontSrcLocalMatching)); + /* Table is not synchronously available, return immediately. */ + if (!DWriteFontLookupTableBuilder::GetInstance() + ->FontUniqueNameTableReady()) { + std::move(callback).Run(false, base::ReadOnlySharedMemoryRegion()); + return; + } + + std::move(callback).Run( + true, + DWriteFontLookupTableBuilder::GetInstance()->DuplicateMemoryRegion()); +} + void DWriteFontProxyImpl::MatchUniqueFont( const std::u16string& unique_font_name, MatchUniqueFontCallback callback) { @@ -561,7 +576,71 @@ void DWriteFontProxyImpl::MatchUniqueFont( std::move(callback).Run(std::move(font_file), ttc_index); } +void DWriteFontProxyImpl::GetUniqueFontLookupMode( + GetUniqueFontLookupModeCallback callback) { + InitializeDirectWrite(); + // If factory3_ is available, that means we can use IDWriteFontSet to filter + // for PostScript name and full font name directly and do not need to build + // the lookup table. + blink::mojom::UniqueFontLookupMode lookup_mode = + factory3_.Get() ? blink::mojom::UniqueFontLookupMode::kSingleLookups + : blink::mojom::UniqueFontLookupMode::kRetrieveTable; + std::move(callback).Run(lookup_mode); +} + +void DWriteFontProxyImpl::GetUniqueNameLookupTable( + GetUniqueNameLookupTableCallback callback) { + DCHECK(base::FeatureList::IsEnabled(features::kFontSrcLocalMatching)); + DWriteFontLookupTableBuilder::GetInstance()->QueueShareMemoryRegionWhenReady( + base::SequencedTaskRunner::GetCurrentDefault(), std::move(callback)); +} + +void DWriteFontProxyImpl::FallbackFamilyAndStyleForCodepoint( + const std::string& base_family_name, + const std::string& locale_name, + uint32_t codepoint, + FallbackFamilyAndStyleForCodepointCallback callback) { + InitializeDirectWrite(); + callback = mojo::WrapCallbackWithDefaultInvokeIfNotRun( + std::move(callback), + blink::mojom::FallbackFamilyAndStyle::New("", + /* weight */ 0, + /* width */ 0, + /* slant */ 0)); + + if (!codepoint || !collection_ || !factory_) + return; + + sk_sp font_mgr( + SkFontMgr_New_DirectWrite(factory_.Get(), collection_.Get())); + + if (!font_mgr) + return; + + const char* bcp47_locales[] = {locale_name.c_str()}; + int num_locales = locale_name.empty() ? 0 : 1; + const char** locales = locale_name.empty() ? nullptr : bcp47_locales; + + sk_sp typeface(font_mgr->matchFamilyStyleCharacter( + base_family_name.c_str(), SkFontStyle(), locales, num_locales, + codepoint)); + + if (!typeface) + return; + + SkString family_name; + typeface->getFamilyName(&family_name); + + SkFontStyle font_style = typeface->fontStyle(); + + auto result_fallback_and_style = blink::mojom::FallbackFamilyAndStyle::New( + family_name.c_str(), font_style.weight(), font_style.width(), + font_style.slant()); + std::move(callback).Run(std::move(result_fallback_and_style)); +} + void DWriteFontProxyImpl::InitializeDirectWrite() { + HRESULT hr; if (direct_write_initialized_) return; direct_write_initialized_ = true; @@ -575,20 +654,30 @@ void DWriteFontProxyImpl::InitializeDirectWrite() { return; } - // QueryInterface for IDWriteFactory2. This should succeed since we only - // support >= Win10. + // QueryInterface for IDWriteFactory2. It's ok for this to fail if we are + // running an older version of DirectWrite (earlier than Win8.1). factory_.As(&factory2_); - DCHECK(factory2_); - // QueryInterface for IDwriteFactory3, needed for MatchUniqueFont on Windows. - // This should succeed since we only support >= Win10. + // QueryInterface for IDwriteFactory3, needed for MatchUniqueFont on Windows + // 10. May fail on older versions, in which case, unique font matching must be + // done through indexing system fonts using DWriteFontLookupTableBuilder. factory_.As(&factory3_); - DCHECK(factory3_); - // Normally identical to factory_->GetSystemFontCollection() unless a - // sideloaded font has been added using SideLoadFontForTesting(). - HRESULT hr = GetLocalFontCollection(factory3_, &collection_); + // On Windows 10 and up (or Vista exkernel/Windows 8.x with modified dwrite.dll from 1809) + // you can take advantage of the extended DirectWrite APIs to sideload local fonts in + // addition to system fonts. But if IDWriteFactory3 is unavailable, fall back to + // GetSystemFontCollection. + // TODO: make DirectWrite optional for the benefit of the NT 5 users. + + if(factory3_ == nullptr) { + hr = factory_->GetSystemFontCollection(&collection_); + DCHECK(SUCCEEDED(hr)); + } + else { + hr = GetLocalFontCollection(factory3_, &collection_); DCHECK(SUCCEEDED(hr)); + } + if (!collection_) { LogMessageFilterError(MessageFilterError::ERROR_NO_COLLECTION); diff --git a/content/browser/renderer_host/dwrite_font_proxy_impl_win.h b/content/browser/renderer_host/dwrite_font_proxy_impl_win.h index 421d471aaa6e1..a5c4d44998d4f 100644 --- a/content/browser/renderer_host/dwrite_font_proxy_impl_win.h +++ b/content/browser/renderer_host/dwrite_font_proxy_impl_win.h @@ -14,6 +14,7 @@ #include #include "base/memory/read_only_shared_memory_region.h" +#include "content/browser/renderer_host/dwrite_font_lookup_table_builder_win.h" #include "content/common/content_export.h" #include "content/public/browser/browser_message_filter.h" #include "content/public/browser/browser_thread.h" @@ -64,6 +65,21 @@ class CONTENT_EXPORT DWriteFontProxyImpl void MatchUniqueFont(const std::u16string& unique_font_name, MatchUniqueFontCallback callback) override; + void GetUniqueFontLookupMode( + GetUniqueFontLookupModeCallback callback) override; + + void GetUniqueNameLookupTableIfAvailable( + GetUniqueNameLookupTableIfAvailableCallback callback) override; + + void GetUniqueNameLookupTable( + GetUniqueNameLookupTableCallback callback) override; + + void FallbackFamilyAndStyleForCodepoint( + const std::string& base_family_name, + const std::string& locale_name, + uint32_t codepoint, + FallbackFamilyAndStyleForCodepointCallback callback) override; + void InitializeDirectWrite(); private: diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc index 7aefaf5d13278..f956167021a87 100644 --- a/content/public/browser/content_browser_client.cc +++ b/content/public/browser/content_browser_client.cc @@ -708,6 +708,10 @@ std::string ContentBrowserClient::GetDefaultDownloadName() { return std::string(); } +base::FilePath ContentBrowserClient::GetFontLookupTableCacheDir() { + return base::FilePath(); +} + base::FilePath ContentBrowserClient::GetShaderDiskCacheDirectory() { return base::FilePath(); } diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h index 825248a9a8411..a86c53b7d7566 100644 --- a/content/public/browser/content_browser_client.h +++ b/content/public/browser/content_browser_client.h @@ -1141,6 +1141,11 @@ class CONTENT_EXPORT ContentBrowserClient { // else we should do with the file. virtual std::string GetDefaultDownloadName(); + // Returns the path to the font lookup table cache directory in which - on + // Windows 7 & 8 - we cache font name meta information to perform @font-face { + // src: local() } lookups. + virtual base::FilePath GetFontLookupTableCacheDir(); + // Returns the path to the browser shader disk cache root. virtual base::FilePath GetShaderDiskCacheDirectory(); diff --git a/content/shell/browser/shell_content_browser_client.cc b/content/shell/browser/shell_content_browser_client.cc index d532bf353fe56..ef117e30094c2 100644 --- a/content/shell/browser/shell_content_browser_client.cc +++ b/content/shell/browser/shell_content_browser_client.cc @@ -450,6 +450,11 @@ std::string ShellContentBrowserClient::GetDefaultDownloadName() { return "download"; } +base::FilePath ShellContentBrowserClient::GetFontLookupTableCacheDir() { + return browser_context()->GetPath().Append( + FILE_PATH_LITERAL("FontLookupTableCache")); +} + std::unique_ptr ShellContentBrowserClient::GetWebContentsViewDelegate( WebContents* web_contents) { diff --git a/content/shell/browser/shell_content_browser_client.h b/content/shell/browser/shell_content_browser_client.h index 70ae93fd9301d..a42ed9fca0aaa 100644 --- a/content/shell/browser/shell_content_browser_client.h +++ b/content/shell/browser/shell_content_browser_client.h @@ -86,6 +86,7 @@ class ShellContentBrowserClient : public ContentBrowserClient { override; void OverrideWebkitPrefs(WebContents* web_contents, blink::web_pref::WebPreferences* prefs) override; + base::FilePath GetFontLookupTableCacheDir() override; std::unique_ptr CreateDevToolsManagerDelegate() override; void ExposeInterfacesToRenderer( diff --git a/device/bluetooth/bluetooth_adapter_winrt.cc b/device/bluetooth/bluetooth_adapter_winrt.cc index a2ba812053fa5..195ec4ee6afe8 100644 --- a/device/bluetooth/bluetooth_adapter_winrt.cc +++ b/device/bluetooth/bluetooth_adapter_winrt.cc @@ -105,6 +105,11 @@ using ABI::Windows::Storage::Streams::IDataReaderStatics; using Microsoft::WRL::Callback; using Microsoft::WRL::ComPtr; +bool ResolveCoreWinRT() { + return base::win::ResolveCoreWinRTDelayload() && + base::win::ScopedHString::ResolveCoreWinRTStringDelayload(); +} + // Query string for powered Bluetooth radios. GUID Reference: // https://docs.microsoft.com/en-us/windows-hardware/drivers/install/guid-bthport-device-interface // TODO(https://crbug.com/821766): Consider adding WindowsCreateStringReference @@ -666,6 +671,14 @@ void BluetoothAdapterWinrt::InitForTests( ComPtr bluetooth_adapter_statics, ComPtr device_information_statics, ComPtr radio_statics) { + + if (!ResolveCoreWinRT()) { + CompleteInit(std::move(init_callback), std::move(bluetooth_adapter_statics), + std::move(device_information_statics), + std::move(radio_statics)); + return; + } + auto statics = PerformSlowInitTasks(); // This allows any passed in values (which would be fakes) to replace @@ -689,6 +702,8 @@ void BluetoothAdapterWinrt::InitForTests( BluetoothAdapterWinrt::StaticsInterfaces BluetoothAdapterWinrt::PerformSlowInitTasks() { base::win::AssertComApartmentType(base::win::ComApartmentType::MTA); + if (!ResolveCoreWinRT()) + return BluetoothAdapterWinrt::StaticsInterfaces(); ComPtr adapter_statics; HRESULT hr = base::win::GetActivationFactory< IBluetoothAdapterStatics, diff --git a/device/gamepad/wgi_data_fetcher_win.cc b/device/gamepad/wgi_data_fetcher_win.cc index 3a4edd52a90ab..3faa079730ca5 100644 --- a/device/gamepad/wgi_data_fetcher_win.cc +++ b/device/gamepad/wgi_data_fetcher_win.cc @@ -210,6 +210,11 @@ GamepadSource WgiDataFetcherWin::source() { void WgiDataFetcherWin::OnAddedToProvider() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (!base::win::HStringReference::ResolveCoreWinRTStringDelayload()) { + initialization_state_ = + InitializationState::kCoreWinrtStringDelayLoadFailed; + return; + } HRESULT hr = get_activation_factory_function_( base::win::HStringReference(RuntimeClass_Windows_Gaming_Input_Gamepad) .Get(), diff --git a/device/gamepad/wgi_data_fetcher_win.h b/device/gamepad/wgi_data_fetcher_win.h index a5a27848749a2..450ad10130f76 100644 --- a/device/gamepad/wgi_data_fetcher_win.h +++ b/device/gamepad/wgi_data_fetcher_win.h @@ -36,6 +36,7 @@ class DEVICE_GAMEPAD_EXPORT WgiDataFetcherWin final kAddGamepadAddedFailed, kAddGamepadRemovedFailed, kRoGetActivationFactoryFailed, + kCoreWinrtStringDelayLoadFailed, }; using Factory = diff --git a/media/audio/win/audio_low_latency_input_win.cc b/media/audio/win/audio_low_latency_input_win.cc index cb3f192994152..ab1a511b5df45 100644 --- a/media/audio/win/audio_low_latency_input_win.cc +++ b/media/audio/win/audio_low_latency_input_win.cc @@ -236,6 +236,13 @@ bool InitializeUWPSupport() { // 10.0.10240.0. DCHECK_GE(base::win::OSInfo::GetInstance()->version_number().build, 10240u); + if (!(base::win::ResolveCoreWinRTDelayload() && + base::win::ScopedHString::ResolveCoreWinRTStringDelayload())) { + // Failed loading functions from combase.dll. + DLOG(WARNING) << "Failed to initialize WinRT/UWP"; + return false; + } + return true; }(); diff --git a/media/capture/video/win/video_capture_device_factory_win.cc b/media/capture/video/win/video_capture_device_factory_win.cc index 3466553f74609..1dfe88e84669f 100644 --- a/media/capture/video/win/video_capture_device_factory_win.cc +++ b/media/capture/video/win/video_capture_device_factory_win.cc @@ -304,6 +304,16 @@ bool DevicesInfoContainsDeviceId(const DevicesInfo& devices_info, }); } +bool IsEnclosureLocationSupported() { + if (!(base::win::ResolveCoreWinRTDelayload() && + ScopedHString::ResolveCoreWinRTStringDelayload())) { + DLOG(ERROR) << "Failed loading functions from combase.dll"; + return false; + } + + return true; +} + // Returns a non DirectShow descriptor DevicesInfo with the provided name and // model. DevicesInfo::const_iterator FindNonDirectShowDeviceInfoByNameAndModel( @@ -631,17 +641,23 @@ void VideoCaptureDeviceFactoryWin::GetDevicesInfo( devices_info = GetDevicesInfoDirectShow(devices_info); } - com_thread_.init_com_with_mta(true); - com_thread_.Start(); - com_thread_data_ = + if (IsEnclosureLocationSupported()) { + com_thread_.init_com_with_mta(true); + com_thread_.Start(); + com_thread_data_ = base::MakeRefCounted( weak_ptr_factory_.GetWeakPtr(), com_thread_.task_runner(), base::SingleThreadTaskRunner::GetCurrentDefault()); - com_thread_.task_runner()->PostTask( + com_thread_.task_runner()->PostTask( FROM_HERE, base::BindOnce( &VideoCaptureDeviceFactoryWin::ComThreadData::EnumerateDevicesUWP, com_thread_data_, std::move(devices_info), std::move(callback))); + + } else { + DeviceInfoReady(std::move(devices_info), std::move(callback)); + } + } void VideoCaptureDeviceFactoryWin::ComThreadData::EnumerateDevicesUWP( diff --git a/media/cdm/win/media_foundation_cdm_module.cc b/media/cdm/win/media_foundation_cdm_module.cc index 28fbd5d233a83..963314b8c0452 100644 --- a/media/cdm/win/media_foundation_cdm_module.cc +++ b/media/cdm/win/media_foundation_cdm_module.cc @@ -129,6 +129,10 @@ HRESULT MediaFoundationCdmModule::ActivateCdmFactory() { return kErrorLoadLibrary; } + // Initialization required to call base::win::ScopedHString::Create(); + if (!base::win::ScopedHString::ResolveCoreWinRTStringDelayload()) + return kErrorResolveCoreWinRTStringDelayload; + // Get function pointer to the activation factory. using GetActivationFactoryFunc = HRESULT(WINAPI*)(_In_ HSTRING activatible_class_id, diff --git a/media/midi/midi_manager_winrt.cc b/media/midi/midi_manager_winrt.cc index d5ce6175bffbf..5ee947135e9ee 100644 --- a/media/midi/midi_manager_winrt.cc +++ b/media/midi/midi_manager_winrt.cc @@ -822,6 +822,17 @@ void MidiManagerWinrt::InitializeOnComRunner() { DCHECK(service()->task_service()->IsOnTaskRunner(kComTaskRunner)); + bool preload_success = base::win::ResolveCoreWinRTDelayload() && + ScopedHString::ResolveCoreWinRTStringDelayload(); + + if (!preload_success) { + service()->task_service()->PostBoundTask( + kDefaultTaskRunner, + base::BindOnce(&MidiManagerWinrt::CompleteInitialization, + base::Unretained(this), Result::INITIALIZATION_ERROR)); + return; + } + port_manager_in_ = std::make_unique(this); port_manager_out_ = std::make_unique(this); diff --git a/media/renderers/win/media_foundation_protection_manager.cc b/media/renderers/win/media_foundation_protection_manager.cc index cd4b85d979afa..cd27c6f07fd86 100644 --- a/media/renderers/win/media_foundation_protection_manager.cc +++ b/media/renderers/win/media_foundation_protection_manager.cc @@ -37,6 +37,9 @@ HRESULT MediaFoundationProtectionManager::RuntimeClassInitialize( task_runner_ = std::move(task_runner); waiting_cb_ = std::move(waiting_cb); + if (!base::win::ScopedHString::ResolveCoreWinRTStringDelayload()) + return kErrorResolveCoreWinRTStringDelayload; + // Init an empty |property_set_| as MFMediaEngine could access it via // |get_Properties| before we populate it within SetPMPServer. base::win::ScopedHString property_set_id = base::win::ScopedHString::Create( diff --git a/mojo/core/embedder/embedder.cc b/mojo/core/embedder/embedder.cc index da19df4f20b5d..ba05f58ae6762 100644 --- a/mojo/core/embedder/embedder.cc +++ b/mojo/core/embedder/embedder.cc @@ -28,6 +28,10 @@ #include "mojo/core/node_controller.h" #include "mojo/public/c/system/thunks.h" +#if BUILDFLAG(IS_WIN) +#include "base/win/windows_version.h" +#endif // BUILDFLAG(IS_WIN) + #if !BUILDFLAG(IS_NACL) #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) #include "mojo/core/channel_linux.h" @@ -86,7 +90,20 @@ void InitFeatures() { } void EnableMojoIpcz() { - g_mojo_ipcz_enabled.store(true, std::memory_order_release); +#if BUILDFLAG(IS_WIN) + // TODO(https://crbug.com/1299283): Sandboxed processes on Windows versions + // older than 8.1 require some extra (not yet implemented... err... never implemented) setup for ipcz to + // work properly. This is omitted for early experimentation. + const bool kIsIpczSupported = + base::win::GetVersion() >= base::win::Version::WIN8_1; +#else + const bool kIsIpczSupported = true; +#endif + if (kIsIpczSupported) { + g_mojo_ipcz_enabled.store(true, std::memory_order_release); + } + else + g_mojo_ipcz_enabled.store(false, std::memory_order_release); } void Init(const Configuration& configuration) { diff --git a/net/proxy_resolution/win/winhttp_status.h b/net/proxy_resolution/win/winhttp_status.h index ae5f9ee08ba6a..975d714dab343 100644 --- a/net/proxy_resolution/win/winhttp_status.h +++ b/net/proxy_resolution/win/winhttp_status.h @@ -19,6 +19,9 @@ enum class WinHttpStatus { // Aborted by caller. kAborted, + // WinHttp binary failed to load. + kFunctionsNotLoaded, + // WinHttpOpen() API failed. kWinHttpOpenFailed, diff --git a/profile_manager() b/profile_manager() new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/sandbox/policy/win/sandbox_win.cc b/sandbox/policy/win/sandbox_win.cc index 490ecf09ab473..5f151a0f0358f 100644 --- a/sandbox/policy/win/sandbox_win.cc +++ b/sandbox/policy/win/sandbox_win.cc @@ -252,6 +252,7 @@ std::wstring PrependWindowsSessionPath(const wchar_t* object) { return base::StringPrintf(L"\\Sessions\\%lu%ls", s_session_id, object); } + // Adds the generic config rules to a sandbox TargetConfig. ResultCode AddGenericConfig(sandbox::TargetConfig* config) { DCHECK(!config->IsConfigured()); @@ -321,7 +322,9 @@ ResultCode AddDefaultConfigForSandboxedProcess(TargetConfig* config) { config->SetLockdownDefaultDacl(); - result = config->AddKernelObjectToClose(L"File", L"\\Device\\DeviceApi"); + // Win8+ adds a device DeviceApi that we don't need. + if (base::win::GetVersion() >= base::win::Version::WIN8) + result = config->AddKernelObjectToClose(L"File", L"\\Device\\DeviceApi"); if (result != SBOX_ALL_OK) return result; @@ -707,13 +710,22 @@ ResultCode LaunchWithoutSandbox( // on process shutdown, in which case TerminateProcess can fail. See // https://crbug.com/820996. if (delegate->ShouldUnsandboxedRunInJob()) { - static base::NoDestructor job_object; - if (!job_object->IsValid()) { - DWORD result = job_object->Init(JobLevel::kUnprotected, 0, 0); - if (result != ERROR_SUCCESS) - return SBOX_ERROR_CANNOT_INIT_JOB; + BOOL in_job = true; + // Prior to Windows 8 nested jobs aren't possible. + if (base::win::GetVersion() >= base::win::Version::WIN8 || + (::IsProcessInJob(::GetCurrentProcess(), nullptr, &in_job) && + !in_job)) { + static Job* job_object = nullptr; + if (!job_object) { + job_object = new Job; + DWORD result = job_object->Init(JobLevel::kUnprotected, 0, 0); + if (result != ERROR_SUCCESS) { + job_object = nullptr; + return SBOX_ERROR_CANNOT_INIT_JOB; + } + } + options.job_handle = job_object->GetHandle(); } - options.job_handle = job_object->GetHandle(); } // Chromium binaries are marked as CET Compatible but some processes @@ -804,6 +816,10 @@ ResultCode SandboxWin::AddAppContainerPolicy(TargetConfig* config, ResultCode SandboxWin::AddWin32kLockdownPolicy(TargetConfig* config) { DCHECK(!config->IsConfigured()); #if !defined(NACL_WIN64) + // Win32k Lockdown is supported on Windows 8+. + if (base::win::GetVersion() < base::win::Version::WIN8) + return SBOX_ALL_OK; + MitigationFlags flags = config->GetProcessMitigations(); // Check not enabling twice. Should not happen. DCHECK_EQ(0U, flags & MITIGATION_WIN32K_DISABLE); diff --git a/sandbox/win/src/app_container_base.cc b/sandbox/win/src/app_container_base.cc index 37cc8fa8f8996..d966f133f185b 100644 --- a/sandbox/win/src/app_container_base.cc +++ b/sandbox/win/src/app_container_base.cc @@ -20,6 +20,18 @@ namespace sandbox { namespace { +typedef decltype(::CreateAppContainerProfile) CreateAppContainerProfileFunc; + +typedef decltype(::DeriveAppContainerSidFromAppContainerName) + DeriveAppContainerSidFromAppContainerNameFunc; + +typedef decltype(::DeleteAppContainerProfile) DeleteAppContainerProfileFunc; + +typedef decltype(::GetAppContainerFolderPath) GetAppContainerFolderPathFunc; + +typedef decltype( + ::GetAppContainerRegistryLocation) GetAppContainerRegistryLocationFunc; + struct FreeSidDeleter { inline void operator()(void* ptr) const { ::FreeSid(ptr); } }; @@ -30,8 +42,14 @@ struct FreeSidDeleter { AppContainerBase* AppContainerBase::CreateProfile(const wchar_t* package_name, const wchar_t* display_name, const wchar_t* description) { - PSID package_sid_ptr = nullptr; - HRESULT hr = ::CreateAppContainerProfile( + static auto create_app_container_profile = + reinterpret_cast(GetProcAddress( + GetModuleHandle(L"userenv"), "CreateAppContainerProfile")); + if (!create_app_container_profile) + return nullptr; + + PSID package_sid_ptr = nullptr; + HRESULT hr = create_app_container_profile( package_name, display_name, description, nullptr, 0, &package_sid_ptr); if (hr == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS)) return Open(package_name); @@ -47,9 +65,15 @@ AppContainerBase* AppContainerBase::CreateProfile(const wchar_t* package_name, // static AppContainerBase* AppContainerBase::Open(const wchar_t* package_name) { + static auto derive_app_container_sid = + reinterpret_cast( + GetProcAddress(GetModuleHandle(L"userenv"), + "DeriveAppContainerSidFromAppContainerName")); + if (!derive_app_container_sid) + return nullptr; + PSID package_sid_ptr = nullptr; - HRESULT hr = ::DeriveAppContainerSidFromAppContainerName(package_name, - &package_sid_ptr); + HRESULT hr = derive_app_container_sid(package_name, &package_sid_ptr); if (FAILED(hr)) return nullptr; @@ -71,7 +95,13 @@ AppContainerBase* AppContainerBase::CreateLowbox(const wchar_t* sid) { // static bool AppContainerBase::Delete(const wchar_t* package_name) { - return SUCCEEDED(::DeleteAppContainerProfile(package_name)); + static auto delete_app_container_profile = + reinterpret_cast(GetProcAddress( + GetModuleHandle(L"userenv"), "DeleteAppContainerProfile")); + if (!delete_app_container_profile) + return false; + + return SUCCEEDED(delete_app_container_profile(package_name)); } AppContainerBase::AppContainerBase(base::win::Sid& package_sid, diff --git a/sandbox/win/src/job.cc b/sandbox/win/src/job.cc index 2dc76c19df5ba..f28b5bc5c00f3 100644 --- a/sandbox/win/src/job.cc +++ b/sandbox/win/src/job.cc @@ -9,21 +9,24 @@ #include #include +#include "base/win/windows_version.h" #include "sandbox/win/src/restricted_token.h" namespace sandbox { -Job::Job() = default; -Job::~Job() = default; +Job::Job() : job_handle_(nullptr) {} + +Job::~Job() {} DWORD Job::Init(JobLevel security_level, DWORD ui_exceptions, size_t memory_limit) { - if (job_handle_.is_valid()) + if (job_handle_.IsValid()) return ERROR_ALREADY_INITIALIZED; - job_handle_.Set(::CreateJobObject(nullptr, nullptr)); - if (!job_handle_.is_valid()) + job_handle_.Set(::CreateJobObject(nullptr, // No security attribute + nullptr)); + if (!job_handle_.IsValid()) return ::GetLastError(); JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = {}; @@ -64,6 +67,9 @@ DWORD Job::Init(JobLevel security_level, JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; break; } + case JobLevel::kNone: { + return ERROR_BAD_ARGUMENTS; + } } if (!::SetInformationJobObject(job_handle_.Get(), @@ -83,20 +89,42 @@ DWORD Job::Init(JobLevel security_level, } bool Job::IsValid() { - return job_handle_.is_valid(); + return job_handle_.IsValid(); } HANDLE Job::GetHandle() { - return job_handle_.get(); + return job_handle_.Get(); +} + +DWORD Job::UserHandleGrantAccess(HANDLE handle) { + if (!job_handle_.IsValid()) + return ERROR_NO_DATA; + + if (!::UserHandleGrantAccess(handle, job_handle_.Get(), + true)) { // Access allowed. + return ::GetLastError(); + } + + return ERROR_SUCCESS; +} + +DWORD Job::AssignProcessToJob(HANDLE process_handle) { + if (!job_handle_.IsValid()) + return ERROR_NO_DATA; + + if (!::AssignProcessToJobObject(job_handle_.Get(), process_handle)) + return ::GetLastError(); + + return ERROR_SUCCESS; } DWORD Job::SetActiveProcessLimit(DWORD processes) { JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = {}; - if (!job_handle_.is_valid()) + if (!job_handle_.IsValid()) return ERROR_NO_DATA; - if (!::QueryInformationJobObject(job_handle_.get(), + if (!::QueryInformationJobObject(job_handle_.Get(), JobObjectExtendedLimitInformation, &jeli, sizeof(jeli), nullptr)) { return ::GetLastError(); @@ -104,7 +132,7 @@ DWORD Job::SetActiveProcessLimit(DWORD processes) { jeli.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_ACTIVE_PROCESS; jeli.BasicLimitInformation.ActiveProcessLimit = processes; - if (!::SetInformationJobObject(job_handle_.get(), + if (!::SetInformationJobObject(job_handle_.Get(), JobObjectExtendedLimitInformation, &jeli, sizeof(jeli))) { return ::GetLastError(); diff --git a/sandbox/win/src/job.h b/sandbox/win/src/job.h index 31037e1b7aff7..a148179e108a5 100644 --- a/sandbox/win/src/job.h +++ b/sandbox/win/src/job.h @@ -15,7 +15,8 @@ enum class JobLevel; // Handles the creation of job objects based on a security profile. // Sample usage: // Job job; -// job.Init(JobLevel::kLockdown, 0, 0); +// job.Init(JobLevel::kLockdown, nullptr); //no job name +// job.AssignProcessToJob(process_handle); class Job { public: Job(); @@ -27,6 +28,7 @@ class Job { // Initializes and creates the job object. The security of the job is based // on the security_level parameter. + // job_name can be nullptr if the job is unnamed. // If the chosen profile has too many ui restrictions, you can disable some // by specifying them in the ui_exceptions parameters. // If the function succeeds, the return value is ERROR_SUCCESS. If the @@ -34,6 +36,19 @@ class Job { // the error. DWORD Init(JobLevel security_level, DWORD ui_exceptions, size_t memory_limit); + // Assigns the process referenced by process_handle to the job. + // If the function succeeds, the return value is ERROR_SUCCESS. If the + // function fails, the return value is the win32 error code corresponding to + // the error. + DWORD AssignProcessToJob(HANDLE process_handle); + + // Grants access to "handle" to the job. All processes in the job can + // subsequently recognize and use the handle. + // If the function succeeds, the return value is ERROR_SUCCESS. If the + // function fails, the return value is the win32 error code corresponding to + // the error. + DWORD UserHandleGrantAccess(HANDLE handle); + // True if the job has been initialized and has a valid handle. bool IsValid(); diff --git a/sandbox/win/src/nt_internals.h b/sandbox/win/src/nt_internals.h index 72d96b96f4fd4..c3dedf262abcf 100644 --- a/sandbox/win/src/nt_internals.h +++ b/sandbox/win/src/nt_internals.h @@ -162,7 +162,13 @@ typedef NTSTATUS(WINAPI* NtSetInformationThreadFunction)( IN PVOID ThreadInformation, IN ULONG ThreadInformationLength); +typedef struct _PROCESS_ACCESS_TOKEN { + HANDLE token; + HANDLE thread; +} PROCESS_ACCESS_TOKEN; + // Partial definition only for values not in PROCESS_INFO_CLASS. +constexpr auto ProcessInformationAccessToken = static_cast(9); #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wenum-constexpr-conversion" constexpr auto ProcessHandleTable = static_cast(58); diff --git a/sandbox/win/src/process_mitigations.cc b/sandbox/win/src/process_mitigations.cc index b31b832685af2..f298558463894 100644 --- a/sandbox/win/src/process_mitigations.cc +++ b/sandbox/win/src/process_mitigations.cc @@ -37,22 +37,39 @@ namespace sandbox { namespace { +// API defined in libloaderapi.h >= Win8. Also available in Vista/7 starting with KB2533623. +// Known to be buggy on Vista, but not known to affect Chromium. +using SetDefaultDllDirectoriesFunction = decltype(&SetDefaultDllDirectories); + +// APIs defined in processthreadsapi.h >= Win8. +using SetProcessMitigationPolicyFunction = + decltype(&SetProcessMitigationPolicy); +using GetProcessMitigationPolicyFunction = + decltype(&GetProcessMitigationPolicy); +using SetThreadInformationFunction = decltype(&SetThreadInformation); + // Returns a two-element array of mitigation flags supported on this machine. const ULONG64* GetSupportedMitigations() { static ULONG64 mitigations[2] = {}; // This static variable will only be initialized once. if (!mitigations[0] && !mitigations[1]) { - // NOTE: the two-element-sized input array is only supported on >= Win10 - // RS2. If an earlier version, the second element will be left 0. - size_t mits_size = - (base::win::GetVersion() >= base::win::Version::WIN10_RS2) - ? (sizeof(mitigations[0]) * 2) - : sizeof(mitigations[0]); - if (!::GetProcessMitigationPolicy(::GetCurrentProcess(), - ProcessMitigationOptionsMask, - &mitigations, mits_size)) { - NOTREACHED(); + GetProcessMitigationPolicyFunction get_process_mitigation_policy = + reinterpret_cast(::GetProcAddress( + ::GetModuleHandleA("kernel32.dll"), "GetProcessMitigationPolicy")); + if (get_process_mitigation_policy) { + // NOTE: the two-element-sized input array is only supported on >= Win10 + // RS2. + // If an earlier version, the second element will be left 0. + size_t mits_size = + (base::win::GetVersion() >= base::win::Version::WIN10_RS2) + ? (sizeof(mitigations[0]) * 2) + : sizeof(mitigations[0]); + if (!get_process_mitigation_policy(::GetCurrentProcess(), + ProcessMitigationOptionsMask, + &mitigations, mits_size)) { + NOTREACHED(); + } } } @@ -76,7 +93,14 @@ bool IsRunning32bitEmulatedOnArm64() { bool SetProcessMitigationPolicyInternal(PROCESS_MITIGATION_POLICY policy, PVOID lpBuffer, SIZE_T dwLength) { - PCHECK(::SetProcessMitigationPolicy(policy, lpBuffer, dwLength)) + HMODULE module = ::GetModuleHandleA("kernel32.dll"); + SetProcessMitigationPolicyFunction set_process_mitigation_policy_function = + reinterpret_cast( + ::GetProcAddress(module, "SetProcessMitigationPolicy")); + if (!set_process_mitigation_policy_function) + return false; + + PCHECK(set_process_mitigation_policy_function(policy, lpBuffer, dwLength)) << "SetProcessMitigationPolicy failed with Policy: " << policy; return true; @@ -92,21 +116,29 @@ bool ApplyProcessMitigationsToCurrentProcess(MitigationFlags starting_flags, base::win::Version version = base::win::GetVersion(); - if (flags & MITIGATION_DLL_SEARCH_ORDER) { + if (flags & MITIGATION_DLL_SEARCH_ORDER) { + HMODULE module = ::GetModuleHandleA("kernel32.dll"); + SetDefaultDllDirectoriesFunction set_default_dll_directories = + reinterpret_cast( + ::GetProcAddress(module, "SetDefaultDllDirectories")); + + // Check for SetDefaultDllDirectories since it requires KB2533623. + if (set_default_dll_directories) { #if defined(COMPONENT_BUILD) - const DWORD directory_flags = LOAD_LIBRARY_SEARCH_DEFAULT_DIRS; + const DWORD directory_flags = LOAD_LIBRARY_SEARCH_DEFAULT_DIRS; #else - // In a non-component build, all DLLs will be loaded manually, or via - // manifest definition, so these flags can be stronger. This prevents DLL - // planting in the application directory. - const DWORD directory_flags = - LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_USER_DIRS; + // In a non-component build, all DLLs will be loaded manually, or via + // manifest definition, so these flags can be stronger. This prevents DLL + // planting in the application directory. + const DWORD directory_flags = + LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_USER_DIRS; #endif - if (!::SetDefaultDllDirectories(directory_flags)) { - return false; - } + if (!set_default_dll_directories(directory_flags)) { + return false; + } - applied_flags |= MITIGATION_DLL_SEARCH_ORDER; + applied_flags |= MITIGATION_DLL_SEARCH_ORDER; + } } // Set the heap to terminate on corruption @@ -149,6 +181,10 @@ bool ApplyProcessMitigationsToCurrentProcess(MitigationFlags starting_flags, } #endif + // This is all we can do in Win7 and below. + if (version < base::win::Version::WIN8) + return true; + // Enable ASLR policies. if (flags & MITIGATION_RELOCATE_IMAGE) { PROCESS_MITIGATION_ASLR_POLICY policy = {}; @@ -212,6 +248,9 @@ bool ApplyProcessMitigationsToCurrentProcess(MitigationFlags starting_flags, applied_flags |= MITIGATION_EXTENSION_POINT_DISABLE; } + if (version < base::win::Version::WIN8_1) + return true; + // Enable dynamic code policies. if (!IsRunning32bitEmulatedOnArm64() && (flags & MITIGATION_DYNAMIC_CODE_DISABLE)) { @@ -228,6 +267,9 @@ bool ApplyProcessMitigationsToCurrentProcess(MitigationFlags starting_flags, applied_flags |= MITIGATION_DYNAMIC_CODE_DISABLE; } + if (version < base::win::Version::WIN10) + return true; + // Enable font policies. if (flags & MITIGATION_NONSYSTEM_FONT_DISABLE) { PROCESS_MITIGATION_FONT_DISABLE_POLICY policy = {}; @@ -349,9 +391,20 @@ bool ApplyMitigationsToCurrentThread(MitigationFlags flags) { if (flags & MITIGATION_DYNAMIC_CODE_OPT_OUT_THIS_THREAD) { DWORD thread_policy = THREAD_DYNAMIC_CODE_ALLOW; + // NOTE: SetThreadInformation API only exists on >= Win8. Dynamically + // get function handle. + base::ScopedNativeLibrary dll(base::FilePath(L"kernel32.dll")); + if (!dll.is_valid()) + return false; + SetThreadInformationFunction set_thread_info_function = + reinterpret_cast( + dll.GetFunctionPointer("SetThreadInformation")); + if (!set_thread_info_function) + return false; + // NOTE: Must use the pseudo-handle here, a thread HANDLE won't work. - if (!::SetThreadInformation(::GetCurrentThread(), ThreadDynamicCodePolicy, - &thread_policy, sizeof(thread_policy))) { + if (!set_thread_info_function(::GetCurrentThread(), ThreadDynamicCodePolicy, + &thread_policy, sizeof(thread_policy))) { return false; } } @@ -372,8 +425,14 @@ void ConvertProcessMitigationsToPolicy(MitigationFlags flags, *policy_value_1 = 0; *policy_value_2 = 0; -#if defined(_WIN64) || defined(_M_IX86) +#if defined(_WIN64) *size = sizeof(*policy_flags); +#elif defined(_M_IX86) + // A 64-bit flags attribute is illegal on 32-bit Win 7. + if (version < base::win::Version::WIN8) + *size = sizeof(DWORD); + else + *size = sizeof(*policy_flags); #else #error This platform is not supported. #endif @@ -391,53 +450,73 @@ void ConvertProcessMitigationsToPolicy(MitigationFlags flags, *policy_value_1 |= PROCESS_CREATION_MITIGATION_POLICY_SEHOP_ENABLE; #endif - if (flags & MITIGATION_RELOCATE_IMAGE) { - *policy_value_1 |= - PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON; - if (flags & MITIGATION_RELOCATE_IMAGE_REQUIRED) { + // Win 7 + if (version < base::win::Version::WIN8) + return; + + // Everything >= Win8, do not return before the end of the function where + // the final policy bitmap is sanity checked against what is supported on this + // machine. The API required to do so is only available since Win8. + + // Mitigations >= Win8: + //---------------------------------------------------------------------------- + if (version >= base::win::Version::WIN8) { + if (flags & MITIGATION_RELOCATE_IMAGE) { *policy_value_1 |= - PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON_REQ_RELOCS; + PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON; + if (flags & MITIGATION_RELOCATE_IMAGE_REQUIRED) { + *policy_value_1 |= + PROCESS_CREATION_MITIGATION_POLICY_FORCE_RELOCATE_IMAGES_ALWAYS_ON_REQ_RELOCS; + } } - } - if (flags & MITIGATION_HEAP_TERMINATE) { - *policy_value_1 |= - PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_ALWAYS_ON; - } + if (flags & MITIGATION_HEAP_TERMINATE) { + *policy_value_1 |= + PROCESS_CREATION_MITIGATION_POLICY_HEAP_TERMINATE_ALWAYS_ON; + } - if (flags & MITIGATION_BOTTOM_UP_ASLR) { - *policy_value_1 |= - PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_ON; - } + if (flags & MITIGATION_BOTTOM_UP_ASLR) { + *policy_value_1 |= + PROCESS_CREATION_MITIGATION_POLICY_BOTTOM_UP_ASLR_ALWAYS_ON; + } - if (flags & MITIGATION_HIGH_ENTROPY_ASLR) { - *policy_value_1 |= - PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_ALWAYS_ON; - } + if (flags & MITIGATION_HIGH_ENTROPY_ASLR) { + *policy_value_1 |= + PROCESS_CREATION_MITIGATION_POLICY_HIGH_ENTROPY_ASLR_ALWAYS_ON; + } - if (flags & MITIGATION_STRICT_HANDLE_CHECKS) { - *policy_value_1 |= - PROCESS_CREATION_MITIGATION_POLICY_STRICT_HANDLE_CHECKS_ALWAYS_ON; - } + if (flags & MITIGATION_STRICT_HANDLE_CHECKS) { + *policy_value_1 |= + PROCESS_CREATION_MITIGATION_POLICY_STRICT_HANDLE_CHECKS_ALWAYS_ON; + } - if (flags & MITIGATION_WIN32K_DISABLE) { - *policy_value_1 |= - PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_ALWAYS_ON; - } + if (flags & MITIGATION_WIN32K_DISABLE) { + *policy_value_1 |= + PROCESS_CREATION_MITIGATION_POLICY_WIN32K_SYSTEM_CALL_DISABLE_ALWAYS_ON; + } - if (flags & MITIGATION_EXTENSION_POINT_DISABLE) { - *policy_value_1 |= - PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON; + if (flags & MITIGATION_EXTENSION_POINT_DISABLE) { + *policy_value_1 |= + PROCESS_CREATION_MITIGATION_POLICY_EXTENSION_POINT_DISABLE_ALWAYS_ON; + } } - if (flags & MITIGATION_DYNAMIC_CODE_DISABLE) { - *policy_value_1 |= - PROCESS_CREATION_MITIGATION_POLICY_PROHIBIT_DYNAMIC_CODE_ALWAYS_ON; + // Mitigations >= Win8.1: + //---------------------------------------------------------------------------- + if (version >= base::win::Version::WIN8_1) { + if (flags & MITIGATION_DYNAMIC_CODE_DISABLE) { + *policy_value_1 |= + PROCESS_CREATION_MITIGATION_POLICY_PROHIBIT_DYNAMIC_CODE_ALWAYS_ON; + } } - if (flags & MITIGATION_NONSYSTEM_FONT_DISABLE) { - *policy_value_1 |= - PROCESS_CREATION_MITIGATION_POLICY_FONT_DISABLE_ALWAYS_ON; + // Mitigations >= Win10: + //---------------------------------------------------------------------------- + if (version >= base::win::Version::WIN10) { + if (flags & MITIGATION_NONSYSTEM_FONT_DISABLE) { + *policy_value_1 |= + PROCESS_CREATION_MITIGATION_POLICY_FONT_DISABLE_ALWAYS_ON; + } } // Mitigations >= Win10 TH2: @@ -539,6 +618,15 @@ void ConvertProcessMitigationsToComponentFilter(MitigationFlags flags, } MitigationFlags FilterPostStartupProcessMitigations(MitigationFlags flags) { + base::win::Version version = base::win::GetVersion(); + + // Windows 7. + if (version < base::win::Version::WIN8) { + return flags & (MITIGATION_BOTTOM_UP_ASLR | MITIGATION_DLL_SEARCH_ORDER | + MITIGATION_HEAP_TERMINATE); + } + + // Windows 8 and above. return flags & (MITIGATION_BOTTOM_UP_ASLR | MITIGATION_DLL_SEARCH_ORDER); } diff --git a/sandbox/win/src/process_mitigations_unittest.cc b/sandbox/win/src/process_mitigations_unittest.cc index a45a6361b450f..07ec3865b033a 100644 --- a/sandbox/win/src/process_mitigations_unittest.cc +++ b/sandbox/win/src/process_mitigations_unittest.cc @@ -35,6 +35,22 @@ namespace { +//------------------------------------------------------------------------------ +// Internal Defines & Functions +//------------------------------------------------------------------------------ + +// API defined in winbase.h. +using GetProcessDEPPolicyFunction = decltype(&GetProcessDEPPolicy); + +// API defined in processthreadsapi.h. +using GetProcessMitigationPolicyFunction = + decltype(&GetProcessMitigationPolicy); +GetProcessMitigationPolicyFunction get_process_mitigation_policy; + +// APIs defined in wingdi.h. +using AddFontMemResourceExFunction = decltype(&AddFontMemResourceEx); +using RemoveFontMemResourceExFunction = decltype(&RemoveFontMemResourceEx); + //------------------------------------------------------------------------------ // NonSystemFont test helper function. // @@ -88,6 +104,13 @@ SBOX_TESTS_COMMAND int CheckPolicy(int argc, wchar_t** argv) { if (!test) return SBOX_TEST_INVALID_PARAMETER; + get_process_mitigation_policy = + reinterpret_cast(::GetProcAddress( + ::GetModuleHandleW(L"kernel32.dll"), "GetProcessMitigationPolicy")); + if (!get_process_mitigation_policy) + return SBOX_TEST_NOT_FOUND; + + switch (test) { //-------------------------------------------------- // MITIGATION_DEP @@ -97,8 +120,9 @@ SBOX_TESTS_COMMAND int CheckPolicy(int argc, wchar_t** argv) { #if !defined(_WIN64) // DEP - always enabled on 64-bit. PROCESS_MITIGATION_DEP_POLICY policy = {}; - if (!::GetProcessMitigationPolicy(::GetCurrentProcess(), ProcessDEPPolicy, - &policy, sizeof(policy))) { + if (!get_process_mitigation_policy(::GetCurrentProcess(), + ProcessDEPPolicy, &policy, + sizeof(policy))) { return SBOX_TEST_NOT_FOUND; } if (!policy.Enable || !policy.Permanent) @@ -112,9 +136,9 @@ SBOX_TESTS_COMMAND int CheckPolicy(int argc, wchar_t** argv) { //-------------------------------------------------- case (TESTPOLICY_ASLR): { PROCESS_MITIGATION_ASLR_POLICY policy = {}; - if (!::GetProcessMitigationPolicy(::GetCurrentProcess(), - ProcessASLRPolicy, &policy, - sizeof(policy))) { + if (!get_process_mitigation_policy(::GetCurrentProcess(), + ProcessASLRPolicy, &policy, + sizeof(policy))) { return SBOX_TEST_NOT_FOUND; } if (!policy.EnableForceRelocateImages || !policy.DisallowStrippedImages) @@ -127,9 +151,9 @@ SBOX_TESTS_COMMAND int CheckPolicy(int argc, wchar_t** argv) { //-------------------------------------------------- case (TESTPOLICY_STRICTHANDLE): { PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY policy = {}; - if (!::GetProcessMitigationPolicy(::GetCurrentProcess(), - ProcessStrictHandleCheckPolicy, &policy, - sizeof(policy))) { + if (!get_process_mitigation_policy(::GetCurrentProcess(), + ProcessStrictHandleCheckPolicy, + &policy, sizeof(policy))) { return SBOX_TEST_NOT_FOUND; } if (!policy.RaiseExceptionOnInvalidHandleReference || @@ -144,9 +168,9 @@ SBOX_TESTS_COMMAND int CheckPolicy(int argc, wchar_t** argv) { //-------------------------------------------------- case (TESTPOLICY_WIN32K): { PROCESS_MITIGATION_SYSTEM_CALL_DISABLE_POLICY policy = {}; - if (!::GetProcessMitigationPolicy(::GetCurrentProcess(), - ProcessSystemCallDisablePolicy, &policy, - sizeof(policy))) { + if (!get_process_mitigation_policy(::GetCurrentProcess(), + ProcessSystemCallDisablePolicy, + &policy, sizeof(policy))) { return SBOX_TEST_NOT_FOUND; } if (!policy.DisallowWin32kSystemCalls) @@ -163,7 +187,7 @@ SBOX_TESTS_COMMAND int CheckPolicy(int argc, wchar_t** argv) { //-------------------------------------------------- case (TESTPOLICY_EXTENSIONPOINT): { PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY policy = {}; - if (!::GetProcessMitigationPolicy(::GetCurrentProcess(), + if (!get_process_mitigation_policy(::GetCurrentProcess(), ProcessExtensionPointDisablePolicy, &policy, sizeof(policy))) { return SBOX_TEST_NOT_FOUND; @@ -178,7 +202,7 @@ SBOX_TESTS_COMMAND int CheckPolicy(int argc, wchar_t** argv) { //-------------------------------------------------- case (TESTPOLICY_DYNAMICCODE): { PROCESS_MITIGATION_DYNAMIC_CODE_POLICY policy = {}; - if (!::GetProcessMitigationPolicy(::GetCurrentProcess(), + if (!get_process_mitigation_policy(::GetCurrentProcess(), ProcessDynamicCodePolicy, &policy, sizeof(policy))) { return SBOX_TEST_NOT_FOUND; @@ -193,7 +217,7 @@ SBOX_TESTS_COMMAND int CheckPolicy(int argc, wchar_t** argv) { //-------------------------------------------------- case (TESTPOLICY_NONSYSFONT): { PROCESS_MITIGATION_FONT_DISABLE_POLICY policy = {}; - if (!::GetProcessMitigationPolicy(::GetCurrentProcess(), + if (!get_process_mitigation_policy(::GetCurrentProcess(), ProcessFontDisablePolicy, &policy, sizeof(policy))) { return SBOX_TEST_NOT_FOUND; @@ -208,7 +232,7 @@ SBOX_TESTS_COMMAND int CheckPolicy(int argc, wchar_t** argv) { //-------------------------------------------------- case (TESTPOLICY_MSSIGNED): { PROCESS_MITIGATION_BINARY_SIGNATURE_POLICY policy = {}; - if (!::GetProcessMitigationPolicy(::GetCurrentProcess(), + if (!get_process_mitigation_policy(::GetCurrentProcess(), ProcessSignaturePolicy, &policy, sizeof(policy))) { return SBOX_TEST_NOT_FOUND; @@ -223,7 +247,7 @@ SBOX_TESTS_COMMAND int CheckPolicy(int argc, wchar_t** argv) { //-------------------------------------------------- case (TESTPOLICY_LOADNOREMOTE): { PROCESS_MITIGATION_IMAGE_LOAD_POLICY policy = {}; - if (!::GetProcessMitigationPolicy(::GetCurrentProcess(), + if (!get_process_mitigation_policy(::GetCurrentProcess(), ProcessImageLoadPolicy, &policy, sizeof(policy))) { return SBOX_TEST_NOT_FOUND; @@ -238,7 +262,7 @@ SBOX_TESTS_COMMAND int CheckPolicy(int argc, wchar_t** argv) { //-------------------------------------------------- case (TESTPOLICY_LOADNOLOW): { PROCESS_MITIGATION_IMAGE_LOAD_POLICY policy = {}; - if (!::GetProcessMitigationPolicy(::GetCurrentProcess(), + if (!get_process_mitigation_policy(::GetCurrentProcess(), ProcessImageLoadPolicy, &policy, sizeof(policy))) { return SBOX_TEST_NOT_FOUND; @@ -253,7 +277,7 @@ SBOX_TESTS_COMMAND int CheckPolicy(int argc, wchar_t** argv) { //-------------------------------------------------- case (TESTPOLICY_DYNAMICCODEOPTOUT): { PROCESS_MITIGATION_DYNAMIC_CODE_POLICY policy = {}; - if (!::GetProcessMitigationPolicy(::GetCurrentProcess(), + if (!get_process_mitigation_policy(::GetCurrentProcess(), ProcessDynamicCodePolicy, &policy, sizeof(policy))) { return SBOX_TEST_NOT_FOUND; @@ -268,7 +292,7 @@ SBOX_TESTS_COMMAND int CheckPolicy(int argc, wchar_t** argv) { //-------------------------------------------------- case (TESTPOLICY_LOADPREFERSYS32): { PROCESS_MITIGATION_IMAGE_LOAD_POLICY policy = {}; - if (!::GetProcessMitigationPolicy(::GetCurrentProcess(), + if (!get_process_mitigation_policy(::GetCurrentProcess(), ProcessImageLoadPolicy, &policy, sizeof(policy))) { return SBOX_TEST_NOT_FOUND; @@ -293,7 +317,7 @@ SBOX_TESTS_COMMAND int CheckPolicy(int argc, wchar_t** argv) { //-------------------------------------------------- case (TESTPOLICY_CETDISABLED): { PROCESS_MITIGATION_USER_SHADOW_STACK_POLICY policy = {}; - if (!::GetProcessMitigationPolicy(::GetCurrentProcess(), + if (!get_process_mitigation_policy(::GetCurrentProcess(), ProcessUserShadowStackPolicy, &policy, sizeof(policy))) { return SBOX_TEST_NOT_FOUND; @@ -309,7 +333,7 @@ SBOX_TESTS_COMMAND int CheckPolicy(int argc, wchar_t** argv) { //-------------------------------------------------- case (TESTPOLICY_CETDYNAMICAPIS): { PROCESS_MITIGATION_USER_SHADOW_STACK_POLICY policy = {}; - if (!::GetProcessMitigationPolicy(::GetCurrentProcess(), + if (!get_process_mitigation_policy(::GetCurrentProcess(), ProcessUserShadowStackPolicy, &policy, sizeof(policy))) { return SBOX_TEST_NOT_FOUND; @@ -332,7 +356,7 @@ SBOX_TESTS_COMMAND int CheckPolicy(int argc, wchar_t** argv) { //-------------------------------------------------- case (TESTPOLICY_CETSTRICT): { PROCESS_MITIGATION_USER_SHADOW_STACK_POLICY policy = {}; - if (!::GetProcessMitigationPolicy(::GetCurrentProcess(), + if (!get_process_mitigation_policy(::GetCurrentProcess(), ProcessUserShadowStackPolicy, &policy, sizeof(policy))) { return SBOX_TEST_NOT_FOUND; @@ -372,7 +396,7 @@ SBOX_TESTS_COMMAND int CheckPolicy(int argc, wchar_t** argv) { case (TESTPOLICY_PREANDPOSTSTARTUP): { // Both policies should be set now. PROCESS_MITIGATION_IMAGE_LOAD_POLICY policy = {}; - if (!::GetProcessMitigationPolicy(::GetCurrentProcess(), + if (!get_process_mitigation_policy(::GetCurrentProcess(), ProcessImageLoadPolicy, &policy, sizeof(policy))) { return SBOX_TEST_NOT_FOUND; @@ -483,11 +507,18 @@ SBOX_TESTS_COMMAND int TestChildProcess(int argc, wchar_t** argv) { return SBOX_TEST_SUCCEEDED; } } + + auto get_process_mitigation_policy = + reinterpret_cast(::GetProcAddress( + ::GetModuleHandleW(L"kernel32.dll"), "GetProcessMitigationPolicy")); + if (!get_process_mitigation_policy) + return SBOX_TEST_NOT_FOUND; + // Process failed to be created. // Note: GetLastError from CreateProcess returns 5, "ERROR_ACCESS_DENIED". // Validate the NoChildProcessCreation policy is applied. PROCESS_MITIGATION_CHILD_PROCESS_POLICY policy = {}; - if (!::GetProcessMitigationPolicy(::GetCurrentProcess(), + if (!get_process_mitigation_policy(::GetCurrentProcess(), ProcessChildProcessPolicy, &policy, sizeof(policy))) { return SBOX_TEST_NOT_FOUND; @@ -860,10 +891,14 @@ TEST(ProcessMitigationsTest, CetDisablePolicy) { // Verify policy is available and set for this process (i.e. CET is // enabled via IFEO or through the CETCOMPAT bit on the executable). + auto get_process_mitigation_policy = + reinterpret_cast(::GetProcAddress( + ::GetModuleHandleA("kernel32.dll"), "GetProcessMitigationPolicy")); + PROCESS_MITIGATION_USER_SHADOW_STACK_POLICY uss_policy; - if (!::GetProcessMitigationPolicy(GetCurrentProcess(), - ProcessUserShadowStackPolicy, &uss_policy, - sizeof(uss_policy))) { + if (!get_process_mitigation_policy(GetCurrentProcess(), + ProcessUserShadowStackPolicy, &uss_policy, + sizeof(uss_policy))) { return; } @@ -900,10 +935,14 @@ TEST(ProcessMitigationsTest, CetAllowDynamicApis) { // Verify policy is available and set for this process (i.e. CET is // enabled via IFEO or through the CETCOMPAT bit on the executable). + auto get_process_mitigation_policy = + reinterpret_cast(::GetProcAddress( + ::GetModuleHandleA("kernel32.dll"), "GetProcessMitigationPolicy")); + PROCESS_MITIGATION_USER_SHADOW_STACK_POLICY uss_policy; - if (!::GetProcessMitigationPolicy(GetCurrentProcess(), - ProcessUserShadowStackPolicy, &uss_policy, - sizeof(uss_policy))) { + if (!get_process_mitigation_policy(GetCurrentProcess(), + ProcessUserShadowStackPolicy, &uss_policy, + sizeof(uss_policy))) { return; } @@ -938,10 +977,14 @@ TEST(ProcessMitigationsTest, CetStrictMode) { // Verify policy is available and set for this process (i.e. CET is // enabled via IFEO or through the CETCOMPAT bit on the executable). + auto get_process_mitigation_policy = + reinterpret_cast(::GetProcAddress( + ::GetModuleHandleA("kernel32.dll"), "GetProcessMitigationPolicy")); + PROCESS_MITIGATION_USER_SHADOW_STACK_POLICY uss_policy; - if (!::GetProcessMitigationPolicy(GetCurrentProcess(), - ProcessUserShadowStackPolicy, &uss_policy, - sizeof(uss_policy))) { + if (!get_process_mitigation_policy(GetCurrentProcess(), + ProcessUserShadowStackPolicy, &uss_policy, + sizeof(uss_policy))) { return; } diff --git a/sandbox/win/src/restricted_token_utils.cc b/sandbox/win/src/restricted_token_utils.cc index f0c6598f7aa00..9aa7ef688b2bf 100644 --- a/sandbox/win/src/restricted_token_utils.cc +++ b/sandbox/win/src/restricted_token_utils.cc @@ -10,8 +10,10 @@ #include "base/check.h" #include "base/notreached.h" #include "base/win/access_token.h" +#include "base/win/scoped_handle.h" #include "base/win/security_descriptor.h" #include "sandbox/win/src/acl.h" +#include "sandbox/win/src/job.h" #include "sandbox/win/src/restricted_token.h" #include "sandbox/win/src/sandbox_nt_util.h" #include "sandbox/win/src/security_level.h" @@ -190,6 +192,66 @@ DWORD HardenTokenIntegrityLevelPolicy(const base::win::AccessToken& token) { return ERROR_SUCCESS; } +bool CreateLowBoxToken(HANDLE base_token, + TokenType token_type, + const base::win::Sid& package_sid, + const std::vector& capabilities, + base::win::ScopedHandle* token) { + if (!token) { + return false; + } + + absl::optional base_token_handle; + if (!base_token) { + base_token_handle = base::win::AccessToken::FromCurrentProcess( + /*impersonation=*/false, TOKEN_DUPLICATE); + } else { + base_token_handle = + base::win::AccessToken::FromToken(base_token, TOKEN_DUPLICATE); + } + if (!base_token_handle.has_value()) { + return false; + } + + absl::optional token_lowbox = + base_token_handle->CreateAppContainer(package_sid, capabilities, + TOKEN_ALL_ACCESS); + if (!token_lowbox.has_value()) { + return false; + } + + // Default from CreateAppContainer is a Primary token. + if (token_type == TokenType::kPrimary) { + *token = token_lowbox->release(); + return true; + } + + absl::optional token_dup = + token_lowbox->DuplicateImpersonation( + base::win::SecurityImpersonationLevel::kImpersonation, + TOKEN_ALL_ACCESS); + if (!token_dup.has_value()) { + return false; + } + + absl::optional sd = + base::win::SecurityDescriptor::FromHandle( + token_lowbox->get(), base::win::SecurityObjectType::kKernel, + DACL_SECURITY_INFORMATION); + if (!sd) { + return false; + } + + if (!sd->WriteToHandle(token_dup->get(), + base::win::SecurityObjectType::kKernel, + DACL_SECURITY_INFORMATION)) { + return false; + } + + *token = token_dup->release(); + return true; +} + bool CanLowIntegrityAccessDesktop() { // Access required for UI thread to initialize (when user32.dll loads without // win32k lockdown). diff --git a/sandbox/win/src/restricted_token_utils.h b/sandbox/win/src/restricted_token_utils.h index 344b416ab5102..f866c9f3021ac 100644 --- a/sandbox/win/src/restricted_token_utils.h +++ b/sandbox/win/src/restricted_token_utils.h @@ -51,6 +51,19 @@ absl::optional CreateRestrictedToken( // the error. DWORD HardenTokenIntegrityLevelPolicy(const base::win::AccessToken& token); +// Create a lowbox token. +// `base_token` a base token to derive the lowbox token from. Can be nullptr. +// `token_type` specify to create either a primary or impersonation token. +// `package_sid` is the AppContainer package SID. +// `capabilities` is the list of AppContainer capabilities. +// `token` is the output value containing the handle of the newly created +// If the function succeeds, the return value is true. +bool CreateLowBoxToken(HANDLE base_token, + TokenType token_type, + const base::win::Sid& package_sid, + const std::vector& capabilities, + base::win::ScopedHandle* token); + // Returns true if a low IL token can access the current desktop, false // otherwise. bool CanLowIntegrityAccessDesktop(); diff --git a/sandbox/win/src/sandbox_policy_diagnostic.cc b/sandbox/win/src/sandbox_policy_diagnostic.cc index 2bc39502fe26f..358bd5b62d585 100644 --- a/sandbox/win/src/sandbox_policy_diagnostic.cc +++ b/sandbox/win/src/sandbox_policy_diagnostic.cc @@ -82,6 +82,8 @@ std::string GetJobLevelInEnglish(JobLevel job) { return "Interactive"; case JobLevel::kUnprotected: return "Unprotected"; + case JobLevel::kNone: + return "None"; } } diff --git a/sandbox/win/src/security_level.h b/sandbox/win/src/security_level.h index 60e42e97d6f48..846ceab2b189e 100644 --- a/sandbox/win/src/security_level.h +++ b/sandbox/win/src/security_level.h @@ -95,6 +95,9 @@ enum TokenLevel { // JobLevel |General |Quota | // |restrictions |restrictions | // -----------------|---------------------------------- |--------------------| +// kNone | No job is assigned to the | None | +// | sandboxed process. | | +// -----------------|---------------------------------- |--------------------| // kUnprotected | None | *Kill on Job close.| // -----------------|---------------------------------- |--------------------| // kInteractive | *Forbid system-wide changes using | | @@ -120,7 +123,7 @@ enum TokenLevel { // In the context of the above table, 'user handles' refers to the handles of // windows, bitmaps, menus, etc. Files, treads and registry handles are kernel // handles and are not affected by the job level settings. -enum class JobLevel { kLockdown = 0, kLimitedUser, kInteractive, kUnprotected }; +enum class JobLevel { kLockdown = 0, kLimitedUser, kInteractive, kUnprotected, kNone }; // These flags correspond to various process-level mitigations (eg. ASLR and // DEP). Most are implemented via UpdateProcThreadAttribute() plus flags for diff --git a/services/device/geolocation/win/location_provider_winrt.cc b/services/device/geolocation/win/location_provider_winrt.cc index b95a6dd7c8846..67c5b745338d2 100644 --- a/services/device/geolocation/win/location_provider_winrt.cc +++ b/services/device/geolocation/win/location_provider_winrt.cc @@ -70,6 +70,11 @@ void RecordUmaEvent(WindowsRTLocationRequestEvent event) { base::UmaHistogramEnumeration("Windows.RT.LocationRequest.Event", event); } +bool IsWinRTSupported() { + return base::win::ResolveCoreWinRTDelayload() && + base::win::ScopedHString::ResolveCoreWinRTStringDelayload(); +} + template absl::optional GetOptionalDouble(F&& getter) { DOUBLE value = 0; @@ -504,6 +509,7 @@ std::unique_ptr NewSystemLocationProvider( GeolocationManager* geolocation_manager) { if (!base::FeatureList::IsEnabled( features::kWinrtGeolocationImplementation) || + !IsWinRTSupported() || !IsSystemLocationSettingEnabled()) { return nullptr; } diff --git a/services/proxy_resolver_win/BUILD.gn b/services/proxy_resolver_win/BUILD.gn index ed4b004f06350..c3fa7ec452180 100644 --- a/services/proxy_resolver_win/BUILD.gn +++ b/services/proxy_resolver_win/BUILD.gn @@ -11,6 +11,8 @@ component("proxy_resolver_win") { "winhttp_api_wrapper.h", "winhttp_api_wrapper_impl.cc", "winhttp_api_wrapper_impl.h", + "winhttp_proxy_resolver_functions.cc", + "winhttp_proxy_resolver_functions.h", ] libs = [ "winhttp.lib" ] diff --git a/services/proxy_resolver_win/public/cpp/proxy_resolver_win_mojom_traits.cc b/services/proxy_resolver_win/public/cpp/proxy_resolver_win_mojom_traits.cc index 68801e4636cab..e22cdfbb1fa0e 100644 --- a/services/proxy_resolver_win/public/cpp/proxy_resolver_win_mojom_traits.cc +++ b/services/proxy_resolver_win/public/cpp/proxy_resolver_win_mojom_traits.cc @@ -15,6 +15,8 @@ EnumTraits:: case proxy_resolver_win::mojom::WinHttpStatus::kAborted: *output = net::WinHttpStatus::kAborted; return true; + case proxy_resolver_win::mojom::WinHttpStatus::kFunctionsNotLoaded: + *output = net::WinHttpStatus::kFunctionsNotLoaded; + return true; case proxy_resolver_win::mojom::WinHttpStatus::kWinHttpOpenFailed: *output = net::WinHttpStatus::kWinHttpOpenFailed; return true; diff --git a/services/proxy_resolver_win/public/mojom/proxy_resolver_win.mojom b/services/proxy_resolver_win/public/mojom/proxy_resolver_win.mojom index c05d1f63d7d9b..ff3447e285e46 100644 --- a/services/proxy_resolver_win/public/mojom/proxy_resolver_win.mojom +++ b/services/proxy_resolver_win/public/mojom/proxy_resolver_win.mojom @@ -12,6 +12,7 @@ import "url/mojom/url.mojom"; enum WinHttpStatus { kOk, kAborted, + kFunctionsNotLoaded, kWinHttpOpenFailed, kWinHttpSetTimeoutsFailed, kWinHttpSetStatusCallbackFailed, diff --git a/services/proxy_resolver_win/winhttp_api_wrapper_impl.cc b/services/proxy_resolver_win/winhttp_api_wrapper_impl.cc index 54baece710f7a..78e4538bd2ded 100644 --- a/services/proxy_resolver_win/winhttp_api_wrapper_impl.cc +++ b/services/proxy_resolver_win/winhttp_api_wrapper_impl.cc @@ -9,6 +9,7 @@ #include #include "base/check_op.h" +#include "services/proxy_resolver_win/winhttp_proxy_resolver_functions.h" namespace proxy_resolver_win { @@ -34,9 +35,9 @@ WinHttpAPIWrapperImpl::~WinHttpAPIWrapperImpl() { bool WinHttpAPIWrapperImpl::CallWinHttpOpen() { DCHECK_EQ(nullptr, session_handle_); - session_handle_ = ::WinHttpOpen(nullptr, WINHTTP_ACCESS_TYPE_NO_PROXY, - WINHTTP_NO_PROXY_NAME, - WINHTTP_NO_PROXY_BYPASS, WINHTTP_FLAG_ASYNC); + session_handle_ = + WinHttpOpen(nullptr, WINHTTP_ACCESS_TYPE_NO_PROXY, WINHTTP_NO_PROXY_NAME, + WINHTTP_NO_PROXY_BYPASS, WINHTTP_FLAG_ASYNC); return (session_handle_ != nullptr); } @@ -45,16 +46,15 @@ bool WinHttpAPIWrapperImpl::CallWinHttpSetTimeouts(int resolve_timeout, int send_timeout, int receive_timeout) { DCHECK_NE(nullptr, session_handle_); - return (!!::WinHttpSetTimeouts(session_handle_, resolve_timeout, - connect_timeout, send_timeout, - receive_timeout)); + return (!!WinHttpSetTimeouts(session_handle_, resolve_timeout, + connect_timeout, send_timeout, receive_timeout)); } bool WinHttpAPIWrapperImpl::CallWinHttpSetStatusCallback( WINHTTP_STATUS_CALLBACK internet_callback) { DCHECK_NE(nullptr, session_handle_); const WINHTTP_STATUS_CALLBACK winhttp_status_callback = - ::WinHttpSetStatusCallback( + WinHttpSetStatusCallback( session_handle_, internet_callback, WINHTTP_CALLBACK_FLAG_REQUEST_ERROR | WINHTTP_CALLBACK_FLAG_GETPROXYFORURL_COMPLETE, @@ -64,14 +64,15 @@ bool WinHttpAPIWrapperImpl::CallWinHttpSetStatusCallback( bool WinHttpAPIWrapperImpl::CallWinHttpGetIEProxyConfigForCurrentUser( WINHTTP_CURRENT_USER_IE_PROXY_CONFIG* ie_proxy_config) { - return !!::WinHttpGetIEProxyConfigForCurrentUser(ie_proxy_config); + return !!WinHttpGetIEProxyConfigForCurrentUser(ie_proxy_config); } bool WinHttpAPIWrapperImpl::CallWinHttpCreateProxyResolver( HINTERNET* out_resolver_handle) { DCHECK_NE(nullptr, session_handle_); const DWORD result = - ::WinHttpCreateProxyResolver(session_handle_, out_resolver_handle); + WinHttpProxyResolverFunctions::GetInstance().create_proxy_resolver( + session_handle_, out_resolver_handle); return (result == ERROR_SUCCESS); } @@ -83,25 +84,28 @@ bool WinHttpAPIWrapperImpl::CallWinHttpGetProxyForUrlEx( const std::wstring wide_url(url.begin(), url.end()); // TODO(https://crbug.com/1032820): Upgrade to WinHttpGetProxyForUrlEx2() // if there is a clear reason to do so. - const DWORD result = ::WinHttpGetProxyForUrlEx( - resolver_handle, wide_url.data(), autoproxy_options, context); + const DWORD result = + WinHttpProxyResolverFunctions::GetInstance().get_proxy_for_url_ex( + resolver_handle, wide_url.data(), autoproxy_options, context); return (result == ERROR_IO_PENDING); } bool WinHttpAPIWrapperImpl::CallWinHttpGetProxyResult( HINTERNET resolver_handle, WINHTTP_PROXY_RESULT* proxy_result) { - const DWORD result = ::WinHttpGetProxyResult(resolver_handle, proxy_result); + const DWORD result = + WinHttpProxyResolverFunctions::GetInstance().get_proxy_result( + resolver_handle, proxy_result); return (result == ERROR_SUCCESS); } VOID WinHttpAPIWrapperImpl::CallWinHttpFreeProxyResult( WINHTTP_PROXY_RESULT* proxy_result) { - WinHttpFreeProxyResult(proxy_result); + WinHttpProxyResolverFunctions::GetInstance().free_proxy_result(proxy_result); } void WinHttpAPIWrapperImpl::CallWinHttpCloseHandle(HINTERNET internet_handle) { - ::WinHttpCloseHandle(internet_handle); + WinHttpCloseHandle(internet_handle); } void WinHttpAPIWrapperImpl::CloseSessionHandle() { diff --git a/services/proxy_resolver_win/winhttp_proxy_resolver_functions.cc b/services/proxy_resolver_win/winhttp_proxy_resolver_functions.cc new file mode 100644 index 0000000000000..b00c5670bb517 --- /dev/null +++ b/services/proxy_resolver_win/winhttp_proxy_resolver_functions.cc @@ -0,0 +1,43 @@ +// Copyright 2020 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "services/proxy_resolver_win/winhttp_proxy_resolver_functions.h" + +#include "base/no_destructor.h" + +namespace proxy_resolver_win { + +WinHttpProxyResolverFunctions::WinHttpProxyResolverFunctions() { + HMODULE winhttp_module = + LoadLibraryEx(L"winhttp.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32); + if (winhttp_module) { + create_proxy_resolver = reinterpret_cast( + ::GetProcAddress(winhttp_module, "WinHttpCreateProxyResolver")); + get_proxy_for_url_ex = reinterpret_cast( + ::GetProcAddress(winhttp_module, "WinHttpGetProxyForUrlEx")); + get_proxy_result = reinterpret_cast( + ::GetProcAddress(winhttp_module, "WinHttpGetProxyResult")); + free_proxy_result = reinterpret_cast( + ::GetProcAddress(winhttp_module, "WinHttpFreeProxyResult")); + } +} + +// Never called due to base::NoDestructor. +WinHttpProxyResolverFunctions::~WinHttpProxyResolverFunctions() = default; + +bool WinHttpProxyResolverFunctions::are_all_functions_loaded() const { + return create_proxy_resolver && get_proxy_for_url_ex && get_proxy_result && + free_proxy_result; +} + +// static +const WinHttpProxyResolverFunctions& +WinHttpProxyResolverFunctions::GetInstance() { + // This is a singleton for performance reasons. This avoids having to load + // proxy resolver functions multiple times. + static base::NoDestructor instance; + return *instance; +} + +} // namespace proxy_resolver_win \ No newline at end of file diff --git a/services/proxy_resolver_win/winhttp_proxy_resolver_functions.h b/services/proxy_resolver_win/winhttp_proxy_resolver_functions.h new file mode 100644 index 0000000000000..768269019cd0e --- /dev/null +++ b/services/proxy_resolver_win/winhttp_proxy_resolver_functions.h @@ -0,0 +1,47 @@ +// Copyright 2020 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SERVICES_PROXY_RESOLVER_WIN_WINHTTP_PROXY_RESOLVER_FUNCTIONS_H_ +#define SERVICES_PROXY_RESOLVER_WIN_WINHTTP_PROXY_RESOLVER_FUNCTIONS_H_ + +#include +#include + +#include "base/no_destructor.h" + +namespace proxy_resolver_win { + +// Not all WinHttp APIs we'll be using exist in all versions of Windows. +// Several only exist in Windows 8+. Thus, each function entry point must be +// loaded dynamically. +struct WinHttpProxyResolverFunctions { + public: + WinHttpProxyResolverFunctions(const WinHttpProxyResolverFunctions&) = delete; + WinHttpProxyResolverFunctions& operator=( + const WinHttpProxyResolverFunctions&) = delete; + + bool are_all_functions_loaded() const; + + static const WinHttpProxyResolverFunctions& GetInstance(); + + using WinHttpCreateProxyResolverFunc = decltype(WinHttpCreateProxyResolver)*; + using WinHttpGetProxyForUrlExFunc = decltype(WinHttpGetProxyForUrlEx)*; + using WinHttpGetProxyResultFunc = decltype(WinHttpGetProxyResult)*; + using WinHttpFreeProxyResultFunc = decltype(WinHttpFreeProxyResult)*; + + WinHttpCreateProxyResolverFunc create_proxy_resolver = nullptr; + WinHttpGetProxyForUrlExFunc get_proxy_for_url_ex = nullptr; + WinHttpGetProxyResultFunc get_proxy_result = nullptr; + WinHttpFreeProxyResultFunc free_proxy_result = nullptr; + + private: + friend class base::NoDestructor; + + WinHttpProxyResolverFunctions(); + ~WinHttpProxyResolverFunctions(); +}; + +} // namespace proxy_resolver_win + +#endif // SERVICES_PROXY_RESOLVER_WIN_WINHTTP_PROXY_RESOLVER_FUNCTIONS_H_ \ No newline at end of file diff --git a/services/shape_detection/face_detection_provider_win.cc b/services/shape_detection/face_detection_provider_win.cc index 59e9eb36d95a5..dbe49923cf948 100644 --- a/services/shape_detection/face_detection_provider_win.cc +++ b/services/shape_detection/face_detection_provider_win.cc @@ -49,6 +49,11 @@ BitmapPixelFormat GetPreferredPixelFormat(IFaceDetectorStatics* factory) { void FaceDetectionProviderWin::CreateFaceDetection( mojo::PendingReceiver receiver, shape_detection::mojom::FaceDetectorOptionsPtr options) { + if (!(base::win::ResolveCoreWinRTDelayload() && + ScopedHString::ResolveCoreWinRTStringDelayload())) { + DLOG(ERROR) << "Failed loading functions from combase.dll"; + return; + } ComPtr factory; HRESULT hr = GetActivationFactory< IFaceDetectorStatics, diff --git a/services/shape_detection/text_detection_impl_win.cc b/services/shape_detection/text_detection_impl_win.cc index a442dced19ad6..ca4d116a84863 100644 --- a/services/shape_detection/text_detection_impl_win.cc +++ b/services/shape_detection/text_detection_impl_win.cc @@ -42,6 +42,13 @@ using Microsoft::WRL::ComPtr; // static void TextDetectionImpl::Create( mojo::PendingReceiver receiver) { + +if (!(base::win::ResolveCoreWinRTDelayload() && + ScopedHString::ResolveCoreWinRTStringDelayload())) { + DLOG(ERROR) << "Failed loading functions from combase.dll"; + return; + } + // Text Detection specification only supports Latin-1 text as documented in // https://wicg.github.io/shape-detection-api/text.html#text-detection-api. // TODO(junwei.fu): https://crbug.com/794097 consider supporting other Latin diff --git a/third_party/blink/public/mojom/dwrite_font_proxy/dwrite_font_proxy.mojom b/third_party/blink/public/mojom/dwrite_font_proxy/dwrite_font_proxy.mojom index a66ddcf4d9031..b53a952116ece 100644 --- a/third_party/blink/public/mojom/dwrite_font_proxy/dwrite_font_proxy.mojom +++ b/third_party/blink/public/mojom/dwrite_font_proxy/dwrite_font_proxy.mojom @@ -28,6 +28,11 @@ struct MapCharactersResult { DWriteFontStyle font_style; }; +enum UniqueFontLookupMode { + kRetrieveTable, + kSingleLookups +}; + interface DWriteFontProxy { // Locates the index of the specified font family within the system // collection. @@ -51,14 +56,47 @@ interface DWriteFontProxy { GetFontFileHandles(uint32 family_index) => (array file_handles); - // Matches a unique PostScript or full font name against the installed fonts - // using DirectWrite API. Returns a pre-opened file handle and ttc_index from - // which the unique font can be instantiated. Returns null handle and 0 ttc - // index if no font is found. + // Returns which font unique name matching lookup mode is to be used on the + // current machine. On DirectWrite 10 and above, single lookups can be + // performed directly against DirectWrite API. On older DirectWrite (Windows + // 7-8.1), unique font lookups need to be performed against a shared memory + // region which contains the lookup table. Compare GetUniqueFontLookupTable() + // for lookup mode kRetrieveTable and MatchUniqueFont for + // lookup mode kSingleLookups. + [Sync] + GetUniqueFontLookupMode() => (UniqueFontLookupMode lookup_mode); + + // On supported Windows versions, matches a unique PostScript or full font + // name against the installed fonts using DirectWrite API. Returns a + // pre-opened file handle and ttc_index from which the unique font can be + // instantiated. Check which mode is supported using + // GetFontUniqueNameLookupMode(). Returns null handle and 0 ttc index + // if no font is found. Must not be called if GetUniqueFontLookupMode() + // returned kRetrieveTable. [Sync] MatchUniqueFont(mojo_base.mojom.String16 font_unique_name) => (mojo_base.mojom.ReadOnlyFile? file_handle, uint32 ttc_index); + // Synchronously returns a protobuf structured lookup list of + // (full_font_name|postscript_name) => (font_file + ttc_index) to the + // renderer process as a ReadOnlySharedMemoryRegion if it is available + // immediately without any blocking operations. Use FontTableMatcher to + // perform searches in it. If it is not available without blocking operations, + // sync_available is false and no shared memory region is provided. + [Sync] + GetUniqueNameLookupTableIfAvailable() + => (bool sync_available, + mojo_base.mojom.ReadOnlySharedMemoryRegion? font_lookup_table); + + // Asynchronously returns a protobuf structured lookup list of + // (full_font_name|postscript_name) => (font_file + ttc_index) to the + // renderer process as a ReadOnlySharedMemoryRegion. The lookup list is built + // on the first renderer call to retrieving this list. Use FontTableMatcher + // to perform searches in it. Retrieval may take up to several seconds if the + // table needs rebuilding on browser side. + GetUniqueNameLookupTable() => + (mojo_base.mojom.ReadOnlySharedMemoryRegion? font_lookup_table); + // Locates a font family that is able to render the specified text using the // specified style. If successful, the family_index and family_name will // indicate which family in the system font collection can render the diff --git a/third_party/blink/renderer/platform/fonts/win/font_unique_name_lookup_win.cc b/third_party/blink/renderer/platform/fonts/win/font_unique_name_lookup_win.cc index 3b1c3db022fd0..2f825c618b83e 100644 --- a/third_party/blink/renderer/platform/fonts/win/font_unique_name_lookup_win.cc +++ b/third_party/blink/renderer/platform/fonts/win/font_unique_name_lookup_win.cc @@ -10,6 +10,7 @@ #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/metrics/histogram_macros.h" +#include "mojo/public/mojom/base/shared_memory.mojom-blink.h" #include "third_party/blink/public/common/features.h" #include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h" #include "third_party/blink/public/mojom/dwrite_font_proxy/dwrite_font_proxy.mojom-blink.h" @@ -26,11 +27,14 @@ FontUniqueNameLookupWin::~FontUniqueNameLookupWin() = default; sk_sp FontUniqueNameLookupWin::MatchUniqueName( const String& font_unique_name) { - return MatchUniqueNameSingleLookup(font_unique_name); + if (lookup_mode_ == blink::mojom::UniqueFontLookupMode::kSingleLookups) + return MatchUniqueNameSingleLookup(font_unique_name); + return MatchUniqueNameLookupTable(font_unique_name); } sk_sp FontUniqueNameLookupWin::MatchUniqueNameSingleLookup( const String& font_unique_name) { + DCHECK(lookup_mode_ == blink::mojom::UniqueFontLookupMode::kSingleLookups); base::File font_file; uint32_t ttc_index = 0; @@ -43,6 +47,31 @@ sk_sp FontUniqueNameLookupWin::MatchUniqueNameSingleLookup( return InstantiateFromFileAndTtcIndex(std::move(font_file), ttc_index); } +sk_sp FontUniqueNameLookupWin::MatchUniqueNameLookupTable( + const String& font_unique_name) { + DCHECK(lookup_mode_ == blink::mojom::UniqueFontLookupMode::kRetrieveTable); + + if (!IsFontUniqueNameLookupReadyForSyncLookup()) + return nullptr; + + absl::optional match_result = + font_table_matcher_->MatchName(font_unique_name.Utf8()); + if (!match_result) + return nullptr; + + base::FilePath file_path = + base::FilePath::FromUTF8Unsafe(match_result->font_path.c_str()); + return InstantiateFromPathAndTtcIndex(file_path, match_result->ttc_index); +} + +// Used for font matching with table lookup case only. +sk_sp FontUniqueNameLookupWin::InstantiateFromPathAndTtcIndex( + base::FilePath font_file_path, + uint32_t ttc_index) { + return SkTypeface::MakeFromFile(font_file_path.AsUTF8Unsafe().c_str(), + ttc_index); +} + // Used for font matching with single lookup case only. sk_sp FontUniqueNameLookupWin::InstantiateFromFileAndTtcIndex( base::File file_handle, @@ -60,11 +89,52 @@ sk_sp FontUniqueNameLookupWin::InstantiateFromFileAndTtcIndex( } bool FontUniqueNameLookupWin::IsFontUniqueNameLookupReadyForSyncLookup() { - if (RuntimeEnabledFeatures::FontSrcLocalMatchingEnabled()) { - EnsureServiceConnected(); + if (!RuntimeEnabledFeatures::FontSrcLocalMatchingEnabled()) + return true; + + EnsureServiceConnected(); + + if (!lookup_mode_.has_value()) { + blink::mojom::UniqueFontLookupMode lookup_mode_from_mojo; + service_->GetUniqueFontLookupMode(&lookup_mode_from_mojo); + lookup_mode_ = lookup_mode_from_mojo; + } + + if (lookup_mode_ == blink::mojom::UniqueFontLookupMode::kSingleLookups) { + return true; } - return true; + DCHECK(lookup_mode_ == blink::mojom::UniqueFontLookupMode::kRetrieveTable); + + // If we have the table already, we're ready for sync lookups. + if (font_table_matcher_.get()) + return true; + + // We have previously determined via IPC whether the table is sync available. + // Return what we found out before. + if (sync_available_.has_value()) + return sync_available_.value(); + + // If we haven't asked the browser before, probe synchronously - if the table + // is available on the browser side, we can continue with sync operation. + + bool sync_available_from_mojo = false; + base::ReadOnlySharedMemoryRegion shared_memory_region; + service_->GetUniqueNameLookupTableIfAvailable(&sync_available_from_mojo, + &shared_memory_region); + sync_available_ = sync_available_from_mojo; + + if (*sync_available_) { + // Adopt the shared memory region, do not notify anyone in callbacks as + // PrepareFontUniqueNameLookup must not have been called yet. Just return + // true from this function. + DCHECK_EQ(pending_callbacks_.size(), 0u); + ReceiveReadOnlySharedMemoryRegion(std::move(shared_memory_region)); + } + + // If it wasn't available synchronously LocalFontFaceSource has to call + // PrepareFontUniqueNameLookup. + return *sync_available_; } void FontUniqueNameLookupWin::EnsureServiceConnected() { @@ -74,11 +144,66 @@ void FontUniqueNameLookupWin::EnsureServiceConnected() { service_.BindNewPipeAndPassReceiver()); } +void FontUniqueNameLookupWin::PrepareFontUniqueNameLookup( + NotifyFontUniqueNameLookupReady callback) { + DCHECK(!font_table_matcher_.get()); + DCHECK(RuntimeEnabledFeatures::FontSrcLocalMatchingEnabled()); + DCHECK(lookup_mode_ == blink::mojom::UniqueFontLookupMode::kRetrieveTable); + + pending_callbacks_.push_back(std::move(callback)); + + // We bind the service on the first call to PrepareFontUniqueNameLookup. After + // that we do not need to make additional IPC requests to retrieve the table. + // The observing callback was added to the list, so all clients will be + // informed when the lookup table has arrived. + if (pending_callbacks_.size() > 1) + return; + + EnsureServiceConnected(); + + service_->GetUniqueNameLookupTable(base::BindOnce( + &FontUniqueNameLookupWin::ReceiveReadOnlySharedMemoryRegion, + base::Unretained(this))); +} + void FontUniqueNameLookupWin::Init() { if (!base::FeatureList::IsEnabled(features::kPrefetchFontLookupTables)) return; EnsureServiceConnected(); + + if (lookup_mode_.has_value()) { + InitWithLookupMode(lookup_mode_.value()); + return; + } + + service_->GetUniqueFontLookupMode(base::BindOnce( + &FontUniqueNameLookupWin::InitWithLookupMode, base::Unretained(this))); +} + +void FontUniqueNameLookupWin::ReceiveReadOnlySharedMemoryRegion( + base::ReadOnlySharedMemoryRegion shared_memory_region) { + DCHECK(lookup_mode_ == blink::mojom::UniqueFontLookupMode::kRetrieveTable); + font_table_matcher_ = + std::make_unique(shared_memory_region.Map()); + while (!pending_callbacks_.empty()) { + NotifyFontUniqueNameLookupReady callback = pending_callbacks_.TakeFirst(); + std::move(callback).Run(); + } +} + +void FontUniqueNameLookupWin::InitWithLookupMode( + blink::mojom::UniqueFontLookupMode lookup_mode) { + lookup_mode_ = lookup_mode; + + if (!font_table_matcher_.get() && + RuntimeEnabledFeatures::FontSrcLocalMatchingEnabled() && + lookup_mode_ == blink::mojom::UniqueFontLookupMode::kRetrieveTable) { + // This call primes IsFontUniqueNameLookupReadyForSyncLookup() by + // asynchronously fetching the font table so it will be ready when needed. + // It isn't needed now, so base::DoNothing() is passed as the callback. + PrepareFontUniqueNameLookup(base::DoNothing()); + } } } // namespace blink diff --git a/third_party/blink/renderer/platform/fonts/win/font_unique_name_lookup_win.h b/third_party/blink/renderer/platform/fonts/win/font_unique_name_lookup_win.h index 7b31b5af1cabc..abdf287af3677 100644 --- a/third_party/blink/renderer/platform/fonts/win/font_unique_name_lookup_win.h +++ b/third_party/blink/renderer/platform/fonts/win/font_unique_name_lookup_win.h @@ -14,8 +14,14 @@ namespace blink { // Performs the IPC towards the browser process for font unique name -// matching. Direct individual sync Mojo IPC calls are made to lookup fonts, -// and the class reponds synchronously. +// matching. This class operates in one of two lookup modes, depending on +// lookup_mode_. On Windows 10 or when IDWriteFontFactory3 is available, direct +// individual sync Mojo IPC calls are made too lookup fonts - and the class +// reponds synchronously. On Windows Vista, 7 & 8, a shared memory region is retrieved +// asynchronously, then lookups are performed against that table. When the +// asynchronous request to retrieve the table completes, the clients are +// notified. And once the table was retrieved, this class returns to operating +// in synchronous mode as matching can be performed instantly. class FontUniqueNameLookupWin : public FontUniqueNameLookup { public: FontUniqueNameLookupWin(); @@ -26,17 +32,32 @@ class FontUniqueNameLookupWin : public FontUniqueNameLookup { bool IsFontUniqueNameLookupReadyForSyncLookup() override; + void PrepareFontUniqueNameLookup( + NotifyFontUniqueNameLookupReady callback) override; + void Init() override; private: void EnsureServiceConnected(); + sk_sp MatchUniqueNameLookupTable(const String& font_unique_name); + sk_sp MatchUniqueNameSingleLookup(const String& font_unique_name); + sk_sp InstantiateFromPathAndTtcIndex( + base::FilePath font_file_path, + uint32_t ttc_index); sk_sp InstantiateFromFileAndTtcIndex(base::File file_handle, uint32_t ttc_index); + void InitWithLookupMode(blink::mojom::UniqueFontLookupMode lookup_mode); + WTF::Deque pending_callbacks_; mojo::Remote service_; + absl::optional sync_available_; + absl::optional lookup_mode_; + + void ReceiveReadOnlySharedMemoryRegion( + base::ReadOnlySharedMemoryRegion shared_memory_region); }; } // namespace blink diff --git a/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.cc b/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.cc index e079f9ccd09d2..ed9cb666ff09b 100644 --- a/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.cc +++ b/ui/base/ime/win/on_screen_keyboard_display_manager_input_pane.cc @@ -91,6 +91,11 @@ class OnScreenKeyboardDisplayManagerInputPane::VirtualKeyboardInputPane if (input_pane2_) return true; + if (!base::win::ResolveCoreWinRTDelayload() || + !base::win::ScopedHString::ResolveCoreWinRTStringDelayload()) { + return false; + } + base::win::AssertComApartmentType(base::win::ComApartmentType::STA); base::win::ScopedHString input_pane_guid = base::win::ScopedHString::Create( diff --git a/ui/display/win/screen_win.cc b/ui/display/win/screen_win.cc index 9baa5162825a0..cabd7a1514747 100644 --- a/ui/display/win/screen_win.cc +++ b/ui/display/win/screen_win.cc @@ -45,13 +45,47 @@ namespace { // resolved with Desktop Aura and WindowTreeHost. ScreenWin* g_instance = nullptr; +bool IsProcessPerMonitorDpiAware() { + enum class PerMonitorDpiAware { + UNKNOWN = 0, + PER_MONITOR_DPI_UNAWARE, + PER_MONITOR_DPI_AWARE, + }; + static PerMonitorDpiAware per_monitor_dpi_aware = PerMonitorDpiAware::UNKNOWN; + if (per_monitor_dpi_aware == PerMonitorDpiAware::UNKNOWN) { + per_monitor_dpi_aware = PerMonitorDpiAware::PER_MONITOR_DPI_UNAWARE; + HMODULE shcore_dll = ::LoadLibrary(L"shcore.dll"); + if (shcore_dll) { + auto get_process_dpi_awareness_func = + reinterpret_cast( + ::GetProcAddress(shcore_dll, "GetProcessDpiAwareness")); + if (get_process_dpi_awareness_func) { + PROCESS_DPI_AWARENESS awareness; + if (SUCCEEDED(get_process_dpi_awareness_func(nullptr, &awareness)) && + awareness == PROCESS_PER_MONITOR_DPI_AWARE) + per_monitor_dpi_aware = PerMonitorDpiAware::PER_MONITOR_DPI_AWARE; + } + } + } + return per_monitor_dpi_aware == PerMonitorDpiAware::PER_MONITOR_DPI_AWARE; +} + // Gets the DPI for a particular monitor. absl::optional GetPerMonitorDPI(HMONITOR monitor) { + if (!IsProcessPerMonitorDpiAware()) + return absl::nullopt; + + static auto get_dpi_for_monitor_func = []() { + const HMODULE shcore_dll = ::LoadLibrary(L"shcore.dll"); + return reinterpret_cast( + shcore_dll ? ::GetProcAddress(shcore_dll, "GetDpiForMonitor") + : nullptr); + }(); UINT dpi_x, dpi_y; - if (!SUCCEEDED( - ::GetDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &dpi_x, &dpi_y))) { + if (!get_dpi_for_monitor_func || + !SUCCEEDED( + get_dpi_for_monitor_func(monitor, MDT_EFFECTIVE_DPI, &dpi_x, &dpi_y))) return absl::nullopt; - } DCHECK_EQ(dpi_x, dpi_y); return static_cast(dpi_x); diff --git a/ui/display/win/uwp_text_scale_factor.cc b/ui/display/win/uwp_text_scale_factor.cc index f6867edea301e..2d2d18c212bca 100644 --- a/ui/display/win/uwp_text_scale_factor.cc +++ b/ui/display/win/uwp_text_scale_factor.cc @@ -52,6 +52,13 @@ bool g_default_instance_cleaned_up = false; bool CreateUiSettingsComObject(ComPtr& ptr) { DCHECK(!ptr); + // This is required setup before using ScopedHString. + if (!(base::win::ResolveCoreWinRTDelayload() && + base::win::ScopedHString::ResolveCoreWinRTStringDelayload())) { + DLOG(ERROR) << "Failed loading functions from combase.dll"; + return false; + } + // Create the COM object. auto hstring = base::win::ScopedHString::Create( RuntimeClass_Windows_UI_ViewManagement_UISettings); diff --git a/ui/gfx/render_text.cc b/ui/gfx/render_text.cc index 17d8659f9c6fd..19667fe1cea84 100644 --- a/ui/gfx/render_text.cc +++ b/ui/gfx/render_text.cc @@ -42,6 +42,10 @@ #include "ui/gfx/text_utils.h" #include "ui/gfx/utf16_indexing.h" +#if BUILDFLAG(IS_WIN) +#include "base/win/windows_version.h" +#endif + namespace gfx { namespace { @@ -253,23 +257,25 @@ UChar32 ReplaceControlCharacter(UChar32 codepoint) { // Support Microsoft defined PUA on Windows. // see: // https://docs.microsoft.com/en-us/windows/uwp/design/style/segoe-ui-symbol-font - switch (codepoint) { - case 0xF093: // ButtonA - case 0xF094: // ButtonB - case 0xF095: // ButtonY - case 0xF096: // ButtonX - case 0xF108: // LeftStick - case 0xF109: // RightStick - case 0xF10A: // TriggerLeft - case 0xF10B: // TriggerRight - case 0xF10C: // BumperLeft - case 0xF10D: // BumperRight - case 0xF10E: // Dpad - case 0xEECA: // ButtonView2 - case 0xEDE3: // ButtonMenu - return codepoint; - default: - break; + if (base::win::GetVersion() >= base::win::Version::WIN10) { + switch (codepoint) { + case 0xF093: // ButtonA + case 0xF094: // ButtonB + case 0xF095: // ButtonY + case 0xF096: // ButtonX + case 0xF108: // LeftStick + case 0xF109: // RightStick + case 0xF10A: // TriggerLeft + case 0xF10B: // TriggerRight + case 0xF10C: // BumperLeft + case 0xF10D: // BumperRight + case 0xF10E: // Dpad + case 0xEECA: // ButtonView2 + case 0xEDE3: // ButtonMenu + return codepoint; + default: + break; + } } #endif const int8_t codepoint_category = u_charType(codepoint); diff --git a/ui/gfx/win/direct_write.cc b/ui/gfx/win/direct_write.cc index 6e091a20069c0..ff07f3fc157b0 100644 --- a/ui/gfx/win/direct_write.cc +++ b/ui/gfx/win/direct_write.cc @@ -9,9 +9,11 @@ #include #include "base/debug/alias.h" +#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" #include "base/strings/utf_string_conversions.h" #include "base/trace_event/trace_event.h" +#include "base/win/windows_version.h" #include "skia/ext/fontmgr_default.h" #include "third_party/skia/include/core/SkFontMgr.h" #include "third_party/skia/include/ports/SkTypeface_win.h" @@ -60,9 +62,38 @@ void InitializeDirectWrite() { CHECK(!!factory); SetDirectWriteFactory(factory.Get()); +// The skia call to create a new DirectWrite font manager instance can fail + // if we are unable to get the system font collection from the DirectWrite + // factory. The GetSystemFontCollection method in the IDWriteFactory + // interface fails with E_INVALIDARG on certain Windows 7 gold versions + // (6.1.7600.*). sk_sp direct_write_font_mgr = SkFontMgr_New_DirectWrite(factory.Get()); - CHECK(!!direct_write_font_mgr); + + int iteration = 0; + if (!direct_write_font_mgr && + base::win::GetVersion() == base::win::Version::WIN7) { + // Windows (win7_rtm) may fail to map the service sections + // (crbug.com/956064). + constexpr int kMaxRetries = 5; + constexpr base::TimeDelta kRetrySleepTime = base::Microseconds(500); + while (iteration < kMaxRetries) { + base::PlatformThread::Sleep(kRetrySleepTime); + direct_write_font_mgr = SkFontMgr_New_DirectWrite(factory.Get()); + if (direct_write_font_mgr) + break; + ++iteration; + } + } + if (!direct_write_font_mgr) + iteration = -1; + base::UmaHistogramSparse("DirectWrite.Fonts.Gfx.InitializeLoopCount", + iteration); + // TODO(crbug.com/956064): Move to a CHECK when the cause of the crash is + // fixed and remove the if statement that fallback to GDI font manager. + DCHECK(!!direct_write_font_mgr); + if (!direct_write_font_mgr) + direct_write_font_mgr = SkFontMgr_New_GDI(); // Override the default skia font manager. This must be called before any // use of the skia font manager is done (e.g. before any call to @@ -143,4 +174,4 @@ absl::optional RetrieveLocalizedFontName( } } // namespace win -} // namespace gfx +} // namespace gfx \ No newline at end of file diff --git a/ui/native_theme/caption_style_win.cc b/ui/native_theme/caption_style_win.cc index 2c27d56f29eaa..9c314a5185c7f 100644 --- a/ui/native_theme/caption_style_win.cc +++ b/ui/native_theme/caption_style_win.cc @@ -14,6 +14,7 @@ #include "base/numerics/safe_conversions.h" #include "base/trace_event/trace_event.h" #include "base/win/core_winrt_util.h" +#include "base/win/windows_version.h" #include "skia/ext/skia_utils_win.h" #include "ui/base/ui_base_features.h" #include "ui/gfx/color_utils.h" @@ -172,8 +173,18 @@ std::string GetCssColorWithAlpha(CC::ClosedCaptionColor caption_color, absl::optional InitializeFromSystemSettings() { TRACE_EVENT0("ui", "InitializeFromSystemSettings"); + DCHECK_GE(base::win::GetVersion(), base::win::Version::WIN10); DCHECK(base::FeatureList::IsEnabled(features::kSystemCaptionStyle)); + // Need to do this check before using ScopedHString. + bool can_use_scoped_hstring = + base::win::ResolveCoreWinRTDelayload() && + base::win::ScopedHString::ResolveCoreWinRTStringDelayload(); + + if (!can_use_scoped_hstring) + return absl::nullopt; + + base::win::ScopedHString closed_caption_properties_string = base::win::ScopedHString::Create( RuntimeClass_Windows_Media_ClosedCaptioning_ClosedCaptionProperties); @@ -270,10 +281,12 @@ absl::optional InitializeFromSystemSettings() { } // namespace absl::optional CaptionStyle::FromSystemSettings() { - if (base::FeatureList::IsEnabled(features::kSystemCaptionStyle)) { + if (base::win::GetVersion() >= base::win::Version::WIN10 && + base::FeatureList::IsEnabled(features::kSystemCaptionStyle)) { return InitializeFromSystemSettings(); } - // Return default CaptionStyle if kSystemCaptionStyle is not enabled. + // Return default CaptionStyle for pre Win10 versions since system settings + // don't allow caption styling. return absl::nullopt; } diff --git a/ui/views/win/hwnd_message_handler.cc b/ui/views/win/hwnd_message_handler.cc index a1bd556e733fa..c021d80a8692a 100644 --- a/ui/views/win/hwnd_message_handler.cc +++ b/ui/views/win/hwnd_message_handler.cc @@ -2222,8 +2222,12 @@ LRESULT HWNDMessageHandler::OnMouseRange(UINT message, LRESULT HWNDMessageHandler::OnPointerActivate(UINT message, WPARAM w_param, LPARAM l_param) { + using GetPointerTypeFn = BOOL(WINAPI*)(UINT32, POINTER_INPUT_TYPE*); + UINT32 pointer_id = GET_POINTERID_WPARAM(w_param); POINTER_INPUT_TYPE pointer_type; - if (::GetPointerType(GET_POINTERID_WPARAM(w_param), &pointer_type) && + static const auto get_pointer_type = reinterpret_cast( + base::win::GetUser32FunctionPointer("GetPointerType")); + if (get_pointer_type && get_pointer_type(pointer_id, &pointer_type) && pointer_type == PT_TOUCHPAD) { return PA_NOACTIVATE; } @@ -2231,18 +2235,24 @@ LRESULT HWNDMessageHandler::OnPointerActivate(UINT message, return -1; } + LRESULT HWNDMessageHandler::OnPointerEvent(UINT message, WPARAM w_param, LPARAM l_param) { + UINT32 pointer_id = GET_POINTERID_WPARAM(w_param); + using GetPointerTypeFn = BOOL(WINAPI*)(UINT32, POINTER_INPUT_TYPE*); POINTER_INPUT_TYPE pointer_type; + static const auto get_pointer_type = reinterpret_cast( + base::win::GetUser32FunctionPointer("GetPointerType")); // If the WM_POINTER messages are not sent from a stylus device, then we do // not handle them to make sure we do not change the current behavior of // touch and mouse inputs. - if (!::GetPointerType(GET_POINTERID_WPARAM(w_param), &pointer_type)) { + if (!get_pointer_type || !get_pointer_type(pointer_id, &pointer_type)) { SetMsgHandled(FALSE); return -1; } + // |HandlePointerEventTypePenClient| assumes all pen events happen on the // client area, so WM_NCPOINTER messages sent to it would eventually be // dropped and the native frame wouldn't be able to respond to pens. @@ -3570,12 +3580,18 @@ LRESULT HWNDMessageHandler::HandlePointerEventTypePenClient(UINT message, WPARAM w_param, LPARAM l_param) { UINT32 pointer_id = GET_POINTERID_WPARAM(w_param); + using GetPointerPenInfoFn = BOOL(WINAPI*)(UINT32, POINTER_PEN_INFO*); POINTER_PEN_INFO pointer_pen_info; - if (!GetPointerPenInfo(pointer_id, &pointer_pen_info)) { + static const auto get_pointer_pen_info = + reinterpret_cast( + base::win::GetUser32FunctionPointer("GetPointerPenInfo")); + if (!get_pointer_pen_info || + !get_pointer_pen_info(pointer_id, &pointer_pen_info)) { SetMsgHandled(FALSE); return -1; } + return HandlePointerEventTypePen(message, pointer_id, pointer_pen_info); } diff --git a/ui/views/win/pen_id_handler.cc b/ui/views/win/pen_id_handler.cc index cf9d785f2bfbe..626f842c9aa4f 100644 --- a/ui/views/win/pen_id_handler.cc +++ b/ui/views/win/pen_id_handler.cc @@ -37,6 +37,13 @@ class PenIdStatics { if (skip_initialization_) { return; } + + if(!base::win::ResolveCoreWinRTDelayload()){ + pen_device_statics_ = nullptr; + pointer_point_statics_ = nullptr; + return; + } + base::win::AssertComInitialized(); base::win::RoGetActivationFactory( base::win::HStringReference( @@ -243,4 +250,4 @@ void PenIdHandler::InitPenIdStatics() { base::BindOnce(base::IgnoreResult(&PenIdStatics::GetInstance))); } -} // namespace views +} // namespace views \ No newline at end of file