mirror of
https://github.com/lucannez64/darling-lol.git
synced 2026-10-26 19:47:42 +00:00
Merge remote-tracking branch 'origin/main' into fix/mic-input
This commit is contained in:
commit
fdc579c2e6
7 files changed
+119
-14
No files matched your search
@@ -1,9 +1,12 @@
|
||||
# Explicit platform identity overrides
|
||||
|
||||
By default, Darling keeps the existing host-derived UUID and `DARLING-` serial.
|
||||
No override file is generated by installation or launch. Import mode uses values supplied by the user. Explicit `--provision` mode can
|
||||
generate synthetic identifiers; it does not issue authentic Apple identities
|
||||
or change CPU, GPU, or security metadata.
|
||||
First-time setup (`scripts/install-runtime.sh` creating a new prefix) runs
|
||||
`--provision --write` once, so each new prefix gets its own synthetic identity.
|
||||
A prefix without saved identity files keeps the host-derived UUID and
|
||||
`DARLING-` serial; launching never generates an override. Import mode uses
|
||||
values supplied by the user. `--provision` generates synthetic identifiers; it
|
||||
does not issue authentic Apple identities or change CPU, GPU, or security
|
||||
metadata.
|
||||
|
||||
Preview an OpenCore `config.plist`, a flat GenSMBIOS JSON file, or an existing
|
||||
`darling-smbios.conf` without changing the selected prefix:
|
||||
@@ -89,8 +92,13 @@ python3 tools/configure-darling-platform.py --prefix /absolute/prefix --provisio
|
||||
```
|
||||
|
||||
Launch Darling normally afterwards. This requires the updated iokitd from this
|
||||
PR; the config tool alone cannot update an older running daemon. Provisioning
|
||||
is never called automatically by installation or launch.
|
||||
PR; the config tool alone cannot update an older running daemon. Besides
|
||||
first-time setup above, provisioning runs automatically in one other case:
|
||||
after installing, `scripts/update.sh` runs
|
||||
`configure-darling-platform.py --replace-known-defaults --write`, which
|
||||
provisions the prefix only if its saved identity still contains the shared
|
||||
serial or UUID below. Prefixes without saved identity files, or whose saved
|
||||
values are all custom, are left byte-for-byte unchanged.
|
||||
|
||||
Missing serials use 12 characters and missing MLBs use 17 characters, sampled
|
||||
with Python's `secrets` module from `0123456789ABCDEFGHJKLMNPQRSTUVWXYZ` (Base-34).
|
||||
@@ -106,7 +114,8 @@ example with your chosen unicast OUI). It only affects a missing ROM. An OUI
|
||||
does not make a generated identity Apple-issued.
|
||||
|
||||
Provisioning replaces the known shared serial `C02ZL0GVMD6N` and UUID
|
||||
`6F3B2A1E-8C4D-4E5F-9A7B-1D2C3E4F5A6B`, along with the latter's derived fields.
|
||||
`6F3B2A1E-8C4D-4E5F-9A7B-1D2C3E4F5A6B`, along with the latter's derived fields
|
||||
(including a standalone `system-id` or `provisioning_UDID` derived from it).
|
||||
It preserves other existing custom values, including imported serials and UUIDs
|
||||
that do not follow the generated formats. A standalone custom `system-id` is
|
||||
preserved by deriving its UUID instead of generating a different one. Model,
|
||||
|
||||
@@ -16,6 +16,9 @@ if [ -d build/venv/bin ]; then PATH="$repo/build/venv/bin:$PATH"; export PATH; f
|
||||
# A server killed by the base install leaves a stale .init.pid that makes darling shell fail.
|
||||
python3 build/runtime/tools/ensure-darling-runtime.py
|
||||
# Initialize the normal user-owned prefix before installing overrides.
|
||||
# Darling treats a missing prefix directory as new; only then is an identity generated below.
|
||||
new_prefix=
|
||||
[ -e "$prefix_dir" ] || new_prefix=1
|
||||
darling shell /usr/bin/true
|
||||
# The prefix has no /private/tmp of its own, so the guest falls through to the root-owned
|
||||
# installed layer and every write there (the Riot installer's temp files) fails with EACCES.
|
||||
@@ -26,6 +29,12 @@ chmod 1777 "$prefix/private/tmp"
|
||||
python3 build/runtime/tools/ensure-darling-root-certificates.py || \
|
||||
echo 'Darling system root store not installed; the launcher retries it' >&2
|
||||
python3 build/runtime/tools/stop-darling-runtime.py
|
||||
# Give a new prefix its own synthetic serial, MLB, UUID and ROM instead of the host-derived defaults.
|
||||
# Existing prefixes keep their identity; update.sh only replaces the old shared serial and UUID.
|
||||
if [ -n "$new_prefix" ]; then
|
||||
python3 tools/configure-darling-platform.py --prefix "$prefix_dir" --provision --write || \
|
||||
echo 'Platform identity not provisioned; run tools/configure-darling-platform.py --provision --write' >&2
|
||||
fi
|
||||
sh build/runtime/tools/install-riot-presentation-runtime.sh
|
||||
sh build/runtime/tools/install-riot-gpu-runtime.sh
|
||||
# darling-lol perf: build and install optimized libc/libc++/libplatform.
|
||||
|
||||
@@ -7,6 +7,13 @@
|
||||
set -eu
|
||||
repo=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
|
||||
cd "$repo"
|
||||
# Older setups shipped one serial and UUID shared by every install. Give a prefix that still
|
||||
# has them its own identity; any other saved values, and prefixes without them, are left alone.
|
||||
replace_shared_identity() {
|
||||
python3 build/runtime/tools/stop-darling-runtime.py
|
||||
python3 tools/configure-darling-platform.py --replace-known-defaults --write || \
|
||||
echo 'Could not replace the shared platform identity; run tools/configure-darling-platform.py --provision --write' >&2
|
||||
}
|
||||
if [ -n "${DARLING_WORKSPACE:-}" ]; then
|
||||
python3 scripts/nix-idle.py
|
||||
# Initial setup and upgrades use the same supported user-owned install path.
|
||||
@@ -21,6 +28,7 @@ if [ -n "${DARLING_WORKSPACE:-}" ]; then
|
||||
cmake --install build/darling-src/build
|
||||
python3 scripts/nix-state.py stamp-base
|
||||
./scripts/install-runtime.sh
|
||||
replace_shared_identity
|
||||
echo 'Rootless update installed. In this shell use scripts/run.sh; otherwise exit this shell and start darling-lol.'
|
||||
exit 0
|
||||
fi
|
||||
@@ -45,4 +53,5 @@ PY
|
||||
python3 build/runtime/tools/stop-darling-runtime.py
|
||||
sudo cmake --install build/darling-src/build
|
||||
./scripts/install-runtime.sh
|
||||
replace_shared_identity
|
||||
echo 'Update installed. Start Darling with: sh scripts/run.sh'
|
||||
@@ -91,6 +91,17 @@ class InGameCloseTests(unittest.TestCase):
|
||||
self.assertIn('closed the client UI for the running match (2 processes: 123,124)',
|
||||
self.output.getvalue())
|
||||
|
||||
def test_match_soon_after_boot_still_closes_the_client_ui(self):
|
||||
# time.monotonic() counts from boot; a fresh machine (or CI runner) is
|
||||
# still inside the first cooldown window.
|
||||
self.client_ui(123)
|
||||
self.process(125, GAME)
|
||||
with patch.object(in_game.time, 'monotonic', return_value=5.0):
|
||||
result, calls = self.run_once()
|
||||
self.assertEqual(result, 0)
|
||||
self.assertEqual(sorted(calls), sorted([(123, in_game.signal.SIGTERM),
|
||||
(123, in_game.signal.SIGKILL)]))
|
||||
|
||||
def test_marker_in_arguments_does_not_make_a_process_client_ui(self):
|
||||
self.client_ui(123)
|
||||
self.process(124, CRASH_HANDLER, args=CRASH_ARGUMENTS)
|
||||
@@ -209,7 +220,8 @@ class InGameCloseTests(unittest.TestCase):
|
||||
|
||||
def test_close_decision_covers_limits_and_cooldown(self):
|
||||
state = {'game': True, 'ui': {'123': 1}}
|
||||
self.assertEqual(in_game.close_decision(state, 0, 0.0, 100.0), 'close')
|
||||
self.assertEqual(in_game.close_decision(state, 0, None, 100.0), 'close')
|
||||
self.assertEqual(in_game.close_decision(state, 0, None, 5.0), 'close')
|
||||
self.assertIsNone(in_game.close_decision(state, 0, 90.0, 100.0))
|
||||
self.assertEqual(in_game.close_decision(state, in_game.MAX_CLOSES, 0.0, 100.0), 'limit')
|
||||
self.assertIsNone(in_game.close_decision({'game': False, 'ui': {'123': 1}}, 0, 0.0, 100.0))
|
||||
|
||||
@@ -157,3 +157,43 @@ class ProvisioningChecks(unittest.TestCase):
|
||||
self.assertEqual(platform.provision(supplied)['IOPlatformUUID'], value['IOPlatformUUID'])
|
||||
with self.assertRaises(ValueError):
|
||||
platform.validate({'IOPlatformUUID': value['IOPlatformUUID'], 'provisioning_UDID': str(uuid.uuid4())})
|
||||
|
||||
def test_replace_known_defaults_only_touches_shared_identities(self):
|
||||
replace = [sys.executable, str(SCRIPT), '--prefix', str(self.prefix), '--runtime-root',
|
||||
str(self.runtime), '--replace-known-defaults', '--write']
|
||||
# A prefix without identity files is not created or provisioned.
|
||||
result = subprocess.run(replace, capture_output=True, text=True)
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
self.assertFalse(self.prefix.exists())
|
||||
# A custom identity stays byte-for-byte unchanged.
|
||||
custom = {'IOPlatformSerialNumber': 'MY-SERIAL', 'model': 'CustomModel'}
|
||||
platform.save(self.prefix, custom)
|
||||
canonical = platform.destination(self.prefix)
|
||||
before = canonical.read_bytes()
|
||||
result = subprocess.run(replace, capture_output=True, text=True)
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
self.assertEqual(canonical.read_bytes(), before)
|
||||
self.assertFalse((self.prefix / 'private/etc/darling-smbios.conf').exists())
|
||||
# The shared values are replaced; custom fields survive and a rerun is stable.
|
||||
platform.save(self.prefix, {**custom, 'IOPlatformSerialNumber': platform.KNOWN_SERIAL,
|
||||
'IOPlatformUUID': platform.KNOWN_UUID})
|
||||
result = subprocess.run(replace, capture_output=True, text=True)
|
||||
self.assertEqual(result.returncode, 0, result.stderr)
|
||||
value = platform.load(canonical)
|
||||
self.assertNotEqual(value['IOPlatformSerialNumber'], platform.KNOWN_SERIAL)
|
||||
self.assertNotEqual(value['IOPlatformUUID'], platform.KNOWN_UUID)
|
||||
self.assertFalse(platform.has_known_defaults(value))
|
||||
self.assertEqual(value['model'], 'CustomModel')
|
||||
self.assertNotIn('board-id', value)
|
||||
self.assertNotIn('manufacturer', value)
|
||||
self.assertEqual(platform.load(self.prefix / 'private/etc/darling-smbios.conf'), value)
|
||||
after = canonical.read_bytes()
|
||||
subprocess.run(replace, capture_output=True, text=True, check=True)
|
||||
self.assertEqual(canonical.read_bytes(), after)
|
||||
|
||||
def test_standalone_fields_derived_from_known_uuid_are_replaced(self):
|
||||
known_id = uuid.UUID(platform.KNOWN_UUID).bytes_le
|
||||
for supplied in [{'system-id': known_id}, {'provisioning_UDID': platform.KNOWN_UUID}]:
|
||||
value = platform.provision(supplied)
|
||||
self.assertNotEqual(value['IOPlatformUUID'], platform.KNOWN_UUID)
|
||||
self.assertNotEqual(value['system-id'], known_id)
|
||||
@@ -160,7 +160,9 @@ def close_decision(state, closes, last_close, now):
|
||||
return None
|
||||
if closes >= MAX_CLOSES:
|
||||
return 'limit'
|
||||
if now - last_close < COOLDOWN_SECONDS:
|
||||
# last_close is None until the first close: monotonic time counts from boot,
|
||||
# so a 0.0 start would block closes for the first COOLDOWN_SECONDS of uptime.
|
||||
if last_close is not None and now - last_close < COOLDOWN_SECONDS:
|
||||
return None
|
||||
return 'close'
|
||||
|
||||
@@ -189,7 +191,7 @@ def supervise(proc_root=Path('/proc'), prefix=None, once=False, dry_run=False, o
|
||||
'opt out with RCLOL_CLOSE_CLIENT_IN_GAME=0' % prefix, file=out, flush=True)
|
||||
in_game = False
|
||||
closes = 0
|
||||
last_close = 0.0
|
||||
last_close = None
|
||||
limit_reported = False
|
||||
seen = False
|
||||
idle_since = None
|
||||
@@ -203,7 +205,7 @@ def supervise(proc_root=Path('/proc'), prefix=None, once=False, dry_run=False, o
|
||||
if state['game'] and not in_game:
|
||||
in_game = True
|
||||
closes = 0
|
||||
last_close = 0.0
|
||||
last_close = None
|
||||
limit_reported = False
|
||||
print('close-league-client-in-game: a match started', file=out, flush=True)
|
||||
elif not state['game'] and in_game:
|
||||
|
||||
@@ -182,13 +182,23 @@ def save(prefix, properties):
|
||||
return atomic_write(destination(prefix), encoded)
|
||||
|
||||
|
||||
def has_known_defaults(properties):
|
||||
"""True when an identity still carries the shared serial, UUID, or a field derived from that UUID."""
|
||||
return (properties.get('IOPlatformSerialNumber') == KNOWN_SERIAL
|
||||
or str(properties.get('IOPlatformUUID', '')).upper() == KNOWN_UUID
|
||||
or str(properties.get('provisioning_UDID', '')).upper() == KNOWN_UUID
|
||||
or properties.get('system-id') == uuid.UUID(KNOWN_UUID).bytes_le)
|
||||
|
||||
|
||||
def provision(properties, rom_oui=None):
|
||||
"""Fill missing identifiers, replacing only the two known shared defaults."""
|
||||
result = validate(properties)
|
||||
if result.get('IOPlatformSerialNumber') == KNOWN_SERIAL:
|
||||
result.pop('IOPlatformSerialNumber')
|
||||
if result.get('IOPlatformUUID', '').upper() == KNOWN_UUID:
|
||||
result.pop('IOPlatformUUID')
|
||||
if (result.get('IOPlatformUUID', '').upper() == KNOWN_UUID
|
||||
or result.get('provisioning_UDID', '').upper() == KNOWN_UUID
|
||||
or result.get('system-id') == uuid.UUID(KNOWN_UUID).bytes_le):
|
||||
result.pop('IOPlatformUUID', None)
|
||||
result.pop('system-id', None)
|
||||
result.pop('provisioning_UDID', None)
|
||||
for key, length in [('IOPlatformSerialNumber', 12), ('mlb-serial-number', 17)]:
|
||||
@@ -274,8 +284,14 @@ def main(argv=None):
|
||||
parser.add_argument('--provision', action='store_true', help='Generate missing synthetic identifiers and provision prefix metadata')
|
||||
parser.add_argument('--runtime-root', type=Path, help='Runtime supplying SystemVersion.plist (default: saved SDK or /usr/local/libexec/darling)')
|
||||
parser.add_argument('--rom-oui', help='Explicit three-byte unicast OUI for a missing ROM; default is locally administered')
|
||||
parser.add_argument('--replace-known-defaults', action='store_true',
|
||||
help='Provision only if the prefix identity still has the shared serial or UUID; otherwise change nothing')
|
||||
parser.add_argument('--write', action='store_true', help='Write validated overrides to a stopped prefix (otherwise preview only)')
|
||||
args = parser.parse_args(argv)
|
||||
if args.replace_known_defaults:
|
||||
if args.source or args.set:
|
||||
parser.error('--replace-known-defaults cannot be combined with --import or --set')
|
||||
args.provision = True
|
||||
config = Path(__file__).resolve().parents[1] / 'build/config.json'
|
||||
saved = json.loads(config.read_text()) if config.exists() else {}
|
||||
prefix = args.prefix or Path(os.environ.get('DPREFIX') or saved.get('prefix', str(Path.home() / '.darling')))
|
||||
@@ -288,11 +304,19 @@ def main(argv=None):
|
||||
rom_oui = bytes.fromhex(args.rom_oui.replace(':', '').replace('-', ''))
|
||||
if len(rom_oui) != 3 or rom_oui[0] & 1:
|
||||
raise ValueError('--rom-oui requires exactly three unicast bytes')
|
||||
identity_files = [checked_path(prefix, 'private/etc/darling-smbios.conf'), destination(prefix)]
|
||||
if args.replace_known_defaults and not any(path.exists() for path in identity_files):
|
||||
print('No saved platform identity; nothing to replace.')
|
||||
return 0
|
||||
with prefix_lock(prefix) if args.write else nullcontext():
|
||||
path = destination(prefix)
|
||||
properties = {}
|
||||
if args.replace_known_defaults and not any(
|
||||
path.exists() and has_known_defaults(load(path)) for path in identity_files):
|
||||
print('Platform identity has no shared defaults; nothing changed.')
|
||||
return 0
|
||||
if args.provision:
|
||||
legacy = checked_path(prefix, 'private/etc/darling-smbios.conf')
|
||||
legacy = identity_files[0]
|
||||
if legacy.exists():
|
||||
properties.update(load(legacy))
|
||||
if path.exists():
|
||||
|
||||
Reference in new issue
Block a user