• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 android.app.sdksandbox.sdkprovider;
18 
19 import android.annotation.NonNull;
20 import android.app.Activity;
21 import android.os.Binder;
22 import android.os.Build;
23 import android.os.IBinder;
24 import android.util.ArrayMap;
25 
26 import androidx.annotation.RequiresApi;
27 
28 import com.android.internal.annotations.GuardedBy;
29 
30 import java.util.Map;
31 
32 /**
33  * It is a Singleton class to store the registered {@link SdkSandboxActivityHandler} instances and
34  * their associated {@link Activity} instances.
35  *
36  * @hide
37  */
38 public class SdkSandboxActivityRegistry {
39     private static final Object sLock = new Object();
40 
41     @GuardedBy("sLock")
42     private static SdkSandboxActivityRegistry sInstance;
43 
44     // A lock to keep all map synchronized
45     private final Object mMapsLock = new Object();
46 
47     @GuardedBy("mMapsLock")
48     private final Map<SdkSandboxActivityHandler, HandlerInfo> mHandlerToHandlerInfoMap =
49             new ArrayMap<>();
50 
51     @GuardedBy("mMapsLock")
52     private final Map<IBinder, HandlerInfo> mTokenToHandlerInfoMap = new ArrayMap<>();
53 
SdkSandboxActivityRegistry()54     private SdkSandboxActivityRegistry() {}
55 
56     /** Returns a singleton instance of this class. */
getInstance()57     public static SdkSandboxActivityRegistry getInstance() {
58         synchronized (sLock) {
59             if (sInstance == null) {
60                 sInstance = new SdkSandboxActivityRegistry();
61             }
62             return sInstance;
63         }
64     }
65 
66     /**
67      * Registers the passed {@link SdkSandboxActivityHandler} and returns a {@link IBinder} token
68      * that identifies it.
69      *
70      * <p>If {@link SdkSandboxActivityHandler} is already registered, its {@link IBinder} identifier
71      * will be returned.
72      *
73      * @param sdkName is the name of the SDK registering {@link SdkSandboxActivityHandler}
74      * @param handler is the {@link SdkSandboxActivityHandler} to register.
75      */
76     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
77     @NonNull
register(@onNull String sdkName, @NonNull SdkSandboxActivityHandler handler)78     public IBinder register(@NonNull String sdkName, @NonNull SdkSandboxActivityHandler handler) {
79         synchronized (mMapsLock) {
80             if (mHandlerToHandlerInfoMap.containsKey(handler)) {
81                 HandlerInfo handlerInfo = mHandlerToHandlerInfoMap.get(handler);
82                 return handlerInfo.getToken();
83             }
84 
85             IBinder token = new Binder();
86             HandlerInfo handlerInfo = new HandlerInfo(sdkName, handler, token);
87             mHandlerToHandlerInfoMap.put(handlerInfo.getHandler(), handlerInfo);
88             mTokenToHandlerInfoMap.put(handlerInfo.getToken(), handlerInfo);
89             return token;
90         }
91     }
92 
93     /**
94      * Unregisters the passed {@link SdkSandboxActivityHandler}.
95      *
96      * @param handler is the {@link SdkSandboxActivityHandler} to unregister.
97      */
98     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
unregister(@onNull SdkSandboxActivityHandler handler)99     public void unregister(@NonNull SdkSandboxActivityHandler handler) {
100         synchronized (mMapsLock) {
101             HandlerInfo handlerInfo = mHandlerToHandlerInfoMap.get(handler);
102             if (handlerInfo == null) {
103                 return;
104             }
105             mHandlerToHandlerInfoMap.remove(handlerInfo.getHandler());
106             mTokenToHandlerInfoMap.remove(handlerInfo.getToken());
107         }
108     }
109 
110     /**
111      * It notifies the SDK about {@link Activity} creation.
112      *
113      * <p>This should be called by the sandbox {@link Activity} while being created to notify the
114      * SDK that registered the {@link SdkSandboxActivityHandler} that identified by the passed
115      * {@link IBinder} token.
116      *
117      * @param token is the {@link IBinder} identifier for the {@link SdkSandboxActivityHandler}.
118      * @param activity is the {@link Activity} is being created.
119      * @throws IllegalArgumentException if there is no registered handler identified by the passed
120      *     {@link IBinder} token (that mostly would mean that the handler is de-registered before
121      *     the passed {@link Activity} is created), or the {@link SdkSandboxActivityHandler} is
122      *     already notified about a previous {@link Activity}, in both cases the passed {@link
123      *     Activity} will not start.
124      */
125     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
notifyOnActivityCreation(@onNull IBinder token, @NonNull Activity activity)126     public void notifyOnActivityCreation(@NonNull IBinder token, @NonNull Activity activity) {
127         synchronized (mMapsLock) {
128             HandlerInfo handlerInfo = mTokenToHandlerInfoMap.get(token);
129             if (handlerInfo == null) {
130                 throw new IllegalArgumentException(
131                         "There is no registered SdkSandboxActivityHandler to notify");
132             }
133             handlerInfo.getHandler().onActivityCreated(activity);
134         }
135     }
136 
137     /**
138      * Holds the information about {@link SdkSandboxActivityHandler}.
139      *
140      * @hide
141      */
142     private static class HandlerInfo {
143         private final String mSdkName;
144         private final SdkSandboxActivityHandler mHandler;
145         private final IBinder mToken;
146 
147 
HandlerInfo(String sdkName, SdkSandboxActivityHandler handler, IBinder token)148         HandlerInfo(String sdkName, SdkSandboxActivityHandler handler, IBinder token) {
149             this.mSdkName = sdkName;
150             this.mHandler = handler;
151             this.mToken = token;
152         }
153 
154         @NonNull
getSdkName()155         public String getSdkName() {
156             return mSdkName;
157         }
158 
159         @NonNull
getHandler()160         public SdkSandboxActivityHandler getHandler() {
161             return mHandler;
162         }
163 
164         @NonNull
getToken()165         public IBinder getToken() {
166             return mToken;
167         }
168     }
169 }
170