#include "displayserver.h" #include "common/settings.h" #include "common/processing.h" #include "linux/displayserver_linux.h" #include 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); }