1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.server.wm; 17 18 import android.annotation.Nullable; 19 import android.util.ArrayMap; 20 import android.window.TaskSnapshot; 21 22 import java.io.PrintWriter; 23 24 /** 25 * Base class for an app snapshot cache 26 * @param <TYPE> The basic type, either Task or ActivityRecord 27 */ 28 abstract class SnapshotCache<TYPE extends WindowContainer> { 29 protected final WindowManagerService mService; 30 protected final String mName; 31 protected final ArrayMap<ActivityRecord, Integer> mAppIdMap = new ArrayMap<>(); 32 protected final ArrayMap<Integer, CacheEntry> mRunningCache = new ArrayMap<>(); 33 SnapshotCache(WindowManagerService service, String name)34 SnapshotCache(WindowManagerService service, String name) { 35 mService = service; 36 mName = name; 37 } 38 putSnapshot(TYPE window, TaskSnapshot snapshot)39 abstract void putSnapshot(TYPE window, TaskSnapshot snapshot); 40 clearRunningCache()41 void clearRunningCache() { 42 mRunningCache.clear(); 43 } 44 45 @Nullable getSnapshot(Integer id)46 final TaskSnapshot getSnapshot(Integer id) { 47 synchronized (mService.mGlobalLock) { 48 // Try the running cache. 49 final CacheEntry entry = mRunningCache.get(id); 50 if (entry != null) { 51 return entry.snapshot; 52 } 53 } 54 return null; 55 } 56 57 /** Called when an app token has been removed. */ onAppRemoved(ActivityRecord activity)58 void onAppRemoved(ActivityRecord activity) { 59 final Integer id = mAppIdMap.get(activity); 60 if (id != null) { 61 removeRunningEntry(id); 62 } 63 } 64 65 /** Called when an app window token's process died. */ onAppDied(ActivityRecord activity)66 void onAppDied(ActivityRecord activity) { 67 final Integer id = mAppIdMap.get(activity); 68 if (id != null) { 69 removeRunningEntry(id); 70 } 71 } 72 onIdRemoved(Integer index)73 void onIdRemoved(Integer index) { 74 removeRunningEntry(index); 75 } 76 removeRunningEntry(Integer id)77 void removeRunningEntry(Integer id) { 78 final CacheEntry entry = mRunningCache.get(id); 79 if (entry != null) { 80 mAppIdMap.remove(entry.topApp); 81 mRunningCache.remove(id); 82 } 83 } 84 dump(PrintWriter pw, String prefix)85 void dump(PrintWriter pw, String prefix) { 86 final String doublePrefix = prefix + " "; 87 final String triplePrefix = doublePrefix + " "; 88 pw.println(prefix + "SnapshotCache " + mName); 89 for (int i = mRunningCache.size() - 1; i >= 0; i--) { 90 final CacheEntry entry = mRunningCache.valueAt(i); 91 pw.println(doublePrefix + "Entry token=" + mRunningCache.keyAt(i)); 92 pw.println(triplePrefix + "topApp=" + entry.topApp); 93 pw.println(triplePrefix + "snapshot=" + entry.snapshot); 94 } 95 } 96 97 static final class CacheEntry { 98 /** The snapshot. */ 99 final TaskSnapshot snapshot; 100 /** The app token that was on top of the task when the snapshot was taken */ 101 final ActivityRecord topApp; CacheEntry(TaskSnapshot snapshot, ActivityRecord topApp)102 CacheEntry(TaskSnapshot snapshot, ActivityRecord topApp) { 103 this.snapshot = snapshot; 104 this.topApp = topApp; 105 } 106 } 107 } 108