• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 
17 package com.android.server.wm;
18 
19 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SYNC_ENGINE;
20 
21 import android.annotation.NonNull;
22 import android.util.ArraySet;
23 import android.util.SparseArray;
24 import android.view.SurfaceControl;
25 
26 import com.android.internal.protolog.common.ProtoLog;
27 
28 /**
29  * Utility class for collecting WindowContainers that will merge transactions.
30  * For example to use to synchronously resize all the children of a window container
31  *   1. Open a new sync set, and pass the listener that will be invoked
32  *        int id startSyncSet(TransactionReadyListener)
33  *      the returned ID will be eventually passed to the TransactionReadyListener in combination
34  *      with a set of WindowContainers that are ready, meaning onTransactionReady was called for
35  *      those WindowContainers. You also use it to refer to the operation in future steps.
36  *   2. Ask each child to participate:
37  *       addToSyncSet(int id, WindowContainer wc)
38  *      if the child thinks it will be affected by a configuration change (a.k.a. has a visible
39  *      window in its sub hierarchy, then we will increment a counter of expected callbacks
40  *      At this point the containers hierarchy will redirect pendingTransaction and sub hierarchy
41  *      updates in to the sync engine.
42  *   3. Apply your configuration changes to the window containers.
43  *   4. Tell the engine that the sync set is ready
44  *       setReady(int id)
45  *   5. If there were no sub windows anywhere in the hierarchy to wait on, then
46  *      transactionReady is immediately invoked, otherwise all the windows are poked
47  *      to redraw and to deliver a buffer to {@link WindowState#finishDrawing}.
48  *      Once all this drawing is complete, all the transactions will be merged and delivered
49  *      to TransactionReadyListener.
50  *
51  * This works primarily by setting-up state and then watching/waiting for the registered subtrees
52  * to enter into a "finished" state (either by receiving drawn content or by disappearing). This
53  * checks the subtrees during surface-placement.
54  */
55 class BLASTSyncEngine {
56     private static final String TAG = "BLASTSyncEngine";
57 
58     interface TransactionReadyListener {
onTransactionReady(int mSyncId, SurfaceControl.Transaction transaction)59         void onTransactionReady(int mSyncId, SurfaceControl.Transaction transaction);
60     }
61 
62     /**
63      * Holds state associated with a single synchronous set of operations.
64      */
65     class SyncGroup {
66         final int mSyncId;
67         final TransactionReadyListener mListener;
68         boolean mReady = false;
69         final ArraySet<WindowContainer> mRootMembers = new ArraySet<>();
70         private SurfaceControl.Transaction mOrphanTransaction = null;
71 
SyncGroup(TransactionReadyListener listener, int id)72         private SyncGroup(TransactionReadyListener listener, int id) {
73             mSyncId = id;
74             mListener = listener;
75         }
76 
77         /**
78          * Gets a transaction to dump orphaned operations into. Orphaned operations are operations
79          * that were on the mSyncTransactions of "root" subtrees which have been removed during the
80          * sync period.
81          */
82         @NonNull
getOrphanTransaction()83         SurfaceControl.Transaction getOrphanTransaction() {
84             if (mOrphanTransaction == null) {
85                 // Lazy since this isn't common
86                 mOrphanTransaction = mWm.mTransactionFactory.get();
87             }
88             return mOrphanTransaction;
89         }
90 
onSurfacePlacement()91         private void onSurfacePlacement() {
92             if (!mReady) return;
93             ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: onSurfacePlacement checking %s",
94                     mSyncId, mRootMembers);
95             for (int i = mRootMembers.size() - 1; i >= 0; --i) {
96                 final WindowContainer wc = mRootMembers.valueAt(i);
97                 if (!wc.isSyncFinished()) {
98                     ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d:  Unfinished container: %s",
99                             mSyncId, wc);
100                     return;
101                 }
102             }
103             finishNow();
104         }
105 
finishNow()106         private void finishNow() {
107             ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Finished!", mSyncId);
108             SurfaceControl.Transaction merged = mWm.mTransactionFactory.get();
109             if (mOrphanTransaction != null) {
110                 merged.merge(mOrphanTransaction);
111             }
112             for (WindowContainer wc : mRootMembers) {
113                 wc.finishSync(merged, false /* cancel */);
114             }
115             mListener.onTransactionReady(mSyncId, merged);
116             mActiveSyncs.remove(mSyncId);
117         }
118 
setReady(boolean ready)119         private void setReady(boolean ready) {
120             ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Set ready", mSyncId);
121             mReady = ready;
122             if (!ready) return;
123             mWm.mWindowPlacerLocked.requestTraversal();
124         }
125 
addToSync(WindowContainer wc)126         private void addToSync(WindowContainer wc) {
127             if (!mRootMembers.add(wc)) {
128                 return;
129             }
130             ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Adding to group: %s", mSyncId, wc);
131             wc.setSyncGroup(this);
132             wc.prepareSync();
133             mWm.mWindowPlacerLocked.requestTraversal();
134         }
135 
onCancelSync(WindowContainer wc)136         void onCancelSync(WindowContainer wc) {
137             mRootMembers.remove(wc);
138         }
139     }
140 
141     private final WindowManagerService mWm;
142     private int mNextSyncId = 0;
143     private final SparseArray<SyncGroup> mActiveSyncs = new SparseArray<>();
144 
BLASTSyncEngine(WindowManagerService wms)145     BLASTSyncEngine(WindowManagerService wms) {
146         mWm = wms;
147     }
148 
startSyncSet(TransactionReadyListener listener)149     int startSyncSet(TransactionReadyListener listener) {
150         final int id = mNextSyncId++;
151         final SyncGroup s = new SyncGroup(listener, id);
152         mActiveSyncs.put(id, s);
153         ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Started for listener: %s", id, listener);
154         return id;
155     }
156 
addToSyncSet(int id, WindowContainer wc)157     void addToSyncSet(int id, WindowContainer wc) {
158         mActiveSyncs.get(id).addToSync(wc);
159     }
160 
setReady(int id, boolean ready)161     void setReady(int id, boolean ready) {
162         mActiveSyncs.get(id).setReady(ready);
163     }
164 
setReady(int id)165     void setReady(int id) {
166         setReady(id, true);
167     }
168 
169     /**
170      * Aborts the sync (ie. it doesn't wait for ready or anything to finish)
171      */
abort(int id)172     void abort(int id) {
173         mActiveSyncs.get(id).finishNow();
174     }
175 
onSurfacePlacement()176     void onSurfacePlacement() {
177         // backwards since each state can remove itself if finished
178         for (int i = mActiveSyncs.size() - 1; i >= 0; --i) {
179             mActiveSyncs.valueAt(i).onSurfacePlacement();
180         }
181     }
182 }
183