Merge "Add throttling to generateDisplayHash" into sc-dev

This commit is contained in:
Chavi Weingarten
2021-03-30 14:10:00 +00:00
committed by Android (Google) Code Review
11 changed files with 218 additions and 4 deletions

View File

@@ -51550,6 +51550,7 @@ package android.view.displayhash {
field public static final int DISPLAY_HASH_ERROR_INVALID_HASH_ALGORITHM = -5; // 0xfffffffb
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_TOO_MANY_REQUESTS = -6; // 0xfffffffa
field public static final int DISPLAY_HASH_ERROR_UNKNOWN = -1; // 0xffffffff
}

View File

@@ -321,6 +321,7 @@ package android {
field public static final int requiredSystemPropertyValue = 16844134; // 0x1010566
field public static final int sdkVersion = 16844304; // 0x1010610
field public static final int supportsAmbientMode = 16844173; // 0x101058d
field public static final int throttleDurationMillis = 16844360; // 0x1010648
field public static final int userRestriction = 16844164; // 0x1010584
}
@@ -9794,6 +9795,7 @@ package android.service.displayhash {
method @NonNull public abstract java.util.Map<java.lang.String,android.service.displayhash.DisplayHashParams> onGetDisplayHashAlgorithms();
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";
field public static final String SERVICE_META_DATA = "android.displayhash.display_hasher_service";
}
}

View File

@@ -2877,6 +2877,14 @@ package android.view.contentcapture {
}
package android.view.displayhash {
public final class DisplayHashManager {
method @RequiresPermission("android.permission.READ_FRAME_BUFFER") public void setDisplayHashThrottlingEnabled(boolean);
}
}
package android.view.inputmethod {
public final class InlineSuggestion implements android.os.Parcelable {

View File

@@ -51,6 +51,16 @@ public abstract class DisplayHasherService extends Service {
public static final String EXTRA_VERIFIED_DISPLAY_HASH =
"android.service.displayhash.extra.VERIFIED_DISPLAY_HASH";
/**
* Name under which a DisplayHasherService component publishes information
* about itself. This meta-data must reference an XML resource containing a
* {@link com.android.internal.R.styleable#DisplayHasherService} tag.
*
* @hide
*/
@SystemApi
public static final String SERVICE_META_DATA = "android.displayhash.display_hasher_service";
/**
* 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.

View File

@@ -776,6 +776,15 @@ interface IWindowManager
*/
VerifiedDisplayHash verifyDisplayHash(in DisplayHash displayHash);
/**
* Call to enable or disable the throttling when generating a display hash. This should only be
* used for testing. Throttling is enabled by default.
*
* Must be called from a process that has {@link android.Manifest.permission#READ_FRAME_BUFFER}
* permission.
*/
void setDisplayHashThrottlingEnabled(boolean enable);
/**
* Registers a listener for a {@link android.window.WindowContext} to handle configuration
* changes from the server side.

View File

@@ -21,7 +21,9 @@ import static android.content.Context.DISPLAY_HASH_SERVICE;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.os.RemoteException;
import android.util.ArraySet;
import android.util.Log;
@@ -94,4 +96,19 @@ public final class DisplayHashManager {
return null;
}
}
/**
* Call to enable or disable the throttling when generating a display hash. This should only be
* used for testing. Throttling is enabled by default.
*
* @hide
*/
@TestApi
@RequiresPermission(android.Manifest.permission.READ_FRAME_BUFFER)
public void setDisplayHashThrottlingEnabled(boolean enable) {
try {
WindowManagerGlobal.getWindowManagerService().setDisplayHashThrottlingEnabled(enable);
} catch (RemoteException e) {
}
}
}

View File

@@ -72,13 +72,20 @@ public interface DisplayHashResultCallback {
*/
int DISPLAY_HASH_ERROR_INVALID_HASH_ALGORITHM = -5;
/**
* The caller requested to generate the hash too frequently. The caller should try again at a
* after some time has passed to ensure the system isn't overloaded.
*/
int DISPLAY_HASH_ERROR_TOO_MANY_REQUESTS = -6;
/** @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,
DISPLAY_HASH_ERROR_INVALID_HASH_ALGORITHM
DISPLAY_HASH_ERROR_INVALID_HASH_ALGORITHM,
DISPLAY_HASH_ERROR_TOO_MANY_REQUESTS
})
@Retention(RetentionPolicy.SOURCE)
@interface DisplayHashErrorCode {

View File

@@ -9539,4 +9539,10 @@
<attr name="iconfactoryBadgeSize" format="dimension"/>
<!-- Perceptual luminance of a color, in accessibility friendly color space. From 0 to 100. -->
<attr name="lStar" format="float"/>
<declare-styleable name="DisplayHasherService">
<!-- The throttle duration for display hash requests
@hide @SystemApi -->
<attr name="throttleDurationMillis" format="integer" />
</declare-styleable>
</resources>

View File

@@ -3096,6 +3096,8 @@
<!-- @hide @SystemApi -->
<public name="playHomeTransitionSound" />
<public name="lStar" />
<!-- @hide @SystemApi -->
<public name="throttleDurationMillis" />
</public-group>
<public-group type="drawable" first-id="0x010800b5">

View File

@@ -17,7 +17,9 @@
package com.android.server.wm;
import static android.service.displayhash.DisplayHasherService.EXTRA_VERIFIED_DISPLAY_HASH;
import static android.service.displayhash.DisplayHasherService.SERVICE_META_DATA;
import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_INVALID_HASH_ALGORITHM;
import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_TOO_MANY_REQUESTS;
import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_UNKNOWN;
import static android.view.displayhash.DisplayHashResultCallback.EXTRA_DISPLAY_HASH_ERROR_CODE;
@@ -34,6 +36,9 @@ import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -49,15 +54,22 @@ import android.os.UserHandle;
import android.service.displayhash.DisplayHashParams;
import android.service.displayhash.DisplayHasherService;
import android.service.displayhash.IDisplayHasherService;
import android.util.AttributeSet;
import android.util.Size;
import android.util.Slog;
import android.util.Xml;
import android.view.MagnificationSpec;
import android.view.SurfaceControl;
import android.view.displayhash.DisplayHash;
import android.view.displayhash.VerifiedDisplayHash;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
@@ -102,6 +114,41 @@ public class DisplayHashController {
private final Matrix mTmpMatrix = new Matrix();
private final RectF mTmpRectF = new RectF();
/**
* Lock used when retrieving xml metadata. Lock when retrieving the xml data the first time
* since it will be cached after that. Check if {@link #mParsedXml} is set to determine if the
* metadata needs to retrieved.
*/
private final Object mParseXmlLock = new Object();
/**
* Flag whether the xml metadata has been retrieved and parsed. Once this is set to true,
* there's no need to request metadata again.
*/
@GuardedBy("mParseXmlLock")
private boolean mParsedXml;
/**
* Specified throttle time in milliseconds. Don't allow an app to generate a display hash more
* than once per throttleTime
*/
private int mThrottleDurationMillis = 0;
/**
* The last time an app requested to generate a display hash in System time.
*/
private long mLastRequestTimeMs;
/**
* The last uid that requested to generate a hash.
*/
private int mLastRequestUid;
/**
* Only used for testing. Throttling should always be enabled unless running tests
*/
private boolean mDisplayHashThrottlingEnabled = true;
private interface Command {
void run(IDisplayHasherService service) throws RemoteException;
}
@@ -131,6 +178,10 @@ public class DisplayHashController {
return results.getParcelable(EXTRA_VERIFIED_DISPLAY_HASH);
}
void setDisplayHashThrottlingEnabled(boolean enable) {
mDisplayHashThrottlingEnabled = enable;
}
private void generateDisplayHash(HardwareBuffer buffer, Rect bounds,
String hashAlgorithm, RemoteCallback callback) {
connectAndRun(
@@ -138,8 +189,36 @@ public class DisplayHashController {
callback));
}
private boolean allowedToGenerateHash(int uid) {
if (!mDisplayHashThrottlingEnabled) {
// Always allow to generate the hash. This is used to allow tests to run without
// waiting on the designated threshold.
return true;
}
long currentTime = System.currentTimeMillis();
if (mLastRequestUid != uid) {
mLastRequestUid = uid;
mLastRequestTimeMs = currentTime;
return true;
}
int throttleDurationMs = getThrottleDurationMillis();
if (currentTime - mLastRequestTimeMs < throttleDurationMs) {
return false;
}
mLastRequestTimeMs = currentTime;
return true;
}
void generateDisplayHash(SurfaceControl.LayerCaptureArgs.Builder args,
Rect boundsInWindow, String hashAlgorithm, RemoteCallback callback) {
Rect boundsInWindow, String hashAlgorithm, int uid, RemoteCallback callback) {
if (!allowedToGenerateHash(uid)) {
sendDisplayHashError(callback, DISPLAY_HASH_ERROR_TOO_MANY_REQUESTS);
return;
}
final Map<String, DisplayHashParams> displayHashAlgorithmsMap = getDisplayHashAlgorithms();
DisplayHashParams displayHashParams = displayHashAlgorithmsMap.get(hashAlgorithm);
if (displayHashParams == null) {
@@ -277,6 +356,64 @@ public class DisplayHashController {
}
}
private int getThrottleDurationMillis() {
if (!parseXmlProperties()) {
return 0;
}
return mThrottleDurationMillis;
}
private boolean parseXmlProperties() {
// We have a separate lock for the xml parsing 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 xml metadata so we don't need to call into the ExtServices
// process for each request.
synchronized (mParseXmlLock) {
if (mParsedXml) {
return true;
}
final ServiceInfo serviceInfo = getServiceInfo();
if (serviceInfo == null) return false;
final PackageManager pm = mContext.getPackageManager();
XmlResourceParser parser;
parser = serviceInfo.loadXmlMetaData(pm, SERVICE_META_DATA);
if (parser == null) {
return false;
}
Resources res;
try {
res = pm.getResourcesForApplication(serviceInfo.applicationInfo);
} catch (PackageManager.NameNotFoundException e) {
return false;
}
AttributeSet attrs = Xml.asAttributeSet(parser);
int type;
while (true) {
try {
if (!((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& type != XmlPullParser.START_TAG)) {
break;
}
} catch (XmlPullParserException | IOException e) {
return false;
}
}
TypedArray sa = res.obtainAttributes(attrs, R.styleable.DisplayHasherService);
mThrottleDurationMillis = sa.getInt(
R.styleable.DisplayHasherService_throttleDurationMillis, 0);
sa.recycle();
mParsedXml = true;
return true;
}
}
/**
* Run a command, starting the service connection if necessary.
*/

View File

@@ -8626,6 +8626,14 @@ public class WindowManagerService extends IWindowManager.Stub
return mDisplayHashController.verifyDisplayHash(displayHash);
}
@Override
public void setDisplayHashThrottlingEnabled(boolean enable) {
if (!checkCallingPermission(READ_FRAME_BUFFER, "setDisplayHashThrottle()")) {
throw new SecurityException("Requires READ_FRAME_BUFFER permission");
}
mDisplayHashController.setDisplayHashThrottlingEnabled(enable);
}
void generateDisplayHash(Session session, IWindow window, Rect boundsInWindow,
String hashAlgorithm, RemoteCallback callback) {
final SurfaceControl displaySurfaceControl;
@@ -8639,6 +8647,13 @@ public class WindowManagerService extends IWindowManager.Stub
return;
}
if (win.mActivityRecord == null || !win.mActivityRecord.isState(
Task.ActivityState.RESUMED)) {
mDisplayHashController.sendDisplayHashError(callback,
DISPLAY_HASH_ERROR_MISSING_WINDOW);
return;
}
DisplayContent displayContent = win.getDisplayContent();
if (displayContent == null) {
Slog.w(TAG, "Failed to generate DisplayHash. Window is not on a display");
@@ -8669,8 +8684,8 @@ public class WindowManagerService extends IWindowManager.Stub
.setUid(uid)
.setSourceCrop(boundsInDisplay);
mDisplayHashController.generateDisplayHash(args, boundsInWindow,
hashAlgorithm, callback);
mDisplayHashController.generateDisplayHash(args, boundsInWindow, hashAlgorithm, uid,
callback);
}
boolean shouldRestoreImeVisibility(IBinder imeTargetWindowToken) {