summaryrefslogtreecommitdiffstats
path: root/src/detection/displayserver/displayserver_android.c
diff options
context:
space:
mode:
authorsumuel <samuel@yakubos.org>2026-08-17 20:44:55 +0000
committersumuel <samuel@yakubos.org>2026-08-17 20:44:55 +0000
commit76424950e373d3b04ac3dd13019151bfba3e8423 (patch)
tree4c3cfdbda039e592b9186be3e28f8d7cfd439e8a /src/detection/displayserver/displayserver_android.c
Add the files
Diffstat (limited to 'src/detection/displayserver/displayserver_android.c')
-rw-r--r--src/detection/displayserver/displayserver_android.c209
1 files changed, 209 insertions, 0 deletions
diff --git a/src/detection/displayserver/displayserver_android.c b/src/detection/displayserver/displayserver_android.c
new file mode 100644
index 0000000..9b2848a
--- /dev/null
+++ b/src/detection/displayserver/displayserver_android.c
@@ -0,0 +1,209 @@
+#include "displayserver.h"
+#include "common/settings.h"
+#include "common/processing.h"
+#include "linux/displayserver_linux.h"
+
+#include <math.h>
+
+static bool checkHdrStatus(FFDisplayResult* display) {
+ FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
+
+ if (ffSettingsGetAndroidProperty("ro.surface_flinger.has_HDR_display", &buffer)) {
+ if (ffStrbufIgnCaseEqualS(&buffer, "true")) {
+ display->hdrStatus = FF_DISPLAY_HDR_STATUS_SUPPORTED;
+
+ if (ffSettingsGetAndroidProperty("persist.sys.hdr_mode", &buffer) &&
+ ffStrbufToUInt(&buffer, 0) > 0) {
+ display->hdrStatus = FF_DISPLAY_HDR_STATUS_ENABLED;
+ }
+
+ return true;
+ } else {
+ display->hdrStatus = FF_DISPLAY_HDR_STATUS_UNSUPPORTED;
+ return true;
+ }
+ }
+
+ display->hdrStatus = FF_DISPLAY_HDR_STATUS_UNKNOWN;
+ return false;
+}
+
+static void detectWithDumpsys(FFDisplayServerResult* ds) {
+ FF_STRBUF_AUTO_DESTROY buf = ffStrbufCreate();
+ if (ffProcessAppendStdOut(&buf, (char*[]) {
+ "/system/bin/dumpsys",
+ "display",
+ NULL,
+ }) != NULL ||
+ buf.length == 0) {
+ return; // Only works in `adb shell`, or when rooted
+ }
+
+ uint32_t index = 0;
+ while ((index = ffStrbufNextIndexS(&buf, index, "DisplayDeviceInfo")) < buf.length) {
+ index += strlen("DisplayDeviceInfo");
+ uint32_t nextIndex = ffStrbufNextIndexC(&buf, index, '\n');
+ buf.chars[nextIndex] = '\0';
+ const char* info = buf.chars + index;
+
+ // {"Builtin display": uniqueId="local:4630947134992368259", 1440 x 3200, modeId 2, defaultModeId 1, supportedModes [{id=1, width=1440, height=3200, fps=60.000004, alternativeRefreshRates=[24.000002, 30.000002, 40.0, 120.00001, 120.00001, 120.00001, 120.00001, 120.00001]},
+ FF_STRBUF_AUTO_DESTROY name = ffStrbufCreateA(64);
+ unsigned width = 0, height = 0, modeId = 0;
+ double refreshRate = 0;
+ // {"Builtin display": uniqueId="local:4630947134992368259", 1440 x 3200, modeId 2
+ int res = sscanf(info, "{\"%63[^\"]\":%*s%u x %u, modeId%u", name.chars, &width, &height, &modeId);
+ if (res >= 3) {
+ if (res == 4) {
+ ++info; // skip first '{'
+ while ((info = strchr(info, '{'))) {
+ ++info;
+
+ unsigned id;
+ double fps;
+ // id=1, width=1440, height=3200, fps=60.000004,
+ if (sscanf(info, "id=%u, %*s%*s fps=%lf", &id, &fps) >= 2) {
+ if (id == modeId) {
+ refreshRate = fps;
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ }
+
+ ffStrbufRecalculateLength(&name);
+ FFDisplayResult* display = ffdsAppendDisplay(ds,
+ (uint32_t) width,
+ (uint32_t) height,
+ refreshRate,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ &name,
+ FF_DISPLAY_TYPE_UNKNOWN,
+ false,
+ 0,
+ 0,
+ 0,
+ "dumpsys");
+ if (display) {
+ display->hdrStatus = checkHdrStatus(display);
+ }
+ }
+
+ index = nextIndex + 1;
+ }
+}
+
+static bool detectWithGetprop(FFDisplayServerResult* ds) {
+ // Only for MiUI
+ FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
+
+ if (ffSettingsGetAndroidProperty("persist.sys.miui_resolution", &buffer) &&
+ ffStrbufContainC(&buffer, ',')) {
+ // 1440,3200,560 => width,height,densityDpi
+ uint32_t width = (uint32_t) ffStrbufToUInt(&buffer, 0);
+ ffStrbufSubstrAfterFirstC(&buffer, ',');
+ uint32_t height = (uint32_t) ffStrbufToUInt(&buffer, 0);
+ ffStrbufSubstrAfterFirstC(&buffer, ',');
+ uint32_t dpi = (uint32_t) ffStrbufToUInt(&buffer, 0) * 96 / 160;
+ FFDisplayResult* display = ffdsAppendDisplay(ds,
+ width,
+ height,
+ 0,
+ dpi,
+ 0,
+ 0,
+ 0,
+ 0,
+ NULL,
+ FF_DISPLAY_TYPE_BUILTIN,
+ false,
+ 0,
+ 0,
+ 0,
+ "getprop");
+ if (display) {
+ display->hdrStatus = checkHdrStatus(display);
+ }
+ return !!display;
+ }
+
+ return false;
+}
+
+static bool detectDE(FFDisplayServerResult* ds) {
+ if (ffSettingsGetAndroidProperty("ro.vivo.os.build.display.id", &ds->dePrettyName)) // OriginOS 6
+ {
+ ffStrbufAppendC(&ds->dePrettyName, ' ');
+ ffSettingsGetAndroidProperty("ro.vivo.product.version", &ds->dePrettyName); // PD2505D_xxx
+ return true;
+ }
+ if (ffSettingsGetAndroidProperty("ro.build.version.magic", &ds->dePrettyName) ||
+ ffSettingsGetAndroidProperty("ro.build.version.emui", &ds->dePrettyName)) {
+ ffStrbufReplaceAllC(&ds->dePrettyName, '_', ' ');
+ return true;
+ }
+ if (ffSettingsGetAndroidProperty("ro.mi.os.version.name", &ds->dePrettyName)) {
+ // MiUI like
+ ffStrbufClear(&ds->dePrettyName);
+ ffSettingsGetAndroidProperty("ro.build.version.incremental", &ds->dePrettyName); // Detail version number
+ if (ffStrbufStartsWithS(&ds->dePrettyName, "OS")) {
+ ds->dePrettyName.chars[0] = 'S';
+ ds->dePrettyName.chars[1] = ' ';
+ ffStrbufPrependS(&ds->dePrettyName, "HyperO");
+ } else if (ffStrbufStartsWithS(&ds->dePrettyName, "V")) {
+ ds->dePrettyName.chars[0] = ' ';
+ ffStrbufPrependS(&ds->dePrettyName, "MiUI");
+ } else {
+ ffStrbufSetStatic(&ds->dePrettyName, "MiUI");
+ }
+ return true;
+ }
+ if (ffSettingsGetAndroidProperty("ro.build.version.oplusrom", &ds->dePrettyName)) {
+ if (ffStrbufStartsWithS(&ds->dePrettyName, "V")) {
+ ffStrbufSubstrAfter(&ds->dePrettyName, 0);
+ }
+ ffStrbufPrependS(&ds->dePrettyName, "ColorOS");
+ return true;
+ }
+ if (ffSettingsGetAndroidProperty("ro.oxygen.version", &ds->dePrettyName)) {
+ ffStrbufPrependS(&ds->dePrettyName, "OxygenOS");
+ return true;
+ }
+ if (ffSettingsGetAndroidProperty("ro.build.display.id", &ds->dePrettyName)) {
+ if (ffStrbufStartsWithS(&ds->dePrettyName, "RedMagicOS")) {
+ ffStrbufInsertNC(&ds->dePrettyName, strlen("RedMagicOS"), 1, ' ');
+ }
+
+ // Google Pixel uses native Android
+ return true;
+ }
+
+ return false;
+}
+
+void ffConnectDisplayServerImpl(FFDisplayServerResult* ds) {
+ const char* error = ffdsConnectXcbRandr(ds);
+ if (error) {
+ error = ffdsConnectXrandr(ds);
+ }
+ if (!error) {
+ ffdsDetectWMDE(ds);
+ return;
+ }
+
+ // https://source.android.com/docs/core/graphics/surfaceflinger-windowmanager
+ ffStrbufSetStatic(&ds->wmProcessName, "system_server");
+ ffStrbufSetStatic(&ds->wmPrettyName, "WindowManager"); // A system service managed by system_server
+ ffStrbufSetStatic(&ds->wmProtocolName, FF_WM_PROTOCOL_SURFACEFLINGER);
+
+ if (!detectWithGetprop(ds)) {
+ detectWithDumpsys(ds);
+ }
+
+ detectDE(ds);
+}