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

Commit 10abe2fe authored by Jorim Jaggi's avatar Jorim Jaggi
Browse files

When app dies, destroy snapshot

Also destroy snapshot when we remove the AppWindowToken.

Test: runtest frameworks-services -c
com.android.server.wm.SnapshotCacheTest
Test: Open app, go home, kill app, make sure snapshots are
destroyed.

Change-Id: I532c2d7499a86164175f9fcbc8b77c6eb6bfeae6
parent 02d091aa
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -2172,6 +2172,12 @@ public class ActivityManager {
            dest.writeParcelable(mContentInsets, 0);
        }

        @Override
        public String toString() {
            return "TaskSnapshot{mSnapshot=" + mSnapshot + " mOrientation=" + mOrientation
                    + " mContentInsets=" + mContentInsets.toShortString();
        }

        public static final Creator<TaskSnapshot> CREATOR = new Creator<TaskSnapshot>() {
            public TaskSnapshot createFromParcel(Parcel source) {
                return new TaskSnapshot(source);
+1 −0
Original line number Diff line number Diff line
@@ -445,6 +445,7 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree

        mService.mOpeningApps.remove(this);
        mService.mUnknownAppVisibilityController.appRemoved(this);
        mService.mTaskSnapshotController.onAppRemoved(this);
        waitingToShow = false;
        if (mService.mClosingApps.contains(this)) {
            delayed = true;
+57 −3
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ import android.annotation.Nullable;
import android.app.ActivityManager.TaskSnapshot;
import android.util.ArrayMap;

import java.io.PrintWriter;

/**
 * Caches snapshots. See {@link TaskSnapshotController}.
 * <p>
@@ -27,13 +29,65 @@ import android.util.ArrayMap;
 */
class TaskSnapshotCache {

    private final ArrayMap<Task, TaskSnapshot> mCache = new ArrayMap<>();
    private final ArrayMap<AppWindowToken, Task> mAppTaskMap = new ArrayMap<>();
    private final ArrayMap<Task, CacheEntry> mCache = new ArrayMap<>();

    void putSnapshot(Task task, TaskSnapshot snapshot) {
        mCache.put(task, snapshot);
        final CacheEntry entry = mCache.get(task);
        if (entry != null) {
            mAppTaskMap.remove(entry.topApp);
        }
        final AppWindowToken top = task.getTopChild();
        mAppTaskMap.put(top, task);
        mCache.put(task, new CacheEntry(snapshot, task.getTopChild()));
    }

    @Nullable TaskSnapshot getSnapshot(Task task) {
        return mCache.get(task);
        final CacheEntry entry = mCache.get(task);
        return entry != null ? entry.snapshot : null;
    }

    /**
     * Cleans the cache after an app window token's process died.
     */
    void cleanCache(AppWindowToken wtoken) {
        final Task task = mAppTaskMap.get(wtoken);
        if (task != null) {
            removeEntry(task);
        }
    }

    private void removeEntry(Task task) {
        final CacheEntry entry = mCache.get(task);
        if (entry != null) {
            mAppTaskMap.remove(entry.topApp);
            mCache.remove(task);
        }
    }

    void dump(PrintWriter pw, String prefix) {
        final String doublePrefix = prefix + "  ";
        final String triplePrefix = doublePrefix + "  ";
        pw.println(prefix + "SnapshotCache");
        for (int i = mCache.size() - 1; i >= 0; i--) {
            final CacheEntry entry = mCache.valueAt(i);
            pw.println(doublePrefix + "Entry taskId=" + mCache.keyAt(i).mTaskId);
            pw.println(triplePrefix + "topApp=" + entry.topApp);
            pw.println(triplePrefix + "snapshot=" + entry.snapshot);
        }
    }

    private static final class CacheEntry {

        /** The snapshot. */
        final TaskSnapshot snapshot;

        /** The app token that was on top of the task when the snapshot was taken */
        final AppWindowToken topApp;

        CacheEntry(TaskSnapshot snapshot, AppWindowToken topApp) {
            this.snapshot = snapshot;
            this.topApp = topApp;
        }
    }
}
+24 −1
Original line number Diff line number Diff line
@@ -34,6 +34,8 @@ import android.view.WindowManagerPolicy.StartingSurface;

import com.android.internal.annotations.VisibleForTesting;

import java.io.PrintWriter;

/**
 * When an app token becomes invisible, we take a snapshot (bitmap) of the corresponding task and
 * put it into our cache. Internally we use gralloc buffers to be able to draw them wherever we
@@ -92,7 +94,7 @@ class TaskSnapshotController {
    }

    private TaskSnapshot snapshotTask(Task task) {
        final AppWindowToken top = (AppWindowToken) task.getTop();
        final AppWindowToken top = task.getTopChild();
        if (top == null) {
            return null;
        }
@@ -131,4 +133,25 @@ class TaskSnapshotController {
    private boolean canSnapshotTask(Task task) {
        return !StackId.isHomeOrRecentsStack(task.mStack.mStackId);
    }

    /**
     * Called when an {@link AppWindowToken} has been removed.
     */
    void onAppRemoved(AppWindowToken wtoken) {
        // TODO: Clean from both recents and running cache.
        mCache.cleanCache(wtoken);
    }

    /**
     * Called when the process of an {@link AppWindowToken} has died.
     */
    void onAppDied(AppWindowToken wtoken) {

        // TODO: Only clean from running cache.
        mCache.cleanCache(wtoken);
    }

    void dump(PrintWriter pw, String prefix) {
        mCache.dump(pw, prefix);
    }
}
+3 −3
Original line number Diff line number Diff line
@@ -451,9 +451,9 @@ class WindowContainer<E extends WindowContainer> implements Comparable<WindowCon
        return false;
    }

    /** Returns the top child container or this container if there are no children. */
    WindowContainer getTop() {
        return mChildren.isEmpty() ? this : mChildren.peekLast();
    /** Returns the top child container. */
    E getTopChild() {
        return mChildren.peekLast();
    }

    /** Returns true if there is still a removal being deferred */
Loading