mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-11 02:51:10 +00: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 {
|
jniLibs {
|
||||||
useLegacyPackaging = true
|
useLegacyPackaging = true
|
||||||
pickFirsts += ['**/libtermux.so']
|
pickFirsts += ['**/libtermux.so']
|
||||||
// Shipped in the proot and tracking packs (tools/packs) and run or loaded from there.
|
excludes += ['**/libopencv_java4.so', '**/libmediapipe_tasks_jni.so']
|
||||||
excludes += ['**/libproot.so', '**/libproot-loader.so', '**/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(
|
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,
|
supported = gpu.support == GpuInfo.Support.TESTED, unsupported = gpu.support == GpuInfo.Support.UNSUPPORTED,
|
||||||
auto = mode == SessionPrefs.GPU_DRIVERS_AUTO, pairs = pairRows, busy = pairBusy, percent = pairPercent,
|
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,
|
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
|
return
|
||||||
}
|
}
|
||||||
if (DriverPairs.recommendedKey(gpu, emptyList()) == null) {
|
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
|
return
|
||||||
}
|
}
|
||||||
releaseChecking = true
|
releaseChecking = true
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ object DeviceReport {
|
|||||||
|
|
||||||
h("Drivers")
|
h("Drivers")
|
||||||
val gpu = com.droiddeck.launcher.gpu.GpuInfo.detect()
|
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) {
|
if (gpu.model == 740) {
|
||||||
val hint = com.droiddeck.launcher.gpu.TpUbwcHint
|
val hint = com.droiddeck.launcher.gpu.TpUbwcHint
|
||||||
k("TP UBWC hint", hint.forThisDevice(context) ?: "driver default")
|
k("TP UBWC hint", hint.forThisDevice(context) ?: "driver default")
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ object DeviceInfo {
|
|||||||
val vk = VulkanInfo.query()
|
val vk = VulkanInfo.query()
|
||||||
val gpu = GpuInfo.detect()
|
val gpu = GpuInfo.detect()
|
||||||
return listOf(
|
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() }
|
).filter { it.rows.isNotEmpty() }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ object DeviceInfo {
|
|||||||
add("Family", read("/sys/devices/soc0/family"))
|
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("GPU", gpu.name)
|
||||||
add("Family", gpu.family.label)
|
add("Family", gpu.family.label)
|
||||||
add("Model found from", when (gpu.modelSource) {
|
add("Model found from", when (gpu.modelSource) {
|
||||||
@@ -66,7 +66,7 @@ object DeviceInfo {
|
|||||||
add("Clock range", gpuRange())
|
add("Clock range", gpuRange())
|
||||||
add("Load", read("$kgsl/gpu_busy_percentage")?.let { if (it.endsWith("%")) it else "$it %" })
|
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("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>> {
|
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"
|
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) {
|
fun supportText(context: Context): String = context.getString(when (support) {
|
||||||
Support.TESTED -> R.string.gpuinfo_supported
|
Support.TESTED -> R.string.gpuinfo_supported
|
||||||
Support.UNTESTED -> when {
|
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?) {
|
private fun writeResolver(properties: LinkProperties?) {
|
||||||
val own = properties?.dnsServers.orEmpty()
|
val own = properties?.dnsServers.orEmpty()
|
||||||
.filter { !it.isLinkLocalAddress && !it.isLoopbackAddress && !it.isAnyLocalAddress }
|
.filter { !it.isLinkLocalAddress && !it.isLoopbackAddress && !it.isAnyLocalAddress }
|
||||||
.sortedBy { if (it is Inet4Address) 0 else 1 }
|
.sortedBy { if (it is Inet4Address) 0 else 1 }
|
||||||
.mapNotNull { it.hostAddress?.substringBefore('%') }
|
.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 {
|
val text = buildString {
|
||||||
append("# Written by the app from the device's active network; edits are overwritten.\n")
|
append("# Written by the app from the device's active network; edits are overwritten.\n")
|
||||||
for (server in servers) append("nameserver $server\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";
|
private static final String HOST_DIR = "opt/android-host";
|
||||||
/** The downloaded add-on pack. The APK does not ship this binary. */
|
/** 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_PACK = "add-on pack";
|
||||||
|
public static final String PROOT_PACKAGED = "packaged";
|
||||||
/** Termux's unpatched proot inside the rootfs. Developer switch only. */
|
/** Termux's unpatched proot inside the rootfs. Developer switch only. */
|
||||||
public static final String PROOT_ROOTFS = "rootfs fallback";
|
public static final String PROOT_ROOTFS = "rootfs fallback";
|
||||||
public static final String PROOT_MISSING = "missing";
|
public static final String PROOT_MISSING = "missing";
|
||||||
@@ -81,18 +82,32 @@ public final class LinuxRuntime {
|
|||||||
return rootfsProot(context).isFile() && rootfsLoader(context).isFile();
|
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. */
|
/** Patched proot is the add-on pack. The rootfs copy is not that binary. */
|
||||||
public static boolean patchedProot(Context context) {
|
public static boolean patchedProot(Context context) {
|
||||||
return AddonPack.PROOT.installed(context);
|
return AddonPack.PROOT.installed(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static File prootBinary(Context 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 (AddonPack.PROOT.installed(context)) return AddonPack.PROOT.file(context, "libproot.so");
|
||||||
if (SessionPrefs.allowStockProot(context)) return rootfsProot(context);
|
if (SessionPrefs.allowStockProot(context)) return rootfsProot(context);
|
||||||
return AddonPack.PROOT.file(context, "libproot.so");
|
return AddonPack.PROOT.file(context, "libproot.so");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static File prootLoader(Context context) {
|
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 (AddonPack.PROOT.installed(context)) return AddonPack.PROOT.file(context, "libproot-loader.so");
|
||||||
if (SessionPrefs.allowStockProot(context)) return rootfsLoader(context);
|
if (SessionPrefs.allowStockProot(context)) return rootfsLoader(context);
|
||||||
return AddonPack.PROOT.file(context, "libproot-loader.so");
|
return AddonPack.PROOT.file(context, "libproot-loader.so");
|
||||||
@@ -102,6 +117,8 @@ public final class LinuxRuntime {
|
|||||||
public static String prootSource(Context context) {
|
public static String prootSource(Context context) {
|
||||||
File bin = prootBinary(context);
|
File bin = prootBinary(context);
|
||||||
if (!bin.isFile()) return PROOT_MISSING;
|
if (!bin.isFile()) return PROOT_MISSING;
|
||||||
|
if (packagedProotReady(context)
|
||||||
|
&& bin.getPath().equals(packagedProot(context).getPath())) return PROOT_PACKAGED;
|
||||||
if (AddonPack.PROOT.installed(context)
|
if (AddonPack.PROOT.installed(context)
|
||||||
&& bin.getPath().equals(AddonPack.PROOT.file(context, "libproot.so").getPath())) return PROOT_PACK;
|
&& bin.getPath().equals(AddonPack.PROOT.file(context, "libproot.so").getPath())) return PROOT_PACK;
|
||||||
return PROOT_ROOTFS;
|
return PROOT_ROOTFS;
|
||||||
@@ -113,7 +130,7 @@ public final class LinuxRuntime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isInstalled(Context context) {
|
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. */
|
/** 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;
|
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) {
|
public static String gpuStandIn(Context context) {
|
||||||
if (new File(KGSL_DEVICE).exists()) return KGSL_DEVICE;
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2032,6 +2032,8 @@
|
|||||||
<string name="gpuinfo_a850_experimental">Adreno 850 实验支持:需要配套的实验版显示驱动和游戏驱动;尚未在此设备上验证</string>
|
<string name="gpuinfo_a850_experimental">Adreno 850 实验支持:需要配套的实验版显示驱动和游戏驱动;尚未在此设备上验证</string>
|
||||||
<string name="gpuinfo_below_tested">低于已测试的硬件(Adreno 725 及更新):可能无法运行</string>
|
<string name="gpuinfo_below_tested">低于已测试的硬件(Adreno 725 及更新):可能无法运行</string>
|
||||||
<string name="gpuinfo_unsupported">不受支持:DroidDeck 需要 Adreno(骁龙)GPU</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_rate_limited">已达到 GitHub 的请求频率限制 — 请稍后重试</string>
|
||||||
<string name="turnip_github_http">GitHub 返回 HTTP %1$d</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_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_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_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_rate_limited">GitHub\'s rate limit was hit - try again later</string>
|
||||||
<string name="turnip_github_http">GitHub answered HTTP %1$d</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
|
if [ "$(cat /usr/share/droiddeck/kwin-compositor 2>/dev/null)" = opengl ]; then
|
||||||
unset LIBGL_ALWAYS_SOFTWARE QT_QUICK_BACKEND
|
unset LIBGL_ALWAYS_SOFTWARE QT_QUICK_BACKEND
|
||||||
export KWIN_COMPOSE=O2 MESA_LOADER_DRIVER_OVERRIDE=zink GALLIUM_DRIVER=zink LIBGL_KOPPER_DRI2=true
|
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
|
if [ -z "${KWIN_RENDER_NODES:-}" ]; then
|
||||||
export KWIN_RENDER_NODES=/dev/dri/renderD0
|
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
|
fi
|
||||||
mkdir -p /run/droiddeck/kwin
|
mkdir -p /run/droiddeck/kwin
|
||||||
printf '#!/bin/sh\nGALLIUM_THREAD=0 exec /usr/bin/kwin_wayland "$@"\n' > /run/droiddeck/kwin/kwin_wayland
|
printf '#!/bin/sh\nGALLIUM_THREAD=0 exec /usr/bin/kwin_wayland "$@"\n' > /run/droiddeck/kwin/kwin_wayland
|
||||||
|
|||||||
Reference in new issue
Block a user