feat: the session report lists the panel refresh modes, thermal state and hint-session support (#990)

This commit is contained in:
Resul Övür authored and GitHub committed 2026-10-17 02:31:17 +00:00
1 parent 9c9486400b
commit 522e755b37
2 files changed
+76

No files matched your search

@@ -2,10 +2,15 @@ package com.droiddeck.launcher.core
import android.app.ActivityManager import android.app.ActivityManager
import android.content.Context import android.content.Context
import android.hardware.display.DisplayManager
import android.os.Build import android.os.Build
import android.os.Environment import android.os.Environment
import android.os.PerformanceHintManager
import android.os.PowerManager
import android.os.StatFs import android.os.StatFs
import android.provider.Settings
import android.util.Log import android.util.Log
import android.view.Display
import com.droiddeck.launcher.gpu.LinuxVulkanDriver import com.droiddeck.launcher.gpu.LinuxVulkanDriver
import com.droiddeck.launcher.gpu.LinuxVulkanDriverManager import com.droiddeck.launcher.gpu.LinuxVulkanDriverManager
import com.droiddeck.launcher.gpu.TurnipDriver import com.droiddeck.launcher.gpu.TurnipDriver
@@ -54,6 +59,29 @@ object DeviceReport {
else -> "REASON_$reason" else -> "REASON_$reason"
} }
internal fun thermalStatusName(status: Int): String = when (status) {
0 -> "NONE"
1 -> "LIGHT"
2 -> "MODERATE"
3 -> "SEVERE"
4 -> "CRITICAL"
5 -> "EMERGENCY"
6 -> "SHUTDOWN"
else -> "STATUS_$status"
}
internal fun gameModeName(mode: Int): String = when (mode) {
0 -> "UNSUPPORTED"
1 -> "STANDARD"
2 -> "PERFORMANCE"
3 -> "BATTERY"
4 -> "CUSTOM"
else -> "MODE_$mode"
}
internal fun refreshModesSummary(rates: List<Float>): String =
rates.map { Math.round(it) }.distinct().sortedDescending().joinToString(", ") { "$it Hz" }
internal fun exitSummary(processName: String?, reason: Int, status: Int, description: String?): String = internal fun exitSummary(processName: String?, reason: Int, status: Int, description: String?): String =
buildString { buildString {
append(processName ?: "?").append(" ").append(exitReasonName(reason)).append(" status=").append(status) append(processName ?: "?").append(" ").append(exitReasonName(reason)).append(" status=").append(status)
@@ -124,6 +152,19 @@ object DeviceReport {
k("RAM total", FileUtils.sizeToString(mi.totalMem)) k("RAM total", FileUtils.sizeToString(mi.totalMem))
k("RAM available", FileUtils.sizeToString(mi.availMem)) k("RAM available", FileUtils.sizeToString(mi.availMem))
} }
runCatching {
val pm = context.getSystemService(Context.POWER_SERVICE) as PowerManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) k("Thermal status", thermalStatusName(pm.currentThermalStatus))
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
k("Thermal headroom (10 s)", pm.getThermalHeadroom(10).let { if (it.isNaN()) "not reported" else String.format(Locale.US, "%.2f", it) })
}
k("Power saver", pm.isPowerSaveMode)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val rate = runCatching { context.getSystemService(PerformanceHintManager::class.java)?.preferredUpdateRateNanos }.getOrNull()
k("ADPF hint sessions", if (rate == null || rate <= 0) "not supported" else "supported (preferred update ${rate / 1000} us)")
k("Game Mode", runCatching { context.getSystemService(android.app.GameManager::class.java)?.gameMode }.getOrNull()?.let { gameModeName(it) })
}
runCatching { runCatching {
val fs = StatFs(context.filesDir.path) val fs = StatFs(context.filesDir.path)
k("App storage free", FileUtils.sizeToString(fs.availableBlocksLong * fs.blockSizeLong)) k("App storage free", FileUtils.sizeToString(fs.availableBlocksLong * fs.blockSizeLong))
@@ -141,6 +182,13 @@ object DeviceReport {
h("Display") h("Display")
k("Session output", SessionState.outputSize?.let { "${it.first}x${it.second}" }) k("Session output", SessionState.outputSize?.let { "${it.first}x${it.second}" })
k("Session refresh", String.format(Locale.US, "%.2f Hz", SessionState.refreshHz)) k("Session refresh", String.format(Locale.US, "%.2f Hz", SessionState.refreshHz))
runCatching {
val display = context.getSystemService(DisplayManager::class.java).getDisplay(Display.DEFAULT_DISPLAY)
k("Panel refresh now", String.format(Locale.US, "%.2f Hz", display.refreshRate))
k("Panel refresh modes", refreshModesSummary(display.supportedModes.map { it.refreshRate }))
}
k("peak_refresh_rate", runCatching { Settings.System.getString(context.contentResolver, "peak_refresh_rate") }.getOrNull() ?: "not set")
k("refresh_rate_mode", runCatching { Settings.Secure.getString(context.contentResolver, "refresh_rate_mode") }.getOrNull() ?: "not set")
val panelSize = com.droiddeck.launcher.session.SessionDisplay.panelSize(context) val panelSize = com.droiddeck.launcher.session.SessionDisplay.panelSize(context)
for ((label, mode) in listOf("Resolution (Steam)" to SessionService.MODE_STEAM, "Resolution (Desktop)" to SessionService.MODE_DESKTOP)) { for ((label, mode) in listOf("Resolution (Steam)" to SessionService.MODE_STEAM, "Resolution (Desktop)" to SessionService.MODE_DESKTOP)) {
val choice = SessionPrefs.resolutionChoice(context, mode, panelSize) val choice = SessionPrefs.resolutionChoice(context, mode, panelSize)
@@ -0,0 +1,28 @@
package com.droiddeck.launcher.core
import org.junit.Assert.assertEquals
import org.junit.Test
class DeviceReportPerfTest {
@Test fun thermalStatusesHaveTheirPlatformNames() {
assertEquals("NONE", DeviceReport.thermalStatusName(0))
assertEquals("MODERATE", DeviceReport.thermalStatusName(2))
assertEquals("CRITICAL", DeviceReport.thermalStatusName(4))
assertEquals("SHUTDOWN", DeviceReport.thermalStatusName(6))
assertEquals("STATUS_9", DeviceReport.thermalStatusName(9))
}
@Test fun gameModesHaveTheirPlatformNames() {
assertEquals("UNSUPPORTED", DeviceReport.gameModeName(0))
assertEquals("STANDARD", DeviceReport.gameModeName(1))
assertEquals("PERFORMANCE", DeviceReport.gameModeName(2))
assertEquals("BATTERY", DeviceReport.gameModeName(3))
assertEquals("MODE_7", DeviceReport.gameModeName(7))
}
@Test fun refreshModesAreRoundedDeduplicatedAndListedFastestFirst() {
assertEquals("120 Hz, 60 Hz", DeviceReport.refreshModesSummary(listOf(60.0f, 120.00001f, 60.00001f)))
assertEquals("60 Hz", DeviceReport.refreshModesSummary(listOf(59.94f)))
assertEquals("", DeviceReport.refreshModesSummary(emptyList()))
}
}