Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 44f4bcb8 authored by Jorim Jaggi's avatar Jorim Jaggi
Browse files

Fix recents entry delay

- 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
parent d70695ee
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -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
+11 −1
Original line number Diff line number Diff line
@@ -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) {
+24 −7
Original line number Diff line number Diff line
@@ -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);
        }
    }

@@ -607,6 +617,13 @@ public class RecentsTaskLoader {
        return activityInfo;
    }

    /**
     * Starts loading tasks.
     */
    public void startLoader(Context ctx) {
        mLoader.start(ctx);
    }

    /**
     * Stops the task loader and clears all queued, pending task loads.
     */
+6 −0
Original line number Diff line number Diff line
@@ -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