Skip to content

Commit d41bada

Browse files
committed
Support building android-wireguard with GN
This commit adds a BUILD.gn to the repository which enables us to build directly via Chromium's build system. We already use this repository within Brave but via a hand-built AAR that gets extracted. With this commit, we have first-class support for building the repo from source during the brave build. To address the problem that Chromium cannot build Java sources that use the `record` type, the singular instance of a record has been converted to the standard `class` format.
1 parent f0b45d5 commit d41bada

File tree

3 files changed

+255
-1
lines changed

3 files changed

+255
-1
lines changed

BUILD.gn

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
# Copyright (c) 2025 The Brave Authors. All rights reserved.
2+
# This Source Code Form is subject to the terms of the Mozilla Public
3+
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
4+
# You can obtain one at https://mozilla.org/MPL/2.0/.
5+
6+
import("//build/config/android/config.gni")
7+
import("//build/config/android/rules.gni")
8+
import("//build/config/clang/clang.gni")
9+
import("//build/config/sysroot.gni")
10+
import("//build/config/compiler/compiler.gni")
11+
12+
# This target builds the WireGuard Android tunnel library from source.
13+
# C code is built directly with GN. Go code uses the upstream Makefile.
14+
15+
_wireguard_package_name = "com.wireguard.android"
16+
17+
# Common configuration for WireGuard C libraries
18+
config("wireguard_config") {
19+
include_dirs = [
20+
"tunnel/tools/wireguard-tools/src",
21+
"tunnel/tools/wireguard-tools/src/uapi/linux",
22+
"tunnel/tools/ndk-compat",
23+
]
24+
25+
cflags_c = [
26+
# Must come after other std flags to override them
27+
"-std=gnu11",
28+
]
29+
30+
cflags = [
31+
"-include",
32+
rebase_path("tunnel/tools/ndk-compat/compat.h", root_build_dir),
33+
# Disable Chromium's strict warnings for third-party code
34+
"-Wno-unsafe-buffer-usage",
35+
"-Wno-implicit-fallthrough",
36+
"-Wno-shadow",
37+
"-Wno-gnu-pointer-arith",
38+
"-Wno-macro-redefined",
39+
"-Wno-unreachable-code-return",
40+
"-Wno-sign-compare",
41+
"-Wno-implicit-function-declaration",
42+
]
43+
44+
defines = [ "RUNSTATEDIR=\"/data/data/${_wireguard_package_name}/cache\"" ]
45+
46+
ldflags = [ "-Wl,--build-id=none" ]
47+
}
48+
49+
# Build libwg-quick.so - WireGuard quick setup tool
50+
loadable_module("libwg-quick") {
51+
output_name = "wg-quick"
52+
output_dir = "$target_out_dir/$target_cpu"
53+
54+
sources = [
55+
"tunnel/tools/ndk-compat/compat.c",
56+
"tunnel/tools/wireguard-tools/src/wg-quick/android.c",
57+
]
58+
59+
configs += [ ":wireguard_config" ]
60+
# Remove Chromium's clang plugins for third-party code
61+
configs -= [
62+
"//build/config/clang:find_bad_constructs",
63+
"//build/config/clang:unsafe_buffers",
64+
]
65+
66+
defines = [ "WG_PACKAGE_NAME=\"${_wireguard_package_name}\"" ]
67+
68+
libs = [ "dl" ]
69+
}
70+
71+
# Build libwg.so - WireGuard command-line tool
72+
loadable_module("libwg") {
73+
output_name = "wg"
74+
output_dir = "$target_out_dir/$target_cpu"
75+
76+
sources = [
77+
"tunnel/tools/ndk-compat/compat.c",
78+
"tunnel/tools/wireguard-tools/src/config.c",
79+
"tunnel/tools/wireguard-tools/src/curve25519.c",
80+
"tunnel/tools/wireguard-tools/src/encoding.c",
81+
"tunnel/tools/wireguard-tools/src/genkey.c",
82+
"tunnel/tools/wireguard-tools/src/ipc.c",
83+
"tunnel/tools/wireguard-tools/src/pubkey.c",
84+
"tunnel/tools/wireguard-tools/src/set.c",
85+
"tunnel/tools/wireguard-tools/src/setconf.c",
86+
"tunnel/tools/wireguard-tools/src/show.c",
87+
"tunnel/tools/wireguard-tools/src/showconf.c",
88+
"tunnel/tools/wireguard-tools/src/terminal.c",
89+
"tunnel/tools/wireguard-tools/src/wg.c",
90+
]
91+
92+
configs += [ ":wireguard_config" ]
93+
# Remove Chromium's clang plugins for third-party code
94+
configs -= [
95+
"//build/config/clang:find_bad_constructs",
96+
"//build/config/clang:unsafe_buffers",
97+
]
98+
}
99+
100+
# Build libwg-go.so - WireGuard Go implementation
101+
# Use the upstream Makefile since GN doesn't support Go
102+
action("libwg-go") {
103+
script = "//build/gn_run_binary.py"
104+
105+
# Makefile location
106+
_makefile_dir = "tunnel/tools/libwg-go"
107+
108+
sources = [
109+
"tunnel/tools/libwg-go/Makefile",
110+
"tunnel/tools/libwg-go/api-android.go",
111+
"tunnel/tools/libwg-go/go.mod",
112+
]
113+
114+
# Determine architecture mapping
115+
if (target_cpu == "arm") {
116+
_arch_name = "arm"
117+
_target_triple = "armv7a-linux-androideabi21"
118+
} else if (target_cpu == "arm64") {
119+
_arch_name = "arm64"
120+
_target_triple = "aarch64-linux-android21"
121+
} else if (target_cpu == "x86") {
122+
_arch_name = "x86"
123+
_target_triple = "i686-linux-android21"
124+
} else if (target_cpu == "x64") {
125+
_arch_name = "x86_64"
126+
_target_triple = "x86_64-linux-android21"
127+
}
128+
129+
outputs = [ "$target_out_dir/$target_cpu/libwg-go.so" ]
130+
131+
# Use Chromium's clang toolchain - ABSOLUTE paths for Go
132+
_clang_path = rebase_path("$clang_base_path/bin/clang")
133+
_sysroot_path = rebase_path(sysroot)
134+
135+
# Use source tree paths for build artifacts to avoid gen/ directory license issues
136+
_build_dir_abs = rebase_path("tunnel/tools/libwg-go/.gobuild")
137+
_gradle_cache_abs = rebase_path("tunnel/tools/libwg-go/.gradle_cache")
138+
_dest_dir_abs = rebase_path("$target_out_dir/$target_cpu")
139+
140+
# Invoke make with proper environment using Chromium's clang with absolute paths
141+
# Use --unwindlib=none to avoid libunwind.a dependency which doesn't exist in Chromium's clang
142+
args = [
143+
"/usr/bin/make",
144+
"-C",
145+
rebase_path(_makefile_dir, root_build_dir),
146+
"ANDROID_ARCH_NAME=$_arch_name",
147+
"ANDROID_PACKAGE_NAME=$_wireguard_package_name",
148+
"GRADLE_USER_HOME=$_gradle_cache_abs",
149+
"CC=$_clang_path --target=$_target_triple --sysroot=$_sysroot_path",
150+
"CFLAGS=",
151+
"LDFLAGS=-Wl,--build-id=none -fuse-ld=lld --rtlib=compiler-rt --unwindlib=none",
152+
"SYSROOT=$_sysroot_path",
153+
"TARGET=$_target_triple",
154+
"DESTDIR=$_dest_dir_abs",
155+
"BUILDDIR=$_build_dir_abs",
156+
]
157+
}
158+
159+
# Build the Java tunnel library
160+
android_library("com_wireguard_android_java") {
161+
chromium_code = false
162+
163+
sources = [
164+
"tunnel/src/main/java/com/wireguard/android/backend/Backend.java",
165+
"tunnel/src/main/java/com/wireguard/android/backend/BackendException.java",
166+
"tunnel/src/main/java/com/wireguard/android/backend/GoBackend.java",
167+
"tunnel/src/main/java/com/wireguard/android/backend/Statistics.java",
168+
"tunnel/src/main/java/com/wireguard/android/backend/Tunnel.java",
169+
"tunnel/src/main/java/com/wireguard/android/backend/WgQuickBackend.java",
170+
"tunnel/src/main/java/com/wireguard/android/util/RootShell.java",
171+
"tunnel/src/main/java/com/wireguard/android/util/SharedLibraryLoader.java",
172+
"tunnel/src/main/java/com/wireguard/android/util/ToolsInstaller.java",
173+
"tunnel/src/main/java/com/wireguard/config/Attribute.java",
174+
"tunnel/src/main/java/com/wireguard/config/BadConfigException.java",
175+
"tunnel/src/main/java/com/wireguard/config/Config.java",
176+
"tunnel/src/main/java/com/wireguard/config/InetAddresses.java",
177+
"tunnel/src/main/java/com/wireguard/config/InetEndpoint.java",
178+
"tunnel/src/main/java/com/wireguard/config/InetNetwork.java",
179+
"tunnel/src/main/java/com/wireguard/config/Interface.java",
180+
"tunnel/src/main/java/com/wireguard/config/ParseException.java",
181+
"tunnel/src/main/java/com/wireguard/config/Peer.java",
182+
"tunnel/src/main/java/com/wireguard/crypto/Curve25519.java",
183+
"tunnel/src/main/java/com/wireguard/crypto/Key.java",
184+
"tunnel/src/main/java/com/wireguard/crypto/KeyFormatException.java",
185+
"tunnel/src/main/java/com/wireguard/crypto/KeyPair.java",
186+
"tunnel/src/main/java/com/wireguard/util/NonNullForAll.java",
187+
]
188+
189+
deps = [
190+
":libwg",
191+
":libwg-quick",
192+
":libwg-go",
193+
"//third_party/android_deps:com_google_code_findbugs_jsr305_java",
194+
"//third_party/androidx:androidx_annotation_annotation_java",
195+
"//third_party/androidx:androidx_collection_collection_java",
196+
]
197+
}

README.chromium

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
Name: WireGuard for Android
2+
Short Name: wireguard-android
3+
URL: https://git.zx2c4.com/wireguard-android
4+
Version: 1.0.20250531
5+
Date: 2025-05-31
6+
License: Apache 2.0
7+
License File: COPYING
8+
Security Critical: yes
9+
10+
Description:
11+
WireGuard is a fast, modern, secure VPN tunnel. This is the Android
12+
implementation used by Brave VPN.
13+
14+
The library consists of:
15+
- Java sources for configuration and tunnel management
16+
- Go implementation of the WireGuard protocol (libwg-go.so)
17+
- C tools for command-line interface (libwg.so, libwg-quick.so)
18+
19+
Local Modifications:
20+
- Added BUILD.gn to build with GN instead of Gradle
21+
- C code built directly with GN
22+
- Go code built via existing Makefile

tunnel/src/main/java/com/wireguard/android/backend/Statistics.java

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,42 @@
2121
*/
2222
@NonNullForAll
2323
public class Statistics {
24-
public record PeerStats(long rxBytes, long txBytes, long latestHandshakeEpochMillis) { }
24+
// Converted from record to traditional class for Chromium build compatibility
25+
// Original: public record PeerStats(long rxBytes, long txBytes, long latestHandshakeEpochMillis) { }
26+
public static final class PeerStats {
27+
private final long rxBytes;
28+
private final long txBytes;
29+
private final long latestHandshakeEpochMillis;
30+
31+
public PeerStats(long rxBytes, long txBytes, long latestHandshakeEpochMillis) {
32+
this.rxBytes = rxBytes;
33+
this.txBytes = txBytes;
34+
this.latestHandshakeEpochMillis = latestHandshakeEpochMillis;
35+
}
36+
37+
public long rxBytes() { return rxBytes; }
38+
public long txBytes() { return txBytes; }
39+
public long latestHandshakeEpochMillis() { return latestHandshakeEpochMillis; }
40+
41+
@Override
42+
public boolean equals(Object obj) {
43+
if (this == obj) return true;
44+
if (!(obj instanceof PeerStats)) return false;
45+
PeerStats other = (PeerStats) obj;
46+
return rxBytes == other.rxBytes && txBytes == other.txBytes && latestHandshakeEpochMillis == other.latestHandshakeEpochMillis;
47+
}
48+
49+
@Override
50+
public int hashCode() {
51+
return Objects.hash(rxBytes, txBytes, latestHandshakeEpochMillis);
52+
}
53+
54+
@Override
55+
public String toString() {
56+
return "PeerStats[rxBytes=" + rxBytes + ", txBytes=" + txBytes + ", latestHandshakeEpochMillis=" + latestHandshakeEpochMillis + "]";
57+
}
58+
}
59+
2560
private final Map<Key, PeerStats> stats = new HashMap<>();
2661
private long lastTouched = SystemClock.elapsedRealtime();
2762

0 commit comments

Comments
 (0)