Merge "Added public APIs to generate and validate a DisplayHash." into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
c14465c2bb
@@ -10444,6 +10444,7 @@ package android.content {
|
||||
field public static final int CONTEXT_RESTRICTED = 4; // 0x4
|
||||
field public static final String CROSS_PROFILE_APPS_SERVICE = "crossprofileapps";
|
||||
field public static final String DEVICE_POLICY_SERVICE = "device_policy";
|
||||
field public static final String DISPLAY_HASH_SERVICE = "display_hash";
|
||||
field public static final String DISPLAY_SERVICE = "display";
|
||||
field public static final String DOWNLOAD_SERVICE = "download";
|
||||
field public static final String DROPBOX_SERVICE = "dropbox";
|
||||
@@ -48235,6 +48236,7 @@ package android.view {
|
||||
method public android.view.View focusSearch(int);
|
||||
method public void forceHasOverlappingRendering(boolean);
|
||||
method public void forceLayout();
|
||||
method @Nullable public void generateDisplayHash(@NonNull String, @Nullable android.graphics.Rect, @NonNull java.util.concurrent.Executor, @NonNull android.view.displayhash.DisplayHashResultCallback);
|
||||
method public static int generateViewId();
|
||||
method public CharSequence getAccessibilityClassName();
|
||||
method public android.view.View.AccessibilityDelegate getAccessibilityDelegate();
|
||||
@@ -51190,6 +51192,41 @@ package android.view.contentcapture {
|
||||
|
||||
}
|
||||
|
||||
package android.view.displayhash {
|
||||
|
||||
public final class DisplayHash implements android.os.Parcelable {
|
||||
method public int describeContents();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.view.displayhash.DisplayHash> CREATOR;
|
||||
}
|
||||
|
||||
public final class DisplayHashManager {
|
||||
method @NonNull public java.util.Set<java.lang.String> getSupportedHashAlgorithms();
|
||||
method @Nullable public android.view.displayhash.VerifiedDisplayHash verifyDisplayHash(@NonNull android.view.displayhash.DisplayHash);
|
||||
}
|
||||
|
||||
public interface DisplayHashResultCallback {
|
||||
method public void onDisplayHashError(int);
|
||||
method public void onDisplayHashResult(@NonNull android.view.displayhash.DisplayHash);
|
||||
field public static final int DISPLAY_HASH_ERROR_INVALID_BOUNDS = -2; // 0xfffffffe
|
||||
field public static final int DISPLAY_HASH_ERROR_MISSING_WINDOW = -3; // 0xfffffffd
|
||||
field public static final int DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN = -4; // 0xfffffffc
|
||||
field public static final int DISPLAY_HASH_ERROR_UNKNOWN = -1; // 0xffffffff
|
||||
}
|
||||
|
||||
public final class VerifiedDisplayHash implements android.os.Parcelable {
|
||||
ctor public VerifiedDisplayHash(long, @NonNull android.graphics.Rect, @NonNull String, @NonNull byte[]);
|
||||
method public int describeContents();
|
||||
method @NonNull public android.graphics.Rect getBoundsInWindow();
|
||||
method @NonNull public String getHashAlgorithm();
|
||||
method @NonNull public byte[] getImageHash();
|
||||
method public long getTimeMillis();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.view.displayhash.VerifiedDisplayHash> CREATOR;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
package android.view.inputmethod {
|
||||
|
||||
public class BaseInputConnection implements android.view.inputmethod.InputConnection {
|
||||
|
||||
@@ -9984,6 +9984,18 @@ package android.service.dataloader {
|
||||
|
||||
}
|
||||
|
||||
package android.service.displayhash {
|
||||
|
||||
public abstract class DisplayHasherService extends android.app.Service {
|
||||
ctor public DisplayHasherService();
|
||||
method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent);
|
||||
method @Nullable public abstract void onGenerateDisplayHash(@NonNull byte[], @NonNull android.hardware.HardwareBuffer, @NonNull android.graphics.Rect, @NonNull String, @NonNull android.view.displayhash.DisplayHashResultCallback);
|
||||
method @Nullable public abstract android.view.displayhash.VerifiedDisplayHash onVerifyDisplayHash(@NonNull byte[], @NonNull android.view.displayhash.DisplayHash);
|
||||
field public static final String SERVICE_INTERFACE = "android.service.displayhash.DisplayHasherService";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
package android.service.euicc {
|
||||
|
||||
public final class DownloadSubscriptionResult implements android.os.Parcelable {
|
||||
@@ -10344,30 +10356,6 @@ package android.service.rotationresolver {
|
||||
|
||||
}
|
||||
|
||||
package android.service.screenshot {
|
||||
|
||||
public final class ScreenshotHash implements android.os.Parcelable {
|
||||
ctor public ScreenshotHash(long, @NonNull android.graphics.Rect, @NonNull String, @NonNull byte[], @NonNull byte[]);
|
||||
method public int describeContents();
|
||||
method @NonNull public android.graphics.Rect getBoundsInWindow();
|
||||
method @NonNull public String getHashingAlgorithm();
|
||||
method @NonNull public byte[] getHmac();
|
||||
method @NonNull public byte[] getImageHash();
|
||||
method public long getScreenshotTimeMillis();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
field @NonNull public static final android.os.Parcelable.Creator<android.service.screenshot.ScreenshotHash> CREATOR;
|
||||
}
|
||||
|
||||
public abstract class ScreenshotHasherService extends android.app.Service {
|
||||
ctor public ScreenshotHasherService();
|
||||
method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent);
|
||||
method @Nullable public abstract android.service.screenshot.ScreenshotHash onGenerateScreenshotHash(@NonNull byte[], @NonNull android.hardware.HardwareBuffer, @NonNull android.graphics.Rect, @NonNull String);
|
||||
method public abstract boolean onVerifyScreenshotHash(@NonNull byte[], @NonNull android.service.screenshot.ScreenshotHash);
|
||||
field public static final String SERVICE_INTERFACE = "android.service.screenshot.ScreenshotHasherService";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
package android.service.search {
|
||||
|
||||
public abstract class SearchUiService extends android.app.Service {
|
||||
@@ -14399,6 +14387,21 @@ package android.view.contentcapture {
|
||||
|
||||
}
|
||||
|
||||
package android.view.displayhash {
|
||||
|
||||
public final class DisplayHash implements android.os.Parcelable {
|
||||
ctor public DisplayHash(long, @NonNull android.graphics.Rect, @NonNull String, @NonNull byte[], @NonNull byte[]);
|
||||
method public int describeContents();
|
||||
method @NonNull public android.graphics.Rect getBoundsInWindow();
|
||||
method @NonNull public String getHashAlgorithm();
|
||||
method @NonNull public byte[] getHmac();
|
||||
method @NonNull public byte[] getImageHash();
|
||||
method public long getTimeMillis();
|
||||
method public void writeToParcel(@NonNull android.os.Parcel, int);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
package android.view.translation {
|
||||
|
||||
public final class UiTranslationManager {
|
||||
|
||||
@@ -211,6 +211,7 @@ import android.view.autofill.AutofillManager;
|
||||
import android.view.autofill.IAutoFillManager;
|
||||
import android.view.contentcapture.ContentCaptureManager;
|
||||
import android.view.contentcapture.IContentCaptureManager;
|
||||
import android.view.displayhash.DisplayHashManager;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.view.textclassifier.TextClassificationManager;
|
||||
import android.view.textservice.TextServicesManager;
|
||||
@@ -1426,6 +1427,13 @@ public final class SystemServiceRegistry {
|
||||
}
|
||||
});
|
||||
|
||||
registerService(Context.DISPLAY_HASH_SERVICE, DisplayHashManager.class,
|
||||
new CachedServiceFetcher<DisplayHashManager>() {
|
||||
@Override
|
||||
public DisplayHashManager createService(ContextImpl ctx) {
|
||||
return new DisplayHashManager();
|
||||
}});
|
||||
|
||||
sInitializing = true;
|
||||
try {
|
||||
// Note: the following functions need to be @SystemApis, once they become mainline
|
||||
|
||||
@@ -5490,6 +5490,14 @@ public abstract class Context {
|
||||
@SystemApi
|
||||
public static final String DOMAIN_VERIFICATION_SERVICE = "domain_verification";
|
||||
|
||||
/**
|
||||
* Use with {@link #getSystemService(String)} to access
|
||||
* {@link android.view.displayhash.DisplayHashManager} to handle display hashes.
|
||||
*
|
||||
* @see #getSystemService(String)
|
||||
*/
|
||||
public static final String DISPLAY_HASH_SERVICE = "display_hash";
|
||||
|
||||
/**
|
||||
* Determine whether the given permission is allowed for a particular
|
||||
* process and user ID running in the system.
|
||||
|
||||
168
core/java/android/service/displayhash/DisplayHasherService.java
Normal file
168
core/java/android/service/displayhash/DisplayHasherService.java
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.service.displayhash;
|
||||
|
||||
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Rect;
|
||||
import android.hardware.HardwareBuffer;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.RemoteCallback;
|
||||
import android.view.displayhash.DisplayHash;
|
||||
import android.view.displayhash.DisplayHashResultCallback;
|
||||
import android.view.displayhash.VerifiedDisplayHash;
|
||||
|
||||
/**
|
||||
* A service that handles generating and verify {@link DisplayHash}.
|
||||
*
|
||||
* The service will generate a DisplayHash based on arguments passed in. Then later that
|
||||
* same DisplayHash can be verified to determine that it was created by the system.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public abstract class DisplayHasherService extends Service {
|
||||
|
||||
/** @hide **/
|
||||
public static final String EXTRA_VERIFIED_DISPLAY_HASH =
|
||||
"android.service.displayhash.extra.VERIFIED_DISPLAY_HASH";
|
||||
|
||||
/**
|
||||
* Manifest metadata key for the resource string array containing the names of all hashing
|
||||
* algorithms provided by the service.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final String SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS =
|
||||
"android.displayhash.available_algorithms";
|
||||
|
||||
/**
|
||||
* The {@link Intent} action that must be declared as handled by a service in its manifest
|
||||
* for the system to recognize it as a DisplayHash providing service.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public static final String SERVICE_INTERFACE =
|
||||
"android.service.displayhash.DisplayHasherService";
|
||||
|
||||
private DisplayHasherServiceWrapper mWrapper;
|
||||
private Handler mHandler;
|
||||
|
||||
public DisplayHasherService() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
mWrapper = new DisplayHasherServiceWrapper();
|
||||
mHandler = new Handler(Looper.getMainLooper(), null, true);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public final IBinder onBind(@NonNull Intent intent) {
|
||||
return mWrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the DisplayHash that can be used to validate that the system generated the
|
||||
* token.
|
||||
*
|
||||
* @param salt The salt to use when generating the hmac. This should be unique to the
|
||||
* caller so the token cannot be verified by any other process.
|
||||
* @param buffer The buffer for the content to generate the hash for.
|
||||
* @param bounds The size and position of the content in window space.
|
||||
* @param hashAlgorithm The String for the hashing algorithm to use based values in
|
||||
* {@link #SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS)}.
|
||||
* @param callback The callback to invoke
|
||||
* {@link DisplayHashResultCallback#onDisplayHashResult(DisplayHash)}
|
||||
* if successfully generated a DisplayHash or {@link
|
||||
* DisplayHashResultCallback#onDisplayHashError(int)} if failed.
|
||||
*/
|
||||
@Nullable
|
||||
public abstract void onGenerateDisplayHash(@NonNull byte[] salt,
|
||||
@NonNull HardwareBuffer buffer, @NonNull Rect bounds,
|
||||
@NonNull String hashAlgorithm, @NonNull DisplayHashResultCallback callback);
|
||||
|
||||
/**
|
||||
* Call to verify that the DisplayHash passed in was generated by the system.
|
||||
*
|
||||
* @param salt The salt value to use when verifying the hmac. This should be the
|
||||
* same value that was passed to
|
||||
* {@link #onGenerateDisplayHash(byte[],
|
||||
* HardwareBuffer, Rect, String, DisplayHashResultCallback)} to
|
||||
* generate the token.
|
||||
* @param displayHash The token to verify that it was generated by the system.
|
||||
* @return a {@link VerifiedDisplayHash} if the token was generated by the system or null
|
||||
* if the token cannot be verified.
|
||||
*/
|
||||
@Nullable
|
||||
public abstract VerifiedDisplayHash onVerifyDisplayHash(@NonNull byte[] salt,
|
||||
@NonNull DisplayHash displayHash);
|
||||
|
||||
private void verifyDisplayHash(byte[] salt, DisplayHash displayHash,
|
||||
RemoteCallback callback) {
|
||||
VerifiedDisplayHash verifiedDisplayHash = onVerifyDisplayHash(salt,
|
||||
displayHash);
|
||||
final Bundle data = new Bundle();
|
||||
data.putParcelable(EXTRA_VERIFIED_DISPLAY_HASH, verifiedDisplayHash);
|
||||
callback.sendResult(data);
|
||||
}
|
||||
|
||||
private final class DisplayHasherServiceWrapper extends IDisplayHasherService.Stub {
|
||||
@Override
|
||||
public void generateDisplayHash(byte[] salt, HardwareBuffer buffer, Rect bounds,
|
||||
String hashAlgorithm, RemoteCallback callback) {
|
||||
mHandler.sendMessage(
|
||||
obtainMessage(DisplayHasherService::onGenerateDisplayHash,
|
||||
DisplayHasherService.this, salt, buffer, bounds,
|
||||
hashAlgorithm, new DisplayHashResultCallback() {
|
||||
@Override
|
||||
public void onDisplayHashResult(
|
||||
@NonNull DisplayHash displayHash) {
|
||||
Bundle result = new Bundle();
|
||||
result.putParcelable(EXTRA_DISPLAY_HASH, displayHash);
|
||||
callback.sendResult(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisplayHashError(int errorCode) {
|
||||
Bundle result = new Bundle();
|
||||
result.putInt(EXTRA_DISPLAY_HASH_ERROR_CODE, errorCode);
|
||||
callback.sendResult(result);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void verifyDisplayHash(byte[] salt, DisplayHash displayHash,
|
||||
RemoteCallback callback) {
|
||||
mHandler.sendMessage(
|
||||
obtainMessage(DisplayHasherService::verifyDisplayHash,
|
||||
DisplayHasherService.this, salt, displayHash, callback));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,43 +14,41 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.service.screenshot;
|
||||
package android.service.displayhash;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.hardware.HardwareBuffer;
|
||||
import android.os.RemoteCallback;
|
||||
import android.service.screenshot.ScreenshotHash;
|
||||
import android.view.displayhash.DisplayHash;
|
||||
|
||||
/**
|
||||
* Service used to handle ScreenshotHash requests.
|
||||
* Service used to handle DisplayHash requests.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
oneway interface IScreenshotHasherService {
|
||||
oneway interface IDisplayHasherService {
|
||||
/**
|
||||
* Generates the ScreenshotHash token that can be used to validate that the system generated the
|
||||
* token.
|
||||
* Generates the DisplayHash that can be used to validate that the system generated the token.
|
||||
*
|
||||
* @param salt The salt to use when generating the hmac. This should be unique to the caller so
|
||||
* the token cannot be verified by any other process.
|
||||
* @param screenshot The screenshot to generate the hash and add to the token.
|
||||
* @param bounds The size and position of the content being screenshot in the window.
|
||||
* @param hashAlgorithm The String for the hashing algorithm to use based on values in
|
||||
* @param buffer The buffer to generate the hash for.
|
||||
* @param bounds The size and position of the content being hashed in window space.
|
||||
* @param hashAlgorithm The String for the hash algorithm to use based on values in
|
||||
* {@link #SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS}.
|
||||
* @param Callback The callback invoked to send back the ScreenshotHash token.
|
||||
* @param Callback The callback invoked to send back the DisplayHash.
|
||||
*/
|
||||
void generateScreenshotHash(in byte[] salt, in HardwareBuffer screenshot, in Rect bounds,
|
||||
void generateDisplayHash(in byte[] salt, in HardwareBuffer buffer, in Rect bounds,
|
||||
in String hashAlgorithm, in RemoteCallback callback);
|
||||
|
||||
/**
|
||||
* Call to verify that the ScreenshotHash passed in was generated by the system. The result
|
||||
* will be sent in the callback as a boolean with the key {@link #EXTRA_VERIFICATION_STATUS}.
|
||||
* Call to verify that the DisplayHash passed in was generated by the system. The result
|
||||
* will be sent in the callback as a boolean with the key {@link #EXTRA_VERIFIED_DISPLAY_HASH}.
|
||||
*
|
||||
* @param salt The salt value to use when verifying the hmac. This should be the same value that
|
||||
* was passed to {@link generateScreenshotHash()} to generate the token.
|
||||
* @param screenshotHash The hash to verify that it was generated by the system.
|
||||
* @param callback The callback invoked to send back the verification status.
|
||||
* was passed to {@link generateDisplayHash()} to generate the DisplayHash.
|
||||
* @param displayHash The hash to verify that it was generated by the system.
|
||||
* @param callback The callback invoked to send back the VerifiedDisplayHash.
|
||||
*/
|
||||
void verifyScreenshotHash(in byte[] salt, in ScreenshotHash screenshotHash,
|
||||
in RemoteCallback callback);
|
||||
void verifyDisplayHash(in byte[] salt, in DisplayHash displayHash, in RemoteCallback callback);
|
||||
}
|
||||
@@ -1,256 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.service.screenshot;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SystemApi;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.android.internal.util.DataClass;
|
||||
|
||||
/**
|
||||
* The screenshot hash used to validate information about what was present on screen.
|
||||
* @hide
|
||||
*
|
||||
* TODO: Remove hide and SystemAPI since this will be a public class
|
||||
*/
|
||||
@SystemApi
|
||||
@DataClass(genToString = true, genAidl = true)
|
||||
public final class ScreenshotHash implements Parcelable {
|
||||
/**
|
||||
* The timestamp when the screenshot was generated.
|
||||
*/
|
||||
private final long mScreenshotTimeMillis;
|
||||
|
||||
/**
|
||||
* The bounds of the requested area to take the screenshot. This is in window space passed in
|
||||
* by the client.
|
||||
*/
|
||||
@NonNull
|
||||
private final Rect mBoundsInWindow;
|
||||
|
||||
/**
|
||||
* The selected hashing algorithm that generated the image hash.
|
||||
*/
|
||||
@NonNull
|
||||
private final String mHashingAlgorithm;
|
||||
|
||||
/**
|
||||
* The image hash generated when creating the ScreenshotHash from the screenshot taken.
|
||||
*/
|
||||
@NonNull
|
||||
private final byte[] mImageHash;
|
||||
|
||||
/**
|
||||
* The hmac generated by the system and used to verify whether this token was generated by
|
||||
* the system. This should only be accessed by a system process.
|
||||
*/
|
||||
@NonNull
|
||||
private final byte[] mHmac;
|
||||
|
||||
/**
|
||||
* The hmac generated by the system and used to verify whether this token was generated by
|
||||
* the system. This should only be accessed by a system process.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@NonNull
|
||||
public byte[] getHmac() {
|
||||
return mHmac;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Code below generated by codegen v1.0.22.
|
||||
//
|
||||
// DO NOT MODIFY!
|
||||
// CHECKSTYLE:OFF Generated code
|
||||
//
|
||||
// To regenerate run:
|
||||
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/screenshot
|
||||
// /ScreenshotHash.java
|
||||
//
|
||||
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
|
||||
// Settings > Editor > Code Style > Formatter Control
|
||||
//@formatter:off
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new ScreenshotHash.
|
||||
*
|
||||
* @param screenshotTimeMillis
|
||||
* The timestamp when the screenshot was generated.
|
||||
* @param boundsInWindow
|
||||
* The bounds of the requested area to take the screenshot. This is in window space passed in
|
||||
* by the client.
|
||||
* @param hashingAlgorithm
|
||||
* The selected hashing algorithm that generated the image hash.
|
||||
* @param imageHash
|
||||
* The image hash generated when creating the ScreenshotHash from the screenshot taken.
|
||||
* @param hmac
|
||||
* The hmac generated by the system and used to verify whether this token was generated by
|
||||
* the system. This should only be accessed by a system process.
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public ScreenshotHash(
|
||||
long screenshotTimeMillis,
|
||||
@NonNull Rect boundsInWindow,
|
||||
@NonNull String hashingAlgorithm,
|
||||
@NonNull byte[] imageHash,
|
||||
@NonNull byte[] hmac) {
|
||||
this.mScreenshotTimeMillis = screenshotTimeMillis;
|
||||
this.mBoundsInWindow = boundsInWindow;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mBoundsInWindow);
|
||||
this.mHashingAlgorithm = hashingAlgorithm;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mHashingAlgorithm);
|
||||
this.mImageHash = imageHash;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mImageHash);
|
||||
this.mHmac = hmac;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mHmac);
|
||||
|
||||
// onConstructed(); // You can define this method to get a callback
|
||||
}
|
||||
|
||||
/**
|
||||
* The timestamp when the screenshot was generated.
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public long getScreenshotTimeMillis() {
|
||||
return mScreenshotTimeMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* The bounds of the requested area to take the screenshot. This is in window space passed in
|
||||
* by the client.
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @NonNull Rect getBoundsInWindow() {
|
||||
return mBoundsInWindow;
|
||||
}
|
||||
|
||||
/**
|
||||
* The selected hashing algorithm that generated the image hash.
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @NonNull String getHashingAlgorithm() {
|
||||
return mHashingAlgorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* The image hash generated when creating the ScreenshotHash from the screenshot taken.
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @NonNull byte[] getImageHash() {
|
||||
return mImageHash;
|
||||
}
|
||||
|
||||
@Override
|
||||
@DataClass.Generated.Member
|
||||
public String toString() {
|
||||
// You can override field toString logic by defining methods like:
|
||||
// String fieldNameToString() { ... }
|
||||
|
||||
return "ScreenshotHash { " +
|
||||
"screenshotTimeMillis = " + mScreenshotTimeMillis + ", " +
|
||||
"boundsInWindow = " + mBoundsInWindow + ", " +
|
||||
"hashingAlgorithm = " + mHashingAlgorithm + ", " +
|
||||
"imageHash = " + java.util.Arrays.toString(mImageHash) + ", " +
|
||||
"hmac = " + java.util.Arrays.toString(mHmac) +
|
||||
" }";
|
||||
}
|
||||
|
||||
@Override
|
||||
@DataClass.Generated.Member
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
// You can override field parcelling by defining methods like:
|
||||
// void parcelFieldName(Parcel dest, int flags) { ... }
|
||||
|
||||
dest.writeLong(mScreenshotTimeMillis);
|
||||
dest.writeTypedObject(mBoundsInWindow, flags);
|
||||
dest.writeString(mHashingAlgorithm);
|
||||
dest.writeByteArray(mImageHash);
|
||||
dest.writeByteArray(mHmac);
|
||||
}
|
||||
|
||||
@Override
|
||||
@DataClass.Generated.Member
|
||||
public int describeContents() { return 0; }
|
||||
|
||||
/** @hide */
|
||||
@SuppressWarnings({"unchecked", "RedundantCast"})
|
||||
@DataClass.Generated.Member
|
||||
/* package-private */ ScreenshotHash(@NonNull Parcel in) {
|
||||
// You can override field unparcelling by defining methods like:
|
||||
// static FieldType unparcelFieldName(Parcel in) { ... }
|
||||
|
||||
long screenshotTimeMillis = in.readLong();
|
||||
Rect boundsInWindow = (Rect) in.readTypedObject(Rect.CREATOR);
|
||||
String hashingAlgorithm = in.readString();
|
||||
byte[] imageHash = in.createByteArray();
|
||||
byte[] hmac = in.createByteArray();
|
||||
|
||||
this.mScreenshotTimeMillis = screenshotTimeMillis;
|
||||
this.mBoundsInWindow = boundsInWindow;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mBoundsInWindow);
|
||||
this.mHashingAlgorithm = hashingAlgorithm;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mHashingAlgorithm);
|
||||
this.mImageHash = imageHash;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mImageHash);
|
||||
this.mHmac = hmac;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mHmac);
|
||||
|
||||
// onConstructed(); // You can define this method to get a callback
|
||||
}
|
||||
|
||||
@DataClass.Generated.Member
|
||||
public static final @NonNull Parcelable.Creator<ScreenshotHash> CREATOR
|
||||
= new Parcelable.Creator<ScreenshotHash>() {
|
||||
@Override
|
||||
public ScreenshotHash[] newArray(int size) {
|
||||
return new ScreenshotHash[size];
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScreenshotHash createFromParcel(@NonNull Parcel in) {
|
||||
return new ScreenshotHash(in);
|
||||
}
|
||||
};
|
||||
|
||||
@DataClass.Generated(
|
||||
time = 1612383172822L,
|
||||
codegenVersion = "1.0.22",
|
||||
sourceFile = "frameworks/base/core/java/android/service/screenshot/ScreenshotHash.java",
|
||||
inputSignatures = "private final long mScreenshotTimeMillis\nprivate final @android.annotation.NonNull android.graphics.Rect mBoundsInWindow\nprivate final @android.annotation.NonNull java.lang.String mHashingAlgorithm\nprivate final @android.annotation.NonNull byte[] mImageHash\nprivate final @android.annotation.NonNull byte[] mHmac\npublic @android.annotation.SystemApi @android.annotation.NonNull byte[] getHmac()\nclass ScreenshotHash extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genAidl=true)")
|
||||
@Deprecated
|
||||
private void __metadata() {}
|
||||
|
||||
|
||||
//@formatter:on
|
||||
// End of generated code
|
||||
|
||||
}
|
||||
@@ -1,160 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.service.screenshot;
|
||||
|
||||
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemApi;
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Rect;
|
||||
import android.hardware.HardwareBuffer;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.RemoteCallback;
|
||||
|
||||
/**
|
||||
* A service that handles generating and verify {@link ScreenshotHash}.
|
||||
*
|
||||
* The service will generate a ScreenshotHash based on arguments passed in. Then later that
|
||||
* same ScreenshotHash can be verified to determine that it was created by the system.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public abstract class ScreenshotHasherService extends Service {
|
||||
/** @hide **/
|
||||
public static final String EXTRA_SCREENSHOT_HASH =
|
||||
"android.service.screenshot.extra.SCREENSHOT_HASH";
|
||||
|
||||
/** @hide **/
|
||||
public static final String EXTRA_VERIFICATION_STATUS =
|
||||
"android.service.screenshot.extra.VERIFICATION_STATUS";
|
||||
|
||||
/**
|
||||
* Manifest metadata key for the resource string array containing the names of all hashing
|
||||
* algorithms provided by the service.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final String SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS =
|
||||
"android.screenshot.available_algorithms";
|
||||
|
||||
/**
|
||||
* The {@link Intent} action that must be declared as handled by a service in its manifest
|
||||
* for the system to recognize it as a ScreenshotHash providing service.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public static final String SERVICE_INTERFACE =
|
||||
"android.service.screenshot.ScreenshotHasherService";
|
||||
|
||||
private ScreenshotHasherServiceWrapper mWrapper;
|
||||
private Handler mHandler;
|
||||
|
||||
public ScreenshotHasherService() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
mWrapper = new ScreenshotHasherServiceWrapper();
|
||||
mHandler = new Handler(Looper.getMainLooper(), null, true);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public final IBinder onBind(@NonNull Intent intent) {
|
||||
return mWrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the ScreenshotHash that can be used to validate that the system generated the
|
||||
* token.
|
||||
*
|
||||
* @param salt The salt to use when generating the hmac. This should be unique to the
|
||||
* caller so the token cannot be verified by any other process.
|
||||
* @param screenshot The screenshot buffer for the content.
|
||||
* @param bounds The size and position of the content being screenshot in the window.
|
||||
* @param hashAlgorithm The String for the hashing algorithm to use based values in
|
||||
* {@link #SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS)}.
|
||||
* @return A ScreenshotHash that can be used to validate information about the content.
|
||||
* Returns null when the arguments sent are invalid.
|
||||
*/
|
||||
@Nullable
|
||||
public abstract ScreenshotHash onGenerateScreenshotHash(@NonNull byte[] salt,
|
||||
@NonNull HardwareBuffer screenshot, @NonNull Rect bounds,
|
||||
@NonNull String hashAlgorithm);
|
||||
|
||||
/**
|
||||
* Call to verify that the ScreenshotHash passed in was generated by the system.
|
||||
*
|
||||
* @param salt The salt value to use when verifying the hmac. This should be the
|
||||
* same value that was passed to
|
||||
* {@link #onGenerateScreenshotHash(byte[],
|
||||
* HardwareBuffer, Rect, String)} to
|
||||
* generate the token.
|
||||
* @param screenshotHash The token to verify that it was generated by the system.
|
||||
* @return true if the token can be verified that it was generated by the system.
|
||||
*/
|
||||
public abstract boolean onVerifyScreenshotHash(@NonNull byte[] salt,
|
||||
@NonNull ScreenshotHash screenshotHash);
|
||||
|
||||
private void generateScreenshotHash(byte[] salt, HardwareBuffer screenshot, Rect bounds,
|
||||
String hashAlgorithm, RemoteCallback callback) {
|
||||
ScreenshotHash screenshotHash = onGenerateScreenshotHash(salt, screenshot,
|
||||
bounds,
|
||||
hashAlgorithm);
|
||||
final Bundle data = new Bundle();
|
||||
data.putParcelable(EXTRA_SCREENSHOT_HASH, screenshotHash);
|
||||
callback.sendResult(data);
|
||||
}
|
||||
|
||||
private void verifyScreenshotHash(byte[] salt, ScreenshotHash screenshotHash,
|
||||
RemoteCallback callback) {
|
||||
boolean verificationStatus = onVerifyScreenshotHash(salt, screenshotHash);
|
||||
final Bundle data = new Bundle();
|
||||
data.putBoolean(EXTRA_VERIFICATION_STATUS, verificationStatus);
|
||||
callback.sendResult(data);
|
||||
}
|
||||
|
||||
private final class ScreenshotHasherServiceWrapper extends
|
||||
IScreenshotHasherService.Stub {
|
||||
@Override
|
||||
public void generateScreenshotHash(byte[] salt, HardwareBuffer screenshot, Rect bounds,
|
||||
String hashAlgorithm, RemoteCallback callback) {
|
||||
mHandler.sendMessage(
|
||||
obtainMessage(ScreenshotHasherService::generateScreenshotHash,
|
||||
ScreenshotHasherService.this, salt, screenshot, bounds,
|
||||
hashAlgorithm, callback));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void verifyScreenshotHash(byte[] salt, ScreenshotHash screenshotHash,
|
||||
RemoteCallback callback) {
|
||||
mHandler.sendMessage(
|
||||
obtainMessage(ScreenshotHasherService::verifyScreenshotHash,
|
||||
ScreenshotHasherService.this, salt, screenshotHash,
|
||||
callback));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,6 @@ import android.graphics.Region;
|
||||
import android.os.Bundle;
|
||||
import android.os.IRemoteCallback;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.service.screenshot.ScreenshotHash;
|
||||
import android.view.DisplayCutout;
|
||||
import android.view.IApplicationToken;
|
||||
import android.view.IAppTransitionAnimationSpecsFuture;
|
||||
@@ -63,6 +62,8 @@ import android.view.AppTransitionAnimationSpec;
|
||||
import android.view.WindowContentFrameStats;
|
||||
import android.view.WindowManager;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.displayhash.DisplayHash;
|
||||
import android.view.displayhash.VerifiedDisplayHash;
|
||||
|
||||
/**
|
||||
* System private interface to the window manager.
|
||||
@@ -757,23 +758,23 @@ interface IWindowManager
|
||||
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 ScreenshotHash.
|
||||
* Gets an array of support hash algorithms that can be used to generate a DisplayHash. The
|
||||
* String value of one algorithm should be used when requesting to generate
|
||||
* the DisplayHash.
|
||||
*
|
||||
* @return a String array of supported hashing algorithms.
|
||||
* @return a String array of supported hash algorithms.
|
||||
*/
|
||||
String[] getSupportedScreenshotHashingAlgorithms();
|
||||
String[] getSupportedDisplayHashAlgorithms();
|
||||
|
||||
/**
|
||||
* Validate the ScreenshotHash was generated by the system. The ScreenshotHash passed in
|
||||
* should be the token generated when calling {@link IWindowSession#generateScreenshotHash}
|
||||
* Validate the DisplayHash was generated by the system. The DisplayHash passed in should be
|
||||
* the object generated when calling {@link IWindowSession#generateDisplayHash}
|
||||
*
|
||||
* @param ScreenshotHash 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.
|
||||
* @param DisplayHash The hash to verify that it was generated by the system.
|
||||
* @return a {@link VerifiedDisplayHash} if the hash was generated by the system or null
|
||||
* if the token cannot be verified.
|
||||
*/
|
||||
boolean verifyScreenshotHash(in ScreenshotHash screenshotHash);
|
||||
VerifiedDisplayHash verifyDisplayHash(in DisplayHash displayHash);
|
||||
|
||||
/**
|
||||
* Registers a listener for a {@link android.app.WindowContext} to handle configuration changes
|
||||
|
||||
@@ -22,7 +22,7 @@ import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Region;
|
||||
import android.os.Bundle;
|
||||
import android.service.screenshot.ScreenshotHash;
|
||||
import android.os.RemoteCallback;
|
||||
import android.util.MergedConfiguration;
|
||||
import android.view.DisplayCutout;
|
||||
import android.view.InputChannel;
|
||||
@@ -337,14 +337,15 @@ interface IWindowSession {
|
||||
void grantEmbeddedWindowFocus(IWindow window, in IBinder inputToken, boolean grantFocus);
|
||||
|
||||
/**
|
||||
* Generates an ScreenshotHash that can be used to validate whether specific content was on
|
||||
* Generates an DisplayHash that can be used to validate whether specific content was on
|
||||
* screen.
|
||||
*
|
||||
* @param window The token for the window where the view to screenshot 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#getSupportedHashingAlgorithms()}
|
||||
* @param window The token for the window to generate the hash of.
|
||||
* @param boundsInWindow The size and position in the window of where to generate the hash.
|
||||
* @param hashAlgorithm The String for the hash algorithm to use based on values returned
|
||||
* from {@link IWindowManager#getSupportedDisplayHashAlgorithms()}
|
||||
* @param callback The callback invoked to get the results of generateDisplayHash
|
||||
*/
|
||||
ScreenshotHash generateScreenshotHash(IWindow window, in Rect boundsInWindow,
|
||||
in String hashAlgorithm);
|
||||
oneway void generateDisplayHash(IWindow window, in Rect boundsInWindow,
|
||||
in String hashAlgorithm, in RemoteCallback callback);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,12 @@ package android.view;
|
||||
|
||||
import static android.content.res.Resources.ID_NULL;
|
||||
import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED;
|
||||
import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_INVALID_BOUNDS;
|
||||
import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_MISSING_WINDOW;
|
||||
import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN;
|
||||
import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_UNKNOWN;
|
||||
import static android.view.displayhash.DisplayHashResultCallback.EXTRA_DISPLAY_HASH;
|
||||
import static android.view.displayhash.DisplayHashResultCallback.EXTRA_DISPLAY_HASH_ERROR_CODE;
|
||||
|
||||
import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DEEP_PRESS;
|
||||
import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS;
|
||||
@@ -89,6 +95,7 @@ import android.os.IBinder;
|
||||
import android.os.Message;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.RemoteCallback;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.os.Trace;
|
||||
@@ -135,6 +142,9 @@ import android.view.autofill.AutofillValue;
|
||||
import android.view.contentcapture.ContentCaptureContext;
|
||||
import android.view.contentcapture.ContentCaptureManager;
|
||||
import android.view.contentcapture.ContentCaptureSession;
|
||||
import android.view.displayhash.DisplayHash;
|
||||
import android.view.displayhash.DisplayHashManager;
|
||||
import android.view.displayhash.DisplayHashResultCallback;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.view.inputmethod.InputConnection;
|
||||
import android.view.inspector.InspectableProperty;
|
||||
@@ -176,6 +186,7 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@@ -30707,4 +30718,71 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
public void onTranslationComplete(@NonNull TranslationRequest request) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to generate a {@link DisplayHash} for this view.
|
||||
*
|
||||
* @param hashAlgorithm The hash algorithm to use when hashing the display. Must be one of
|
||||
* the values returned from
|
||||
* {@link DisplayHashManager#getSupportedHashAlgorithms()}
|
||||
* @param bounds The bounds for the content within the View to generate the hash for. If
|
||||
* bounds are null, the entire View's bounds will be used. If empty, it will
|
||||
* invoke the callback
|
||||
* {@link DisplayHashResultCallback#onDisplayHashError} with error
|
||||
* {@link DisplayHashResultCallback#DISPLAY_HASH_ERROR_INVALID_BOUNDS}
|
||||
* @param executor The executor that the callback should be invoked on.
|
||||
* @param callback The callback to handle the results of generating the display hash
|
||||
*/
|
||||
@Nullable
|
||||
public void generateDisplayHash(@NonNull String hashAlgorithm,
|
||||
@Nullable Rect bounds, @NonNull Executor executor,
|
||||
@NonNull DisplayHashResultCallback callback) {
|
||||
IWindowSession session = getWindowSession();
|
||||
if (session == null) {
|
||||
callback.onDisplayHashError(DISPLAY_HASH_ERROR_MISSING_WINDOW);
|
||||
return;
|
||||
}
|
||||
IWindow window = getWindow();
|
||||
if (window == null) {
|
||||
callback.onDisplayHashError(DISPLAY_HASH_ERROR_MISSING_WINDOW);
|
||||
return;
|
||||
}
|
||||
|
||||
Rect visibleBounds = new Rect();
|
||||
getGlobalVisibleRect(visibleBounds);
|
||||
|
||||
if (bounds != null && bounds.isEmpty()) {
|
||||
callback.onDisplayHashError(DISPLAY_HASH_ERROR_INVALID_BOUNDS);
|
||||
return;
|
||||
}
|
||||
|
||||
if (bounds != null) {
|
||||
bounds.offset(visibleBounds.left, visibleBounds.top);
|
||||
visibleBounds.intersectUnchecked(bounds);
|
||||
}
|
||||
|
||||
if (visibleBounds.isEmpty()) {
|
||||
callback.onDisplayHashError(DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN);
|
||||
return;
|
||||
}
|
||||
|
||||
RemoteCallback remoteCallback = new RemoteCallback(result ->
|
||||
executor.execute(() -> {
|
||||
DisplayHash displayHash = result.getParcelable(EXTRA_DISPLAY_HASH);
|
||||
int errorCode = result.getInt(EXTRA_DISPLAY_HASH_ERROR_CODE,
|
||||
DISPLAY_HASH_ERROR_UNKNOWN);
|
||||
if (displayHash != null) {
|
||||
callback.onDisplayHashResult(displayHash);
|
||||
} else {
|
||||
callback.onDisplayHashError(errorCode);
|
||||
}
|
||||
}));
|
||||
|
||||
try {
|
||||
session.generateDisplayHash(window, visibleBounds, hashAlgorithm, remoteCallback);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(VIEW_LOG_TAG, "Failed to call generateDisplayHash");
|
||||
callback.onDisplayHashError(DISPLAY_HASH_ERROR_UNKNOWN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +23,8 @@ import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Region;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteCallback;
|
||||
import android.os.RemoteException;
|
||||
import android.service.screenshot.ScreenshotHash;
|
||||
import android.util.Log;
|
||||
import android.util.MergedConfiguration;
|
||||
import android.window.ClientWindowFrames;
|
||||
@@ -487,8 +487,7 @@ public class WindowlessWindowManager implements IWindowSession {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScreenshotHash generateScreenshotHash(IWindow window, Rect boundsInWindow,
|
||||
String hashAlgorithm) {
|
||||
return null;
|
||||
public void generateDisplayHash(IWindow window, Rect boundsInWindow, String hashAlgorithm,
|
||||
RemoteCallback callback) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -14,6 +14,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.service.screenshot;
|
||||
package android.view.displayhash;
|
||||
|
||||
parcelable ScreenshotHash;
|
||||
parcelable DisplayHash;
|
||||
226
core/java/android/view/displayhash/DisplayHash.java
Normal file
226
core/java/android/view/displayhash/DisplayHash.java
Normal file
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.view.displayhash;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SystemApi;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.android.internal.util.AnnotationValidations;
|
||||
|
||||
/**
|
||||
* The DisplayHash used to validate information about what was present on screen.
|
||||
*/
|
||||
public final class DisplayHash implements Parcelable {
|
||||
/**
|
||||
* The timestamp when the hash was generated.
|
||||
*/
|
||||
private final long mTimeMillis;
|
||||
|
||||
/**
|
||||
* The bounds of the requested area to generate the hash. This is in window space passed in
|
||||
* by the client.
|
||||
*/
|
||||
@NonNull
|
||||
private final Rect mBoundsInWindow;
|
||||
|
||||
/**
|
||||
* The selected hash algorithm that generated the image hash.
|
||||
*/
|
||||
@NonNull
|
||||
private final String mHashAlgorithm;
|
||||
|
||||
/**
|
||||
* The image hash generated when creating the DisplayHash.
|
||||
*/
|
||||
@NonNull
|
||||
private final byte[] mImageHash;
|
||||
|
||||
/**
|
||||
* The hmac generated by the system and used to verify whether this token was generated by
|
||||
* the system.
|
||||
*/
|
||||
@NonNull
|
||||
private final byte[] mHmac;
|
||||
|
||||
/**
|
||||
* Creates a new DisplayHash.
|
||||
*
|
||||
* @param timeMillis The timestamp when the hash was generated.
|
||||
* @param boundsInWindow The bounds of the requested area to generate the hash. This is
|
||||
* in window space passed in by the client.
|
||||
* @param hashAlgorithm The selected hash algorithm that generated the image hash.
|
||||
* @param imageHash The image hash generated when creating the DisplayHash.
|
||||
* @param hmac The hmac generated by the system and used to verify whether this
|
||||
* token was generated by
|
||||
* the system. This should only be accessed by a system process.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public DisplayHash(long timeMillis, @NonNull Rect boundsInWindow,
|
||||
@NonNull String hashAlgorithm, @NonNull byte[] imageHash, @NonNull byte[] hmac) {
|
||||
mTimeMillis = timeMillis;
|
||||
mBoundsInWindow = boundsInWindow;
|
||||
AnnotationValidations.validate(NonNull.class, null, mBoundsInWindow);
|
||||
mHashAlgorithm = hashAlgorithm;
|
||||
AnnotationValidations.validate(NonNull.class, null, mHashAlgorithm);
|
||||
mImageHash = imageHash;
|
||||
AnnotationValidations.validate(NonNull.class, null, mImageHash);
|
||||
mHmac = hmac;
|
||||
AnnotationValidations.validate(NonNull.class, null, mHmac);
|
||||
}
|
||||
|
||||
/**
|
||||
* The timestamp when the hash was generated.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public long getTimeMillis() {
|
||||
return mTimeMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* The bounds of the requested area to to generate the hash. This is in window space passed in
|
||||
* by the client.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@NonNull
|
||||
public Rect getBoundsInWindow() {
|
||||
return mBoundsInWindow;
|
||||
}
|
||||
|
||||
/**
|
||||
* The selected hash algorithm that generated the image hash.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@NonNull
|
||||
public String getHashAlgorithm() {
|
||||
return mHashAlgorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* The image hash generated when creating the DisplayHash.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@NonNull
|
||||
public byte[] getImageHash() {
|
||||
return mImageHash;
|
||||
}
|
||||
|
||||
/**
|
||||
* The hmac generated by the system and used to verify whether this token was generated by
|
||||
* the system. This should only be accessed by a system process.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
@NonNull
|
||||
public byte[] getHmac() {
|
||||
return mHmac;
|
||||
}
|
||||
|
||||
/** @hide **/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DisplayHash { "
|
||||
+ "timeMillis = " + mTimeMillis + ", "
|
||||
+ "boundsInWindow = " + mBoundsInWindow + ", "
|
||||
+ "hashAlgorithm = " + mHashAlgorithm + ", "
|
||||
+ "imageHash = " + byteArrayToString(mImageHash) + ", "
|
||||
+ "hmac = " + byteArrayToString(mHmac)
|
||||
+ " }";
|
||||
}
|
||||
|
||||
private String byteArrayToString(byte[] byteArray) {
|
||||
if (byteArray == null) {
|
||||
return "null";
|
||||
}
|
||||
int iMax = byteArray.length - 1;
|
||||
if (iMax == -1) {
|
||||
return "[]";
|
||||
}
|
||||
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append('[');
|
||||
for (int i = 0; ; i++) {
|
||||
String formatted = String.format("%02X", byteArray[i] & 0xFF);
|
||||
b.append(formatted);
|
||||
if (i == iMax) {
|
||||
return b.append(']').toString();
|
||||
}
|
||||
b.append(", ");
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide **/
|
||||
@SystemApi
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeLong(mTimeMillis);
|
||||
dest.writeTypedObject(mBoundsInWindow, flags);
|
||||
dest.writeString(mHashAlgorithm);
|
||||
dest.writeByteArray(mImageHash);
|
||||
dest.writeByteArray(mHmac);
|
||||
}
|
||||
|
||||
/** @hide **/
|
||||
@SystemApi
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private DisplayHash(@NonNull Parcel in) {
|
||||
mTimeMillis = in.readLong();
|
||||
Rect boundsInWindow = in.readTypedObject(Rect.CREATOR);
|
||||
String hashAlgorithm = in.readString();
|
||||
byte[] imageHash = in.createByteArray();
|
||||
byte[] hmac = in.createByteArray();
|
||||
|
||||
mBoundsInWindow = boundsInWindow;
|
||||
AnnotationValidations.validate(NonNull.class, null, mBoundsInWindow);
|
||||
mHashAlgorithm = hashAlgorithm;
|
||||
AnnotationValidations.validate(NonNull.class, null, mHashAlgorithm);
|
||||
mImageHash = imageHash;
|
||||
AnnotationValidations.validate(NonNull.class, null, mImageHash);
|
||||
mHmac = hmac;
|
||||
AnnotationValidations.validate(NonNull.class, null, mHmac);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static final Parcelable.Creator<DisplayHash> CREATOR =
|
||||
new Parcelable.Creator<DisplayHash>() {
|
||||
@Override
|
||||
public DisplayHash[] newArray(int size) {
|
||||
return new DisplayHash[size];
|
||||
}
|
||||
|
||||
@Override
|
||||
public DisplayHash createFromParcel(@NonNull Parcel in) {
|
||||
return new DisplayHash(in);
|
||||
}
|
||||
};
|
||||
}
|
||||
97
core/java/android/view/displayhash/DisplayHashManager.java
Normal file
97
core/java/android/view/displayhash/DisplayHashManager.java
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.view.displayhash;
|
||||
|
||||
|
||||
import static android.content.Context.DISPLAY_HASH_SERVICE;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SystemService;
|
||||
import android.os.RemoteException;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
import android.view.WindowManagerGlobal;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Utility class for DisplayHash requests.
|
||||
*/
|
||||
@SystemService(DISPLAY_HASH_SERVICE)
|
||||
public final class DisplayHashManager {
|
||||
private static final String TAG = "DisplayHashManager";
|
||||
|
||||
private final Object mSupportedHashingAlgorithmLock = new Object();
|
||||
|
||||
@GuardedBy("mSupportedAlgorithmLock")
|
||||
private static Set<String> sSupportedHashAlgorithms;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public DisplayHashManager() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a Set of DisplayHash algorithms that the device supports.
|
||||
*
|
||||
* @return a String Set of supported hashing algorithms. The String value of one
|
||||
* algorithm should be used when requesting to generate the DisplayHash.
|
||||
*/
|
||||
@NonNull
|
||||
public Set<String> getSupportedHashAlgorithms() {
|
||||
synchronized (mSupportedHashingAlgorithmLock) {
|
||||
if (sSupportedHashAlgorithms != null) {
|
||||
return sSupportedHashAlgorithms;
|
||||
}
|
||||
|
||||
try {
|
||||
String[] supportedAlgorithms = WindowManagerGlobal.getWindowManagerService()
|
||||
.getSupportedDisplayHashAlgorithms();
|
||||
if (supportedAlgorithms == null) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
sSupportedHashAlgorithms = new ArraySet<>(supportedAlgorithms);
|
||||
return sSupportedHashAlgorithms;
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to send request getSupportedHashingAlgorithms", e);
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call to verify that the DisplayHash passed in was generated by the system.
|
||||
*
|
||||
* @param displayHash The hash to verify that it was generated by the system.
|
||||
* @return a {@link VerifiedDisplayHash} if the hash was generated by the system or null
|
||||
* if the hash cannot be verified.
|
||||
*/
|
||||
@Nullable
|
||||
public VerifiedDisplayHash verifyDisplayHash(@NonNull DisplayHash displayHash) {
|
||||
try {
|
||||
return WindowManagerGlobal.getWindowManagerService().verifyDisplayHash(displayHash);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to send request verifyImpressionToken", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.view.displayhash;
|
||||
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.graphics.Rect;
|
||||
import android.view.View;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* Use when calling {@link View#generateDisplayHash(String, Rect, Executor,
|
||||
* DisplayHashResultCallback)}.
|
||||
*
|
||||
* The callback will only invoke either {@link #onDisplayHashResult} when the system successfully
|
||||
* generated the {@link DisplayHash} or {@link #onDisplayHashError(int)} when it failed.
|
||||
*/
|
||||
public interface DisplayHashResultCallback {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
String EXTRA_DISPLAY_HASH = "DISPLAY_HASH";
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
String EXTRA_DISPLAY_HASH_ERROR_CODE = "DISPLAY_HASH_ERROR_CODE";
|
||||
|
||||
/**
|
||||
* An unknown error occurred.
|
||||
*/
|
||||
int DISPLAY_HASH_ERROR_UNKNOWN = -1;
|
||||
|
||||
/**
|
||||
* The bounds used when requesting the hash hash were invalid or empty.
|
||||
*/
|
||||
int DISPLAY_HASH_ERROR_INVALID_BOUNDS = -2;
|
||||
|
||||
/**
|
||||
* The window for the view that requested the hash is no longer around. This can happen if the
|
||||
* window is getting torn down.
|
||||
*/
|
||||
int DISPLAY_HASH_ERROR_MISSING_WINDOW = -3;
|
||||
|
||||
/**
|
||||
* The view that requested the hash is not visible on screen. This could either mean
|
||||
* that the view bounds are offscreen, window bounds are offscreen, view is not visible, or
|
||||
* window is not visible.
|
||||
*/
|
||||
int DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN = -4;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(prefix = {"DISPLAY_HASH_ERROR_"}, value = {
|
||||
DISPLAY_HASH_ERROR_UNKNOWN,
|
||||
DISPLAY_HASH_ERROR_INVALID_BOUNDS,
|
||||
DISPLAY_HASH_ERROR_MISSING_WINDOW,
|
||||
DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@interface DisplayHashErrorCode {
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback invoked when calling
|
||||
* {@link android.view.View#generateDisplayHash(String, Rect, Executor,
|
||||
* DisplayHashResultCallback)}
|
||||
*
|
||||
* @param displayHash The DisplayHash generated. If the hash cannot be generated,
|
||||
* {@link #onDisplayHashError(int)} will be called instead
|
||||
*/
|
||||
void onDisplayHashResult(@NonNull DisplayHash displayHash);
|
||||
|
||||
/**
|
||||
* Callback invoked when
|
||||
* {@link android.view.View#generateDisplayHash(String, Rect, Executor,
|
||||
* DisplayHashResultCallback)} results in an error and cannot generate a display hash.
|
||||
*
|
||||
* @param errorCode One of the values in {@link DisplayHashErrorCode}
|
||||
*/
|
||||
void onDisplayHashError(@DisplayHashErrorCode int errorCode);
|
||||
}
|
||||
1
core/java/android/view/displayhash/OWNERS
Normal file
1
core/java/android/view/displayhash/OWNERS
Normal file
@@ -0,0 +1 @@
|
||||
include /services/core/java/com/android/server/wm/OWNERS
|
||||
19
core/java/android/view/displayhash/VerifiedDisplayHash.aidl
Normal file
19
core/java/android/view/displayhash/VerifiedDisplayHash.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.view.displayhash;
|
||||
|
||||
parcelable VerifiedDisplayHash;
|
||||
242
core/java/android/view/displayhash/VerifiedDisplayHash.java
Normal file
242
core/java/android/view/displayhash/VerifiedDisplayHash.java
Normal file
@@ -0,0 +1,242 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.view.displayhash;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.android.internal.util.DataClass;
|
||||
|
||||
/**
|
||||
* The verified display hash used to validate information about what was present on screen.
|
||||
*/
|
||||
@DataClass(genToString = true, genAidl = true)
|
||||
public final class VerifiedDisplayHash implements Parcelable {
|
||||
/**
|
||||
* The timestamp when the hash was generated.
|
||||
*/
|
||||
private final long mTimeMillis;
|
||||
|
||||
/**
|
||||
* The bounds of the requested area to generate the hash. This is in window space passed in
|
||||
* by the client.
|
||||
*/
|
||||
@NonNull
|
||||
private final Rect mBoundsInWindow;
|
||||
|
||||
/**
|
||||
* The selected hash algorithm that generated the image hash.
|
||||
*/
|
||||
@NonNull
|
||||
private final String mHashAlgorithm;
|
||||
|
||||
/**
|
||||
* The image hash generated when creating the DisplayHash.
|
||||
*/
|
||||
@NonNull
|
||||
private final byte[] mImageHash;
|
||||
|
||||
private String imageHashToString() {
|
||||
return byteArrayToString(mImageHash);
|
||||
}
|
||||
|
||||
private String byteArrayToString(byte[] byteArray) {
|
||||
if (byteArray == null) {
|
||||
return "null";
|
||||
}
|
||||
int iMax = byteArray.length - 1;
|
||||
if (iMax == -1) {
|
||||
return "[]";
|
||||
}
|
||||
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append('[');
|
||||
for (int i = 0; ; i++) {
|
||||
String formatted = String.format("%02X", byteArray[i] & 0xFF);
|
||||
b.append(formatted);
|
||||
if (i == iMax) {
|
||||
return b.append(']').toString();
|
||||
}
|
||||
b.append(", ");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Code below generated by codegen v1.0.22.
|
||||
//
|
||||
// DO NOT MODIFY!
|
||||
// CHECKSTYLE:OFF Generated code
|
||||
//
|
||||
// To regenerate run:
|
||||
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/view/displayhash/VerifiedDisplayHash.java
|
||||
//
|
||||
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
|
||||
// Settings > Editor > Code Style > Formatter Control
|
||||
//@formatter:off
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new VerifiedDisplayHash.
|
||||
*
|
||||
* @param timeMillis
|
||||
* The timestamp when the hash was generated.
|
||||
* @param boundsInWindow
|
||||
* The bounds of the requested area to generate the hash. This is in window space passed in
|
||||
* by the client.
|
||||
* @param hashAlgorithm
|
||||
* The selected hash algorithm that generated the image hash.
|
||||
* @param imageHash
|
||||
* The image hash generated when creating the DisplayHash.
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public VerifiedDisplayHash(
|
||||
long timeMillis,
|
||||
@NonNull Rect boundsInWindow,
|
||||
@NonNull String hashAlgorithm,
|
||||
@NonNull byte[] imageHash) {
|
||||
this.mTimeMillis = timeMillis;
|
||||
this.mBoundsInWindow = boundsInWindow;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mBoundsInWindow);
|
||||
this.mHashAlgorithm = hashAlgorithm;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mHashAlgorithm);
|
||||
this.mImageHash = imageHash;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mImageHash);
|
||||
|
||||
// onConstructed(); // You can define this method to get a callback
|
||||
}
|
||||
|
||||
/**
|
||||
* The timestamp when the hash was generated.
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public long getTimeMillis() {
|
||||
return mTimeMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* The bounds of the requested area to generate the hash. This is in window space passed in
|
||||
* by the client.
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @NonNull Rect getBoundsInWindow() {
|
||||
return mBoundsInWindow;
|
||||
}
|
||||
|
||||
/**
|
||||
* The selected hash algorithm that generated the image hash.
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @NonNull String getHashAlgorithm() {
|
||||
return mHashAlgorithm;
|
||||
}
|
||||
|
||||
/**
|
||||
* The image hash generated when creating the DisplayHash.
|
||||
*/
|
||||
@DataClass.Generated.Member
|
||||
public @NonNull byte[] getImageHash() {
|
||||
return mImageHash;
|
||||
}
|
||||
|
||||
@Override
|
||||
@DataClass.Generated.Member
|
||||
public String toString() {
|
||||
// You can override field toString logic by defining methods like:
|
||||
// String fieldNameToString() { ... }
|
||||
|
||||
return "VerifiedDisplayHash { " +
|
||||
"timeMillis = " + mTimeMillis + ", " +
|
||||
"boundsInWindow = " + mBoundsInWindow + ", " +
|
||||
"hashAlgorithm = " + mHashAlgorithm + ", " +
|
||||
"imageHash = " + imageHashToString() +
|
||||
" }";
|
||||
}
|
||||
|
||||
@Override
|
||||
@DataClass.Generated.Member
|
||||
public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
|
||||
// You can override field parcelling by defining methods like:
|
||||
// void parcelFieldName(Parcel dest, int flags) { ... }
|
||||
|
||||
dest.writeLong(mTimeMillis);
|
||||
dest.writeTypedObject(mBoundsInWindow, flags);
|
||||
dest.writeString(mHashAlgorithm);
|
||||
dest.writeByteArray(mImageHash);
|
||||
}
|
||||
|
||||
@Override
|
||||
@DataClass.Generated.Member
|
||||
public int describeContents() { return 0; }
|
||||
|
||||
/** @hide */
|
||||
@SuppressWarnings({"unchecked", "RedundantCast"})
|
||||
@DataClass.Generated.Member
|
||||
/* package-private */ VerifiedDisplayHash(@NonNull android.os.Parcel in) {
|
||||
// You can override field unparcelling by defining methods like:
|
||||
// static FieldType unparcelFieldName(Parcel in) { ... }
|
||||
|
||||
long timeMillis = in.readLong();
|
||||
Rect boundsInWindow = (Rect) in.readTypedObject(Rect.CREATOR);
|
||||
String hashAlgorithm = in.readString();
|
||||
byte[] imageHash = in.createByteArray();
|
||||
|
||||
this.mTimeMillis = timeMillis;
|
||||
this.mBoundsInWindow = boundsInWindow;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mBoundsInWindow);
|
||||
this.mHashAlgorithm = hashAlgorithm;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mHashAlgorithm);
|
||||
this.mImageHash = imageHash;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mImageHash);
|
||||
|
||||
// onConstructed(); // You can define this method to get a callback
|
||||
}
|
||||
|
||||
@DataClass.Generated.Member
|
||||
public static final @NonNull Parcelable.Creator<VerifiedDisplayHash> CREATOR
|
||||
= new Parcelable.Creator<VerifiedDisplayHash>() {
|
||||
@Override
|
||||
public VerifiedDisplayHash[] newArray(int size) {
|
||||
return new VerifiedDisplayHash[size];
|
||||
}
|
||||
|
||||
@Override
|
||||
public VerifiedDisplayHash createFromParcel(@NonNull android.os.Parcel in) {
|
||||
return new VerifiedDisplayHash(in);
|
||||
}
|
||||
};
|
||||
|
||||
@DataClass.Generated(
|
||||
time = 1613168749684L,
|
||||
codegenVersion = "1.0.22",
|
||||
sourceFile = "frameworks/base/core/java/android/view/displayhash/VerifiedDisplayHash.java",
|
||||
inputSignatures = "private final long mTimeMillis\nprivate final @android.annotation.NonNull android.graphics.Rect mBoundsInWindow\nprivate final @android.annotation.NonNull java.lang.String mHashAlgorithm\nprivate final @android.annotation.NonNull byte[] mImageHash\nprivate java.lang.String imageHashToString()\nprivate java.lang.String byteArrayToString(byte[])\nclass VerifiedDisplayHash extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genAidl=true)")
|
||||
@Deprecated
|
||||
private void __metadata() {}
|
||||
|
||||
|
||||
//@formatter:on
|
||||
// End of generated code
|
||||
|
||||
}
|
||||
@@ -5498,11 +5498,11 @@
|
||||
android:protectionLevel="signature" />
|
||||
|
||||
<!-- Must be required by a
|
||||
{@link android.service.screenshot.ScreenshotHasherService}
|
||||
{@link android.service.displayhash.DisplayHasherService}
|
||||
to ensure that only the system can bind to it.
|
||||
@hide This is not a third-party API (intended for OEMs and system apps).
|
||||
-->
|
||||
<permission android:name="android.permission.BIND_SCREENSHOT_HASHER_SERVICE"
|
||||
<permission android:name="android.permission.BIND_DISPLAY_HASHER_SERVICE"
|
||||
android:protectionLevel="signature" />
|
||||
|
||||
<!-- @hide @TestApi Allows an application to enable/disable toast rate limiting.
|
||||
|
||||
@@ -16,9 +16,8 @@
|
||||
|
||||
package com.android.server.wm;
|
||||
|
||||
import static android.service.screenshot.ScreenshotHasherService.EXTRA_SCREENSHOT_HASH;
|
||||
import static android.service.screenshot.ScreenshotHasherService.EXTRA_VERIFICATION_STATUS;
|
||||
import static android.service.screenshot.ScreenshotHasherService.SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS;
|
||||
import static android.service.displayhash.DisplayHasherService.EXTRA_VERIFIED_DISPLAY_HASH;
|
||||
import static android.service.displayhash.DisplayHasherService.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;
|
||||
@@ -46,11 +45,12 @@ import android.os.Message;
|
||||
import android.os.RemoteCallback;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.service.screenshot.IScreenshotHasherService;
|
||||
import android.service.screenshot.ScreenshotHash;
|
||||
import android.service.screenshot.ScreenshotHasherService;
|
||||
import android.service.displayhash.DisplayHasherService;
|
||||
import android.service.displayhash.IDisplayHasherService;
|
||||
import android.util.Slog;
|
||||
import android.view.MagnificationSpec;
|
||||
import android.view.displayhash.DisplayHash;
|
||||
import android.view.displayhash.VerifiedDisplayHash;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
|
||||
@@ -61,29 +61,29 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
/**
|
||||
* Handles requests into {@link android.service.screenshot.ScreenshotHasherService}
|
||||
* Handles requests into {@link android.service.displayhash.DisplayHasherService}
|
||||
*
|
||||
* Do not hold the {@link WindowManagerService#mGlobalLock} when calling methods since they are
|
||||
* blocking calls into another service.
|
||||
*/
|
||||
public class ScreenshotHashController {
|
||||
private static final String TAG = TAG_WITH_CLASS_NAME ? "ScreenshotHashController" : TAG_WM;
|
||||
public class DisplayHashController {
|
||||
private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayHashController" : TAG_WM;
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private final Object mServiceConnectionLock = new Object();
|
||||
|
||||
@GuardedBy("mServiceConnectionLock")
|
||||
private ScreenshotHasherServiceConnection mServiceConnection;
|
||||
private DisplayHasherServiceConnection mServiceConnection;
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
/**
|
||||
* Lock used for the cached {@link #mHashingAlgorithms} array
|
||||
* Lock used for the cached {@link #mHashAlgorithms} array
|
||||
*/
|
||||
private final Object mHashingAlgorithmsLock = new Object();
|
||||
private final Object mHashAlgorithmsLock = new Object();
|
||||
|
||||
@GuardedBy("mHashingAlgorithmsLock")
|
||||
private String[] mHashingAlgorithms;
|
||||
private String[] mHashAlgorithms;
|
||||
|
||||
private final Handler mHandler;
|
||||
|
||||
@@ -94,24 +94,24 @@ public class ScreenshotHashController {
|
||||
private final RectF mTmpRectF = new RectF();
|
||||
|
||||
private interface Command {
|
||||
void run(IScreenshotHasherService service) throws RemoteException;
|
||||
void run(IDisplayHasherService service) throws RemoteException;
|
||||
}
|
||||
|
||||
ScreenshotHashController(Context context) {
|
||||
DisplayHashController(Context context) {
|
||||
mContext = context;
|
||||
mHandler = new Handler(Looper.getMainLooper());
|
||||
mSalt = UUID.randomUUID().toString().getBytes();
|
||||
}
|
||||
|
||||
String[] getSupportedHashingAlgorithms() {
|
||||
String[] getSupportedHashAlgorithms() {
|
||||
// We have a separate lock for the hashing algorithm array since it doesn't need to make
|
||||
// the request through the service connection. Instead, we have a lock to ensure we can
|
||||
// properly cache the hashing algorithms array so we don't need to call into the
|
||||
// ExtServices process for each request.
|
||||
synchronized (mHashingAlgorithmsLock) {
|
||||
synchronized (mHashAlgorithmsLock) {
|
||||
// Already have cached values
|
||||
if (mHashingAlgorithms != null) {
|
||||
return mHashingAlgorithms;
|
||||
if (mHashAlgorithms != null) {
|
||||
return mHashAlgorithms;
|
||||
}
|
||||
|
||||
final ServiceInfo serviceInfo = getServiceInfo();
|
||||
@@ -128,55 +128,48 @@ public class ScreenshotHashController {
|
||||
|
||||
final int resourceId = serviceInfo.metaData.getInt(
|
||||
SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS);
|
||||
mHashingAlgorithms = res.getStringArray(resourceId);
|
||||
mHashAlgorithms = res.getStringArray(resourceId);
|
||||
|
||||
return mHashingAlgorithms;
|
||||
return mHashAlgorithms;
|
||||
}
|
||||
}
|
||||
|
||||
boolean verifyScreenshotHash(ScreenshotHash screenshotHash) {
|
||||
@Nullable
|
||||
VerifiedDisplayHash verifyDisplayHash(DisplayHash displayHash) {
|
||||
final SyncCommand syncCommand = new SyncCommand();
|
||||
Bundle results = syncCommand.run((service, remoteCallback) -> {
|
||||
try {
|
||||
service.verifyScreenshotHash(mSalt, screenshotHash, remoteCallback);
|
||||
service.verifyDisplayHash(mSalt, displayHash, remoteCallback);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Failed to invoke verifyScreenshotHash command");
|
||||
Slog.e(TAG, "Failed to invoke verifyDisplayHash command");
|
||||
}
|
||||
});
|
||||
|
||||
return results.getBoolean(EXTRA_VERIFICATION_STATUS);
|
||||
return results.getParcelable(EXTRA_VERIFIED_DISPLAY_HASH);
|
||||
}
|
||||
|
||||
ScreenshotHash generateScreenshotHash(HardwareBuffer screenshot, Rect bounds,
|
||||
String hashAlgorithm) {
|
||||
final SyncCommand syncCommand = new SyncCommand();
|
||||
Bundle results = syncCommand.run((service, remoteCallback) -> {
|
||||
try {
|
||||
service.generateScreenshotHash(mSalt, screenshot, bounds, hashAlgorithm,
|
||||
remoteCallback);
|
||||
} catch (RemoteException e) {
|
||||
Slog.e(TAG, "Failed to invoke generateScreenshotHash command", e);
|
||||
}
|
||||
});
|
||||
|
||||
return results.getParcelable(EXTRA_SCREENSHOT_HASH);
|
||||
void generateDisplayHash(HardwareBuffer buffer, Rect bounds,
|
||||
String hashAlgorithm, RemoteCallback callback) {
|
||||
connectAndRun(
|
||||
service -> service.generateDisplayHash(mSalt, buffer, bounds, hashAlgorithm,
|
||||
callback));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the bounds to take the screenshot when generating the ScreenshotHash. This
|
||||
* takes into account window transform, magnification, and display bounds.
|
||||
* Calculate the bounds to generate the hash for. This takes into account window transform,
|
||||
* magnification, and display bounds.
|
||||
*
|
||||
* Call while holding {@link WindowManagerService#mGlobalLock}
|
||||
*
|
||||
* @param win Window that the ScreenshotHash 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
|
||||
* @param win Window that the DisplayHash is generated for.
|
||||
* @param boundsInWindow The bounds in the window where to generate the hash.
|
||||
* @param outBounds The result of the calculated bounds
|
||||
*/
|
||||
void calculateScreenshotHashBoundsLocked(WindowState win, Rect boundsInWindow,
|
||||
void calculateDisplayHashBoundsLocked(WindowState win, Rect boundsInWindow,
|
||||
Rect outBounds) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG,
|
||||
"calculateScreenshotHashBoundsLocked: boundsInWindow=" + boundsInWindow);
|
||||
"calculateDisplayHashBoundsLocked: boundsInWindow=" + boundsInWindow);
|
||||
}
|
||||
outBounds.set(boundsInWindow);
|
||||
|
||||
@@ -195,7 +188,7 @@ public class ScreenshotHashController {
|
||||
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG,
|
||||
"calculateScreenshotHashBoundsLocked: boundsIntersectWindow=" + outBounds);
|
||||
"calculateDisplayHashBoundsLocked: boundsIntersectWindow=" + outBounds);
|
||||
}
|
||||
|
||||
if (outBounds.isEmpty()) {
|
||||
@@ -210,7 +203,7 @@ public class ScreenshotHashController {
|
||||
outBounds.set((int) mTmpRectF.left, (int) mTmpRectF.top, (int) mTmpRectF.right,
|
||||
(int) mTmpRectF.bottom);
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "calculateScreenshotHashBoundsLocked: boundsInDisplay=" + outBounds);
|
||||
Slog.d(TAG, "calculateDisplayHashBoundsLocked: boundsInDisplay=" + outBounds);
|
||||
}
|
||||
|
||||
// Apply the magnification spec values to the bounds since the content could be magnified
|
||||
@@ -221,7 +214,7 @@ public class ScreenshotHashController {
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "calculateScreenshotHashBoundsLocked: boundsWithMagnification="
|
||||
Slog.d(TAG, "calculateDisplayHashBoundsLocked: boundsWithMagnification="
|
||||
+ outBounds);
|
||||
}
|
||||
|
||||
@@ -229,12 +222,12 @@ public class ScreenshotHashController {
|
||||
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.
|
||||
// Intersect with the display bounds since content outside the display are not visible to
|
||||
// the user.
|
||||
final Rect displayBounds = displayContent.getBounds();
|
||||
outBounds.intersectUnchecked(displayBounds);
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "calculateScreenshotHashBoundsLocked: finalBounds=" + outBounds);
|
||||
Slog.d(TAG, "calculateDisplayHashBoundsLocked: finalBounds=" + outBounds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,7 +241,7 @@ public class ScreenshotHashController {
|
||||
if (DEBUG) Slog.v(TAG, "creating connection");
|
||||
|
||||
// Create the connection
|
||||
mServiceConnection = new ScreenshotHasherServiceConnection();
|
||||
mServiceConnection = new DisplayHasherServiceConnection();
|
||||
|
||||
final ComponentName component = getServiceComponentName();
|
||||
if (DEBUG) Slog.v(TAG, "binding to: " + component);
|
||||
@@ -279,7 +272,7 @@ public class ScreenshotHashController {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Intent intent = new Intent(ScreenshotHasherService.SERVICE_INTERFACE);
|
||||
final Intent intent = new Intent(DisplayHasherService.SERVICE_INTERFACE);
|
||||
intent.setPackage(packageName);
|
||||
final ResolveInfo resolveInfo = mContext.getPackageManager().resolveService(intent,
|
||||
PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
|
||||
@@ -296,10 +289,10 @@ public class ScreenshotHashController {
|
||||
if (serviceInfo == null) return null;
|
||||
|
||||
final ComponentName name = new ComponentName(serviceInfo.packageName, serviceInfo.name);
|
||||
if (!Manifest.permission.BIND_SCREENSHOT_HASHER_SERVICE
|
||||
if (!Manifest.permission.BIND_DISPLAY_HASHER_SERVICE
|
||||
.equals(serviceInfo.permission)) {
|
||||
Slog.w(TAG, name.flattenToShortString() + " requires permission "
|
||||
+ Manifest.permission.BIND_SCREENSHOT_HASHER_SERVICE);
|
||||
+ Manifest.permission.BIND_DISPLAY_HASHER_SERVICE);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -312,7 +305,7 @@ public class ScreenshotHashController {
|
||||
private Bundle mResult;
|
||||
private final CountDownLatch mCountDownLatch = new CountDownLatch(1);
|
||||
|
||||
public Bundle run(BiConsumer<IScreenshotHasherService, RemoteCallback> func) {
|
||||
public Bundle run(BiConsumer<IDisplayHasherService, RemoteCallback> func) {
|
||||
connectAndRun(service -> {
|
||||
RemoteCallback callback = new RemoteCallback(result -> {
|
||||
mResult = result;
|
||||
@@ -331,9 +324,9 @@ public class ScreenshotHashController {
|
||||
}
|
||||
}
|
||||
|
||||
private class ScreenshotHasherServiceConnection implements ServiceConnection {
|
||||
private class DisplayHasherServiceConnection implements ServiceConnection {
|
||||
@GuardedBy("mServiceConnectionLock")
|
||||
private IScreenshotHasherService mRemoteService;
|
||||
private IDisplayHasherService mRemoteService;
|
||||
|
||||
@GuardedBy("mServiceConnectionLock")
|
||||
private ArrayList<Command> mQueuedCommands;
|
||||
@@ -342,7 +335,7 @@ public class ScreenshotHashController {
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
if (DEBUG) Slog.v(TAG, "onServiceConnected(): " + name);
|
||||
synchronized (mServiceConnectionLock) {
|
||||
mRemoteService = IScreenshotHasherService.Stub.asInterface(service);
|
||||
mRemoteService = IDisplayHasherService.Stub.asInterface(service);
|
||||
if (mQueuedCommands != null) {
|
||||
final int size = mQueuedCommands.size();
|
||||
if (DEBUG) Slog.d(TAG, "running " + size + " queued commands");
|
||||
@@ -54,10 +54,10 @@ import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.Parcel;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteCallback;
|
||||
import android.os.RemoteException;
|
||||
import android.os.Trace;
|
||||
import android.os.UserHandle;
|
||||
import android.service.screenshot.ScreenshotHash;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArraySet;
|
||||
import android.util.MergedConfiguration;
|
||||
@@ -850,11 +850,11 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScreenshotHash generateScreenshotHash(IWindow window, Rect boundsInWindow,
|
||||
String hashAlgorithm) {
|
||||
public void generateDisplayHash(IWindow window, Rect boundsInWindow, String hashAlgorithm,
|
||||
RemoteCallback callback) {
|
||||
final long origId = Binder.clearCallingIdentity();
|
||||
try {
|
||||
return mService.generateScreenshotHash(this, window, boundsInWindow, hashAlgorithm);
|
||||
mService.generateDisplayHash(this, window, boundsInWindow, hashAlgorithm, callback);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(origId);
|
||||
}
|
||||
|
||||
@@ -83,6 +83,10 @@ import static android.view.WindowManagerGlobal.ADD_OKAY;
|
||||
import static android.view.WindowManagerGlobal.RELAYOUT_RES_BLAST_SYNC;
|
||||
import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
|
||||
import static android.view.WindowManagerPolicyConstants.NAV_BAR_INVALID;
|
||||
import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_MISSING_WINDOW;
|
||||
import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN;
|
||||
import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_UNKNOWN;
|
||||
import static android.view.displayhash.DisplayHashResultCallback.EXTRA_DISPLAY_HASH_ERROR_CODE;
|
||||
|
||||
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
|
||||
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_BOOT;
|
||||
@@ -187,6 +191,7 @@ import android.os.PowerManager;
|
||||
import android.os.PowerManager.ServiceType;
|
||||
import android.os.PowerManagerInternal;
|
||||
import android.os.PowerSaveState;
|
||||
import android.os.RemoteCallback;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ResultReceiver;
|
||||
import android.os.ServiceManager;
|
||||
@@ -199,7 +204,6 @@ import android.os.Trace;
|
||||
import android.os.UserHandle;
|
||||
import android.os.WorkSource;
|
||||
import android.provider.Settings;
|
||||
import android.service.screenshot.ScreenshotHash;
|
||||
import android.service.vr.IVrManager;
|
||||
import android.service.vr.IVrStateCallbacks;
|
||||
import android.sysprop.SurfaceFlingerProperties;
|
||||
@@ -261,6 +265,8 @@ import android.view.WindowManager.LayoutParams;
|
||||
import android.view.WindowManager.RemoveContentMode;
|
||||
import android.view.WindowManagerGlobal;
|
||||
import android.view.WindowManagerPolicyConstants.PointerEventListener;
|
||||
import android.view.displayhash.DisplayHash;
|
||||
import android.view.displayhash.VerifiedDisplayHash;
|
||||
import android.window.ClientWindowFrames;
|
||||
import android.window.TaskSnapshot;
|
||||
|
||||
@@ -768,7 +774,8 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
final EmbeddedWindowController mEmbeddedWindowController;
|
||||
final AnrController mAnrController;
|
||||
|
||||
private final ScreenshotHashController mScreenshotHashController;
|
||||
private final DisplayHashController mDisplayHashController;
|
||||
|
||||
@VisibleForTesting
|
||||
final WindowContextListenerController mWindowContextListenerController =
|
||||
new WindowContextListenerController();
|
||||
@@ -1419,7 +1426,7 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
mDisplayAreaPolicyProvider = DisplayAreaPolicy.Provider.fromResources(
|
||||
mContext.getResources());
|
||||
|
||||
mScreenshotHashController = new ScreenshotHashController(mContext);
|
||||
mDisplayHashController = new DisplayHashController(mContext);
|
||||
setGlobalShadowSettings();
|
||||
mAnrController = new AnrController(this);
|
||||
mStartingSurfaceController = new StartingSurfaceController(this);
|
||||
@@ -8599,39 +8606,42 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSupportedScreenshotHashingAlgorithms() {
|
||||
return mScreenshotHashController.getSupportedHashingAlgorithms();
|
||||
public String[] getSupportedDisplayHashAlgorithms() {
|
||||
return mDisplayHashController.getSupportedHashAlgorithms();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean verifyScreenshotHash(ScreenshotHash screenshotHash) {
|
||||
return mScreenshotHashController.verifyScreenshotHash(screenshotHash);
|
||||
public VerifiedDisplayHash verifyDisplayHash(DisplayHash displayHash) {
|
||||
return mDisplayHashController.verifyDisplayHash(displayHash);
|
||||
}
|
||||
|
||||
ScreenshotHash generateScreenshotHash(Session session, IWindow window,
|
||||
Rect boundsInWindow, String hashAlgorithm) {
|
||||
void generateDisplayHash(Session session, IWindow window, Rect boundsInWindow,
|
||||
String hashAlgorithm, RemoteCallback callback) {
|
||||
final SurfaceControl displaySurfaceControl;
|
||||
final Rect boundsInDisplay = new Rect(boundsInWindow);
|
||||
synchronized (mGlobalLock) {
|
||||
final WindowState win = windowForClientLocked(session, window, false);
|
||||
if (win == null) {
|
||||
Slog.w(TAG, "Failed to generate ScreenshotHash. Invalid window");
|
||||
return null;
|
||||
Slog.w(TAG, "Failed to generate DisplayHash. Invalid window");
|
||||
sendDisplayHashError(callback, DISPLAY_HASH_ERROR_MISSING_WINDOW);
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayContent displayContent = win.getDisplayContent();
|
||||
if (displayContent == null) {
|
||||
Slog.w(TAG, "Failed to generate ScreenshotHash. Window is not on a display");
|
||||
return null;
|
||||
Slog.w(TAG, "Failed to generate DisplayHash. Window is not on a display");
|
||||
sendDisplayHashError(callback, DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN);
|
||||
return;
|
||||
}
|
||||
|
||||
displaySurfaceControl = displayContent.getSurfaceControl();
|
||||
mScreenshotHashController.calculateScreenshotHashBoundsLocked(win,
|
||||
boundsInWindow, boundsInDisplay);
|
||||
mDisplayHashController.calculateDisplayHashBoundsLocked(win, boundsInWindow,
|
||||
boundsInDisplay);
|
||||
|
||||
if (boundsInDisplay.isEmpty()) {
|
||||
Slog.w(TAG, "Failed to generate ScreenshotHash. Bounds are not on screen");
|
||||
return null;
|
||||
Slog.w(TAG, "Failed to generate DisplayHash. Bounds are not on screen");
|
||||
sendDisplayHashError(callback, DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8650,11 +8660,18 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
SurfaceControl.captureLayers(args);
|
||||
if (screenshotHardwareBuffer == null
|
||||
|| screenshotHardwareBuffer.getHardwareBuffer() == null) {
|
||||
Slog.w(TAG, "Failed to generate ScreenshotHash. Failed to take screenshot");
|
||||
return null;
|
||||
Slog.w(TAG, "Failed to generate DisplayHash. Couldn't capture content");
|
||||
sendDisplayHashError(callback, DISPLAY_HASH_ERROR_UNKNOWN);
|
||||
return;
|
||||
}
|
||||
|
||||
return mScreenshotHashController.generateScreenshotHash(
|
||||
screenshotHardwareBuffer.getHardwareBuffer(), boundsInWindow, hashAlgorithm);
|
||||
mDisplayHashController.generateDisplayHash(screenshotHardwareBuffer.getHardwareBuffer(),
|
||||
boundsInWindow, hashAlgorithm, callback);
|
||||
}
|
||||
|
||||
private void sendDisplayHashError(RemoteCallback callback, int errorCode) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt(EXTRA_DISPLAY_HASH_ERROR_CODE, errorCode);
|
||||
callback.sendResult(bundle);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user