mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-23 20:29:06 -05:00
feat: name Android BIOS folders out of reach
DraStic keeps its BIOS in its private data and Flycast in Android/data, which Termux cannot write on Android 11 and later. An installed one is now named with the files not copied, and a writable Flycast folder is a standalone copy target.
This commit is contained in:
1 parent
05d8f944a9
commit
43bb0c9b29
6 files changed
+113
-3
No files matched your search
+1
-1
@@ -11,7 +11,7 @@
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$defaultInstallUrl = "https://raw.githubusercontent.com/Abdess/retrobios/main/install.py"
|
||||
$defaultInstallSha256 = "956eba5f9d01138abda5550973810ccdc1138daa54c9065bf3f04cc0ba051468"
|
||||
$defaultInstallSha256 = "6ae8bdd7bbe9a0c3e6cb2d92947bb4e135e38d6446d206ae30b988a045eaa536"
|
||||
$maximumInstallerBytes = 2MB
|
||||
$installerExit = 0
|
||||
$installer = if ($PSScriptRoot) { Join-Path $PSScriptRoot "install.py" } else { $null }
|
||||
|
||||
+42
@@ -1199,6 +1199,46 @@ def _detect_android() -> list[tuple[str, Path]]:
|
||||
return found
|
||||
|
||||
|
||||
# Android emulators that keep their BIOS outside RetroArch's folder:
|
||||
# (name, package, folder, files read there). DraStic keeps it in its private
|
||||
# data (GammaOS Next 14 bb28e71d, gammaos/setup.sh:345-363 extracts it to
|
||||
# /data/data/com.dsemu.drastic/files/DraStic/system), which no other app
|
||||
# writes without root. Flycast reads <home>/data/ (flycast a9bd1c74,
|
||||
# shell/android-studio/flycast/src/main/jni/src/Android.cpp:143-159), its
|
||||
# home being Android/data/com.flycast.emulator/files, which Android 11 and
|
||||
# later keep from other apps.
|
||||
ANDROID_APP_DATA = Path("/data/data")
|
||||
_ANDROID_APP_FOLDERS = (
|
||||
("DraStic", "com.dsemu.drastic", "/data/data/com.dsemu.drastic/files/DraStic/system",
|
||||
("nds_bios_arm7.bin", "nds_bios_arm9.bin", "nds_firmware.bin")),
|
||||
("Flycast", "com.flycast.emulator",
|
||||
"$STORAGE/Android/data/com.flycast.emulator/files/data",
|
||||
("dc_boot.bin", "dc_nvmem.bin")),
|
||||
)
|
||||
|
||||
|
||||
def android_unreachable_folders() -> list[str]:
|
||||
"""A line for each Android emulator installed here whose BIOS folder
|
||||
this shell cannot write, said instead of skipping it in silence.
|
||||
|
||||
An app's private folder can be tested for existence by any app, so the
|
||||
emulator is known to be installed even where its folder is out of reach.
|
||||
"""
|
||||
lines = []
|
||||
storage = str(_android_storage_root())
|
||||
for name, package, folder, files in _ANDROID_APP_FOLDERS:
|
||||
target = Path(folder.replace("$STORAGE", storage, 1))
|
||||
if folder.startswith("/data/data/"):
|
||||
target = ANDROID_APP_DATA / Path(folder).relative_to("/data/data")
|
||||
if not (ANDROID_APP_DATA / package).exists() and not target.exists():
|
||||
continue
|
||||
if target.is_dir() and os.access(target, os.W_OK):
|
||||
continue
|
||||
lines.append(f"{name} is installed, but this shell cannot write its BIOS folder "
|
||||
f"{target} without root: {', '.join(files)} are not copied there.")
|
||||
return lines
|
||||
|
||||
|
||||
def _lnk_target(lnk_path: Path, exe_name: str) -> Path | None:
|
||||
"""Read the target path of a Windows shortcut.
|
||||
|
||||
@@ -1539,6 +1579,8 @@ def detect_platforms(os_type: str) -> list[tuple[str, Path]]:
|
||||
|
||||
if os_type == "android":
|
||||
found.extend(_detect_android())
|
||||
for line in android_unreachable_folders():
|
||||
print(line, file=sys.stderr)
|
||||
|
||||
if os_type in ("linux", "wsl"):
|
||||
found.extend(_detect_embedded())
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ esac
|
||||
TEMP_INSTALLER=""
|
||||
TEMP_DIRECTORY=""
|
||||
DEFAULT_INSTALL_URL="https://raw.githubusercontent.com/Abdess/retrobios/main/install.py"
|
||||
DEFAULT_INSTALL_SHA256="956eba5f9d01138abda5550973810ccdc1138daa54c9065bf3f04cc0ba051468"
|
||||
DEFAULT_INSTALL_SHA256="6ae8bdd7bbe9a0c3e6cb2d92947bb4e135e38d6446d206ae30b988a045eaa536"
|
||||
MAX_INSTALLER_BYTES=2097152
|
||||
|
||||
cleanup() {
|
||||
|
||||
@@ -158,6 +158,10 @@ _standalone_copies: &standalone_copies
|
||||
# shell/apple/emulator-osx/emulator-osx/osx-main.mm:83-101 (flycast 6bb0fc3e).
|
||||
darwin:
|
||||
- $HOME/Library/Application Support/Flycast/data
|
||||
# <home>/data/ (shell/android-studio/flycast/src/main/jni/src/Android.cpp:
|
||||
# 143-159, flycast a9bd1c74), writable from Termux up to Android 10.
|
||||
android:
|
||||
- $EXTERNAL_STORAGE/Android/data/com.flycast.emulator/files/data
|
||||
- file: dc/dc_nvmem.bin
|
||||
targets:
|
||||
linux:
|
||||
@@ -168,6 +172,10 @@ _standalone_copies: &standalone_copies
|
||||
# shell/apple/emulator-osx/emulator-osx/osx-main.mm:83-101 (flycast 6bb0fc3e).
|
||||
darwin:
|
||||
- $HOME/Library/Application Support/Flycast/data
|
||||
# <home>/data/ (shell/android-studio/flycast/src/main/jni/src/Android.cpp:
|
||||
# 143-159, flycast a9bd1c74), writable from Termux up to Android 10.
|
||||
android:
|
||||
- $EXTERNAL_STORAGE/Android/data/com.flycast.emulator/files/data
|
||||
|
||||
platforms:
|
||||
retroarch:
|
||||
|
||||
@@ -2724,6 +2724,57 @@ class AndroidCitationsNameTheRelease(unittest.TestCase):
|
||||
self.assertNotIn("2836-2851", text)
|
||||
|
||||
|
||||
class AndroidEmulatorsOutOfReachAreSaid(unittest.TestCase):
|
||||
"""DraStic keeps its BIOS in its private data and Flycast in
|
||||
Android/data, which Termux cannot write on Android 11 and later: both
|
||||
were skipped without a word."""
|
||||
|
||||
def _lines(self, make) -> list[str]:
|
||||
root = Path(_tempdir(self))
|
||||
app_data, storage = root / "data", root / "storage"
|
||||
app_data.mkdir()
|
||||
make(app_data, storage)
|
||||
with unittest.mock.patch.object(install, "ANDROID_APP_DATA", app_data), \
|
||||
unittest.mock.patch.dict(os.environ, {"EXTERNAL_STORAGE": str(storage)}):
|
||||
return install.android_unreachable_folders()
|
||||
|
||||
def test_nothing_installed_says_nothing(self):
|
||||
self.assertEqual(self._lines(lambda data, storage: None), [])
|
||||
|
||||
def test_an_installed_drastic_is_named(self):
|
||||
lines = self._lines(lambda data, storage: (data / "com.dsemu.drastic").mkdir())
|
||||
self.assertEqual(len(lines), 1)
|
||||
self.assertIn("DraStic is installed", lines[0])
|
||||
self.assertIn("nds_bios_arm7.bin", lines[0])
|
||||
|
||||
def test_flycast_out_of_reach_is_named(self):
|
||||
lines = self._lines(lambda data, storage: (data / "com.flycast.emulator").mkdir())
|
||||
self.assertEqual(len(lines), 1)
|
||||
self.assertIn("Flycast is installed", lines[0])
|
||||
self.assertIn("dc_boot.bin", lines[0])
|
||||
|
||||
def test_a_writable_flycast_folder_is_a_copy_target(self):
|
||||
def make(data, storage):
|
||||
(data / "com.flycast.emulator").mkdir()
|
||||
(storage / "Android/data/com.flycast.emulator/files/data").mkdir(parents=True)
|
||||
self.assertEqual(self._lines(make), [])
|
||||
import yaml # noqa: PLC0415
|
||||
|
||||
registry = yaml.safe_load((REPO_ROOT / "platforms" / "_registry.yml").read_text())
|
||||
copies = {entry.get("file"): entry for entry in registry["_standalone_copies"]}
|
||||
self.assertEqual(copies["dc/dc_boot.bin"]["targets"]["android"],
|
||||
["$EXTERNAL_STORAGE/Android/data/com.flycast.emulator/files/data"])
|
||||
|
||||
def test_detection_prints_them(self):
|
||||
err = io.StringIO()
|
||||
with unittest.mock.patch.object(install, "_detect_android", return_value=[]), \
|
||||
unittest.mock.patch.object(install, "android_unreachable_folders",
|
||||
return_value=["DraStic is installed, but"]), \
|
||||
contextlib.redirect_stderr(err):
|
||||
install.detect_platforms("android")
|
||||
self.assertIn("DraStic is installed", err.getvalue())
|
||||
|
||||
|
||||
class TheBoardTheSystemNamesIsTheTarget(unittest.TestCase):
|
||||
"""Batocera, Recalbox and ROCKNIX each write the board they were built
|
||||
for, but the installer read none of them, so a Batocera RPi4 installed
|
||||
|
||||
+10
-1
@@ -504,7 +504,16 @@ left at `default` resolves against `<shared storage>/RetroArch`, where the
|
||||
directory also sits when no config has been written yet
|
||||
(`platform_unix.c:1670-1697`).
|
||||
|
||||
Under scoped storage those two config paths are unreadable from Termux on
|
||||
Two Android emulators keep their BIOS elsewhere. DraStic reads
|
||||
`/data/data/com.dsemu.drastic/files/DraStic/system`, private to the app, and
|
||||
Flycast reads `Android/data/com.flycast.emulator/files/data` in shared
|
||||
storage, which Android 11 and later keep from other apps. No app can write
|
||||
the first without root, and Termux cannot write the second on Android 11 and
|
||||
later. When either emulator is installed and its folder is out of reach, the
|
||||
run names it and the files that are not copied. Where the Flycast folder is
|
||||
writable (Android 10 and earlier), it is a standalone copy target.
|
||||
|
||||
Under scoped storage the two RetroArch config paths are unreadable from Termux on
|
||||
Android 11 and later, so on current devices the shared directory is what
|
||||
answers. Running `termux-setup-storage` once is what makes it reachable:
|
||||
|
||||
|
||||
Reference in new issue
Block a user