From 22097eb271cba3aee9a5f210ffa63a075d4b1d48 Mon Sep 17 00:00:00 2001 From: DtHnAme <1904685725@qq.com> Date: Thu, 9 Nov 2023 12:52:02 +0800 Subject: [PATCH 1/3] FreeformWindow: only create virtual display once --- .../io/sunshine0523/freeform/ui/freeform/FreeformWindow.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/freeform-server/src/main/java/io/sunshine0523/freeform/ui/freeform/FreeformWindow.kt b/freeform-server/src/main/java/io/sunshine0523/freeform/ui/freeform/FreeformWindow.kt index 5f88060..f956d54 100644 --- a/freeform-server/src/main/java/io/sunshine0523/freeform/ui/freeform/FreeformWindow.kt +++ b/freeform-server/src/main/java/io/sunshine0523/freeform/ui/freeform/FreeformWindow.kt @@ -76,7 +76,9 @@ class FreeformWindow( override fun onSurfaceTextureAvailable(surfaceTexture: SurfaceTexture, width: Int, height: Int) { MLog.i(TAG, "onSurfaceTextureAvailable width:$width height:$height") - MiFreeformServiceHolder.createDisplay(freeformConfig, appConfig, Surface(surfaceTexture), this) + if (displayId < 0) { + MiFreeformServiceHolder.createDisplay(freeformConfig, appConfig, Surface(surfaceTexture), this) + } surfaceTexture.setDefaultBufferSize(freeformConfig.freeformWidth, freeformConfig.freeformHeight) } From 9905d0a305aea6c9f09d37bb023eddc755bd82a7 Mon Sep 17 00:00:00 2001 From: DtHnAme <1904685725@qq.com> Date: Thu, 9 Nov 2023 12:58:33 +0800 Subject: [PATCH 2/3] MiFreeformDisplayAdapter: Delayed search for display device --- .../display/MiFreeformRDisplayAdapter.java | 28 ++++---------- .../display/MiFreeformTDisplayAdapter.java | 38 ++++--------------- 2 files changed, 16 insertions(+), 50 deletions(-) diff --git a/freeform-server/src/main/java/com/android/server/display/MiFreeformRDisplayAdapter.java b/freeform-server/src/main/java/com/android/server/display/MiFreeformRDisplayAdapter.java index e9bca2c..032f220 100644 --- a/freeform-server/src/main/java/com/android/server/display/MiFreeformRDisplayAdapter.java +++ b/freeform-server/src/main/java/com/android/server/display/MiFreeformRDisplayAdapter.java @@ -51,27 +51,15 @@ public void createFreeformLocked(String name, IMiFreeformDisplayCallback callbac mFreeformDisplayDevices.put(appToken, device); miFreeformDisplayCallbackArrayMap.put(device, callback); - new Thread(new Runnable() { - @Override - public void run() { - int count = 10; - LogicalDisplay display = findLogicalDisplayForDevice(device); - while (count-- > 0 && display == null) { - display = findLogicalDisplayForDevice(device); - Log.i(TAG, "findLogicalDisplayForDevice " + display); - if (display == null) { - try { - Thread.sleep(200); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - } - try { - callback.onDisplayAdd(display.getDisplayIdLocked()); - } catch (Exception ignored) {} + mHandler.postDelayed(() -> { + LogicalDisplay display = findLogicalDisplayForDevice(device); + MLog.i(TAG, "findLogicalDisplayForDevice " + display); + try { + callback.onDisplayAdd(display.getDisplayIdLocked()); + } catch (Exception ignored) { + } - }).start(); + }, 500); try { appToken.linkToDeath(device, 0); diff --git a/freeform-server/src/main/java/com/android/server/display/MiFreeformTDisplayAdapter.java b/freeform-server/src/main/java/com/android/server/display/MiFreeformTDisplayAdapter.java index 9a097e5..33ff8ca 100644 --- a/freeform-server/src/main/java/com/android/server/display/MiFreeformTDisplayAdapter.java +++ b/freeform-server/src/main/java/com/android/server/display/MiFreeformTDisplayAdapter.java @@ -1,22 +1,13 @@ package com.android.server.display; -import static com.android.server.display.DisplayDeviceInfo.FLAG_TRUSTED; - import android.content.Context; import android.os.Handler; import android.os.IBinder; -import android.os.Message; import android.os.RemoteException; -import android.util.ArrayMap; -//@RefineAs(Display.class) import android.util.Log; -import android.view.DisplayHidden; import android.view.Surface; -//@RefineAs(SurfaceControl.class) import android.view.SurfaceControlHidden; -import java.io.PrintWriter; - import io.sunshine0523.freeform.IMiFreeformDisplayCallback; import io.sunshine0523.freeform.util.MLog; @@ -60,27 +51,15 @@ public void createFreeformLocked(String name, IMiFreeformDisplayCallback callbac mFreeformDisplayDevices.put(appToken, device); miFreeformDisplayCallbackArrayMap.put(device, callback); - new Thread(new Runnable() { - @Override - public void run() { - int count = 10; - LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device); - while (count-- > 0 && display == null) { - display = mLogicalDisplayMapper.getDisplayLocked(device); - Log.i(TAG, "findLogicalDisplayForDevice " + display); - if (display == null) { - try { - Thread.sleep(200); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - } - try { - callback.onDisplayAdd(display.getDisplayIdLocked()); - } catch (Exception ignored) {} + mHandler.postDelayed(() -> { + LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device); + MLog.i(TAG, "findLogicalDisplayForDevice " + display); + try { + callback.onDisplayAdd(display.getDisplayIdLocked()); + } catch (Exception e) { + } - }).start(); + }, 500); try { appToken.linkToDeath(device, 0); @@ -88,7 +67,6 @@ public void run() { mFreeformDisplayDevices.remove(appToken); device.destroyLocked(false); } - //MLog.i(TAG, "createFreeformLocked"); } } From 9c97b8104b18088a67d659bb9877d9331934b81e Mon Sep 17 00:00:00 2001 From: DtHnAme <1904685725@qq.com> Date: Thu, 9 Nov 2023 13:07:20 +0800 Subject: [PATCH 3/3] MiFreeformDisplayAdapter: support android 14 (34) new apis --- .../display/MiFreeformDisplayAdapter.java | 10 +- .../display/MiFreeformUDisplayAdapter.java | 115 ++++++++++++++++++ .../io/sunshine0523/freeform/ZygoteMain.java | 3 + .../java/android/view/DisplayShapeHidden.java | 13 ++ .../server/display/DisplayControl.java | 44 +++++++ .../server/display/DisplayDeviceInfo.java | 6 + 6 files changed, 186 insertions(+), 5 deletions(-) create mode 100644 freeform-server/src/main/java/com/android/server/display/MiFreeformUDisplayAdapter.java create mode 100644 hidden-api/src/main/java/android/view/DisplayShapeHidden.java create mode 100644 hidden-api/src/main/java/com/android/server/display/DisplayControl.java diff --git a/freeform-server/src/main/java/com/android/server/display/MiFreeformDisplayAdapter.java b/freeform-server/src/main/java/com/android/server/display/MiFreeformDisplayAdapter.java index 3bd88d2..fec214e 100644 --- a/freeform-server/src/main/java/com/android/server/display/MiFreeformDisplayAdapter.java +++ b/freeform-server/src/main/java/com/android/server/display/MiFreeformDisplayAdapter.java @@ -101,12 +101,12 @@ public class FreeformDisplayDevice extends DisplayDevice implements IBinder.Deat private int mWidth; private int mHeight; private int mDensityDpi; - private DisplayHidden.Mode mMode; - private Surface mSurface; - private DisplayDeviceInfo mInfo; + protected DisplayHidden.Mode mMode; + protected Surface mSurface; + protected DisplayDeviceInfo mInfo; - private final Callback mCallback; - private final IBinder mAppToken; + protected final Callback mCallback; + protected final IBinder mAppToken; private int mPendingChanges; diff --git a/freeform-server/src/main/java/com/android/server/display/MiFreeformUDisplayAdapter.java b/freeform-server/src/main/java/com/android/server/display/MiFreeformUDisplayAdapter.java new file mode 100644 index 0000000..47af3b0 --- /dev/null +++ b/freeform-server/src/main/java/com/android/server/display/MiFreeformUDisplayAdapter.java @@ -0,0 +1,115 @@ +package com.android.server.display; + +import android.content.Context; +import android.os.Handler; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; +import android.view.DisplayShapeHidden; +import android.view.Surface; + +import io.sunshine0523.freeform.IMiFreeformDisplayCallback; + +/** + * A display adapter that provides freeform displays on behalf of applications. + *
+ * Display adapters are guarded by the {@link DisplayManagerService.SyncRoot} lock. + *
+ * This adapter only support Android U + */ +public final class MiFreeformUDisplayAdapter extends MiFreeformDisplayAdapter { + private final LogicalDisplayMapper mLogicalDisplayMapper; + + public MiFreeformUDisplayAdapter( + DisplayManagerService.SyncRoot syncRoot, + Context context, + Handler handler, + DisplayDeviceRepository listener, + LogicalDisplayMapper logicalDisplayMapper, + Handler uiHandler + ) { + super(syncRoot, context, handler, listener, uiHandler, TAG); + mLogicalDisplayMapper = logicalDisplayMapper; + } + + @Override + public void createFreeformLocked(String name, IMiFreeformDisplayCallback callback, + int width, int height, int densityDpi, + boolean secure, boolean ownContentOnly, boolean shouldShowSystemDecorations, + Surface surface, float refreshRate, long presentationDeadlineNanos) { + synchronized (getSyncRoot()) { + IBinder appToken = callback.asBinder(); + FreeformFlags flags = new FreeformFlags(secure, ownContentOnly, shouldShowSystemDecorations); + IBinder displayToken = DisplayControl.createDisplay(UNIQUE_ID_PREFIX + name, flags.mSecure, refreshRate); + FreeformDisplayDevice device = new FreeformUDisplayDevice(displayToken, UNIQUE_ID_PREFIX + name, width, height, densityDpi, + refreshRate, presentationDeadlineNanos, + flags, surface, new Callback(callback, mHandler), callback.asBinder()); + + sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED); + mFreeformDisplayDevices.put(appToken, device); + miFreeformDisplayCallbackArrayMap.put(device, callback); + + mHandler.postDelayed(() -> { + LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device); + Log.i(TAG, "findLogicalDisplayForDevice " + display); + try { + callback.onDisplayAdd(display.getDisplayIdLocked()); + } catch (Exception ignored) { + + } + }, 500); + + try { + appToken.linkToDeath(device, 0); + } catch (RemoteException ex) { + mFreeformDisplayDevices.remove(appToken); + device.destroyLocked(false); + } + } + } + + @Override + public void resizeFreeform(IBinder appToken, int width, int height, int densityDpi) { + super.resizeFreeform(appToken, width, height, densityDpi); + } + + @Override + public void releaseFreeform(IBinder appToken) { + super.releaseFreeform(appToken); + } + + private class FreeformUDisplayDevice extends FreeformDisplayDevice { + + FreeformUDisplayDevice(IBinder displayToken, String uniqueId, + int width, int height, int density, + float refreshRate, long presentationDeadlineNanos, + FreeformFlags flags, Surface surface, + Callback callback, IBinder appToken) { + super(displayToken, uniqueId, + width, height, density, + refreshRate, presentationDeadlineNanos, + flags, surface, callback, appToken); + } + + @Override + public DisplayDeviceInfo getDisplayDeviceInfoLocked() { + super.getDisplayDeviceInfoLocked(); + mInfo.displayShape = DisplayShapeHidden.createDefaultDisplayShape(mInfo.width, mInfo.height, false); + + return mInfo; + } + + @Override + public void destroyLocked(boolean binderAlive) { + if (mSurface != null) { + mSurface.release(); + mSurface = null; + } + DisplayControl.destroyDisplay(getDisplayTokenLocked()); + if (binderAlive) { + mCallback.dispatchDisplayStopped(); + } + + } + } +} diff --git a/freeform-server/src/main/java/io/sunshine0523/freeform/ZygoteMain.java b/freeform-server/src/main/java/io/sunshine0523/freeform/ZygoteMain.java index fb52dc4..645a709 100644 --- a/freeform-server/src/main/java/io/sunshine0523/freeform/ZygoteMain.java +++ b/freeform-server/src/main/java/io/sunshine0523/freeform/ZygoteMain.java @@ -88,6 +88,9 @@ private static void instanceMFService(Binder service) throws NoSuchFieldExceptio Object mDisplayDeviceRepo = mDisplayDeviceRepoField.get(displayManagerServiceObj); Object mLogicalDisplayMapper = mLogicalDisplayMapperField.get(displayManagerServiceObj); Class> mfdaClass = classLoader.loadClass("com.android.server.display.MiFreeformTDisplayAdapter"); + if (Build.VERSION.SDK_INT == Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + mfdaClass = classLoader.loadClass("com.android.server.display.MiFreeformUDisplayAdapter"); + } miFreeformDisplayAdapterObj = mfdaClass.getConstructors()[0].newInstance(mSyncRoot, mContext, mHandler, mDisplayDeviceRepo, mLogicalDisplayMapper, mUiHandler); mfdaClass.getMethod("registerLocked").invoke(miFreeformDisplayAdapterObj); } diff --git a/hidden-api/src/main/java/android/view/DisplayShapeHidden.java b/hidden-api/src/main/java/android/view/DisplayShapeHidden.java new file mode 100644 index 0000000..aa5a21a --- /dev/null +++ b/hidden-api/src/main/java/android/view/DisplayShapeHidden.java @@ -0,0 +1,13 @@ +package android.view; + +import dev.rikka.tools.refine.RefineAs; + +@RefineAs(DisplayShape.class) +public class DisplayShapeHidden { + + public static DisplayShape createDefaultDisplayShape( + int displayWidth, int displayHeight, boolean isScreenRound) { + throw new RuntimeException("Stub!"); + } + +} diff --git a/hidden-api/src/main/java/com/android/server/display/DisplayControl.java b/hidden-api/src/main/java/com/android/server/display/DisplayControl.java new file mode 100644 index 0000000..98a4e90 --- /dev/null +++ b/hidden-api/src/main/java/com/android/server/display/DisplayControl.java @@ -0,0 +1,44 @@ +package com.android.server.display; + +import android.os.IBinder; + +public class DisplayControl { + + /** + * Create a display in SurfaceFlinger. + * + * @param name The name of the display + * @param secure Whether this display is secure. + * @return The token reference for the display in SurfaceFlinger. + */ + public static IBinder createDisplay(String name, boolean secure) { + throw new RuntimeException("Stub!"); + } + + /** + * Create a display in SurfaceFlinger. + * + * @param name The name of the display + * @param secure Whether this display is secure. + * @param requestedRefreshRate The requested refresh rate in frames per second. + * For best results, specify a divisor of the physical refresh rate, e.g., 30 or 60 on + * 120hz display. If an arbitrary refresh rate is specified, the rate will be rounded + * up or down to a divisor of the physical display. If 0 is specified, the virtual + * display is refreshed at the physical display refresh rate. + * @return The token reference for the display in SurfaceFlinger. + */ + public static IBinder createDisplay(String name, boolean secure, + float requestedRefreshRate) { + throw new RuntimeException("Stub!"); + } + + /** + * Destroy a display in SurfaceFlinger. + * + * @param displayToken The display token for the display to be destroyed. + */ + public static void destroyDisplay(IBinder displayToken) { + throw new RuntimeException("Stub!"); + } + +} diff --git a/hidden-api/src/main/java/com/android/server/display/DisplayDeviceInfo.java b/hidden-api/src/main/java/com/android/server/display/DisplayDeviceInfo.java index 60228eb..c432cbd 100644 --- a/hidden-api/src/main/java/com/android/server/display/DisplayDeviceInfo.java +++ b/hidden-api/src/main/java/com/android/server/display/DisplayDeviceInfo.java @@ -1,6 +1,7 @@ package com.android.server.display; import android.view.DisplayHidden; +import android.view.DisplayShape; final class DisplayDeviceInfo { /** @@ -118,6 +119,11 @@ final class DisplayDeviceInfo { */ public int flags; + /** + * The {@link RoundedCorners} if present or {@code null} otherwise. + */ + public DisplayShape displayShape; + /** * The touch attachment, per {@link DisplayViewport#touch}. */