summaryrefslogtreecommitdiff
path: root/core/java/android/app/WindowTokenClient.java
diff options
context:
space:
mode:
authorCharles Chen <charlesccchen@google.com>2020-03-11 10:17:19 +0800
committerCharles Chen <charlesccchen@google.com>2020-04-08 21:30:24 +0800
commit4bff5be1a91e7598731412981ed512c9060ef188 (patch)
tree16f9ca5d4a184144776613c5a1c6c1b2e67ffe90 /core/java/android/app/WindowTokenClient.java
parent884aa6afe156ec88cfc89e9d5dac4480223c9495 (diff)
Fix WindowContext leak
The root causes of this issue are: 1. WindowTokenClient#attachContext makes WindowTokenClient has strong reference to WindowContext, which leads to WindowContext cannot be GC'd. 2. WMS#removeWindowToken needs MANAGE_APP_TOKEN permission which normal apps don't hold. This CL does following things: 1. Use weak reference instead on WindowTokenClient#mContext. 2. Relax WMS#removeWindowToken to check callingUid if MANAGE_WINDOW_TOKEN permission is not held 3. Deliver config changes to the client side in WMS#addWindowTokenWithOption 4. Some minor fixes fixes: 150812449 Bug: 150715095 Test: atest WindowContextTest Test: atest WindowManagerServiceTests Test: atest WindowTokenTests Test: atest WindowManagerPermissionTests#testMANAGE_APP_TOKENS Test: atest WindowManagerPermissionTests#testADD_WINDOW_TOKEN_WITH_OPTIONS Change-Id: I9f1d73af2abb78fc9844e6d9eb25e9f0293514e7
Diffstat (limited to 'core/java/android/app/WindowTokenClient.java')
-rw-r--r--core/java/android/app/WindowTokenClient.java39
1 files changed, 29 insertions, 10 deletions
diff --git a/core/java/android/app/WindowTokenClient.java b/core/java/android/app/WindowTokenClient.java
index ed0179bb9839..301960ec53f9 100644
--- a/core/java/android/app/WindowTokenClient.java
+++ b/core/java/android/app/WindowTokenClient.java
@@ -20,6 +20,9 @@ import android.content.Context;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.IBinder;
+import android.view.WindowManagerGlobal;
+
+import java.lang.ref.WeakReference;
/**
* Client implementation of {@link IWindowToken}. It can receive configuration change callbacks from
@@ -31,9 +34,9 @@ import android.os.IBinder;
public class WindowTokenClient extends IWindowToken.Stub {
/**
* Attached {@link Context} for this window token to update configuration and resources.
- * Initialized by {@link #attachContext(Context)}.
+ * Initialized by {@link #attachContext(WindowContext)}.
*/
- private Context mContext = null;
+ private WeakReference<WindowContext> mContextRef = null;
private final ResourcesManager mResourcesManager = ResourcesManager.getInstance();
@@ -47,30 +50,46 @@ public class WindowTokenClient extends IWindowToken.Stub {
* @param context context to be attached
* @throws IllegalStateException if attached context has already existed.
*/
- void attachContext(@NonNull Context context) {
- if (mContext != null) {
+ void attachContext(@NonNull WindowContext context) {
+ if (mContextRef != null) {
throw new IllegalStateException("Context is already attached.");
}
- mContext = context;
- ContextImpl impl = ContextImpl.getImpl(mContext);
+ mContextRef = new WeakReference<>(context);
+ final ContextImpl impl = ContextImpl.getImpl(context);
impl.setResources(impl.createWindowContextResources());
}
@Override
public void onConfigurationChanged(Configuration newConfig, int newDisplayId) {
- final int currentDisplayId = mContext.getDisplayId();
+ final Context context = mContextRef.get();
+ if (context == null) {
+ return;
+ }
+ final int currentDisplayId = context.getDisplayId();
final boolean displayChanged = newDisplayId != currentDisplayId;
- final Configuration config = new Configuration(mContext.getResources()
+ final Configuration config = new Configuration(context.getResources()
.getConfiguration());
final boolean configChanged = config.isOtherSeqNewer(newConfig)
&& config.updateFrom(newConfig) != 0;
if (displayChanged || configChanged) {
// TODO(ag/9789103): update resource manager logic to track non-activity tokens
- mResourcesManager.updateResourcesForActivity(asBinder(), config, newDisplayId,
+ mResourcesManager.updateResourcesForActivity(this, config, newDisplayId,
displayChanged);
}
if (displayChanged) {
- mContext.updateDisplay(newDisplayId);
+ context.updateDisplay(newDisplayId);
+ }
+ }
+
+ @Override
+ public void onWindowTokenRemoved() {
+ final WindowContext context = mContextRef.get();
+ if (context != null) {
+ context.destroy();
+ mContextRef.clear();
}
+ // If a secondary display is detached, release all views attached to this token.
+ WindowManagerGlobal.getInstance().closeAll(this, mContextRef.getClass().getName(),
+ "WindowContext");
}
}