Merge "Limit number of window context without any window" into rvc-dev
This commit is contained in:
@@ -16,6 +16,7 @@
|
|||||||
package android.app;
|
package android.app;
|
||||||
|
|
||||||
import static android.view.WindowManagerGlobal.ADD_OKAY;
|
import static android.view.WindowManagerGlobal.ADD_OKAY;
|
||||||
|
import static android.view.WindowManagerGlobal.ADD_TOO_MANY_TOKENS;
|
||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
@@ -81,6 +82,11 @@ public class WindowContext extends ContextWrapper {
|
|||||||
mOwnsToken = false;
|
mOwnsToken = false;
|
||||||
throw e.rethrowFromSystemServer();
|
throw e.rethrowFromSystemServer();
|
||||||
}
|
}
|
||||||
|
if (result == ADD_TOO_MANY_TOKENS) {
|
||||||
|
throw new UnsupportedOperationException("createWindowContext failed! Too many unused "
|
||||||
|
+ "window contexts. Please see Context#createWindowContext documentation for "
|
||||||
|
+ "detail.");
|
||||||
|
}
|
||||||
mOwnsToken = result == ADD_OKAY;
|
mOwnsToken = result == ADD_OKAY;
|
||||||
Reference.reachabilityFence(this);
|
Reference.reachabilityFence(this);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5812,6 +5812,12 @@ public abstract class Context {
|
|||||||
* display.</b> If there is a need to add different window types, or non-associated windows,
|
* display.</b> If there is a need to add different window types, or non-associated windows,
|
||||||
* separate Contexts should be used.
|
* separate Contexts should be used.
|
||||||
* </p>
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* Creating a window context is an expensive operation. Misuse of this API may lead to a huge
|
||||||
|
* performance drop. The best practice is to use the same window context when possible.
|
||||||
|
* An approach is to create one window context with specific window type and display and
|
||||||
|
* use it everywhere it's needed..
|
||||||
|
* </p>
|
||||||
*
|
*
|
||||||
* @param type Window type in {@link WindowManager.LayoutParams}
|
* @param type Window type in {@link WindowManager.LayoutParams}
|
||||||
* @param options Bundle used to pass window-related options.
|
* @param options Bundle used to pass window-related options.
|
||||||
@@ -5824,7 +5830,9 @@ public abstract class Context {
|
|||||||
* @see #WINDOW_SERVICE
|
* @see #WINDOW_SERVICE
|
||||||
* @see #LAYOUT_INFLATER_SERVICE
|
* @see #LAYOUT_INFLATER_SERVICE
|
||||||
* @see #WALLPAPER_SERVICE
|
* @see #WALLPAPER_SERVICE
|
||||||
* @throws IllegalArgumentException if token is invalid
|
* @throws UnsupportedOperationException if this {@link Context} does not attach to a display or
|
||||||
|
* the current number of window contexts without adding any view by
|
||||||
|
* {@link WindowManager#addView} <b>exceeds five</b>.
|
||||||
*/
|
*/
|
||||||
public @NonNull Context createWindowContext(@WindowType int type, @Nullable Bundle options) {
|
public @NonNull Context createWindowContext(@WindowType int type, @Nullable Bundle options) {
|
||||||
throw new RuntimeException("Not implemented. Must override in a subclass.");
|
throw new RuntimeException("Not implemented. Must override in a subclass.");
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ public final class WindowManagerGlobal {
|
|||||||
public static final int ADD_INVALID_DISPLAY = -9;
|
public static final int ADD_INVALID_DISPLAY = -9;
|
||||||
public static final int ADD_INVALID_TYPE = -10;
|
public static final int ADD_INVALID_TYPE = -10;
|
||||||
public static final int ADD_INVALID_USER = -11;
|
public static final int ADD_INVALID_USER = -11;
|
||||||
|
public static final int ADD_TOO_MANY_TOKENS = -12;
|
||||||
|
|
||||||
@UnsupportedAppUsage
|
@UnsupportedAppUsage
|
||||||
private static WindowManagerGlobal sDefaultWindowManager;
|
private static WindowManagerGlobal sDefaultWindowManager;
|
||||||
|
|||||||
@@ -5534,4 +5534,34 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of window tokens without surface on this display. A {@link WindowToken}
|
||||||
|
* won't have its {@link SurfaceControl} until a window is added to a {@link WindowToken}.
|
||||||
|
* The purpose of this method is to accumulate non-window containing {@link WindowToken}s and
|
||||||
|
* limit the usage if the count exceeds a number.
|
||||||
|
*
|
||||||
|
* @param callingUid app calling uid
|
||||||
|
* @return the number of window tokens without surface on this display
|
||||||
|
* @see WindowToken#addWindow(WindowState)
|
||||||
|
*/
|
||||||
|
int getWindowTokensWithoutSurfaceCount(int callingUid) {
|
||||||
|
List<WindowToken> tokens = new ArrayList<>(mTokenMap.values());
|
||||||
|
int count = 0;
|
||||||
|
for (int i = tokens.size() - 1; i >= 0; i--) {
|
||||||
|
final WindowToken token = tokens.get(i);
|
||||||
|
if (callingUid != token.getOwnerUid()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Skip if token is an Activity
|
||||||
|
if (token.asActivityRecord() != null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (token.mSurfaceControl != null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import static android.Manifest.permission.MANAGE_APP_TOKENS;
|
|||||||
import static android.Manifest.permission.READ_FRAME_BUFFER;
|
import static android.Manifest.permission.READ_FRAME_BUFFER;
|
||||||
import static android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS;
|
import static android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS;
|
||||||
import static android.Manifest.permission.RESTRICTED_VR_ACCESS;
|
import static android.Manifest.permission.RESTRICTED_VR_ACCESS;
|
||||||
|
import static android.Manifest.permission.STATUS_BAR_SERVICE;
|
||||||
import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
|
import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
|
||||||
import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
|
import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
|
||||||
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
|
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
|
||||||
@@ -74,6 +75,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
|
|||||||
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
|
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
|
||||||
import static android.view.WindowManager.REMOVE_CONTENT_MODE_UNDEFINED;
|
import static android.view.WindowManager.REMOVE_CONTENT_MODE_UNDEFINED;
|
||||||
import static android.view.WindowManagerGlobal.ADD_OKAY;
|
import static android.view.WindowManagerGlobal.ADD_OKAY;
|
||||||
|
import static android.view.WindowManagerGlobal.ADD_TOO_MANY_TOKENS;
|
||||||
import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY;
|
import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY;
|
||||||
import static android.view.WindowManagerGlobal.RELAYOUT_RES_BLAST_SYNC;
|
import static android.view.WindowManagerGlobal.RELAYOUT_RES_BLAST_SYNC;
|
||||||
import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
|
import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
|
||||||
@@ -413,6 +415,12 @@ public class WindowManagerService extends IWindowManager.Stub
|
|||||||
|
|
||||||
private static final int ANIMATION_COMPLETED_TIMEOUT_MS = 5000;
|
private static final int ANIMATION_COMPLETED_TIMEOUT_MS = 5000;
|
||||||
|
|
||||||
|
/** The maximum count of window tokens without surface that an app can register. */
|
||||||
|
private static final int MAXIMUM_WINDOW_TOKEN_COUNT_WITHOUT_SURFACE = 5;
|
||||||
|
|
||||||
|
/** System UI can create more window context... */
|
||||||
|
private static final int SYSTEM_UI_MULTIPLIER = 2;
|
||||||
|
|
||||||
// TODO(b/143053092): Remove the settings if it becomes stable.
|
// TODO(b/143053092): Remove the settings if it becomes stable.
|
||||||
private static final String FIXED_ROTATION_TRANSFORM_SETTING_NAME = "fixed_rotation_transform";
|
private static final String FIXED_ROTATION_TRANSFORM_SETTING_NAME = "fixed_rotation_transform";
|
||||||
boolean mIsFixedRotationTransformEnabled;
|
boolean mIsFixedRotationTransformEnabled;
|
||||||
@@ -2594,10 +2602,30 @@ public class WindowManagerService extends IWindowManager.Stub
|
|||||||
@Override
|
@Override
|
||||||
public int addWindowTokenWithOptions(IBinder binder, int type, int displayId, Bundle options,
|
public int addWindowTokenWithOptions(IBinder binder, int type, int displayId, Bundle options,
|
||||||
String packageName) {
|
String packageName) {
|
||||||
|
if (tokenCountExceed()) {
|
||||||
|
return ADD_TOO_MANY_TOKENS;
|
||||||
|
}
|
||||||
return addWindowTokenWithOptions(binder, type, displayId, options, packageName,
|
return addWindowTokenWithOptions(binder, type, displayId, options, packageName,
|
||||||
true /* fromClientToken */);
|
true /* fromClientToken */);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean tokenCountExceed() {
|
||||||
|
final int callingUid = Binder.getCallingUid();
|
||||||
|
// Don't check if caller is from system server.
|
||||||
|
if (callingUid == myPid()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final int limit =
|
||||||
|
(checkCallingPermission(STATUS_BAR_SERVICE, "addWindowTokenWithOptions"))
|
||||||
|
? MAXIMUM_WINDOW_TOKEN_COUNT_WITHOUT_SURFACE * SYSTEM_UI_MULTIPLIER
|
||||||
|
: MAXIMUM_WINDOW_TOKEN_COUNT_WITHOUT_SURFACE;
|
||||||
|
synchronized (mGlobalLock) {
|
||||||
|
int[] count = new int[1];
|
||||||
|
mRoot.forAllDisplays(d -> count[0] += d.getWindowTokensWithoutSurfaceCount(callingUid));
|
||||||
|
return count[0] >= limit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private int addWindowTokenWithOptions(IBinder binder, int type, int displayId, Bundle options,
|
private int addWindowTokenWithOptions(IBinder binder, int type, int displayId, Bundle options,
|
||||||
String packageName, boolean fromClientToken) {
|
String packageName, boolean fromClientToken) {
|
||||||
final boolean callerCanManageAppTokens =
|
final boolean callerCanManageAppTokens =
|
||||||
|
|||||||
Reference in New Issue
Block a user