Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Widevine in Arm64 Brave on Windows #18695

Merged
merged 41 commits into from
Aug 21, 2023
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
f2279a4
Add support for Arm64 Widevine on Windows
mherrmann May 23, 2023
a7871e8
Move function into anonymous namespace
mherrmann Jun 12, 2023
b241f3f
Improve macro name
mherrmann Jun 12, 2023
8a1a0ad
Sort some DEPS
mherrmann Jun 12, 2023
498402d
Move some constants into the global namespace
mherrmann Jun 13, 2023
855cc17
Use constexpr for constants
mherrmann Jun 13, 2023
01ed149
Avoid unnecessary patch
mherrmann Jun 13, 2023
ec86f70
Fix compile errors caused by upstream changes
mherrmann Jul 27, 2023
4de9f70
Add comment
mherrmann Jul 27, 2023
9cb542f
Rename header file
mherrmann Jul 27, 2023
3293bd4
Fix layer violation
mherrmann Jul 27, 2023
9910489
Fix compile error
mherrmann Jul 27, 2023
298d2d5
Fix another compile error
mherrmann Jul 28, 2023
a1ea1ee
Store Widevine Arm64 DLL URL in a feature
mherrmann Aug 16, 2023
bd5520e
Revert accidental change
mherrmann Aug 16, 2023
c911392
Fix some presubmit errors
mherrmann Aug 16, 2023
286f3fa
Move feature to anonymous namespace
mherrmann Aug 16, 2023
90f3861
Fix presubmit checks
mherrmann Aug 16, 2023
f995596
Avoid unsafe use of weak_ptr_factory
mherrmann Aug 16, 2023
cd34683
Use dedicated task runner to install Widevine
mherrmann Aug 16, 2023
8dbd092
Fix presubmit errors
mherrmann Aug 17, 2023
7fa737a
Fix sequence constraint violation
mherrmann Aug 17, 2023
fb90323
Fix likely bug in upgrades of Widevine component
mherrmann Aug 17, 2023
19afaa5
Refactor
mherrmann Aug 17, 2023
28ea602
Widevine Arm64 DLL: Use timeout for download only
mherrmann Aug 18, 2023
2580f35
Improve class name
mherrmann Aug 18, 2023
f8c5e51
Improve constant name
mherrmann Aug 18, 2023
fba40a7
Add comment
mherrmann Aug 18, 2023
911d5e0
Reduce scope of `using` directive
mherrmann Aug 18, 2023
13eb316
Simplify code
mherrmann Aug 18, 2023
8ab0dfd
Remove unnecessary DEP include_rule
mherrmann Aug 18, 2023
ed08d3b
Bump Widevine Arm64 DLL URL to latest version
mherrmann Aug 19, 2023
9e12eda
Improve constant name
mherrmann Aug 21, 2023
74b3034
Improve comment
mherrmann Aug 21, 2023
ac7caba
Remove unnecessary use of RetainedRef
mherrmann Aug 21, 2023
4ff1350
Simplify code
mherrmann Aug 21, 2023
96734c5
Simplify header file
mherrmann Aug 21, 2023
131a7b2
Add a sequence checker for safety
mherrmann Aug 21, 2023
0f984d0
Use #define to include upstream's implementation
mherrmann Aug 21, 2023
8c7fd1e
Better resolve a clash with an upstream header
mherrmann Aug 21, 2023
9d328d2
Fix source formatting
mherrmann Aug 21, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion browser/brave_drm_tab_helper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
#include <vector>

#include "base/containers/contains.h"
#include "brave/browser/widevine/constants.h"
#include "brave/browser/widevine/widevine_utils.h"
#include "brave/components/constants/pref_names.h"
#include "brave/components/widevine/constants.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process_impl.h"
#include "chrome/browser/profiles/profile.h"
Expand Down
1 change: 1 addition & 0 deletions browser/net/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ source_set("net") {
"//brave/components/decentralized_dns/content",
"//brave/components/ipfs/buildflags",
"//brave/components/update_client:buildflags",
"//brave/components/widevine:static_buildflags",
"//brave/extensions:common",
"//components/content_settings/core/browser",
"//components/prefs",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "brave/browser/net/brave_geolocation_buildflags.h"
#include "brave/browser/safebrowsing/buildflags.h"
#include "brave/components/constants/network_constants.h"
#include "brave/components/widevine/static_buildflags.h"
#include "extensions/common/url_pattern.h"
#include "net/base/net_errors.h"

Expand Down Expand Up @@ -87,6 +88,10 @@ int OnBeforeURLRequest_StaticRedirectWorkForGURL(
static URLPattern widevine_google_dl_pattern(
URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS,
kWidevineGoogleDlPrefix);
#if BUILDFLAG(WIDEVINE_ARM64_DLL_FIX)
static URLPattern widevine_google_dl_pattern_win_arm64(
URLPattern::SCHEME_HTTPS, kWidevineGoogleDlPrefixWinArm64);
#endif // BUILDFLAG(WIDEVINE_ARM64_DLL_FIX)

if (geo_pattern.MatchesURL(request_url)) {
*new_url = GURL(BUILDFLAG(GOOGLEAPIS_URL));
Expand Down Expand Up @@ -165,6 +170,9 @@ int OnBeforeURLRequest_StaticRedirectWorkForGURL(
}

if (googleDl_pattern.MatchesURL(request_url) &&
#if BUILDFLAG(WIDEVINE_ARM64_DLL_FIX)
!widevine_google_dl_pattern_win_arm64.MatchesURL(request_url) &&
#endif
!widevine_google_dl_pattern.MatchesURL(request_url)) {
replacements.SetSchemeStr("https");
replacements.SetHostStr(kBraveRedirectorProxy);
Expand Down
2 changes: 1 addition & 1 deletion browser/sources.gni
Original file line number Diff line number Diff line change
Expand Up @@ -388,8 +388,8 @@ if (enable_widevine) {
]
brave_chrome_browser_deps += [
"//brave/browser/widevine",
"//brave/browser/widevine:constants",
"//brave/components/brave_drm",
"//brave/components/widevine:constants",
]
}

Expand Down
8 changes: 2 additions & 6 deletions browser/widevine/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ source_set("widevine") {
# Remove when https://github.com/brave/brave-browser/issues/10644 is resolved
check_includes = false
deps = [
":constants",
"//base",
"//brave/app:brave_generated_resources_grit",
"//brave/components/constants",
"//brave/components/widevine:constants",
"//chrome/common",
"//components/component_updater/",
"//components/content_settings/core/common",
Expand All @@ -43,10 +43,6 @@ source_set("widevine") {
]
}

source_set("constants") {
sources = [ "constants.h" ]
}

source_set("unittest") {
testonly = true

Expand All @@ -67,12 +63,12 @@ source_set("browser_tests") {
]

deps = [
":constants",
":widevine",
"//base",
"//brave/browser",
"//brave/common",
"//brave/components/constants",
"//brave/components/widevine:constants",
"//chrome/browser",
"//chrome/browser:browser_process",
"//chrome/browser/profiles:profile",
Expand Down
104 changes: 104 additions & 0 deletions browser/widevine/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Widevine in Brave

Widevine is used to decrypt DRM-protected content, which is served from
streaming services such as Netflix. Widevine is integrated in Chromium as a
component.

## Signature files (brave.exe.sig, chrome.dll.sig, ...)

Streaming services only offer high definition content to clients that are
trusted. Widevine has mechanisms to ensure the integrity of the client. One of
these mechanisms are .sig files. They prove to Widevine that the browser has not
been tampered with. In order for Brave's users to see high-definition content,
the browser must generate and ship with those .sig files.

## Licensing

Brave's licensing agreement for Widevine forbids distribution of Widevine's
binaries. This entails several workarounds, some of which are listed below.

## Workarounds

### Sequential component updates: SequentialUpdateChecker

Brave has its own components and thus uses its own component update server. This
server also gets polled by the browser for Widevine. To comply with the
licensing restriction described above, Brave's component update server responds
with a redirect to Google's server in this case. This works as long as a single
update check request only polls for Widevine, and not also for any other
components. We have a special class, `SequentialUpdateChecker`, that makes sure
that this is the case.

### Widevine in Arm64 Brave on Windows: WIDEVINE_ARM64_DLL_FIX

As of this writing, Google does not offer Arm64 binaries for Widevine on
Windows. When Arm64 Brave polls Google's component update server for Widevine,
then it receives a "noupdate" response, meaning that no version could be found.
In effect, out of the box, Widevine cannot be installed in Arm64 Brave on
Windows.

However, there is a workaround: When we poll for an x64 version of the
component, then we get the necessary base files, plus some x64-specific
binaries. The remaining necessary binaries for Arm64 are available in a Zip file
on Google's servers. By placing them into the
`WidevineCdm\<version>\_platform_specific\win_arm64` directory of the component,
we can obtain a copy of Widevine that works in Arm64 Brave on Windows.

Brave's `WIDEVINE_ARM64_DLL_FIX` implements the above workaround in code. When
an update check for Widevine returns "noupdate", then the workaround repeats the
update check, pretending to be from the `x64` architecture. It installs the x64
version of the component and then additionally downloads the Arm64 zip file from
Google's server. This gives us a working copy of Widevine in Arm64 Brave.

The facts that upstream can be compiled for Arm64 on Windows and that Google
publicly serves Arm64 binaries of Widevine make it seem likely that a native
Widevine component for this architecture will also be available in the future.
For this reason, our workaround is guarded by a build flag. Once the workaround
is no longer required, the build flag makes it very easy to clean up the
associated code.

**Further details about the present implementation of WIDEVINE_ARM64_DLL_FIX:**

The details below were compiled at the time of the initial implementation, to
simplify the associated code review. They may be wholly or partially out of
date by the time you read this.

The first entry point into the implementation is in `update_checker.cc`, in
`SequentialUpdateChecker::UpdateResultAvailable`. It handles the symptom of the
current limitation: The browser asks the component update server "Do you have
the Widevine component?", implicitly sending its architecture, which is Arm64.
The server responds `"noupdate"`, which means there is no such version. When
this happens, `UpdateResultAvailable` repeats the update check with a fake
`x64` architecture.

There is some additional code in `UpdateResultAvailable` that handles the case
when the server responds `noupdate` not because there is no Arm64 version of
Widevine at all, but because there is just no _new_ version. If we ever receive
an Arm64 version of Widevine from the update server, then we disable our
workaround to not fall back to `x64`. This information is persisted via
`SequentialUpdateChecker::SetPersistedFlag` and `...:GetPersistedFlag`.

The fake architecture is passed from `update_checker.cc` to
`protocol_serializer.cc` via the `additional_attributes` parameter of
`MakeProtocolRequest`.

When the browser receives the response from the update server, it installs the
Widevine component. Upstream has some custom logic for this in
`widevine_cdm_component_installer.cc`. We extend this logic to in particular
overwrite `WidevineCdmComponentInstallerPolicy::OnCustomInstall`. This gets
called by upstream when the "normal" installation of the component is complete.
Our additional code downloads and unpacks the external zip file with the
necessary Arm64 binaries. It also applies some patches to make upstream accept
the foreign implementation.

To be able to download the Arm64 binaries, the `OnCustomInstall` method
mentioned above needs a `SharedURLLoaderFactory`. Several sections of our code
make sure that it receives such an instance in our and upstream's calls of
`RegisterWidevineCdmComponent`.

Brave intercepts network requests to certain domains for privacy reasons. One
such domain is `dl.google.com`, which Brave redirects to `redirector.brave.com`.
Our attempt to download the Zip file with additional Arm64 binaries would
normally be prevented by this mechanism. We add an exception to
`brave_static_redirect_network_delegate_helper.cc` so that the Zip file can in
fact be downloaded.
11 changes: 0 additions & 11 deletions browser/widevine/constants.h

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@

#include "base/path_service.h"
#include "brave/browser/brave_drm_tab_helper.h"
#include "brave/browser/widevine/constants.h"
#include "brave/browser/widevine/widevine_permission_request.h"
#include "brave/browser/widevine/widevine_utils.h"
#include "brave/components/constants/brave_paths.h"
#include "brave/components/constants/pref_names.h"
#include "brave/components/widevine/constants.h"
#include "build/build_config.h"
#include "chrome/browser/ssl/cert_verifier_browser_test.h"
#include "chrome/browser/ui/browser.h"
Expand Down
14 changes: 12 additions & 2 deletions browser/widevine/widevine_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@
#include "base/path_service.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "brave/browser/widevine/constants.h"
#include "brave/browser/widevine/widevine_permission_request.h"
#include "brave/components/constants/pref_names.h"
#include "brave/components/widevine/constants.h"
#include "brave/components/widevine/static_buildflags.h"
#include "brave/grit/brave_generated_resources.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/component_updater/component_updater_utils.h"
#include "chrome/browser/component_updater/widevine_cdm_component_installer.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_paths.h"
Expand Down Expand Up @@ -73,14 +75,22 @@ void ClearWidevinePrefs(Profile* profile) {
prefs->ClearPref(kWidevineOptedIn);
}

void InstallWidevineOnceRegistered() {
component_updater::BraveOnDemandUpdate(kWidevineComponentId);
}
mherrmann marked this conversation as resolved.
Show resolved Hide resolved

} // namespace

void EnableWidevineCdmComponent() {
if (IsWidevineOptedIn())
return;

SetWidevineOptedIn(true);
RegisterWidevineCdmComponent(g_browser_process->component_updater());
RegisterWidevineCdmComponent(g_browser_process->component_updater(),
#if BUILDFLAG(WIDEVINE_ARM64_DLL_FIX)
g_browser_process->shared_url_loader_factory(),
#endif
base::BindOnce(&InstallWidevineOnceRegistered));
}

void DisableWidevineCdmComponent() {
Expand Down
4 changes: 4 additions & 0 deletions chromium_src/base/threading/DEPS
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
include_rules = [
# This file is NOT generated and is safe to use without a GN dependency.
"+brave/components/widevine/static_buildflags.h",
]
28 changes: 25 additions & 3 deletions chromium_src/base/threading/thread_restrictions.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#ifndef BRAVE_CHROMIUM_SRC_BASE_THREADING_THREAD_RESTRICTIONS_H_
#define BRAVE_CHROMIUM_SRC_BASE_THREADING_THREAD_RESTRICTIONS_H_

#include "brave/components/widevine/static_buildflags.h"

class BraveBrowsingDataRemoverDelegate;
namespace ipfs {
class IpfsService;
Expand All @@ -14,12 +16,32 @@ namespace brave {
class ProcessLauncher;
}

#define BRAVE_SCOPED_ALLOW_BASE_SYNC_PRIMITIVES_H \
friend class ::BraveBrowsingDataRemoverDelegate; \
friend class ipfs::IpfsService; \
#if BUILDFLAG(WIDEVINE_ARM64_DLL_FIX)
namespace component_updater {
class Arm64DllInstaller;
}
#endif

#define BRAVE_SCOPED_ALLOW_BASE_SYNC_PRIMITIVES_H_BASE \
friend class ::BraveBrowsingDataRemoverDelegate; \
friend class ipfs::IpfsService; \
friend class brave::ProcessLauncher;

#if BUILDFLAG(WIDEVINE_ARM64_DLL_FIX)
// Arm64DllInstaller needs to use TimedWait:
#define BRAVE_SCOPED_ALLOW_BASE_SYNC_PRIMITIVES_WIDEVINE_ARM64_DLL_FIX \
friend class component_updater::Arm64DllInstaller;
#else
#define BRAVE_SCOPED_ALLOW_BASE_SYNC_PRIMITIVES_WIDEVINE_ARM64_DLL_FIX
#endif

#define BRAVE_SCOPED_ALLOW_BASE_SYNC_PRIMITIVES_H \
BRAVE_SCOPED_ALLOW_BASE_SYNC_PRIMITIVES_H_BASE \
BRAVE_SCOPED_ALLOW_BASE_SYNC_PRIMITIVES_WIDEVINE_ARM64_DLL_FIX

#include "src/base/threading/thread_restrictions.h" // IWYU pragma: export
#undef BRAVE_SCOPED_ALLOW_BASE_SYNC_PRIMITIVES_H
#undef BRAVE_SCOPED_ALLOW_BASE_SYNC_PRIMITIVES_H_BASE
#undef BRAVE_SCOPED_ALLOW_BASE_SYNC_PRIMITIVES_WIDEVINE_ARM64_DLL_FIX

#endif // BRAVE_CHROMIUM_SRC_BASE_THREADING_THREAD_RESTRICTIONS_H_
3 changes: 3 additions & 0 deletions chromium_src/chrome/browser/component_updater/DEPS
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
include_rules = [
"+brave/components/widevine/static_buildflags.h",
]
12 changes: 12 additions & 0 deletions chromium_src/chrome/browser/component_updater/registration.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,21 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "chrome/browser/component_updater/registration.h"
#include "brave/components/widevine/static_buildflags.h"

#define RegisterComponentsForUpdate RegisterComponentsForUpdate_ChromiumImpl

#if BUILDFLAG(WIDEVINE_ARM64_DLL_FIX)
#define RegisterWidevineCdmComponent(cus) \
RegisterWidevineCdmComponent(cus, \
g_browser_process->shared_url_loader_factory())
#else
#define RegisterWidevineCdmComponent(cus) RegisterWidevineCdmComponent(cus)
#endif

#include "src/chrome/browser/component_updater/registration.cc"

#undef RegisterWidevineCdmComponent
#undef RegisterComponentsForUpdate

#include "brave/browser/brave_shields/https_everywhere_component_installer.h"
Expand Down
Loading