diff options
Diffstat (limited to 'src/detection/displayserver/displayserver_android.c')
| -rw-r--r-- | src/detection/displayserver/displayserver_android.c | 209 |
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); +} |