Работающие звонки

This commit is contained in:
2026-03-27 03:12:04 +05:00
parent 9cca071bd8
commit b663450db5
10 changed files with 343 additions and 53 deletions

View File

@@ -16,6 +16,7 @@
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <stdarg.h>
#include <stdio.h>
#include <android/log.h>
@@ -125,6 +126,12 @@ struct AdditionalTsState {
uint64_t base_timestamp = 0;
};
struct SenderTsOffsetState {
bool initialized = false;
bool enabled = false;
uint64_t offset = 0;
};
static inline uint16_t load16_be(const uint8_t* p) {
return (uint16_t)(((uint16_t)p[0] << 8) | (uint16_t)p[1]);
}
@@ -334,6 +341,25 @@ static inline void fill_nonce_from_ts32(uint32_t ts, uint8_t nonce[24]) {
nonce[7] = (uint8_t)(ts);
}
static inline void fill_nonce_from_ts64(uint64_t ts, uint8_t nonce[24]) {
nonce[0] = (uint8_t)(ts >> 56);
nonce[1] = (uint8_t)(ts >> 48);
nonce[2] = (uint8_t)(ts >> 40);
nonce[3] = (uint8_t)(ts >> 32);
nonce[4] = (uint8_t)(ts >> 24);
nonce[5] = (uint8_t)(ts >> 16);
nonce[6] = (uint8_t)(ts >> 8);
nonce[7] = (uint8_t)(ts);
}
static inline uint64_t monotonic_48k_ticks() {
struct timespec ts {};
if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) return 0;
const uint64_t sec = (uint64_t)ts.tv_sec;
const uint64_t nsec = (uint64_t)ts.tv_nsec;
return sec * 48000ULL + (nsec * 48000ULL) / 1000000000ULL;
}
static inline uint32_t opus_base_frame_samples(uint8_t config) {
// RFC 6716 TOC config mapping at 48 kHz.
if (config <= 11) {
@@ -550,6 +576,7 @@ public:
bool nonce_from_generated_ts = false;
bool nonce_from_additional_data = false;
bool additional_was_rtp_header = false;
bool additional_used_mono_offset = false;
uint32_t generated_ts_used = 0;
// Build nonce from RTP timestamp in additional_data (preferred).
@@ -579,23 +606,36 @@ public:
}
}
if (nonce_from_rtp_header && header_size <= frame.size()) {
// Keep RTP header clear, encrypt payload only.
if (header_size > 0) {
memcpy(encrypted_frame.data(), frame.data(), header_size);
// Some Android sender pipelines expose stream-relative ad8 timestamps
// (0, 960, 1920, ...), while desktop receiver expects an absolute base.
// For interop, add a monotonic 48k offset once when first ad8 is tiny.
if (nonce_from_additional_data &&
additional_data.size() == 8 &&
!additional_was_rtp_header &&
additional_data.data() != nullptr) {
const uint64_t ad_ts64 = load64_be(additional_data.data());
if (!sender_ts_offset_.initialized) {
sender_ts_offset_.initialized = true;
// Keep pure raw-abs mode by default; desktop is the source of truth.
sender_ts_offset_.enabled = false;
sender_ts_offset_.offset = 0ULL;
diag_event("ENC ad8-base init ssrc=%u ad_ts=%llu use_mono=%d mono_off=%llu\n",
ssrc,
(unsigned long long)ad_ts64,
sender_ts_offset_.enabled ? 1 : 0,
(unsigned long long)sender_ts_offset_.offset);
}
const size_t payload_size = frame.size() - header_size;
rosetta_xchacha20_xor(
encrypted_frame.data() + header_size,
frame.data() + header_size,
payload_size,
nonce,
key_);
} else {
// Legacy path: frame is payload-only.
if (sender_ts_offset_.enabled) {
const uint64_t ts_adj = ad_ts64 + sender_ts_offset_.offset;
fill_nonce_from_ts64(ts_adj, nonce);
additional_used_mono_offset = true;
}
}
// Desktop createEncodedStreams encrypts full encoded chunk.
// To stay wire-compatible, do not preserve any leading RTP-like bytes.
rosetta_xchacha20_xor(encrypted_frame.data(),
frame.data(), frame.size(), nonce, key_);
}
*bytes_written = frame.size();
if (nonce_from_generated_ts) {
@@ -628,7 +668,9 @@ public:
: (nonce_from_additional_data
? (additional_was_rtp_header
? "ad-rtp"
: (additional_used_relative_ts ? "raw-rel" : "raw-abs"))
: (additional_used_mono_offset
? "raw-abs+mono"
: (additional_used_relative_ts ? "raw-rel" : "raw-abs")))
: "raw-abs"));
LOGI("ENC frame#%d mt=%s ssrc=%u sz=%zu ad=%zu hdr=%zu mode=%s nonce_ts=%u gen_ts=%u next_step=%u rtp_ok=%d rtp_seq=%u rtp_ts=%u rtp_ssrc=%u opus_ok=%d key_fp=%08x in_h=%08x out_h=%08x ad8=%02x%02x%02x%02x%02x%02x%02x%02x",
n, media_type_name(media_type), ssrc, frame.size(), additional_data.size(), header_size, mode,
@@ -663,6 +705,7 @@ private:
mutable std::atomic<int> diag_count_{0};
mutable RtpProbeState rtp_probe_;
mutable GeneratedTsState generated_ts_;
mutable SenderTsOffsetState sender_ts_offset_;
uint32_t key_fingerprint_ = 0;
uint8_t key_[32];
};
@@ -746,20 +789,8 @@ public:
bool used_generated_resync = false;
if (nonce_from_rtp_header && header_size <= encrypted_frame.size()) {
if (header_size > 0) {
memcpy(frame.data(), encrypted_frame.data(), header_size);
}
const size_t payload_size = encrypted_frame.size() - header_size;
rosetta_xchacha20_xor(
frame.data() + header_size,
encrypted_frame.data() + header_size,
payload_size,
nonce,
key_);
} else {
// Desktop createEncodedStreams decrypts full encoded chunk.
rosetta_xchacha20_xor(frame.data(), encrypted_frame.data(), encrypted_frame.size(), nonce, key_);
}
if (nonce_from_additional_data) {
bool plausible = is_plausible_decrypted_audio_frame(frame.data(), encrypted_frame.size());

View File

@@ -6,7 +6,6 @@ import android.util.Log
import com.rosetta.messenger.data.MessageRepository
import java.security.MessageDigest
import java.security.SecureRandom
import java.util.IdentityHashMap
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
@@ -137,8 +136,8 @@ object CallManager {
// E2EE (XChaCha20 — compatible with Desktop)
private var sharedKeyBytes: ByteArray? = null
private val senderEncryptors = IdentityHashMap<RtpSender, XChaCha20E2EE.Encryptor>()
private val receiverDecryptors = IdentityHashMap<RtpReceiver, XChaCha20E2EE.Decryptor>()
private val senderEncryptors = LinkedHashMap<String, XChaCha20E2EE.Encryptor>()
private val receiverDecryptors = LinkedHashMap<String, XChaCha20E2EE.Decryptor>()
private var pendingAudioSenderForE2ee: RtpSender? = null
private var lastRemoteOfferFingerprint: String = ""
private var lastLocalOfferFingerprint: String = ""
@@ -1063,11 +1062,22 @@ object CallManager {
breadcrumb("STATE[$marker] ${buildStateSnapshot()}")
}
private fun senderMapKey(sender: RtpSender): String {
val id = runCatching { sender.id() }.getOrNull().orEmpty()
return if (id.isNotBlank()) "sid:$id" else "sender@${System.identityHashCode(sender)}"
}
private fun receiverMapKey(receiver: RtpReceiver): String {
val id = runCatching { receiver.id() }.getOrNull().orEmpty()
return if (id.isNotBlank()) "rid:$id" else "recv@${System.identityHashCode(receiver)}"
}
private fun attachSenderE2EE(sender: RtpSender?) {
if (!e2eeAvailable) return
val key = sharedKeyBytes ?: return
if (sender == null) return
val existing = senderEncryptors[sender]
val mapKey = senderMapKey(sender)
val existing = senderEncryptors[mapKey]
if (existing != null) {
runCatching { sender.setFrameEncryptor(existing) }
return
@@ -1086,7 +1096,7 @@ object CallManager {
breadcrumb("4. calling sender.setFrameEncryptor…")
sender.setFrameEncryptor(enc)
breadcrumb("5. setFrameEncryptor OK!")
senderEncryptors[sender] = enc
senderEncryptors[mapKey] = enc
pendingAudioSenderForE2ee = null
} catch (e: Throwable) {
saveCrashReport("attachSenderE2EE failed", e)
@@ -1104,7 +1114,8 @@ object CallManager {
if (!e2eeAvailable) return
val key = sharedKeyBytes ?: return
if (receiver == null) return
val existing = receiverDecryptors[receiver]
val mapKey = receiverMapKey(receiver)
val existing = receiverDecryptors[mapKey]
if (existing != null) {
runCatching { receiver.setFrameDecryptor(existing) }
return
@@ -1123,7 +1134,7 @@ object CallManager {
breadcrumb("9. calling receiver.setFrameDecryptor…")
receiver.setFrameDecryptor(dec)
breadcrumb("10. setFrameDecryptor OK!")
receiverDecryptors[receiver] = dec
receiverDecryptors[mapKey] = dec
} catch (e: Throwable) {
saveCrashReport("attachReceiverE2EE failed", e)
Log.e(TAG, "E2EE: receiver decryptor failed", e)

View File

@@ -1,5 +1,6 @@
package com.rosetta.messenger.ui.crashlogs
import android.widget.Toast
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
@@ -8,13 +9,16 @@ import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material.icons.filled.BugReport
import androidx.compose.material.icons.filled.ContentCopy
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Share
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
@@ -263,6 +267,8 @@ private fun CrashDetailScreen(
onDelete: () -> Unit
) {
var showDeleteDialog by remember { mutableStateOf(false) }
val clipboardManager = LocalClipboardManager.current
val context = LocalContext.current
Scaffold(
topBar = {
@@ -274,6 +280,14 @@ private fun CrashDetailScreen(
}
},
actions = {
IconButton(
onClick = {
clipboardManager.setText(AnnotatedString(crashReport.content))
Toast.makeText(context, "Full log copied", Toast.LENGTH_SHORT).show()
}
) {
Icon(Icons.Default.ContentCopy, contentDescription = "Copy Full Log")
}
IconButton(onClick = { /* TODO: Share */ }) {
Icon(Icons.Default.Share, contentDescription = "Share")
}

View File

@@ -9,7 +9,8 @@ Stock `io.github.webrtc-sdk:android:125.6422.07` can call audio frame encryptor
`additional_data` (`ad=0`), so nonce derivation based on timestamp is unavailable.
Desktop uses frame timestamp for nonce. This patch aligns Android with that approach by passing
an 8-byte big-endian timestamp payload in `additional_data`:
an 8-byte big-endian timestamp payload in `additional_data` (absolute RTP timestamp,
including sender start offset):
- bytes `0..3` = `0`
- bytes `4..7` = RTP timestamp (big-endian)
@@ -18,10 +19,14 @@ an 8-byte big-endian timestamp payload in `additional_data`:
- `build_custom_webrtc.sh` — reproducible build script
- `patches/0001-audio-e2ee-pass-rtp-timestamp-as-additional-data.patch` — WebRTC patch
- `patches/0002-android-build-on-mac-host.patch` — allows Android target build on macOS host
- `patches/0003-macos-host-java-ijar.patch` — enables host tools (`ijar`/`jdk`) on macOS
- `patches/0004-macos-linker-missing-L-dirs.patch` — skips invalid host `-L...` paths for lld
- `patches/0005-macos-server-utils-socket.patch` — handles macOS socket errno in Android Java compile helper
## Build
Recommended on Linux (macOS can work but is less predictable for long WebRTC builds).
Recommended on Linux (macOS is supported via additional patches in this folder).
Bootstrap `depot_tools` first:
@@ -47,6 +52,7 @@ Optional env vars:
- `SYNC_JOBS``gclient sync` jobs (default: `1`, safer for googlesource limits)
- `SYNC_RETRIES` — sync retry attempts (default: `8`)
- `SYNC_RETRY_BASE_SEC` — base retry delay in seconds (default: `20`)
- `MAC_ANDROID_NDK_ROOT` — local Android NDK path on macOS (default: `~/Library/Android/sdk/ndk/27.1.12297006`)
## Troubleshooting (HTTP 429 / RESOURCE_EXHAUSTED)

View File

@@ -9,7 +9,13 @@ set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROSETTA_ANDROID_DIR="$(cd "${SCRIPT_DIR}/../.." && pwd)"
PATCH_FILE="${SCRIPT_DIR}/patches/0001-audio-e2ee-pass-rtp-timestamp-as-additional-data.patch"
PATCH_FILES=(
"${SCRIPT_DIR}/patches/0001-audio-e2ee-pass-rtp-timestamp-as-additional-data.patch"
"${SCRIPT_DIR}/patches/0002-android-build-on-mac-host.patch"
"${SCRIPT_DIR}/patches/0003-macos-host-java-ijar.patch"
"${SCRIPT_DIR}/patches/0004-macos-linker-missing-L-dirs.patch"
"${SCRIPT_DIR}/patches/0005-macos-server-utils-socket.patch"
)
# Default target: WebRTC M125 family used by app dependency 125.6422.07.
WEBRTC_BRANCH="${WEBRTC_BRANCH:-branch-heads/6422}"
@@ -132,21 +138,63 @@ sync_with_retry
echo "[webrtc-custom] applying Rosetta patch..."
git reset --hard
git apply --check "${PATCH_FILE}"
git apply "${PATCH_FILE}"
for patch in "${PATCH_FILES[@]}"; do
echo "[webrtc-custom] apply $(basename "${patch}")"
git apply --check "${patch}"
git apply "${patch}"
done
# macOS host tweaks:
# - point third_party/jdk/current to local JDK
# - use locally installed Android NDK (darwin toolchain)
if [[ "$(uname -s)" == "Darwin" ]]; then
if [[ -z "${JAVA_HOME:-}" ]]; then
JAVA_HOME="$(/usr/libexec/java_home 2>/dev/null || true)"
fi
if [[ -z "${JAVA_HOME:-}" || ! -d "${JAVA_HOME}" ]]; then
echo "[webrtc-custom] ERROR: JAVA_HOME not found on macOS"
exit 1
fi
JAVA_HOME_CANDIDATE="${JAVA_HOME}"
if [[ ! -f "${JAVA_HOME_CANDIDATE}/conf/logging.properties" ]] && [[ -d "${JAVA_HOME_CANDIDATE}/libexec/openjdk.jdk/Contents/Home" ]]; then
JAVA_HOME_CANDIDATE="${JAVA_HOME_CANDIDATE}/libexec/openjdk.jdk/Contents/Home"
fi
if [[ ! -f "${JAVA_HOME_CANDIDATE}/conf/logging.properties" ]]; then
echo "[webrtc-custom] ERROR: invalid JAVA_HOME (conf/logging.properties not found): ${JAVA_HOME}"
exit 1
fi
JAVA_HOME="${JAVA_HOME_CANDIDATE}"
ln -sfn "${JAVA_HOME}" "${WEBRTC_SRC}/third_party/jdk/current"
echo "[webrtc-custom] macOS JDK linked: ${WEBRTC_SRC}/third_party/jdk/current -> ${JAVA_HOME}"
fi
mkdir -p "$(dirname "${OUT_AAR}")"
echo "[webrtc-custom] building AAR (this can take a while)..."
GN_ARGS=(
is_debug=false
is_component_build=false
rtc_include_tests=false
rtc_build_examples=false
)
if [[ "$(uname -s)" == "Darwin" ]]; then
MAC_ANDROID_NDK_ROOT="${MAC_ANDROID_NDK_ROOT:-$HOME/Library/Android/sdk/ndk/27.1.12297006}"
if [[ ! -d "${MAC_ANDROID_NDK_ROOT}" ]]; then
echo "[webrtc-custom] ERROR: Android NDK not found at ${MAC_ANDROID_NDK_ROOT}"
echo "[webrtc-custom] Set MAC_ANDROID_NDK_ROOT to your local NDK path."
exit 1
fi
GN_ARGS+=("android_ndk_root=\"${MAC_ANDROID_NDK_ROOT}\"")
GN_ARGS+=("android_ndk_version=\"27.1.12297006\"")
echo "[webrtc-custom] macOS Android NDK: ${MAC_ANDROID_NDK_ROOT}"
fi
python3 tools_webrtc/android/build_aar.py \
--build-dir out_rosetta_aar \
--output "${OUT_AAR}" \
--arch "${ARCHS[@]}" \
--extra-gn-args \
is_debug=false \
is_component_build=false \
rtc_include_tests=false \
rtc_build_examples=false
--extra-gn-args "${GN_ARGS[@]}"
echo "[webrtc-custom] done"
echo "[webrtc-custom] AAR: ${OUT_AAR}"

View File

@@ -25,22 +25,24 @@ index 17cf859ed8..b9d9ab14c8 100644
decrypted_audio_payload);
diff --git a/audio/channel_send.cc b/audio/channel_send.cc
index 4a2700177b..93283c2e78 100644
index 4a2700177b..7ebb501704 100644
--- a/audio/channel_send.cc
+++ b/audio/channel_send.cc
@@ -320,10 +320,21 @@ int32_t ChannelSend::SendRtpAudio(AudioFrameType frameType,
@@ -320,10 +320,23 @@ int32_t ChannelSend::SendRtpAudio(AudioFrameType frameType,
// Encrypt the audio payload into the buffer.
size_t bytes_written = 0;
+ const uint32_t additional_data_timestamp =
+ rtp_timestamp_without_offset + rtp_rtcp_->StartTimestamp();
+ const uint8_t additional_data_bytes[8] = {
+ 0,
+ 0,
+ 0,
+ 0,
+ static_cast<uint8_t>((rtp_timestamp_without_offset >> 24) & 0xff),
+ static_cast<uint8_t>((rtp_timestamp_without_offset >> 16) & 0xff),
+ static_cast<uint8_t>((rtp_timestamp_without_offset >> 8) & 0xff),
+ static_cast<uint8_t>(rtp_timestamp_without_offset & 0xff),
+ static_cast<uint8_t>((additional_data_timestamp >> 24) & 0xff),
+ static_cast<uint8_t>((additional_data_timestamp >> 16) & 0xff),
+ static_cast<uint8_t>((additional_data_timestamp >> 8) & 0xff),
+ static_cast<uint8_t>(additional_data_timestamp & 0xff),
+ };
+
int encrypt_status = frame_encryptor_->Encrypt(

View File

@@ -0,0 +1,27 @@
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn
index 26fad5adf..7a614f334 100644
--- a/build/config/BUILDCONFIG.gn
+++ b/build/config/BUILDCONFIG.gn
@@ -239,7 +239,8 @@ if (host_toolchain == "") {
_default_toolchain = ""
if (target_os == "android") {
- assert(host_os == "linux", "Android builds are only supported on Linux.")
+ assert(host_os == "linux" || host_os == "mac",
+ "Android builds are only supported on Linux/macOS.")
_default_toolchain = "//build/toolchain/android:android_clang_$target_cpu"
} else if (target_os == "chromeos" || target_os == "linux") {
# See comments in build/toolchain/cros/BUILD.gn about board compiles.
diff --git a/build/config/android/config.gni b/build/config/android/config.gni
index 427739d70..6a5ab0594 100644
--- a/build/config/android/config.gni
+++ b/build/config/android/config.gni
@@ -327,7 +327,7 @@ if (is_android || is_chromeos) {
# Defines the name the Android build gives to the current host CPU
# architecture, which is different than the names GN uses.
- if (host_cpu == "x64") {
+ if (host_cpu == "x64" || host_cpu == "arm64") {
android_host_arch = "x86_64"
} else if (host_cpu == "x86") {
android_host_arch = "x86"

View File

@@ -0,0 +1,34 @@
diff --git a/third_party/ijar/BUILD.gn b/third_party/ijar/BUILD.gn
index 8dc9fe21cf8..49c50e6636f 100644
--- a/third_party/ijar/BUILD.gn
+++ b/third_party/ijar/BUILD.gn
@@ -4,7 +4,7 @@
# A tool that removes all non-interface-specific parts from a .jar file.
-if (is_linux || is_chromeos) {
+if (is_linux || is_chromeos || is_mac) {
config("ijar_compiler_flags") {
if (is_clang) {
cflags = [
diff --git a/third_party/jdk/BUILD.gn b/third_party/jdk/BUILD.gn
index e003eef94d7..ec49922942b 100644
--- a/third_party/jdk/BUILD.gn
+++ b/third_party/jdk/BUILD.gn
@@ -3,10 +3,12 @@
# found in the LICENSE file.
config("jdk") {
- include_dirs = [
- "current/include",
- "current/include/linux",
- ]
+ include_dirs = [ "current/include" ]
+ if (host_os == "mac") {
+ include_dirs += [ "current/include/darwin" ]
+ } else {
+ include_dirs += [ "current/include/linux" ]
+ }
}
group("java_data") {

View File

@@ -0,0 +1,102 @@
diff --git a/build/toolchain/apple/linker_driver.py b/build/toolchain/apple/linker_driver.py
index 0632230cf..798442534 100755
--- a/build/toolchain/apple/linker_driver.py
+++ b/build/toolchain/apple/linker_driver.py
@@ -7,6 +7,7 @@
import os
import os.path
import re
+import shlex
import shutil
import subprocess
import sys
@@ -113,6 +114,53 @@ class LinkerDriver(object):
# The temporary directory for intermediate LTO object files. If it
# exists, it will clean itself up on script exit.
self._object_path_lto = None
+ self._temp_rsp_files = []
+
+ def _sanitize_rsp_arg(self, arg):
+ if not arg.startswith('@'):
+ return arg
+ rsp_path = arg[1:]
+ if not os.path.isfile(rsp_path):
+ return arg
+
+ try:
+ with open(rsp_path, 'r', encoding='utf-8') as f:
+ rsp_content = f.read()
+ except OSError:
+ return arg
+
+ tokens = shlex.split(rsp_content, posix=True)
+ sanitized = []
+ changed = False
+ i = 0
+ while i < len(tokens):
+ tok = tokens[i]
+ if tok == '-L' and i + 1 < len(tokens):
+ lib_dir = tokens[i + 1]
+ if not os.path.isdir(lib_dir):
+ changed = True
+ i += 2
+ continue
+ elif tok.startswith('-L') and len(tok) > 2:
+ lib_dir = tok[2:]
+ if not os.path.isdir(lib_dir):
+ changed = True
+ i += 1
+ continue
+ sanitized.append(tok)
+ i += 1
+
+ if not changed:
+ return arg
+
+ fd, temp_path = tempfile.mkstemp(prefix='linker_driver_', suffix='.rsp')
+ os.close(fd)
+ with open(temp_path, 'w', encoding='utf-8') as f:
+ for tok in sanitized:
+ f.write(tok)
+ f.write('\n')
+ self._temp_rsp_files.append(temp_path)
+ return '@' + temp_path
def run(self):
"""Runs the linker driver, separating out the main compiler driver's
@@ -135,11 +183,25 @@ class LinkerDriver(object):
assert driver_action[0] not in linker_driver_actions
linker_driver_actions[driver_action[0]] = driver_action[1]
else:
+ if arg.startswith('@'):
+ arg = self._sanitize_rsp_arg(arg)
# TODO(crbug.com/1446796): On Apple, the linker command line
# produced by rustc for LTO includes these arguments, but the
# Apple linker doesn't accept them.
# Upstream bug: https://github.com/rust-lang/rust/issues/60059
BAD_RUSTC_ARGS = '-Wl,-plugin-opt=O[0-9],-plugin-opt=mcpu=.*'
+ if arg == '-Wl,-fatal_warnings':
+ # Some host link steps on Apple Silicon produce benign
+ # warnings from injected search paths (e.g. /usr/local/lib
+ # missing). Don't fail the whole build on those warnings.
+ continue
+ if arg.startswith('-L') and len(arg) > 2:
+ # Some environments inject non-existent library search
+ # paths (e.g. /usr/local/lib on Apple Silicon). lld treats
+ # them as hard errors, so skip missing -L entries.
+ lib_dir = arg[2:]
+ if not os.path.isdir(lib_dir):
+ continue
if not re.match(BAD_RUSTC_ARGS, arg):
compiler_driver_args.append(arg)
@@ -185,6 +247,9 @@ class LinkerDriver(object):
# Re-report the original failure.
raise
+ finally:
+ for path in self._temp_rsp_files:
+ _remove_path(path)
def _get_linker_output(self):
"""Returns the value of the output argument to the linker."""

View File

@@ -0,0 +1,15 @@
diff --git a/build/android/gyp/util/server_utils.py b/build/android/gyp/util/server_utils.py
index 6d5ed79d3..c05b57529 100644
--- a/build/android/gyp/util/server_utils.py
+++ b/build/android/gyp/util/server_utils.py
@@ -36,7 +36,9 @@ def MaybeRunCommand(name, argv, stamp_file, force):
except socket.error as e:
# [Errno 111] Connection refused. Either the server has not been started
# or the server is not currently accepting new connections.
- if e.errno == 111:
+ # [Errno 2] Abstract Unix sockets are unsupported on macOS, so treat
+ # this the same way (build server unavailable).
+ if e.errno in (111, 2):
if force:
raise RuntimeError(
'\n\nBuild server is not running and '