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 
17 package com.android.server.wm;
18 
19 import android.annotation.Nullable;
20 import android.os.Binder;
21 import android.os.IBinder;
22 import android.os.RemoteException;
23 import android.util.ArrayMap;
24 import android.window.AddToSurfaceSyncGroupResult;
25 import android.window.ISurfaceSyncGroupCompletedListener;
26 import android.window.ITransactionReadyCallback;
27 import android.window.SurfaceSyncGroup;
28 
29 import com.android.internal.annotations.GuardedBy;
30 
31 class SurfaceSyncGroupController {
32     private static final String TAG = "SurfaceSyncGroupController";
33     private final Object mLock = new Object();
34 
35     @GuardedBy("mLock")
36     private final ArrayMap<IBinder, SurfaceSyncGroupData> mSurfaceSyncGroups = new ArrayMap<>();
37 
addToSyncGroup(IBinder syncGroupToken, boolean parentSyncGroupMerge, @Nullable ISurfaceSyncGroupCompletedListener completedListener, AddToSurfaceSyncGroupResult outAddToSyncGroupResult)38     boolean addToSyncGroup(IBinder syncGroupToken, boolean parentSyncGroupMerge,
39             @Nullable ISurfaceSyncGroupCompletedListener completedListener,
40             AddToSurfaceSyncGroupResult outAddToSyncGroupResult) {
41         SurfaceSyncGroup root;
42         synchronized (mLock) {
43             SurfaceSyncGroupData syncGroupData = mSurfaceSyncGroups.get(syncGroupToken);
44             if (syncGroupData == null) {
45                 root = new SurfaceSyncGroup(TAG + "-" + syncGroupToken.hashCode());
46                 if (completedListener != null) {
47                     root.addSyncCompleteCallback(Runnable::run, () -> {
48                         try {
49                             completedListener.onSurfaceSyncGroupComplete();
50                         } catch (RemoteException e) {
51                         }
52                     });
53                 }
54                 mSurfaceSyncGroups.put(syncGroupToken,
55                         new SurfaceSyncGroupData(Binder.getCallingUid(), root));
56             } else {
57                 root = syncGroupData.mSurfaceSyncGroup;
58             }
59         }
60 
61         ITransactionReadyCallback callback =
62                 root.createTransactionReadyCallback(parentSyncGroupMerge);
63         if (callback == null) {
64             return false;
65         }
66         outAddToSyncGroupResult.mParentSyncGroup = root.mISurfaceSyncGroup;
67         outAddToSyncGroupResult.mTransactionReadyCallback = callback;
68         return true;
69     }
70 
markSyncGroupReady(IBinder syncGroupToken)71     void markSyncGroupReady(IBinder syncGroupToken) {
72         final SurfaceSyncGroup root;
73         synchronized (mLock) {
74             SurfaceSyncGroupData syncGroupData = mSurfaceSyncGroups.get(syncGroupToken);
75             if (syncGroupData == null) {
76                 throw new IllegalArgumentException(
77                         "SurfaceSyncGroup Token has not been set up or has already been marked as"
78                                 + " ready");
79             }
80             if (syncGroupData.mOwningUid != Binder.getCallingUid()) {
81                 throw new IllegalArgumentException(
82                         "Only process that created the SurfaceSyncGroup can call "
83                                 + "markSyncGroupReady");
84             }
85             root = syncGroupData.mSurfaceSyncGroup;
86             mSurfaceSyncGroups.remove(syncGroupToken);
87         }
88 
89         root.markSyncReady();
90     }
91 
92     private static class SurfaceSyncGroupData {
93         final int mOwningUid;
94         final SurfaceSyncGroup mSurfaceSyncGroup;
95 
SurfaceSyncGroupData(int owningUid, SurfaceSyncGroup surfaceSyncGroup)96         private SurfaceSyncGroupData(int owningUid, SurfaceSyncGroup surfaceSyncGroup) {
97             mOwningUid = owningUid;
98             mSurfaceSyncGroup = surfaceSyncGroup;
99         }
100     }
101 }
102