Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android 13 Release "getDisplayIds" function parameter change, cause scrcpy crash. #3446

Closed
2 tasks done
DerekWuYD opened this issue Aug 16, 2022 · 9 comments
Closed
2 tasks done

Comments

@DerekWuYD
Copy link
Contributor

  • I have read the FAQ.
  • I have searched in existing issues.

Environment

  • OS: macOS
  • scrcpy version: 1.24
  • Android version: Android 13

Describe the bug
The function IDisplayManager.getDisplayIds use in DisplayManager.getDisplayIds().
No longer exist in Android 13, the new function has a bool parameter.
This function cause scrcpy crash.
Please update the scrcpy to fit this issue.

return (int[]) manager.getClass().getMethod("getDisplayIds").invoke(manager);

getDisplayIds detail in android code search
New method detail :

    int[] getDisplayIds(boolean includeDisabled);
@rom1v
Copy link
Collaborator

rom1v commented Aug 16, 2022

Thank you for the report.

Do you want to work on it and modify DisplayManager? (ClipboardManager could be used as an example.)

@DerekWuYD
Copy link
Contributor Author

I have an avaliable workaround using another class DisplayManagerGlobal.java
This class also is have not change from Android 4.4 to now (Android 13)
Which method you will perfer? Use the DisplayManagerGlobal.java or keep the DisplayManager.aidl with android version switch?

I put the code here for you reference.
Here is the DisplayManagerGlobal.java wrapper class code :

public final class DisplayManagerGlobal {
    private final Class<?> managerglobal;
    private final Object managerglobal_instance;

    public DisplayManagerGlobal(Object managerglobal) {
        this.managerglobal = managerglobal.getClass();
        this.managerglobal_instance = managerglobal;
    }

    public DisplayInfo getDisplayInfo(int displayId) {
        try {
            Object displayInfo = managerglobal.getMethod("getDisplayInfo",
                    int.class).invoke(managerglobal_instance, displayId);
            if (displayInfo == null) {
                return null;
            }
            Class<?> cls = displayInfo.getClass();
            // width and height already take the rotation into account
            int width = cls.getDeclaredField("logicalWidth").getInt(displayInfo);
            int height = cls.getDeclaredField("logicalHeight").getInt(displayInfo);
            int rotation = cls.getDeclaredField("rotation").getInt(displayInfo);
            int layerStack = cls.getDeclaredField("layerStack").getInt(displayInfo);
            int flags = cls.getDeclaredField("flags").getInt(displayInfo);
            return new DisplayInfo(displayId, new Size(width, height), rotation, layerStack, flags);
        } catch (Exception e) {
            throw new AssertionError(e);
        }
    }

    public int[] getDisplayIds() {
        try {
            int[] dis = (int[]) managerglobal.getMethod("getDisplayIds").invoke(
                    managerglobal_instance);
            return dis;
        } catch (Exception e) {
            throw new AssertionError(e);
        }
    }
}

And here is the change in ServiceManager.java

    public DisplayManagerGlobal getDisplayManagerGlobal() {
        try {
            if (mDisplayManagerGlobal == null) {
                Object DMG = Class.forName("android.hardware.display.DisplayManagerGlobal")
                        .getMethod("getInstance").invoke(null);
                mDisplayManagerGlobal = new DisplayManagerGlobal(DMG);
                return mDisplayManagerGlobal;
            }
            return mDisplayManagerGlobal;
        } catch (Exception e) {
            throw new AssertionError(e);
        }
    }

rom1v added a commit that referenced this issue Aug 16, 2022
Use the client instance to communicate with the DisplayManager server.

Fixes #3446 <#3446>
@rom1v
Copy link
Collaborator

rom1v commented Aug 16, 2022

@DerekWuYD Thank you very much.

I opened a PR: #3448, based on your work. Please test, and also provide a name and e-mail (Name <email>) so that I change the ownership of the commit.

@DerekWuYD
Copy link
Contributor Author

This branch works good!
I tested it on the following phones and it all works fine.

Pixel 6 / Pixel 6 Pro
Pixel 5
Pixel 4 XL
Pixel 3 XL
Pixel 2
mi12S ultra
mi11 ultra
huawei p50 pro
huawei p40 pro
oppo reno7
sumsang s22 ultra
sumsang s21 ultra
sumsang a52 
vivo x70 pro

my name is Derek Wu,
mail is [email protected]

Thank you.

rom1v pushed a commit that referenced this issue Aug 18, 2022
Use the client instance to communicate with the DisplayManager server.

Fixes #3446 <#3446>

Signed-off-by: Romain Vimont <[email protected]>
@rom1v
Copy link
Collaborator

rom1v commented Aug 18, 2022

my name is Derek Wu,
mail is [email protected]

Thank you, I amended the commit in the PR.

I tested it on the following phones and it all works fine.

[list of 15 devices]

Awesome, I'd like to have access to so many devices :)

Could you also reproduce issue #3416? If so, does the PR #3448 also fix it?

@DerekWuYD
Copy link
Contributor Author

I can't reproduce issue #3416 in those phone,
But base on this method getDisplayInfoLocked which getDisplayInfo method based on.
It will retrun null under some condition, so I think #3416 may still need to avoid null response.

@rom1v
Copy link
Collaborator

rom1v commented Aug 19, 2022

Thanks 👍 merged: 9c1722f

@rom1v rom1v closed this as completed Aug 19, 2022
rom1v pushed a commit that referenced this issue Aug 19, 2022
Use the client instance to communicate with the DisplayManager server.

Fixes #3446 <#3446>

Signed-off-by: Romain Vimont <[email protected]>
@cike1949
Copy link

cike1949 commented Dec 7, 2022

Google Android13.0.0-r16 have reverted the new function DisplayManager.getDisplayIds() with bool parameter and change back to the function without parameter.
So, just need cherry-pick Google revert change, scrcpy 1.24 could work:
https://android.googlesource.com/platform/frameworks/base/+/937ca4b396ebd910b5c9513b09d02b051533bb44

@descosmos
Copy link

I have an avaliable workaround using another class DisplayManagerGlobal.java This class also is have not change from Android 4.4 to now (Android 13) Which method you will perfer? Use the DisplayManagerGlobal.java or keep the DisplayManager.aidl with android version switch?

I put the code here for you reference. Here is the DisplayManagerGlobal.java wrapper class code :

public final class DisplayManagerGlobal {
    private final Class<?> managerglobal;
    private final Object managerglobal_instance;

    public DisplayManagerGlobal(Object managerglobal) {
        this.managerglobal = managerglobal.getClass();
        this.managerglobal_instance = managerglobal;
    }

    public DisplayInfo getDisplayInfo(int displayId) {
        try {
            Object displayInfo = managerglobal.getMethod("getDisplayInfo",
                    int.class).invoke(managerglobal_instance, displayId);
            if (displayInfo == null) {
                return null;
            }
            Class<?> cls = displayInfo.getClass();
            // width and height already take the rotation into account
            int width = cls.getDeclaredField("logicalWidth").getInt(displayInfo);
            int height = cls.getDeclaredField("logicalHeight").getInt(displayInfo);
            int rotation = cls.getDeclaredField("rotation").getInt(displayInfo);
            int layerStack = cls.getDeclaredField("layerStack").getInt(displayInfo);
            int flags = cls.getDeclaredField("flags").getInt(displayInfo);
            return new DisplayInfo(displayId, new Size(width, height), rotation, layerStack, flags);
        } catch (Exception e) {
            throw new AssertionError(e);
        }
    }

    public int[] getDisplayIds() {
        try {
            int[] dis = (int[]) managerglobal.getMethod("getDisplayIds").invoke(
                    managerglobal_instance);
            return dis;
        } catch (Exception e) {
            throw new AssertionError(e);
        }
    }
}

And here is the change in ServiceManager.java

    public DisplayManagerGlobal getDisplayManagerGlobal() {
        try {
            if (mDisplayManagerGlobal == null) {
                Object DMG = Class.forName("android.hardware.display.DisplayManagerGlobal")
                        .getMethod("getInstance").invoke(null);
                mDisplayManagerGlobal = new DisplayManagerGlobal(DMG);
                return mDisplayManagerGlobal;
            }
            return mDisplayManagerGlobal;
        } catch (Exception e) {
            throw new AssertionError(e);
        }
    }

Thank you very much !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants