Merge "Add throttling to generateDisplayHash" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
c312f0f79a
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user