Files
StarPilot/openpilot/starpilot/bluetooth/radio_preference.py
T
firestar5683 a82935f326 User interfaces and Android Auto
Integrate onroad views, configurable widgets, local settings, steering-profile contracts, Bluetooth and Android Auto with their device and runtime services.

Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>
Co-authored-by: Daniel Koepping <elkoled@gmail.com>
Co-authored-by: Danny <dannyirwin31@yahoo.com>
Co-authored-by: DimitriChrysafis <Dimitri.chrysafis@gmail.com>
Co-authored-by: Dom <168790843+firestar5683@users.noreply.github.com>
Co-authored-by: Harald Schäfer <harald.the.engineer@gmail.com>
Co-authored-by: Prabhaav Pillai <prabhaav@msu.edu>
Co-authored-by: Shane Smiskol <shane@smiskol.com>
Co-authored-by: dirwin31 <83434411+dirwin31@users.noreply.github.com>
Co-authored-by: firestarsdog <229254897+firestarsdog@users.noreply.github.com>
Co-authored-by: stef <19478336+stefpi@users.noreply.github.com>
Co-authored-by: whoisdomi <dcantu83@gmail.com>

Co-authored-by: Intelli <contact@intelli.software>
Co-authored-by: pharmacomaniac <blittle65@gmail.com>

Co-authored-by: prabhaavp <prabhaav@msu.edu>
2026-10-14 20:02:39 -05:00

106 lines
3.5 KiB
Python

"""The registered AGNOS radio preference in the global Params namespace.
The service uses /data/params/d independently of named application prefixes.
The key has no manager default: absence must not create or disable the radio."""
from __future__ import annotations
import os
from pathlib import Path
import stat
import tempfile
RADIO_PREFERENCE = Path('/data/params/d/BluetoothEnabled')
class RadioPreference:
def __init__(self, path: Path = RADIO_PREFERENCE):
self.path = path
@staticmethod
def _read(path: Path) -> tuple[bytes | None, tuple | None]:
try:
fd = os.open(path, os.O_RDONLY | os.O_NOFOLLOW | os.O_NONBLOCK)
except FileNotFoundError:
return None, None
with os.fdopen(fd, 'rb') as stream:
info = os.fstat(stream.fileno())
if not stat.S_ISREG(info.st_mode) or info.st_size > 16:
raise OSError('Invalid Bluetooth enable file')
value = stream.read(17)
if len(value) > 16:
raise OSError('Invalid Bluetooth enable file')
return value, (info.st_dev, info.st_ino, info.st_mtime_ns, info.st_size)
def enabled(self) -> bool:
value, _ = self._read(self.path)
return value is not None and value.rstrip(b'\n') == b'1'
def begin(self, enabled: bool) -> RadioPreferenceChange:
return RadioPreferenceChange(self.path, b'1' if enabled else b'0')
class RadioPreferenceChange:
def __init__(self, path: Path, value: bytes):
self.path = path
self.directory = path.parent.resolve(strict=True)
info = self.directory.stat()
self.directory_identity = (info.st_dev, info.st_ino)
self.target = self.directory / path.name
self.previous, self.previous_identity = RadioPreference._read(self.target)
self.value = value
self.owned_identity = None
def apply(self) -> None:
self._write(self.value, self.previous, self.previous_identity)
self.verify()
def current(self, value: bytes | None, identity: tuple | None) -> bool:
try:
directory = self.path.parent.resolve(strict=True)
info = directory.stat()
return (directory == self.directory and (info.st_dev, info.st_ino) == self.directory_identity and
RadioPreference._read(self.target) == (value, identity))
except OSError:
return False
def _write(self, value: bytes, expected: bytes | None, identity: tuple | None) -> None:
fd, temporary = tempfile.mkstemp(prefix='.bluetooth-enable-', dir=self.directory)
try:
with os.fdopen(fd, 'wb') as stream:
stream.write(value)
stream.flush()
os.fsync(stream.fileno())
info = os.fstat(stream.fileno())
written_identity = (info.st_dev, info.st_ino, info.st_mtime_ns, info.st_size)
if not self.current(expected, identity):
raise OSError('Bluetooth preference changed')
os.replace(temporary, self.target)
self.owned_identity = written_identity
self._sync()
finally:
if os.path.exists(temporary):
os.unlink(temporary)
def _sync(self) -> None:
fd = os.open(self.directory, os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW)
try:
os.fsync(fd)
finally:
os.close(fd)
def verify(self) -> None:
if not self.current(self.value, self.owned_identity):
raise OSError('Bluetooth preference changed')
def rollback(self) -> bool:
if not self.current(self.value, self.owned_identity):
return False
if self.previous is None:
self.target.unlink()
self._sync()
else:
self._write(self.previous, self.value, self.owned_identity)
return True