Workaround memory leak in AsyncLayoutInflater
Bug: 33158143
Test: manual using test apk + hprof inspection
Change-Id: I6cd3845182794b1f68c5d2898df36f4540d3ff26
diff --git a/core-ui/java/android/support/v4/view/AsyncLayoutInflater.java b/core-ui/java/android/support/v4/view/AsyncLayoutInflater.java
index e638d05..e194a50 100644
--- a/core-ui/java/android/support/v4/view/AsyncLayoutInflater.java
+++ b/core-ui/java/android/support/v4/view/AsyncLayoutInflater.java
@@ -169,28 +169,35 @@
private ArrayBlockingQueue<InflateRequest> mQueue = new ArrayBlockingQueue<>(10);
private SynchronizedPool<InflateRequest> mRequestPool = new SynchronizedPool<>(10);
+ // Extracted to its own method to ensure locals have a constrained liveness
+ // scope by the GC. This is needed to avoid keeping previous request references
+ // alive for an indeterminate amount of time, see b/33158143 for details
+ public void runInner() {
+ InflateRequest request;
+ try {
+ request = mQueue.take();
+ } catch (InterruptedException ex) {
+ // Odd, just continue
+ Log.w(TAG, ex);
+ return;
+ }
+
+ try {
+ request.view = request.inflater.mInflater.inflate(
+ request.resid, request.parent, false);
+ } catch (RuntimeException ex) {
+ // Probably a Looper failure, retry on the UI thread
+ Log.w(TAG, "Failed to inflate resource in the background! Retrying on the UI"
+ + " thread", ex);
+ }
+ Message.obtain(request.inflater.mHandler, 0, request)
+ .sendToTarget();
+ }
+
@Override
public void run() {
while (true) {
- InflateRequest request;
- try {
- request = mQueue.take();
- } catch (InterruptedException ex) {
- // Odd, just continue
- Log.w(TAG, ex);
- continue;
- }
-
- try {
- request.view = request.inflater.mInflater.inflate(
- request.resid, request.parent, false);
- } catch (RuntimeException ex) {
- // Probably a Looper failure, retry on the UI thread
- Log.w(TAG, "Failed to inflate resource in the background! Retrying on the UI"
- + " thread", ex);
- }
- Message.obtain(request.inflater.mHandler, 0, request)
- .sendToTarget();
+ runInner();
}
}