mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-07 10:46:06 -10:00
local: MaliBridge rc4, auto local DNS, KWin render node
This commit is contained in:
1 parent
69ffc0966b
commit
9419a19c66
11 files changed
+86
-14
No files matched your search
@@ -0,0 +1,4 @@
|
||||
# Copy to .signing.env, fill in, chmod 600 .signing.env
|
||||
RELEASE_KEYSTORE=/path/to/release.p12
|
||||
RELEASE_STORE_PASSWORD=change-me
|
||||
RELEASE_KEY_ALIAS=droiddeck
|
||||
+1
-2
@@ -219,8 +219,7 @@ android {
|
||||
jniLibs {
|
||||
useLegacyPackaging = true
|
||||
pickFirsts += ['**/libtermux.so']
|
||||
// Shipped in the proot and tracking packs (tools/packs) and run or loaded from there.
|
||||
excludes += ['**/libproot.so', '**/libproot-loader.so', '**/libopencv_java4.so', '**/libmediapipe_tasks_jni.so']
|
||||
excludes += ['**/libopencv_java4.so', '**/libmediapipe_tasks_jni.so']
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ internal class DriverMenus(private val activity: Activity, private val ui: Handl
|
||||
}
|
||||
|
||||
fun state() = GpuDriversState(
|
||||
gpuName = gpu.displayName(activity), gpuFamily = gpu.family.label(activity), soc = gpu.soc, supportText = gpu.supportText(activity),
|
||||
gpuName = gpu.displayName(activity), gpuFamily = gpu.family.label(activity), soc = gpu.soc, supportText = gpu.supportText(activity, com.droiddeck.launcher.core.DeviceSupport.vkBridge(activity)),
|
||||
supported = gpu.support == GpuInfo.Support.TESTED, unsupported = gpu.support == GpuInfo.Support.UNSUPPORTED,
|
||||
auto = mode == SessionPrefs.GPU_DRIVERS_AUTO, pairs = pairRows, busy = pairBusy, percent = pairPercent,
|
||||
autoStatus = autoStatus, releaseStatus = releaseStatus.ifEmpty { activity.getString(R.string.drivers_not_checked) }, checking = releaseChecking,
|
||||
@@ -264,7 +264,7 @@ internal class DriverMenus(private val activity: Activity, private val ui: Handl
|
||||
return
|
||||
}
|
||||
if (DriverPairs.recommendedKey(gpu, emptyList()) == null) {
|
||||
autoStatus = activity.getString(R.string.drivers_none_to_set, gpu.supportText(activity).lowercase())
|
||||
autoStatus = activity.getString(R.string.drivers_none_to_set, gpu.supportText(activity, com.droiddeck.launcher.core.DeviceSupport.vkBridge(activity)).lowercase())
|
||||
return
|
||||
}
|
||||
releaseChecking = true
|
||||
|
||||
@@ -209,7 +209,7 @@ object DeviceReport {
|
||||
|
||||
h("Drivers")
|
||||
val gpu = com.droiddeck.launcher.gpu.GpuInfo.detect()
|
||||
k("GPU", "${gpu.name} · ${gpu.family.label} · ${gpu.supportText}" + if (gpu.oneUi8Gen2) " · One UI 8 Gen 2" else "")
|
||||
k("GPU", "${gpu.name} · ${gpu.family.label} · ${gpu.supportText(SessionPrefs.vkBridge(context))}" + if (gpu.oneUi8Gen2) " · One UI 8 Gen 2" else "")
|
||||
if (gpu.model == 740) {
|
||||
val hint = com.droiddeck.launcher.gpu.TpUbwcHint
|
||||
k("TP UBWC hint", hint.forThisDevice(context) ?: "driver default")
|
||||
|
||||
@@ -16,7 +16,7 @@ object DeviceInfo {
|
||||
val vk = VulkanInfo.query()
|
||||
val gpu = GpuInfo.detect()
|
||||
return listOf(
|
||||
chip(), gpu(gpu), cpu(), memory(context), system(), vulkan(context, vk), drivers(context, gpu),
|
||||
chip(), gpu(context, gpu), cpu(), memory(context), system(), vulkan(context, vk), drivers(context, gpu),
|
||||
).filter { it.rows.isNotEmpty() }
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ object DeviceInfo {
|
||||
add("Family", read("/sys/devices/soc0/family"))
|
||||
})
|
||||
|
||||
private fun gpu(gpu: GpuInfo) = Section("GPU", buildList<Pair<String, String>> {
|
||||
private fun gpu(context: Context, gpu: GpuInfo) = Section("GPU", buildList<Pair<String, String>> {
|
||||
add("GPU", gpu.name)
|
||||
add("Family", gpu.family.label)
|
||||
add("Model found from", when (gpu.modelSource) {
|
||||
@@ -66,7 +66,7 @@ object DeviceInfo {
|
||||
add("Clock range", gpuRange())
|
||||
add("Load", read("$kgsl/gpu_busy_percentage")?.let { if (it.endsWith("%")) it else "$it %" })
|
||||
add("Temperature", read("$kgsl/temp")?.toLongOrNull()?.let { if (it > 1000) "${it / 1000} °C" else "$it °C" })
|
||||
add("Support", gpu.supportText)
|
||||
add("Support", gpu.supportText(SessionPrefs.vkBridge(context)))
|
||||
})
|
||||
|
||||
private fun cpu() = Section("CPU", buildList<Pair<String, String>> {
|
||||
|
||||
@@ -53,6 +53,18 @@ data class GpuInfo(
|
||||
Support.UNSUPPORTED -> "Not supported: DroidDeck needs an Adreno (Snapdragon) GPU"
|
||||
}
|
||||
|
||||
fun supportText(bridge: Boolean): String = when {
|
||||
support != Support.UNSUPPORTED -> supportText
|
||||
bridge -> "Runs through the Mali bridge, on the phone's own Vulkan driver"
|
||||
else -> "Not supported with the Mali bridge off: Turnip needs an Adreno (Snapdragon) GPU"
|
||||
}
|
||||
|
||||
fun supportText(context: Context, bridge: Boolean): String = when {
|
||||
support != Support.UNSUPPORTED -> supportText(context)
|
||||
bridge -> context.getString(R.string.gpuinfo_bridge)
|
||||
else -> context.getString(R.string.gpuinfo_bridge_off)
|
||||
}
|
||||
|
||||
fun supportText(context: Context): String = context.getString(when (support) {
|
||||
Support.TESTED -> R.string.gpuinfo_supported
|
||||
Support.UNTESTED -> when {
|
||||
|
||||
@@ -251,12 +251,36 @@ class LinuxNetworkLinkComponent(
|
||||
}
|
||||
}
|
||||
|
||||
private fun localDnsServers(): List<String> {
|
||||
val servers = LinkedHashSet<String>()
|
||||
for (network in connectivity.allNetworks) {
|
||||
val capabilities = connectivity.getNetworkCapabilities(network) ?: continue
|
||||
if (!capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) continue
|
||||
if (!capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) &&
|
||||
!capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) continue
|
||||
val link = connectivity.getLinkProperties(network) ?: continue
|
||||
for (address in link.dnsServers) {
|
||||
if (address.isLinkLocalAddress || address.isLoopbackAddress || address.isAnyLocalAddress) continue
|
||||
address.hostAddress?.substringBefore('%')?.let { servers.add(it) }
|
||||
}
|
||||
link.routes.firstOrNull { it.isDefaultRoute }?.gateway?.let { gateway ->
|
||||
if (gateway is Inet4Address && !gateway.isLoopbackAddress && !gateway.isAnyLocalAddress) {
|
||||
gateway.hostAddress?.substringBefore('%')?.let { servers.add(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
return servers.sortedWith(compareBy<String>(
|
||||
{ if (it.startsWith("192.168.") || it.startsWith("10.")) 0 else 1 },
|
||||
{ if (it.contains(':')) 1 else 0 },
|
||||
)).take(6)
|
||||
}
|
||||
|
||||
private fun writeResolver(properties: LinkProperties?) {
|
||||
val own = properties?.dnsServers.orEmpty()
|
||||
.filter { !it.isLinkLocalAddress && !it.isLoopbackAddress && !it.isAnyLocalAddress }
|
||||
.sortedBy { if (it is Inet4Address) 0 else 1 }
|
||||
.mapNotNull { it.hostAddress?.substringBefore('%') }
|
||||
val servers = (own + listOf("8.8.8.8", "1.1.1.1", "2001:4860:4860::8888")).distinct().take(6)
|
||||
val servers = (localDnsServers() + own + listOf("8.8.8.8", "1.1.1.1", "2001:4860:4860::8888")).distinct().take(6)
|
||||
val text = buildString {
|
||||
append("# Written by the app from the device's active network; edits are overwritten.\n")
|
||||
for (server in servers) append("nameserver $server\n")
|
||||
|
||||
@@ -65,6 +65,7 @@ public final class LinuxRuntime {
|
||||
private static final String HOST_DIR = "opt/android-host";
|
||||
/** The downloaded add-on pack. The APK does not ship this binary. */
|
||||
public static final String PROOT_PACK = "add-on pack";
|
||||
public static final String PROOT_PACKAGED = "packaged";
|
||||
/** Termux's unpatched proot inside the rootfs. Developer switch only. */
|
||||
public static final String PROOT_ROOTFS = "rootfs fallback";
|
||||
public static final String PROOT_MISSING = "missing";
|
||||
@@ -81,18 +82,32 @@ public final class LinuxRuntime {
|
||||
return rootfsProot(context).isFile() && rootfsLoader(context).isFile();
|
||||
}
|
||||
|
||||
private static File packagedProot(Context context) {
|
||||
return new File(context.getApplicationInfo().nativeLibraryDir, "libproot.so");
|
||||
}
|
||||
|
||||
private static File packagedLoader(Context context) {
|
||||
return new File(context.getApplicationInfo().nativeLibraryDir, "libproot-loader.so");
|
||||
}
|
||||
|
||||
private static boolean packagedProotReady(Context context) {
|
||||
return packagedProot(context).isFile() && packagedLoader(context).isFile();
|
||||
}
|
||||
|
||||
/** Patched proot is the add-on pack. The rootfs copy is not that binary. */
|
||||
public static boolean patchedProot(Context context) {
|
||||
return AddonPack.PROOT.installed(context);
|
||||
}
|
||||
|
||||
public static File prootBinary(Context context) {
|
||||
if (packagedProotReady(context)) return packagedProot(context);
|
||||
if (AddonPack.PROOT.installed(context)) return AddonPack.PROOT.file(context, "libproot.so");
|
||||
if (SessionPrefs.allowStockProot(context)) return rootfsProot(context);
|
||||
return AddonPack.PROOT.file(context, "libproot.so");
|
||||
}
|
||||
|
||||
public static File prootLoader(Context context) {
|
||||
if (packagedProotReady(context)) return packagedLoader(context);
|
||||
if (AddonPack.PROOT.installed(context)) return AddonPack.PROOT.file(context, "libproot-loader.so");
|
||||
if (SessionPrefs.allowStockProot(context)) return rootfsLoader(context);
|
||||
return AddonPack.PROOT.file(context, "libproot-loader.so");
|
||||
@@ -102,6 +117,8 @@ public final class LinuxRuntime {
|
||||
public static String prootSource(Context context) {
|
||||
File bin = prootBinary(context);
|
||||
if (!bin.isFile()) return PROOT_MISSING;
|
||||
if (packagedProotReady(context)
|
||||
&& bin.getPath().equals(packagedProot(context).getPath())) return PROOT_PACKAGED;
|
||||
if (AddonPack.PROOT.installed(context)
|
||||
&& bin.getPath().equals(AddonPack.PROOT.file(context, "libproot.so").getPath())) return PROOT_PACK;
|
||||
return PROOT_ROOTFS;
|
||||
@@ -113,7 +130,7 @@ public final class LinuxRuntime {
|
||||
}
|
||||
|
||||
public static boolean isInstalled(Context context) {
|
||||
return hasRootfs(context) && (patchedProot(context) || rootfsProotReady(context));
|
||||
return hasRootfs(context) && (packagedProotReady(context) || patchedProot(context) || rootfsProotReady(context));
|
||||
}
|
||||
|
||||
/** The rootfs alone: enough to read the game library, while the proot pack can still be downloading. */
|
||||
@@ -284,11 +301,21 @@ public final class LinuxRuntime {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static final String MALI_DEVICE = "/dev/mali0";
|
||||
static final String MALI_DEVICE = "/dev/mali0";
|
||||
|
||||
static final String[] DRM_RENDER_NODES = {
|
||||
"/dev/dri/renderD128", "/dev/dri/renderD129", "/dev/dri/renderD130", "/dev/dri/renderD131",
|
||||
};
|
||||
|
||||
public static String gpuStandIn(Context context) {
|
||||
if (new File(KGSL_DEVICE).exists()) return KGSL_DEVICE;
|
||||
if (com.droiddeck.launcher.core.DeviceSupport.INSTANCE.vkBridge(context) && new File(MALI_DEVICE).exists()) return MALI_DEVICE;
|
||||
if (!com.droiddeck.launcher.core.DeviceSupport.INSTANCE.vkBridge(context)) return null;
|
||||
return bridgeStandIn(path -> new File(path).exists());
|
||||
}
|
||||
|
||||
static String bridgeStandIn(java.util.function.Predicate<String> exists) {
|
||||
if (exists.test(MALI_DEVICE)) return MALI_DEVICE;
|
||||
for (String node : DRM_RENDER_NODES) if (exists.test(node)) return node;
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -2032,6 +2032,8 @@
|
||||
<string name="gpuinfo_a850_experimental">Adreno 850 实验支持:需要配套的实验版显示驱动和游戏驱动;尚未在此设备上验证</string>
|
||||
<string name="gpuinfo_below_tested">低于已测试的硬件(Adreno 725 及更新):可能无法运行</string>
|
||||
<string name="gpuinfo_unsupported">不受支持:DroidDeck 需要 Adreno(骁龙)GPU</string>
|
||||
<string name="gpuinfo_bridge">通过 Mali 桥接运行,使用手机自带的 Vulkan 驱动</string>
|
||||
<string name="gpuinfo_bridge_off">关闭 Mali 桥接时不受支持:Turnip 需要 Adreno(骁龙)GPU</string>
|
||||
|
||||
<string name="turnip_rate_limited">已达到 GitHub 的请求频率限制 — 请稍后重试</string>
|
||||
<string name="turnip_github_http">GitHub 返回 HTTP %1$d</string>
|
||||
|
||||
@@ -2111,6 +2111,8 @@
|
||||
<string name="gpuinfo_a850_experimental">Experimental Adreno 850 support: requires compatible experimental display and game drivers; not verified on this device</string>
|
||||
<string name="gpuinfo_below_tested">Below tested hardware (Adreno 725 and newer): it may not run</string>
|
||||
<string name="gpuinfo_unsupported">Not supported: DroidDeck needs an Adreno (Snapdragon) GPU</string>
|
||||
<string name="gpuinfo_bridge">Runs through the Mali bridge, on the phone\'s own Vulkan driver</string>
|
||||
<string name="gpuinfo_bridge_off">Not supported with the Mali bridge off: Turnip needs an Adreno (Snapdragon) GPU</string>
|
||||
|
||||
<string name="turnip_rate_limited">GitHub\'s rate limit was hit - try again later</string>
|
||||
<string name="turnip_github_http">GitHub answered HTTP %1$d</string>
|
||||
|
||||
@@ -107,8 +107,10 @@ fi
|
||||
if [ "$(cat /usr/share/droiddeck/kwin-compositor 2>/dev/null)" = opengl ]; then
|
||||
unset LIBGL_ALWAYS_SOFTWARE QT_QUICK_BACKEND
|
||||
export KWIN_COMPOSE=O2 MESA_LOADER_DRIVER_OVERRIDE=zink GALLIUM_DRIVER=zink LIBGL_KOPPER_DRI2=true
|
||||
if [ -z "${KWIN_RENDER_NODES:-}" ] && [ -c /dev/dri/renderD0 ]; then
|
||||
export KWIN_RENDER_NODES=/dev/dri/renderD0
|
||||
if [ -z "${KWIN_RENDER_NODES:-}" ]; then
|
||||
for node in /dev/dri/renderD0 /dev/dri/renderD307 /dev/dri/renderD*; do
|
||||
if [ -c "$node" ]; then export KWIN_RENDER_NODES="$node"; break; fi
|
||||
done
|
||||
fi
|
||||
mkdir -p /run/droiddeck/kwin
|
||||
printf '#!/bin/sh\nGALLIUM_THREAD=0 exec /usr/bin/kwin_wayland "$@"\n' > /run/droiddeck/kwin/kwin_wayland
|
||||
|
||||
Reference in new issue
Block a user