Loading core/java/android/view/IWindowManager.aidl +20 −0 Original line number Original line Diff line number Diff line Loading @@ -32,6 +32,7 @@ import android.graphics.Region; import android.os.Bundle; import android.os.Bundle; import android.os.IRemoteCallback; import android.os.IRemoteCallback; import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor; import android.service.attestation.ImpressionToken; import android.view.DisplayCutout; import android.view.DisplayCutout; import android.view.IApplicationToken; import android.view.IApplicationToken; import android.view.IAppTransitionAnimationSpecsFuture; import android.view.IAppTransitionAnimationSpecsFuture; Loading Loading @@ -760,4 +761,23 @@ interface IWindowManager * {@link android.content.pm.PackageManager#getHoldLockToken()}. * {@link android.content.pm.PackageManager#getHoldLockToken()}. */ */ void holdLock(in IBinder token, in int durationMs); void holdLock(in IBinder token, in int durationMs); /** * Gets an array of support hashing algorithms that can be used to generate the hash of the * screenshot. The String value of one algorithm should be used when requesting to generate * the impression attestation token. * * @return a String array of supported hashing algorithms. */ String[] getSupportedImpressionAlgorithms(); /** * Validate the impression token was generated by the system. The impression token passed in * should be the token generated when calling {@link IWindowSession#generateImpressionToken} * * @param impressionToken The token to verify that it was generated by the system. * @return true if the token was generated by the system or false if the token cannot be * verified. */ boolean verifyImpressionToken(in ImpressionToken impressionToken); } } core/java/android/view/IWindowSession.aidl +13 −0 Original line number Original line Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.graphics.Point; import android.graphics.Rect; import android.graphics.Rect; import android.graphics.Region; import android.graphics.Region; import android.os.Bundle; import android.os.Bundle; import android.service.attestation.ImpressionToken; import android.util.MergedConfiguration; import android.util.MergedConfiguration; import android.view.DisplayCutout; import android.view.DisplayCutout; import android.view.InputChannel; import android.view.InputChannel; Loading Loading @@ -344,4 +345,16 @@ interface IWindowSession { * window, the system will try to find a new focus target. * window, the system will try to find a new focus target. */ */ void grantEmbeddedWindowFocus(IWindow window, in IBinder inputToken, boolean grantFocus); void grantEmbeddedWindowFocus(IWindow window, in IBinder inputToken, boolean grantFocus); /** * Generates an impression token that can be used to validate whether specific content was on * screen. * * @param window The token for the window where the view to attest is shown. * @param boundsInWindow The size and position of the ads view in the window * @param hashAlgorithm The String for the hashing algorithm to use based on values returned * from {@link IWindowManager#getSupportedImpressionAlgorithms()} */ ImpressionToken generateImpressionToken(IWindow window, in Rect boundsInWindow, in String hashAlgorithm); } } core/java/android/view/WindowlessWindowManager.java +7 −0 Original line number Original line Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.graphics.Rect; import android.graphics.Region; import android.graphics.Region; import android.os.IBinder; import android.os.IBinder; import android.os.RemoteException; import android.os.RemoteException; import android.service.attestation.ImpressionToken; import android.util.Log; import android.util.Log; import android.util.MergedConfiguration; import android.util.MergedConfiguration; import android.window.ClientWindowFrames; import android.window.ClientWindowFrames; Loading Loading @@ -460,4 +461,10 @@ public class WindowlessWindowManager implements IWindowSession { public void grantEmbeddedWindowFocus(IWindow callingWindow, IBinder targetInputToken, public void grantEmbeddedWindowFocus(IWindow callingWindow, IBinder targetInputToken, boolean grantFocus) { boolean grantFocus) { } } @Override public ImpressionToken generateImpressionToken(IWindow window, Rect boundsInWindow, String hashAlgorithm) { return null; } } } services/core/java/com/android/server/wm/DisplayContent.java +4 −0 Original line number Original line Diff line number Diff line Loading @@ -5724,4 +5724,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } } return count; return count; } } MagnificationSpec getMagnificationSpec() { return mMagnificationSpec; } } } services/core/java/com/android/server/wm/ImpressionAttestationController.java +85 −1 Original line number Original line Diff line number Diff line Loading @@ -18,6 +18,9 @@ package com.android.server.wm; import static android.service.attestation.ImpressionAttestationService.SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS; import static android.service.attestation.ImpressionAttestationService.SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.Manifest; import android.Manifest; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; Loading @@ -29,7 +32,9 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.ServiceInfo; import android.content.res.Resources; import android.content.res.Resources; import android.graphics.Matrix; import android.graphics.Rect; import android.graphics.Rect; import android.graphics.RectF; import android.hardware.HardwareBuffer; import android.hardware.HardwareBuffer; import android.os.Binder; import android.os.Binder; import android.os.Bundle; import android.os.Bundle; Loading @@ -43,6 +48,7 @@ import android.service.attestation.IImpressionAttestationService; import android.service.attestation.ImpressionAttestationService; import android.service.attestation.ImpressionAttestationService; import android.service.attestation.ImpressionToken; import android.service.attestation.ImpressionToken; import android.util.Slog; import android.util.Slog; import android.view.MagnificationSpec; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy; Loading @@ -59,7 +65,8 @@ import java.util.function.BiConsumer; * blocking calls into another service. * blocking calls into another service. */ */ public class ImpressionAttestationController { public class ImpressionAttestationController { private static final String TAG = "ImpressionAttestationController"; private static final String TAG = TAG_WITH_CLASS_NAME ? "ImpressionAttestationController" : TAG_WM; private static final boolean DEBUG = false; private static final boolean DEBUG = false; private final Object mServiceConnectionLock = new Object(); private final Object mServiceConnectionLock = new Object(); Loading @@ -81,6 +88,10 @@ public class ImpressionAttestationController { private final String mSalt; private final String mSalt; private final float[] mTmpFloat9 = new float[9]; private final Matrix mTmpMatrix = new Matrix(); private final RectF mTmpRectF = new RectF(); private interface Command { private interface Command { void run(IImpressionAttestationService service) throws RemoteException; void run(IImpressionAttestationService service) throws RemoteException; } } Loading Loading @@ -150,6 +161,79 @@ public class ImpressionAttestationController { return results.getParcelable(ImpressionAttestationService.EXTRA_IMPRESSION_TOKEN); return results.getParcelable(ImpressionAttestationService.EXTRA_IMPRESSION_TOKEN); } } /** * Calculate the bounds to take the screenshot when generating the impression token. This takes * into account window transform, magnification, and display bounds. * * Call while holding {@link WindowManagerService#mGlobalLock} * * @param win Window that the impression token is generated for. * @param boundsInWindow The bounds passed in about where in the window to take the screenshot. * @param outBounds The result of the calculated bounds */ void calculateImpressionTokenBoundsLocked(WindowState win, Rect boundsInWindow, Rect outBounds) { if (DEBUG) { Slog.d(TAG, "calculateImpressionTokenBounds: boundsInWindow=" + boundsInWindow); } outBounds.set(boundsInWindow); DisplayContent displayContent = win.getDisplayContent(); if (displayContent == null) { return; } // Intersect boundsInWindow with the window to make sure it's not outside the window // requesting the token. Offset the window bounds to 0,0 since the boundsInWindow are // offset from the window location, not display. final Rect windowBounds = new Rect(); win.getBounds(windowBounds); windowBounds.offsetTo(0, 0); outBounds.intersectUnchecked(windowBounds); if (DEBUG) { Slog.d(TAG, "calculateImpressionTokenBounds: boundsIntersectWindow=" + outBounds); } if (outBounds.isEmpty()) { return; } // Transform the bounds using the window transform in case there's a scale or offset. // This allows the bounds to be in display space. win.getTransformationMatrix(mTmpFloat9, mTmpMatrix); mTmpRectF.set(outBounds); mTmpMatrix.mapRect(mTmpRectF, mTmpRectF); outBounds.set((int) mTmpRectF.left, (int) mTmpRectF.top, (int) mTmpRectF.right, (int) mTmpRectF.bottom); if (DEBUG) { Slog.d(TAG, "calculateImpressionTokenBounds: boundsInDisplay=" + outBounds); } // Apply the magnification spec values to the bounds since the content could be magnified final MagnificationSpec magSpec = displayContent.getMagnificationSpec(); if (magSpec != null) { outBounds.scale(magSpec.scale); outBounds.offset((int) magSpec.offsetX, (int) magSpec.offsetY); } if (DEBUG) { Slog.d(TAG, "calculateImpressionTokenBounds: boundsWithMagnification=" + outBounds); } if (outBounds.isEmpty()) { return; } // Intersect with the display bounds since it shouldn't take a screenshot of content // outside the display since it's not visible to the user. final Rect displayBounds = displayContent.getBounds(); outBounds.intersectUnchecked(displayBounds); if (DEBUG) { Slog.d(TAG, "calculateImpressionTokenBounds: finalBounds=" + outBounds); } } /** /** * Run a command, starting the service connection if necessary. * Run a command, starting the service connection if necessary. */ */ Loading Loading
core/java/android/view/IWindowManager.aidl +20 −0 Original line number Original line Diff line number Diff line Loading @@ -32,6 +32,7 @@ import android.graphics.Region; import android.os.Bundle; import android.os.Bundle; import android.os.IRemoteCallback; import android.os.IRemoteCallback; import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor; import android.service.attestation.ImpressionToken; import android.view.DisplayCutout; import android.view.DisplayCutout; import android.view.IApplicationToken; import android.view.IApplicationToken; import android.view.IAppTransitionAnimationSpecsFuture; import android.view.IAppTransitionAnimationSpecsFuture; Loading Loading @@ -760,4 +761,23 @@ interface IWindowManager * {@link android.content.pm.PackageManager#getHoldLockToken()}. * {@link android.content.pm.PackageManager#getHoldLockToken()}. */ */ void holdLock(in IBinder token, in int durationMs); void holdLock(in IBinder token, in int durationMs); /** * Gets an array of support hashing algorithms that can be used to generate the hash of the * screenshot. The String value of one algorithm should be used when requesting to generate * the impression attestation token. * * @return a String array of supported hashing algorithms. */ String[] getSupportedImpressionAlgorithms(); /** * Validate the impression token was generated by the system. The impression token passed in * should be the token generated when calling {@link IWindowSession#generateImpressionToken} * * @param impressionToken The token to verify that it was generated by the system. * @return true if the token was generated by the system or false if the token cannot be * verified. */ boolean verifyImpressionToken(in ImpressionToken impressionToken); } }
core/java/android/view/IWindowSession.aidl +13 −0 Original line number Original line Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.graphics.Point; import android.graphics.Rect; import android.graphics.Rect; import android.graphics.Region; import android.graphics.Region; import android.os.Bundle; import android.os.Bundle; import android.service.attestation.ImpressionToken; import android.util.MergedConfiguration; import android.util.MergedConfiguration; import android.view.DisplayCutout; import android.view.DisplayCutout; import android.view.InputChannel; import android.view.InputChannel; Loading Loading @@ -344,4 +345,16 @@ interface IWindowSession { * window, the system will try to find a new focus target. * window, the system will try to find a new focus target. */ */ void grantEmbeddedWindowFocus(IWindow window, in IBinder inputToken, boolean grantFocus); void grantEmbeddedWindowFocus(IWindow window, in IBinder inputToken, boolean grantFocus); /** * Generates an impression token that can be used to validate whether specific content was on * screen. * * @param window The token for the window where the view to attest is shown. * @param boundsInWindow The size and position of the ads view in the window * @param hashAlgorithm The String for the hashing algorithm to use based on values returned * from {@link IWindowManager#getSupportedImpressionAlgorithms()} */ ImpressionToken generateImpressionToken(IWindow window, in Rect boundsInWindow, in String hashAlgorithm); } }
core/java/android/view/WindowlessWindowManager.java +7 −0 Original line number Original line Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.graphics.Rect; import android.graphics.Region; import android.graphics.Region; import android.os.IBinder; import android.os.IBinder; import android.os.RemoteException; import android.os.RemoteException; import android.service.attestation.ImpressionToken; import android.util.Log; import android.util.Log; import android.util.MergedConfiguration; import android.util.MergedConfiguration; import android.window.ClientWindowFrames; import android.window.ClientWindowFrames; Loading Loading @@ -460,4 +461,10 @@ public class WindowlessWindowManager implements IWindowSession { public void grantEmbeddedWindowFocus(IWindow callingWindow, IBinder targetInputToken, public void grantEmbeddedWindowFocus(IWindow callingWindow, IBinder targetInputToken, boolean grantFocus) { boolean grantFocus) { } } @Override public ImpressionToken generateImpressionToken(IWindow window, Rect boundsInWindow, String hashAlgorithm) { return null; } } }
services/core/java/com/android/server/wm/DisplayContent.java +4 −0 Original line number Original line Diff line number Diff line Loading @@ -5724,4 +5724,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp } } return count; return count; } } MagnificationSpec getMagnificationSpec() { return mMagnificationSpec; } } }
services/core/java/com/android/server/wm/ImpressionAttestationController.java +85 −1 Original line number Original line Diff line number Diff line Loading @@ -18,6 +18,9 @@ package com.android.server.wm; import static android.service.attestation.ImpressionAttestationService.SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS; import static android.service.attestation.ImpressionAttestationService.SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import android.Manifest; import android.Manifest; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; Loading @@ -29,7 +32,9 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.ServiceInfo; import android.content.res.Resources; import android.content.res.Resources; import android.graphics.Matrix; import android.graphics.Rect; import android.graphics.Rect; import android.graphics.RectF; import android.hardware.HardwareBuffer; import android.hardware.HardwareBuffer; import android.os.Binder; import android.os.Binder; import android.os.Bundle; import android.os.Bundle; Loading @@ -43,6 +48,7 @@ import android.service.attestation.IImpressionAttestationService; import android.service.attestation.ImpressionAttestationService; import android.service.attestation.ImpressionAttestationService; import android.service.attestation.ImpressionToken; import android.service.attestation.ImpressionToken; import android.util.Slog; import android.util.Slog; import android.view.MagnificationSpec; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy; Loading @@ -59,7 +65,8 @@ import java.util.function.BiConsumer; * blocking calls into another service. * blocking calls into another service. */ */ public class ImpressionAttestationController { public class ImpressionAttestationController { private static final String TAG = "ImpressionAttestationController"; private static final String TAG = TAG_WITH_CLASS_NAME ? "ImpressionAttestationController" : TAG_WM; private static final boolean DEBUG = false; private static final boolean DEBUG = false; private final Object mServiceConnectionLock = new Object(); private final Object mServiceConnectionLock = new Object(); Loading @@ -81,6 +88,10 @@ public class ImpressionAttestationController { private final String mSalt; private final String mSalt; private final float[] mTmpFloat9 = new float[9]; private final Matrix mTmpMatrix = new Matrix(); private final RectF mTmpRectF = new RectF(); private interface Command { private interface Command { void run(IImpressionAttestationService service) throws RemoteException; void run(IImpressionAttestationService service) throws RemoteException; } } Loading Loading @@ -150,6 +161,79 @@ public class ImpressionAttestationController { return results.getParcelable(ImpressionAttestationService.EXTRA_IMPRESSION_TOKEN); return results.getParcelable(ImpressionAttestationService.EXTRA_IMPRESSION_TOKEN); } } /** * Calculate the bounds to take the screenshot when generating the impression token. This takes * into account window transform, magnification, and display bounds. * * Call while holding {@link WindowManagerService#mGlobalLock} * * @param win Window that the impression token is generated for. * @param boundsInWindow The bounds passed in about where in the window to take the screenshot. * @param outBounds The result of the calculated bounds */ void calculateImpressionTokenBoundsLocked(WindowState win, Rect boundsInWindow, Rect outBounds) { if (DEBUG) { Slog.d(TAG, "calculateImpressionTokenBounds: boundsInWindow=" + boundsInWindow); } outBounds.set(boundsInWindow); DisplayContent displayContent = win.getDisplayContent(); if (displayContent == null) { return; } // Intersect boundsInWindow with the window to make sure it's not outside the window // requesting the token. Offset the window bounds to 0,0 since the boundsInWindow are // offset from the window location, not display. final Rect windowBounds = new Rect(); win.getBounds(windowBounds); windowBounds.offsetTo(0, 0); outBounds.intersectUnchecked(windowBounds); if (DEBUG) { Slog.d(TAG, "calculateImpressionTokenBounds: boundsIntersectWindow=" + outBounds); } if (outBounds.isEmpty()) { return; } // Transform the bounds using the window transform in case there's a scale or offset. // This allows the bounds to be in display space. win.getTransformationMatrix(mTmpFloat9, mTmpMatrix); mTmpRectF.set(outBounds); mTmpMatrix.mapRect(mTmpRectF, mTmpRectF); outBounds.set((int) mTmpRectF.left, (int) mTmpRectF.top, (int) mTmpRectF.right, (int) mTmpRectF.bottom); if (DEBUG) { Slog.d(TAG, "calculateImpressionTokenBounds: boundsInDisplay=" + outBounds); } // Apply the magnification spec values to the bounds since the content could be magnified final MagnificationSpec magSpec = displayContent.getMagnificationSpec(); if (magSpec != null) { outBounds.scale(magSpec.scale); outBounds.offset((int) magSpec.offsetX, (int) magSpec.offsetY); } if (DEBUG) { Slog.d(TAG, "calculateImpressionTokenBounds: boundsWithMagnification=" + outBounds); } if (outBounds.isEmpty()) { return; } // Intersect with the display bounds since it shouldn't take a screenshot of content // outside the display since it's not visible to the user. final Rect displayBounds = displayContent.getBounds(); outBounds.intersectUnchecked(displayBounds); if (DEBUG) { Slog.d(TAG, "calculateImpressionTokenBounds: finalBounds=" + outBounds); } } /** /** * Run a command, starting the service connection if necessary. * Run a command, starting the service connection if necessary. */ */ Loading