OSDN Git Service

Fix recents entry delay
authorJorim Jaggi <jjaggi@google.com>
Fri, 12 May 2017 13:40:43 +0000 (15:40 +0200)
committerJorim Jaggi <jjaggi@google.com>
Sat, 13 May 2017 10:33:59 +0000 (12:33 +0200)
- Start loading things after we drew our first frame.
- Don't load high res task until low res tasks have been loaded:
In case the snapshot is already in cache in system_server the
low-res task loader will load the full res snapshot, leading to
GC pressure due to registerNativeAlloc. Now, if both task loader
load the same snapshot at the same time we are very likely
to trigger a blocking GC alloc.

Test: Open recents, look at systrace
Change-Id: I10c263dc8929742611ad9fbb32f65bc8ac3100bd
Fixes: 36851903
Bug: 32668632

packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
packages/SystemUI/src/com/android/systemui/recents/model/HighResThumbnailLoader.java
packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
packages/SystemUI/tests/src/com/android/systemui/recents/model/HighResThumbnailLoaderTest.java

index 7bc591f..c0e4b99 100644 (file)
@@ -222,6 +222,10 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
                                 getApplicationContext()).onActionEnd(
                                 LatencyTracker.ACTION_TOGGLE_RECENTS));
                     }
+                    DejankUtils.postAfterTraversal(() -> {
+                        Recents.getTaskLoader().startLoader(RecentsActivity.this);
+                        Recents.getTaskLoader().getHighResThumbnailLoader().setVisible(true);
+                    });
                     return true;
                 }
             };
@@ -376,8 +380,6 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
 
         // Notify of the next draw
         mRecentsView.getViewTreeObserver().addOnPreDrawListener(mRecentsDrawnEventListener);
-
-        Recents.getTaskLoader().getHighResThumbnailLoader().setVisible(true);
     }
 
     @Override
index be8da9f..974139a 100644 (file)
@@ -50,6 +50,7 @@ public class HighResThumbnailLoader implements TaskCallbacks {
     private boolean mLoading;
     private boolean mVisible;
     private boolean mFlingingFast;
+    private boolean mTaskLoadQueueIdle;
 
     public HighResThumbnailLoader(SystemServicesProxy ssp, Looper looper) {
         mMainThreadHandler = new Handler(looper);
@@ -71,13 +72,22 @@ public class HighResThumbnailLoader implements TaskCallbacks {
         updateLoading();
     }
 
+    /**
+     * Sets whether the other task load queue is idling. Avoid double-loading bitmaps by not
+     * starting this queue until the other queue is idling.
+     */
+    public void setTaskLoadQueueIdle(boolean idle) {
+        mTaskLoadQueueIdle = idle;
+        updateLoading();
+    }
+
     @VisibleForTesting
     boolean isLoading() {
         return mLoading;
     }
 
     private void updateLoading() {
-        setLoading(mVisible && !mFlingingFast);
+        setLoading(mVisible && !mFlingingFast && mTaskLoadQueueIdle);
     }
 
     private void setLoading(boolean loading) {
index 802cb83..97a9659 100644 (file)
@@ -48,6 +48,7 @@ import java.util.concurrent.ConcurrentLinkedQueue;
  * A Task load queue
  */
 class TaskResourceLoadQueue {
+
     ConcurrentLinkedQueue<Task> mQueue = new ConcurrentLinkedQueue<Task>();
 
     /** Adds a new task to the load queue */
@@ -104,15 +105,18 @@ class BackgroundTaskLoader implements Runnable {
     boolean mCancelled;
     boolean mWaitingOnLoadQueue;
 
+    private final OnIdleChangedListener mOnIdleChangedListener;
+
     /** Constructor, creates a new loading thread that loads task resources in the background */
     public BackgroundTaskLoader(TaskResourceLoadQueue loadQueue,
             TaskKeyLruCache<Drawable> iconCache, Bitmap defaultThumbnail,
-            BitmapDrawable defaultIcon) {
+            BitmapDrawable defaultIcon, OnIdleChangedListener onIdleChangedListener) {
         mLoadQueue = loadQueue;
         mIconCache = iconCache;
         mDefaultThumbnail = defaultThumbnail;
         mDefaultIcon = defaultIcon;
         mMainThreadHandler = new Handler();
+        mOnIdleChangedListener = onIdleChangedListener;
         mLoadThread = new HandlerThread("Recents-TaskResourceLoader",
                 android.os.Process.THREAD_PRIORITY_BACKGROUND);
         mLoadThread.start();
@@ -169,7 +173,11 @@ class BackgroundTaskLoader implements Runnable {
                     synchronized(mLoadQueue) {
                         try {
                             mWaitingOnLoadQueue = true;
+                            mMainThreadHandler.post(
+                                    () -> mOnIdleChangedListener.onIdleChanged(true));
                             mLoadQueue.wait();
+                            mMainThreadHandler.post(
+                                    () -> mOnIdleChangedListener.onIdleChanged(false));
                             mWaitingOnLoadQueue = false;
                         } catch (InterruptedException ie) {
                             ie.printStackTrace();
@@ -230,6 +238,10 @@ class BackgroundTaskLoader implements Runnable {
             }
         }
     }
+
+    interface OnIdleChangedListener {
+        void onIdleChanged(boolean idle);
+    }
 }
 
 /**
@@ -298,15 +310,16 @@ public class RecentsTaskLoader {
 
         // Initialize the proxy, cache and loaders
         int numRecentTasks = ActivityManager.getMaxRecentTasksStatic();
+        mHighResThumbnailLoader = new HighResThumbnailLoader(Recents.getSystemServices(),
+                Looper.getMainLooper());
         mLoadQueue = new TaskResourceLoadQueue();
         mIconCache = new TaskKeyLruCache<>(iconCacheSize, mClearActivityInfoOnEviction);
         mActivityLabelCache = new TaskKeyLruCache<>(numRecentTasks, mClearActivityInfoOnEviction);
         mContentDescriptionCache = new TaskKeyLruCache<>(numRecentTasks,
                 mClearActivityInfoOnEviction);
         mActivityInfoCache = new LruCache(numRecentTasks);
-        mLoader = new BackgroundTaskLoader(mLoadQueue, mIconCache, mDefaultThumbnail, mDefaultIcon);
-        mHighResThumbnailLoader = new HighResThumbnailLoader(Recents.getSystemServices(),
-                Looper.getMainLooper());
+        mLoader = new BackgroundTaskLoader(mLoadQueue, mIconCache, mDefaultThumbnail, mDefaultIcon,
+                mHighResThumbnailLoader::setTaskLoadQueueIdle);
     }
 
     /** Returns the size of the app icon cache. */
@@ -360,9 +373,6 @@ public class RecentsTaskLoader {
         mTempCache.evictAll();
         if (!opts.onlyLoadForCache) {
             mNumVisibleTasksLoaded = opts.numVisibleTasks;
-
-            // Start the loader
-            mLoader.start(context);
         }
     }
 
@@ -608,6 +618,13 @@ public class RecentsTaskLoader {
     }
 
     /**
+     * Starts loading tasks.
+     */
+    public void startLoader(Context ctx) {
+        mLoader.start(ctx);
+    }
+
+    /**
      * Stops the task loader and clears all queued, pending task loads.
      */
     private void stopLoader() {
index 4d632af..f57b6b3 100644 (file)
@@ -62,6 +62,7 @@ public class HighResThumbnailLoaderTest extends SysuiTestCase {
         when(mMockSystemServicesProxy.getTaskThumbnail(anyInt(), anyBoolean()))
                 .thenReturn(mThumbnailData);
         mLoader.setVisible(true);
+        mLoader.setTaskLoadQueueIdle(true);
     }
 
     @Test
@@ -75,6 +76,11 @@ public class HighResThumbnailLoaderTest extends SysuiTestCase {
         assertFalse(mLoader.isLoading());
         mLoader.setFlingingFast(false);
         assertTrue(mLoader.isLoading());
+        mLoader.setFlingingFast(false);
+        mLoader.setTaskLoadQueueIdle(false);
+        assertFalse(mLoader.isLoading());
+        mLoader.setTaskLoadQueueIdle(true);
+        assertTrue(mLoader.isLoading());
     }
 
     @Test