diff options
| author | 2017-12-20 15:38:12 -0800 | |
|---|---|---|
| committer | 2017-12-21 15:36:08 -0800 | |
| commit | 1c110302fe3236e7477020aa11b9cb0b8226328a (patch) | |
| tree | 4b006e3f2accd0f1b7b1588fd54aabc2513b1166 | |
| parent | 93592a9b390e2f44a476068e1d732d3d6b13e82e (diff) | |
Fix object pool for lifecycler
The original implementation of object pool for lifecycle
transactions tried to always recycle objects after a
transaction was scheduled. In case when a client was running
in the same process this lead to objects being emptied before
it could actually perform the transaction.
Also when checking if object was already in the pool we should
use "==" instead of equality check.
Bug: 70568084
Bug: 70526039
Bug: 70616950
Test: android.app.servertransaction.ObjectPoolTests
Change-Id: I45eeecc189b9a458d8efdfed256b81cf0baf8b95
5 files changed, 29 insertions, 14 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 84f032d432ea..5e9cc70bde65 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -1650,7 +1650,9 @@ public final class ActivityThread extends ClientTransactionHandler { (String[]) ((SomeArgs) msg.obj).arg2); break; case EXECUTE_TRANSACTION: - mTransactionExecutor.execute(((ClientTransaction) msg.obj)); + final ClientTransaction transaction = (ClientTransaction) msg.obj; + mTransactionExecutor.execute(transaction); + transaction.recycle(); break; } Object obj = msg.obj; diff --git a/core/java/android/app/servertransaction/ClientTransaction.java b/core/java/android/app/servertransaction/ClientTransaction.java index 764ceede5d20..3c96f06945c5 100644 --- a/core/java/android/app/servertransaction/ClientTransaction.java +++ b/core/java/android/app/servertransaction/ClientTransaction.java @@ -54,6 +54,11 @@ public class ClientTransaction implements Parcelable, ObjectPoolItem { /** Target client activity. Might be null if the entire transaction is targeting an app. */ private IBinder mActivityToken; + /** Get the target client of the transaction. */ + public IApplicationThread getClient() { + return mClient; + } + /** * Add a message to the end of the sequence of callbacks. * @param activityCallback A single message that can contain a lifecycle request/callback. diff --git a/core/java/android/app/servertransaction/ObjectPool.java b/core/java/android/app/servertransaction/ObjectPool.java index 98121253f486..2fec30a0dde7 100644 --- a/core/java/android/app/servertransaction/ObjectPool.java +++ b/core/java/android/app/servertransaction/ObjectPool.java @@ -16,8 +16,8 @@ package android.app.servertransaction; +import java.util.ArrayList; import java.util.HashMap; -import java.util.LinkedList; import java.util.Map; /** @@ -27,7 +27,7 @@ import java.util.Map; class ObjectPool { private static final Object sPoolSync = new Object(); - private static final Map<Class, LinkedList<? extends ObjectPoolItem>> sPoolMap = + private static final Map<Class, ArrayList<? extends ObjectPoolItem>> sPoolMap = new HashMap<>(); private static final int MAX_POOL_SIZE = 50; @@ -40,9 +40,9 @@ class ObjectPool { public static <T extends ObjectPoolItem> T obtain(Class<T> itemClass) { synchronized (sPoolSync) { @SuppressWarnings("unchecked") - LinkedList<T> itemPool = (LinkedList<T>) sPoolMap.get(itemClass); + final ArrayList<T> itemPool = (ArrayList<T>) sPoolMap.get(itemClass); if (itemPool != null && !itemPool.isEmpty()) { - return itemPool.poll(); + return itemPool.remove(itemPool.size() - 1); } return null; } @@ -56,16 +56,20 @@ class ObjectPool { public static <T extends ObjectPoolItem> void recycle(T item) { synchronized (sPoolSync) { @SuppressWarnings("unchecked") - LinkedList<T> itemPool = (LinkedList<T>) sPoolMap.get(item.getClass()); + ArrayList<T> itemPool = (ArrayList<T>) sPoolMap.get(item.getClass()); if (itemPool == null) { - itemPool = new LinkedList<>(); + itemPool = new ArrayList<>(); sPoolMap.put(item.getClass(), itemPool); } - if (itemPool.contains(item)) { - throw new IllegalStateException("Trying to recycle already recycled item"); + // Check if the item is already in the pool + final int size = itemPool.size(); + for (int i = 0; i < size; i++) { + if (itemPool.get(i) == item) { + throw new IllegalStateException("Trying to recycle already recycled item"); + } } - if (itemPool.size() < MAX_POOL_SIZE) { + if (size < MAX_POOL_SIZE) { itemPool.add(item); } } diff --git a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java index c19a343957c0..aefc47e95512 100644 --- a/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/ObjectPoolTests.java @@ -42,8 +42,7 @@ import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) @SmallTest -// TODO: b/70616950 -//@Presubmit +@Presubmit public class ObjectPoolTests { // 1. Check if two obtained objects from pool are not the same. diff --git a/services/core/java/com/android/server/am/ClientLifecycleManager.java b/services/core/java/com/android/server/am/ClientLifecycleManager.java index 014f7086efa3..1e7080980d9e 100644 --- a/services/core/java/com/android/server/am/ClientLifecycleManager.java +++ b/services/core/java/com/android/server/am/ClientLifecycleManager.java @@ -21,6 +21,7 @@ import android.app.IApplicationThread; import android.app.servertransaction.ClientTransaction; import android.app.servertransaction.ClientTransactionItem; import android.app.servertransaction.ActivityLifecycleItem; +import android.os.Binder; import android.os.IBinder; import android.os.RemoteException; @@ -43,8 +44,12 @@ class ClientLifecycleManager { */ void scheduleTransaction(ClientTransaction transaction) throws RemoteException { transaction.schedule(); - // TODO: b/70616950 - //transaction.recycle(); + if (!(transaction.getClient() instanceof Binder)) { + // If client is not an instance of Binder - it's a remote call and at this point it is + // safe to recycle the object. All objects used for local calls will be recycled after + // the transaction is executed on client in ActivityThread. + transaction.recycle(); + } } /** |