From 71feb32d93cefbf6921034001b856742dde9ff9c Mon Sep 17 00:00:00 2001 From: Josep del Rio Date: Thu, 16 Feb 2023 22:50:19 +0000 Subject: [PATCH] Use a weak reference to the context in InputManager It has been reported that a recent change to InputManager is causing a memory leak. We were already planning to change it in a way that this issue would no longer happen, but since it's a refactor that will take some time, this is a temporary solution that Prabir suggested; if we keep a weak reference to the context, it will be freed when there is no other active references. Bug: 267241786 Test: will ask for a test run of this change Change-Id: I7e894ba1f014bba36f6ea2566b11426d17d84f68 (cherry picked from commit d87354712e460cad920a8f09df3133fa257cf283) Merged-In: I7e894ba1f014bba36f6ea2566b11426d17d84f68 --- .../android/hardware/input/InputManager.java | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index 2ea9ea06f7203..a33cd9760091b 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -74,6 +74,7 @@ import com.android.internal.os.SomeArgs; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -99,13 +100,12 @@ public final class InputManager { private final IInputManager mIm; /** - * InputManager has historically used its own static getter {@link #getInstance()} that doesn't - * provide a context. We provide a Context to the InputManager instance through the - * {@link android.app.SystemServiceRegistry}. Methods that need a Context must use - * {@link #getContext()} to obtain it. + * We hold a weak reference to the context to avoid leaking it indefinitely, + * since we currently store the input manager instance as a static variable that + * will outlive any context. */ @Nullable - private Context mLateInitContext; + private WeakReference mWeakContext; /** * Whether a PointerIcon is shown for stylus pointers. @@ -372,8 +372,8 @@ public final class InputManager { throw new IllegalStateException(e); } } - if (sInstance.mLateInitContext == null) { - sInstance.mLateInitContext = context; + if (sInstance.mWeakContext == null || sInstance.mWeakContext.get() == null) { + sInstance.mWeakContext = new WeakReference(context); } return sInstance; } @@ -381,9 +381,14 @@ public final class InputManager { @NonNull private Context getContext() { - return Objects.requireNonNull(mLateInitContext, + WeakReference weakContext = Objects.requireNonNull(mWeakContext, "A context is required for InputManager. Get the InputManager instance using " + "Context#getSystemService before calling this method."); + // If we get at this point, an app calling this function could potentially expect a + // Context that has disappeared due to garbage collection. Holding a weak reference + // is a temporary solution that should be resolved before the release of a + // production version. This is being tracked in b/267758905 + return Objects.requireNonNull(weakContext.get(), "missing Context"); } /**