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.sdksandbox;
18 
19 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
20 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
21 import static android.app.adservices.AdServicesManager.AD_SERVICES_SYSTEM_SERVICE;
22 import static android.app.sdksandbox.SdkSandboxManager.ACTION_START_SANDBOXED_ACTIVITY;
23 import static android.app.sdksandbox.SdkSandboxManager.EXTRA_SANDBOXED_ACTIVITY_HANDLER;
24 import static android.app.sdksandbox.SdkSandboxManager.LOAD_SDK_INTERNAL_ERROR;
25 import static android.app.sdksandbox.SdkSandboxManager.LOAD_SDK_SDK_SANDBOX_DISABLED;
26 import static android.app.sdksandbox.SdkSandboxManager.REQUEST_SURFACE_PACKAGE_SDK_NOT_LOADED;
27 import static android.app.sdksandbox.SdkSandboxManager.SDK_SANDBOX_PROCESS_NOT_AVAILABLE;
28 import static android.app.sdksandbox.SdkSandboxManager.SDK_SANDBOX_SERVICE;
29 
30 import static com.android.sdksandbox.flags.Flags.sandboxActivitySdkBasedContext;
31 import static com.android.sdksandbox.service.stats.SdkSandboxStatsLog.SANDBOX_ACTIVITY_EVENT_OCCURRED__CALL_RESULT__FAILURE_SECURITY_EXCEPTION;
32 import static com.android.server.sdksandbox.SdkSandboxStorageManager.StorageDirInfo;
33 import static com.android.server.wm.ActivityInterceptorCallback.MAINLINE_SDK_SANDBOX_ORDER_ID;
34 
35 import android.annotation.NonNull;
36 import android.annotation.Nullable;
37 import android.annotation.RequiresPermission;
38 import android.annotation.WorkerThread;
39 import android.app.ActivityManager;
40 import android.app.sdksandbox.AppOwnedSdkSandboxInterface;
41 import android.app.sdksandbox.ILoadSdkCallback;
42 import android.app.sdksandbox.IRequestSurfacePackageCallback;
43 import android.app.sdksandbox.ISdkSandboxManager;
44 import android.app.sdksandbox.ISdkSandboxProcessDeathCallback;
45 import android.app.sdksandbox.ISdkToServiceCallback;
46 import android.app.sdksandbox.ISharedPreferencesSyncCallback;
47 import android.app.sdksandbox.IUnloadSdkCallback;
48 import android.app.sdksandbox.LoadSdkException;
49 import android.app.sdksandbox.LogUtil;
50 import android.app.sdksandbox.SandboxLatencyInfo;
51 import android.app.sdksandbox.SandboxedSdk;
52 import android.app.sdksandbox.SdkSandboxManager;
53 import android.app.sdksandbox.SharedPreferencesUpdate;
54 import android.app.sdksandbox.sandboxactivity.SdkSandboxActivityAuthority;
55 import android.app.sdksandbox.sdkprovider.SdkSandboxController;
56 import android.content.BroadcastReceiver;
57 import android.content.ComponentName;
58 import android.content.Context;
59 import android.content.Intent;
60 import android.content.IntentFilter;
61 import android.content.ServiceConnection;
62 import android.content.pm.ActivityInfo;
63 import android.content.pm.ApplicationInfo;
64 import android.content.pm.PackageManager;
65 import android.content.pm.ProviderInfo;
66 import android.content.pm.ResolveInfo;
67 import android.content.pm.ServiceInfo;
68 import android.os.Binder;
69 import android.os.Build;
70 import android.os.Bundle;
71 import android.os.Handler;
72 import android.os.HandlerThread;
73 import android.os.IBinder;
74 import android.os.ParcelFileDescriptor;
75 import android.os.Process;
76 import android.os.RemoteCallbackList;
77 import android.os.RemoteException;
78 import android.os.SystemClock;
79 import android.os.SystemProperties;
80 import android.os.UserHandle;
81 import android.provider.Settings;
82 import android.util.ArrayMap;
83 import android.util.ArraySet;
84 import android.util.Log;
85 import android.webkit.WebViewUpdateService;
86 
87 import androidx.annotation.RequiresApi;
88 
89 import com.android.adservices.AdServicesCommon;
90 import com.android.internal.annotations.GuardedBy;
91 import com.android.internal.annotations.VisibleForTesting;
92 import com.android.modules.utils.BackgroundThread;
93 import com.android.modules.utils.build.SdkLevel;
94 import com.android.sdksandbox.IComputeSdkStorageCallback;
95 import com.android.sdksandbox.IRequestSurfacePackageFromSdkCallback;
96 import com.android.sdksandbox.ISdkSandboxService;
97 import com.android.sdksandbox.service.stats.SdkSandboxStatsLog;
98 import com.android.server.LocalManagerRegistry;
99 import com.android.server.SystemService;
100 import com.android.server.am.ActivityManagerLocal;
101 import com.android.server.pm.PackageManagerLocal;
102 import com.android.server.sdksandbox.helpers.StringHelper;
103 import com.android.server.sdksandbox.proto.Services.AllowedService;
104 import com.android.server.sdksandbox.proto.Services.AllowedServices;
105 import com.android.server.wm.ActivityInterceptorCallback;
106 import com.android.server.wm.ActivityInterceptorCallbackRegistry;
107 
108 import java.io.FileDescriptor;
109 import java.io.PrintWriter;
110 import java.util.ArrayList;
111 import java.util.Arrays;
112 import java.util.List;
113 import java.util.Objects;
114 import java.util.Set;
115 
116 /**
117  * Implementation of {@link SdkSandboxManager}.
118  *
119  * @hide
120  */
121 public class SdkSandboxManagerService extends ISdkSandboxManager.Stub {
122 
123     private static final String TAG = "SdkSandboxManager";
124 
125     private static final String STOP_SDK_SANDBOX_PERMISSION =
126             "com.android.app.sdksandbox.permission.STOP_SDK_SANDBOX";
127 
128     private static final String SANDBOX_NOT_AVAILABLE_MSG = "Sandbox is unavailable";
129     private static final String SANDBOX_DISABLED_MSG = "SDK sandbox is disabled";
130 
131     private static final String DUMP_ARG_AD_SERVICES = "--AdServices";
132 
133     private final Context mContext;
134 
135     private final ActivityManager mActivityManager;
136     private final ActivityManagerLocal mActivityManagerLocal;
137     private final Handler mHandler;
138     private final SdkSandboxStorageManager mSdkSandboxStorageManager;
139     private final SdkSandboxServiceProvider mServiceProvider;
140     private final SdkSandboxStatsdLogger mSdkSandboxStatsdLogger;
141     private final SdkSandboxRestrictionManager mSdkSandboxRestrictionManager;
142 
143     @GuardedBy("mLock")
144     private IBinder mAdServicesManager;
145 
146     // TODO(b/282239822): temporary guard to define if dump() should handle the --AdServices otpion
147     @GuardedBy("mLock")
148     private boolean mAdServicesManagerPublished;
149 
150     private final Object mLock = new Object();
151 
152     private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
153 
154     /**
155      * For each app, keep a mapping from SDK name to it's corresponding LoadSdkSession. This can
156      * contain all SDKs that are pending load, have been loaded, unloaded etc. Therefore, it is
157      * important to filter out by the type needed.
158      */
159     @GuardedBy("mLock")
160     private final ArrayMap<CallingInfo, ArrayMap<String, LoadSdkSession>> mLoadSdkSessions =
161             new ArrayMap<>();
162 
163     /**
164      * For each app, keep a mapping from {@link AppOwnedSdkSandboxInterface} name to its
165      * corresponding {@link AppOwnedSdkSandboxInterface}. This contains all
166      * AppOwnedSdkSandboxInterfaces that are registered.
167      */
168     @GuardedBy("mLock")
169     private final ArrayMap<CallingInfo, ArrayMap<String, AppOwnedSdkSandboxInterface>>
170             mHeldInterfaces = new ArrayMap<>();
171 
172     @GuardedBy("mLock")
173     private final ArrayMap<CallingInfo, IBinder> mCallingInfosWithDeathRecipients =
174             new ArrayMap<>();
175 
176     @GuardedBy("mLock")
177     private final Set<CallingInfo> mRunningInstrumentations = new ArraySet<>();
178 
179     @GuardedBy("mLock")
180     private final ArrayMap<CallingInfo, RemoteCallbackList<ISdkSandboxProcessDeathCallback>>
181             mSandboxLifecycleCallbacks = new ArrayMap<>();
182 
183     // Callbacks that need to be invoked when the sandbox binding has occurred (either successfully
184     // or unsuccessfully).
185     @GuardedBy("mLock")
186     private final ArrayMap<CallingInfo, ArrayList<SandboxBindingCallback>>
187             mSandboxBindingCallbacks = new ArrayMap<>();
188 
189     @GuardedBy("mLock")
190     private final ArrayMap<CallingInfo, ISharedPreferencesSyncCallback> mSyncDataCallbacks =
191             new ArrayMap<>();
192 
193     @GuardedBy("mLock")
194     private final UidImportanceListener mUidImportanceListener = new UidImportanceListener();
195 
196     private Injector mInjector;
197 
198     private final SdkSandboxPulledAtoms mSdkSandboxPulledAtoms;
199 
200     private final SdkSandboxSettingsListener mSdkSandboxSettingsListener;
201 
202     private static final boolean DEFAULT_VALUE_DISABLE_SDK_SANDBOX = true;
203 
204     /**
205      * Property to enforce restrictions for SDK sandbox processes. If the value of this property is
206      * {@code true}, the restrictions will be enforced.
207      */
208     static final String PROPERTY_ENFORCE_RESTRICTIONS = "sdksandbox_enforce_restrictions";
209 
210     static final boolean DEFAULT_VALUE_ENFORCE_RESTRICTIONS = true;
211 
212     private static final String WEBVIEW_DEVELOPER_MODE_CONTENT_PROVIDER =
213             "DeveloperModeContentProvider";
214 
215     private static final String WEBVIEW_SAFE_MODE_CONTENT_PROVIDER = "SafeModeContentProvider";
216 
217     // If AdServices register itself as binder service, dump() will ignore the --AdServices option
218     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
219     static final String DUMP_AD_SERVICES_MESSAGE_HANDLED_BY_AD_SERVICES_ITSELF =
220             "Don't need to dump AdServices as it's available as " + AD_SERVICES_SYSTEM_SERVICE;
221 
222     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
223     static final ArraySet<String> DEFAULT_ACTIVITY_ALLOWED_ACTIONS =
224             new ArraySet<>(
225                     Arrays.asList(
226                             Intent.ACTION_VIEW,
227                             Intent.ACTION_DIAL,
228                             Intent.ACTION_EDIT,
229                             Intent.ACTION_INSERT));
230 
231     static final ArraySet<String> DEFAULT_CONTENTPROVIDER_ALLOWED_AUTHORITIES =
232             new ArraySet<>(
233                     Arrays.asList(
234                             Settings.AUTHORITY, "com.android.textclassifier.icons", "downloads"));
235 
236     static class Injector {
237         private final Context mContext;
238         private SdkSandboxManagerLocal mLocalManager;
239         private final SdkSandboxServiceProvider mServiceProvider;
240         private final @Nullable String mAdServicesPackageName;
241         private final SdkSandboxStatsdLogger mSdkSandboxStatsdLogger;
242 
Injector(Context context)243         Injector(Context context) {
244             mContext = context;
245             mServiceProvider = new SdkSandboxServiceProviderImpl(mContext);
246             mAdServicesPackageName = resolveAdServicesPackage(mContext);
247             mSdkSandboxStatsdLogger = new SdkSandboxStatsdLogger();
248         }
249 
250         private static final boolean IS_EMULATOR =
251                 SystemProperties.getBoolean("ro.boot.qemu", false);
252 
resolveAdServicesPackage(Context context)253         private static String resolveAdServicesPackage(Context context) {
254             PackageManager pm = context.getPackageManager();
255             Intent serviceIntent = new Intent(AdServicesCommon.ACTION_TOPICS_SERVICE);
256             List<ResolveInfo> resolveInfos =
257                     pm.queryIntentServices(
258                             serviceIntent,
259                             PackageManager.GET_SERVICES
260                                     | PackageManager.MATCH_SYSTEM_ONLY
261                                     | PackageManager.MATCH_DIRECT_BOOT_AWARE
262                                     | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
263             ServiceInfo serviceInfo =
264                     AdServicesCommon.resolveAdServicesService(
265                             resolveInfos, serviceIntent.getAction());
266             return serviceInfo != null ? serviceInfo.packageName : null;
267         }
268 
elapsedRealtime()269         long elapsedRealtime() {
270             return SystemClock.elapsedRealtime();
271         }
272 
createShellCommand( SdkSandboxManagerService service, Context context, boolean supportsAdServicesShellCmd)273         SdkSandboxShellCommand createShellCommand(
274                 SdkSandboxManagerService service,
275                 Context context,
276                 boolean supportsAdServicesShellCmd) {
277             return new SdkSandboxShellCommand(service, context, supportsAdServicesShellCmd);
278         }
279 
isEmulator()280         boolean isEmulator() {
281             return IS_EMULATOR;
282         }
283 
getSdkSandboxServiceProvider()284         SdkSandboxServiceProvider getSdkSandboxServiceProvider() {
285             return mServiceProvider;
286         }
287 
getSdkSandboxPulledAtoms()288         SdkSandboxPulledAtoms getSdkSandboxPulledAtoms() {
289             return new SdkSandboxPulledAtoms();
290         }
291 
getPackageManagerLocal()292         PackageManagerLocal getPackageManagerLocal() {
293             return LocalManagerRegistry.getManager(PackageManagerLocal.class);
294         }
295 
getSdkSandboxStorageManager()296         SdkSandboxStorageManager getSdkSandboxStorageManager() {
297             return new SdkSandboxStorageManager(mContext, mLocalManager, getPackageManagerLocal());
298         }
299 
setLocalManager(SdkSandboxManagerLocal localManager)300         void setLocalManager(SdkSandboxManagerLocal localManager) {
301             mLocalManager = localManager;
302         }
303 
getLocalManager()304         SdkSandboxManagerLocal getLocalManager() {
305             return mLocalManager;
306         }
307 
getAdServicesPackageName()308         String getAdServicesPackageName() {
309             return mAdServicesPackageName;
310         }
311 
isAdServiceApkPresent()312         boolean isAdServiceApkPresent() {
313             return mAdServicesPackageName != null;
314         }
315 
getSdkSandboxStatsdLogger()316         SdkSandboxStatsdLogger getSdkSandboxStatsdLogger() {
317             return mSdkSandboxStatsdLogger;
318         }
319     }
320 
SdkSandboxManagerService(Context context)321     SdkSandboxManagerService(Context context) {
322         this(context, new Injector(context));
323     }
324 
325     @VisibleForTesting
SdkSandboxManagerService(Context context, Injector injector)326     SdkSandboxManagerService(Context context, Injector injector) {
327         mContext = context;
328         mInjector = injector;
329         mInjector.setLocalManager(new LocalImpl());
330         mServiceProvider = mInjector.getSdkSandboxServiceProvider();
331         mActivityManager = mContext.getSystemService(ActivityManager.class);
332         mActivityManagerLocal = LocalManagerRegistry.getManager(ActivityManagerLocal.class);
333         mSdkSandboxPulledAtoms = mInjector.getSdkSandboxPulledAtoms();
334         mSdkSandboxStorageManager = mInjector.getSdkSandboxStorageManager();
335         mSdkSandboxStatsdLogger = mInjector.getSdkSandboxStatsdLogger();
336         mSdkSandboxRestrictionManager = new SdkSandboxRestrictionManager(mContext);
337 
338         // Start the handler thread.
339         HandlerThread handlerThread = new HandlerThread("SdkSandboxManagerServiceHandler");
340         handlerThread.start();
341         mHandler = new Handler(handlerThread.getLooper());
342 
343         registerBroadcastReceivers();
344 
345         mSdkSandboxSettingsListener = new SdkSandboxSettingsListener(mContext, this);
346         mSdkSandboxPulledAtoms.initialize(mContext);
347 
348         if (SdkLevel.isAtLeastU()) {
349             registerSandboxActivityInterceptor();
350         }
351     }
352 
registerBroadcastReceivers()353     private void registerBroadcastReceivers() {
354         registerPackageUpdateBroadcastReceiver();
355         registerVerifierBroadcastReceiver();
356     }
357 
registerPackageUpdateBroadcastReceiver()358     private void registerPackageUpdateBroadcastReceiver() {
359         // Register for package addition and update
360         final IntentFilter packageAddedIntentFilter = new IntentFilter();
361         packageAddedIntentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
362         packageAddedIntentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
363         packageAddedIntentFilter.addDataScheme("package");
364         BroadcastReceiver packageAddedIntentReceiver =
365                 new BroadcastReceiver() {
366                     @Override
367                     public void onReceive(Context context, Intent intent) {
368                         final String packageName = intent.getData().getSchemeSpecificPart();
369                         final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
370                         final CallingInfo callingInfo = new CallingInfo(uid, packageName);
371                         mHandler.post(
372                                 () ->
373                                         mSdkSandboxStorageManager.onPackageAddedOrUpdated(
374                                                 callingInfo));
375                     }
376                 };
377         mContext.registerReceiver(
378                 packageAddedIntentReceiver,
379                 packageAddedIntentFilter,
380                 /*broadcastPermission=*/ null,
381                 mHandler);
382     }
383 
registerVerifierBroadcastReceiver()384     private void registerVerifierBroadcastReceiver() {
385         final IntentFilter packageNeedsVerificationIntentFilter = new IntentFilter();
386         try {
387             packageNeedsVerificationIntentFilter.addDataType(PACKAGE_MIME_TYPE);
388             packageNeedsVerificationIntentFilter.addAction(
389                     Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
390             mContext.registerReceiverForAllUsers(
391                     new SdkSandboxVerifierReceiver(),
392                     packageNeedsVerificationIntentFilter,
393                     /*broadcastPermission=*/ null,
394                     /*scheduler=*/ null,
395                     Context.RECEIVER_EXPORTED);
396         } catch (IntentFilter.MalformedMimeTypeException e) {
397             Log.e(TAG, "Could not register verifier");
398         }
399     }
400 
401     @Override
getSandboxedSdks( String callingPackageName, SandboxLatencyInfo sandboxLatencyInfo)402     public List<SandboxedSdk> getSandboxedSdks(
403             String callingPackageName, SandboxLatencyInfo sandboxLatencyInfo) {
404         sandboxLatencyInfo.setTimeSystemServerReceivedCallFromApp(mInjector.elapsedRealtime());
405 
406         final int callingUid = Binder.getCallingUid();
407         CallingInfo callingInfo;
408         if (Process.isSdkSandboxUid(callingUid)) {
409             callingInfo =
410                     CallingInfo.fromExternal(
411                             mContext,
412                             Process.getAppUidForSdkSandboxUid(callingUid),
413                             callingPackageName);
414         } else {
415             callingInfo = CallingInfo.fromBinder(mContext, callingPackageName);
416         }
417 
418         final List<SandboxedSdk> sandboxedSdks = new ArrayList<>();
419         synchronized (mLock) {
420             ArrayList<LoadSdkSession> loadedSdks = getLoadedSdksForApp(callingInfo);
421             for (int i = 0; i < loadedSdks.size(); i++) {
422                 LoadSdkSession sdk = loadedSdks.get(i);
423                 SandboxedSdk sandboxedSdk = sdk.getSandboxedSdk();
424                 if (sandboxedSdk != null) {
425                     sandboxedSdks.add(sandboxedSdk);
426                 } else {
427                     Log.w(
428                             TAG,
429                             "SandboxedSdk is null for SDK "
430                                     + sdk.mSdkName
431                                     + " despite being loaded");
432                 }
433             }
434         }
435         sandboxLatencyInfo.setTimeSystemServerCallFinished(mInjector.elapsedRealtime());
436         logSandboxApiLatency(sandboxLatencyInfo);
437         return sandboxedSdks;
438     }
439 
440     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
registerSandboxActivityInterceptor()441     private void registerSandboxActivityInterceptor() {
442         final ActivityInterceptorCallback mActivityInterceptorCallback =
443                 new SdkSandboxInterceptorCallback();
444         ActivityInterceptorCallbackRegistry registry =
445                 ActivityInterceptorCallbackRegistry.getInstance();
446         registry.registerActivityInterceptorCallback(
447                 MAINLINE_SDK_SANDBOX_ORDER_ID, mActivityInterceptorCallback);
448     }
449 
getRegisteredAppOwnedSdkSandboxInterfacesForApp( CallingInfo callingInfo)450     private ArrayList<AppOwnedSdkSandboxInterface> getRegisteredAppOwnedSdkSandboxInterfacesForApp(
451             CallingInfo callingInfo) {
452         synchronized (mLock) {
453             if (!mHeldInterfaces.containsKey(callingInfo)) {
454                 return new ArrayList<>();
455             }
456             return new ArrayList<>(mHeldInterfaces.get(callingInfo).values());
457         }
458     }
459 
getLoadedSdksForApp(CallingInfo callingInfo)460     private ArrayList<LoadSdkSession> getLoadedSdksForApp(CallingInfo callingInfo) {
461         ArrayList<LoadSdkSession> loadedSdks = new ArrayList<>();
462         synchronized (mLock) {
463             if (mLoadSdkSessions.containsKey(callingInfo)) {
464                 ArrayList<LoadSdkSession> loadSessions =
465                         new ArrayList<>(mLoadSdkSessions.get(callingInfo).values());
466                 for (int i = 0; i < loadSessions.size(); i++) {
467                     LoadSdkSession sdk = loadSessions.get(i);
468                     if (sdk.getStatus() == LoadSdkSession.LOADED) {
469                         loadedSdks.add(sdk);
470                     }
471                 }
472             }
473         }
474         return loadedSdks;
475     }
476 
477     @Override
addSdkSandboxProcessDeathCallback( String callingPackageName, SandboxLatencyInfo sandboxLatencyInfo, ISdkSandboxProcessDeathCallback callback)478     public void addSdkSandboxProcessDeathCallback(
479             String callingPackageName,
480             SandboxLatencyInfo sandboxLatencyInfo,
481             ISdkSandboxProcessDeathCallback callback) {
482         sandboxLatencyInfo.setTimeSystemServerReceivedCallFromApp(mInjector.elapsedRealtime());
483 
484         final CallingInfo callingInfo = CallingInfo.fromBinder(mContext, callingPackageName);
485         synchronized (mLock) {
486             if (mSandboxLifecycleCallbacks.containsKey(callingInfo)) {
487                 mSandboxLifecycleCallbacks.get(callingInfo).register(callback);
488             } else {
489                 RemoteCallbackList<ISdkSandboxProcessDeathCallback> sandboxLifecycleCallbacks =
490                         new RemoteCallbackList<>();
491                 sandboxLifecycleCallbacks.register(callback);
492                 mSandboxLifecycleCallbacks.put(callingInfo, sandboxLifecycleCallbacks);
493             }
494         }
495 
496         // addSdkSandboxProcessDeathCallback() can be called without calling loadSdk(). Register for
497         // app death to make sure cleanup occurs.
498         registerForAppDeath(callingInfo, callback.asBinder());
499         sandboxLatencyInfo.setTimeSystemServerCallFinished(mInjector.elapsedRealtime());
500         logSandboxApiLatency(sandboxLatencyInfo);
501     }
502 
503     // Register a handler for app death using any binder object originating from the app. Returns
504     // true if registering the handle succeeded and false if it failed (because the app died by
505     // then).
registerForAppDeath(CallingInfo callingInfo, IBinder appBinderObject)506     private boolean registerForAppDeath(CallingInfo callingInfo, IBinder appBinderObject) {
507         // Register a death recipient to clean up app related state and unbind its service after
508         // the app dies.
509         try {
510             synchronized (mLock) {
511                 if (!mCallingInfosWithDeathRecipients.containsKey(callingInfo)) {
512                     Log.d(TAG, "Registering " + callingInfo + " for death notification");
513                     appBinderObject.linkToDeath(() -> onAppDeath(callingInfo), 0);
514                     mCallingInfosWithDeathRecipients.put(callingInfo, appBinderObject);
515                 }
516             }
517         } catch (RemoteException re) {
518             // App has already died, cleanup sdk link, and unbind its service
519             onAppDeath(callingInfo);
520             return false;
521         }
522 
523         return true;
524     }
525 
526     @Override
removeSdkSandboxProcessDeathCallback( String callingPackageName, SandboxLatencyInfo sandboxLatencyInfo, ISdkSandboxProcessDeathCallback callback)527     public void removeSdkSandboxProcessDeathCallback(
528             String callingPackageName,
529             SandboxLatencyInfo sandboxLatencyInfo,
530             ISdkSandboxProcessDeathCallback callback) {
531         sandboxLatencyInfo.setTimeSystemServerReceivedCallFromApp(mInjector.elapsedRealtime());
532 
533         final CallingInfo callingInfo = CallingInfo.fromBinder(mContext, callingPackageName);
534         synchronized (mLock) {
535             RemoteCallbackList<ISdkSandboxProcessDeathCallback> sandboxLifecycleCallbacks =
536                     mSandboxLifecycleCallbacks.get(callingInfo);
537             if (sandboxLifecycleCallbacks != null) {
538                 sandboxLifecycleCallbacks.unregister(callback);
539             }
540         }
541         sandboxLatencyInfo.setTimeSystemServerCallFinished(mInjector.elapsedRealtime());
542         logSandboxApiLatency(sandboxLatencyInfo);
543     }
544 
545     @Override
getAppOwnedSdkSandboxInterfaces( String callingPackageName, SandboxLatencyInfo sandboxLatencyInfo)546     public List<AppOwnedSdkSandboxInterface> getAppOwnedSdkSandboxInterfaces(
547             String callingPackageName, SandboxLatencyInfo sandboxLatencyInfo) {
548         sandboxLatencyInfo.setTimeSystemServerReceivedCallFromApp(mInjector.elapsedRealtime());
549         final CallingInfo callingInfo = CallingInfo.fromBinder(mContext, callingPackageName);
550         List<AppOwnedSdkSandboxInterface> appOwnedSdkSandboxInterfaces =
551                 getRegisteredAppOwnedSdkSandboxInterfacesForApp(callingInfo);
552         sandboxLatencyInfo.setTimeSystemServerCallFinished(mInjector.elapsedRealtime());
553         logSandboxApiLatency(sandboxLatencyInfo);
554         return appOwnedSdkSandboxInterfaces;
555     }
556 
557     @Override
registerAppOwnedSdkSandboxInterface( String callingPackageName, AppOwnedSdkSandboxInterface appOwnedSdkSandboxInterface, SandboxLatencyInfo sandboxLatencyInfo)558     public void registerAppOwnedSdkSandboxInterface(
559             String callingPackageName,
560             AppOwnedSdkSandboxInterface appOwnedSdkSandboxInterface,
561             SandboxLatencyInfo sandboxLatencyInfo) {
562         sandboxLatencyInfo.setTimeSystemServerReceivedCallFromApp(mInjector.elapsedRealtime());
563         final CallingInfo callingInfo = CallingInfo.fromBinder(mContext, callingPackageName);
564 
565         synchronized (mLock) {
566             if (mHeldInterfaces.containsKey(callingInfo)) {
567                 if (mHeldInterfaces
568                         .get(callingInfo)
569                         .containsKey(appOwnedSdkSandboxInterface.getName())) {
570                     throw new IllegalStateException(
571                             "Already registered interface of name "
572                                     + appOwnedSdkSandboxInterface.getName());
573                 }
574             }
575             mHeldInterfaces.computeIfAbsent(callingInfo, k -> new ArrayMap<>());
576             mHeldInterfaces
577                     .get(callingInfo)
578                     .put(appOwnedSdkSandboxInterface.getName(), appOwnedSdkSandboxInterface);
579         }
580         // registerAppOwnedSdkSandboxInterface() can be called without calling loadSdk(). Register
581         // for app death to make sure cleanup occurs.
582         boolean isRegistrationForAppDeathSuccessful =
583                 registerForAppDeath(callingInfo, appOwnedSdkSandboxInterface.getInterface());
584 
585         sandboxLatencyInfo.setTimeSystemServerCallFinished(mInjector.elapsedRealtime());
586         if (!isRegistrationForAppDeathSuccessful) {
587             sandboxLatencyInfo.setSandboxStatus(
588                     SandboxLatencyInfo.SANDBOX_STATUS_FAILED_AT_SYSTEM_SERVER_APP_TO_SANDBOX);
589         }
590         logSandboxApiLatency(sandboxLatencyInfo);
591     }
592 
593     @Override
unregisterAppOwnedSdkSandboxInterface( String callingPackageName, String name, SandboxLatencyInfo sandboxLatencyInfo)594     public void unregisterAppOwnedSdkSandboxInterface(
595             String callingPackageName, String name, SandboxLatencyInfo sandboxLatencyInfo) {
596         sandboxLatencyInfo.setTimeSystemServerReceivedCallFromApp(mInjector.elapsedRealtime());
597         final CallingInfo callingInfo = CallingInfo.fromBinder(mContext, callingPackageName);
598 
599         synchronized (mLock) {
600             if (mHeldInterfaces.containsKey(callingInfo)) {
601                 mHeldInterfaces.get(callingInfo).remove(name);
602             }
603         }
604 
605         sandboxLatencyInfo.setTimeSystemServerCallFinished(mInjector.elapsedRealtime());
606         logSandboxApiLatency(sandboxLatencyInfo);
607     }
608 
609     @Override
loadSdk( String callingPackageName, IBinder callingAppProcessToken, String sdkName, SandboxLatencyInfo sandboxLatencyInfo, Bundle params, ILoadSdkCallback callback)610     public void loadSdk(
611             String callingPackageName,
612             IBinder callingAppProcessToken,
613             String sdkName,
614             SandboxLatencyInfo sandboxLatencyInfo,
615             Bundle params,
616             ILoadSdkCallback callback) {
617         try {
618             sandboxLatencyInfo.setTimeSystemServerReceivedCallFromApp(mInjector.elapsedRealtime());
619 
620             final int callingUid = Binder.getCallingUid();
621             CallingInfo callingInfo;
622             if (Process.isSdkSandboxUid(callingUid)) {
623                 callingInfo =
624                         CallingInfo.fromExternal(
625                                 mContext,
626                                 Process.getAppUidForSdkSandboxUid(callingUid),
627                                 callingPackageName);
628             } else {
629                 callingInfo =
630                         CallingInfo.fromBinderWithApplicationThread(
631                                 mContext, callingPackageName, callingAppProcessToken);
632             }
633             enforceCallerHasNetworkAccess(callingPackageName);
634             enforceCallerOrItsSandboxRunInForeground(callingInfo);
635             synchronized (mLock) {
636                 if (mRunningInstrumentations.contains(callingInfo)) {
637                     throw new SecurityException(
638                             "Currently running instrumentation of this sdk sandbox process");
639                 }
640             }
641 
642             if (isSdkSandboxDisabled()) {
643                 Log.i(TAG, "Not loading an SDK as the SDK sandbox is disabled");
644                 sandboxLatencyInfo.setTimeSystemServerCallFinished(mInjector.elapsedRealtime());
645                 sandboxLatencyInfo.setSandboxStatus(
646                         SandboxLatencyInfo.SANDBOX_STATUS_FAILED_AT_SYSTEM_SERVER_APP_TO_SANDBOX);
647                 sandboxLatencyInfo.setTimeSystemServerCalledApp(mInjector.elapsedRealtime());
648                 callback.onLoadSdkFailure(
649                         new LoadSdkException(LOAD_SDK_SDK_SANDBOX_DISABLED, SANDBOX_DISABLED_MSG),
650                         sandboxLatencyInfo);
651                 return;
652             }
653 
654             final long token = Binder.clearCallingIdentity();
655             try {
656                 loadSdkWithClearIdentity(
657                         callingInfo,
658                         sdkName,
659                         params,
660                         callback,
661                         sandboxLatencyInfo);
662             } finally {
663                 Binder.restoreCallingIdentity(token);
664             }
665         } catch (Throwable e) {
666             try {
667                 Log.e(TAG, "Failed to load SDK " + sdkName, e);
668                 sandboxLatencyInfo.setTimeSystemServerCallFinished(mInjector.elapsedRealtime());
669                 sandboxLatencyInfo.setSandboxStatus(
670                         SandboxLatencyInfo.SANDBOX_STATUS_FAILED_AT_SYSTEM_SERVER_APP_TO_SANDBOX);
671                 sandboxLatencyInfo.setTimeSystemServerCalledApp(mInjector.elapsedRealtime());
672                 callback.onLoadSdkFailure(
673                         new LoadSdkException(LOAD_SDK_INTERNAL_ERROR, e.getMessage(), e),
674                         sandboxLatencyInfo);
675             } catch (RemoteException ex) {
676                 Log.e(TAG, "Failed to send onLoadSdkFailure", e);
677             }
678         }
679     }
680 
loadSdkWithClearIdentity( CallingInfo callingInfo, String sdkName, Bundle params, ILoadSdkCallback callback, SandboxLatencyInfo sandboxLatencyInfo)681     private void loadSdkWithClearIdentity(
682             CallingInfo callingInfo,
683             String sdkName,
684             Bundle params,
685             ILoadSdkCallback callback,
686             SandboxLatencyInfo sandboxLatencyInfo) {
687         LoadSdkSession loadSdkSession;
688 
689         try {
690             loadSdkSession =
691                     new LoadSdkSession(
692                             mContext, this, mInjector, sdkName, callingInfo, params, callback);
693         } catch (PackageManager.NameNotFoundException e) {
694             Log.w(TAG, e.getMessage(), e);
695             sandboxLatencyInfo.setTimeSystemServerCallFinished(mInjector.elapsedRealtime());
696             sandboxLatencyInfo.setSandboxStatus(
697                     SandboxLatencyInfo.SANDBOX_STATUS_FAILED_AT_SYSTEM_SERVER_APP_TO_SANDBOX);
698 
699             LoadSdkException loadSdkException =
700                     new LoadSdkException(
701                             SdkSandboxManager.LOAD_SDK_NOT_FOUND, e.getMessage() + " not found");
702             sandboxLatencyInfo.setTimeSystemServerCalledApp(mInjector.elapsedRealtime());
703             try {
704                 callback.onLoadSdkFailure(loadSdkException, sandboxLatencyInfo);
705             } catch (RemoteException remoteException) {
706                 Log.w(TAG, "Failed to send onLoadSdkFailure", remoteException);
707             }
708             return;
709         }
710 
711         // Ensure we are not already loading this sdk. That's determined by checking if we already
712         // have a completed LoadSdkSession with the same SDK name for the calling info.
713         synchronized (mLock) {
714             LoadSdkSession prevLoadSession = null;
715             // Get any previous load session for this SDK if exists.
716             if (mLoadSdkSessions.containsKey(callingInfo)) {
717                 prevLoadSession = mLoadSdkSessions.get(callingInfo).get(sdkName);
718             }
719 
720             // If there was a previous load session and the status is loaded, this new load request
721             // should fail.
722             if (prevLoadSession != null && prevLoadSession.getStatus() == LoadSdkSession.LOADED) {
723                 sandboxLatencyInfo.setTimeSystemServerCallFinished(mInjector.elapsedRealtime());
724                 sandboxLatencyInfo.setSandboxStatus(
725                         SandboxLatencyInfo.SANDBOX_STATUS_FAILED_AT_SYSTEM_SERVER_APP_TO_SANDBOX);
726                 loadSdkSession.handleLoadFailure(
727                         new LoadSdkException(
728                                 SdkSandboxManager.LOAD_SDK_ALREADY_LOADED,
729                                 sdkName + " has been loaded already"),
730                         sandboxLatencyInfo);
731                 return;
732             }
733 
734             // If there was an ongoing load session for this SDK, this new load request should fail.
735             if (prevLoadSession != null
736                     && prevLoadSession.getStatus() == LoadSdkSession.LOAD_PENDING) {
737                 sandboxLatencyInfo.setTimeSystemServerCallFinished(mInjector.elapsedRealtime());
738                 sandboxLatencyInfo.setSandboxStatus(
739                         SandboxLatencyInfo.SANDBOX_STATUS_FAILED_AT_SYSTEM_SERVER_APP_TO_SANDBOX);
740                 loadSdkSession.handleLoadFailure(
741                         new LoadSdkException(
742                                 SdkSandboxManager.LOAD_SDK_ALREADY_LOADED,
743                                 sdkName + " is currently being loaded"),
744                         sandboxLatencyInfo);
745                 return;
746             }
747 
748             // If there was no previous load session (or there was one but its load status was
749             // unloaded or failed), it should be replaced by the new load session.
750             mLoadSdkSessions.computeIfAbsent(callingInfo, k -> new ArrayMap<>());
751             mLoadSdkSessions.get(callingInfo).put(sdkName, loadSdkSession);
752         }
753 
754         synchronized (mLock) {
755             if (!callingInfo.isCallFromSdkSandbox()) {
756                 // The code is used to be able to detect app death and app foreground state.
757                 // Hence, it is of no use for the call from sandbox.
758                 mUidImportanceListener.startListening();
759                 if (!registerForAppDeath(callingInfo, callback.asBinder())) {
760                     sandboxLatencyInfo.setTimeSystemServerCallFinished(mInjector.elapsedRealtime());
761                     sandboxLatencyInfo.setSandboxStatus(
762                             SandboxLatencyInfo
763                                     .SANDBOX_STATUS_FAILED_AT_SYSTEM_SERVER_APP_TO_SANDBOX);
764                     // App has already died and there is no point in loading the SDK.
765                     return;
766                 }
767             }
768         }
769 
770         // Callback to be invoked once the sandbox has been created;
771         SandboxBindingCallback sandboxBindingCallback = createSdkLoadCallback(loadSdkSession);
772         startSdkSandboxIfNeeded(callingInfo, sandboxBindingCallback, sandboxLatencyInfo);
773     }
774 
createSdkLoadCallback(LoadSdkSession loadSdkSession)775     private SandboxBindingCallback createSdkLoadCallback(LoadSdkSession loadSdkSession) {
776         return new SandboxBindingCallback() {
777             @Override
778             public void onBindingSuccessful(
779                     ISdkSandboxService service, SandboxLatencyInfo sandboxLatencyInfo) {
780                 loadSdkForService(loadSdkSession, service, sandboxLatencyInfo);
781             }
782 
783             @Override
784             public void onBindingFailed(
785                     LoadSdkException exception, SandboxLatencyInfo sandboxLatencyInfo) {
786                 sandboxLatencyInfo.setTimeSandboxLoaded(mInjector.elapsedRealtime());
787                 sandboxLatencyInfo.setSandboxStatus(
788                         SandboxLatencyInfo.SANDBOX_STATUS_FAILED_AT_LOAD_SANDBOX);
789                 loadSdkSession.handleLoadFailure(
790                         exception,
791                         sandboxLatencyInfo);
792             }
793         };
794     }
795 
796     void startSdkSandboxIfNeeded(
797             CallingInfo callingInfo,
798             SandboxBindingCallback callback,
799             SandboxLatencyInfo sandboxLatencyInfo) {
800 
801         boolean isSandboxStartRequired = false;
802         synchronized (mLock) {
803             @SdkSandboxServiceProvider.SandboxStatus
804             int sandboxStatus = mServiceProvider.getSandboxStatusForApp(callingInfo);
805 
806             // Check if service is already created for the app.
807             if (sandboxStatus == SdkSandboxServiceProvider.NON_EXISTENT) {
808                 // We do not want to start sandbox if the call is from sandbox
809                 // and sandbox is dead/non-existent since SDK loading the other
810                 // SDK itself will be unloaded if sandbox dies after the loadSdk call.
811                 if (callingInfo.isCallFromSdkSandbox()) {
812                     return;
813                 }
814                 addSandboxBindingCallback(callingInfo, callback);
815                 isSandboxStartRequired = true;
816             } else if (sandboxStatus == SdkSandboxServiceProvider.CREATE_PENDING) {
817                 addSandboxBindingCallback(callingInfo, callback);
818                 // The sandbox is in the process of being brought up. Nothing more to do here.
819                 return;
820             }
821         }
822 
823         if (!isSandboxStartRequired) {
824             ISdkSandboxService service = mServiceProvider.getSdkSandboxServiceForApp(callingInfo);
825             if (service == null) {
826                 LoadSdkException exception =
827                         new LoadSdkException(
828                                 SDK_SANDBOX_PROCESS_NOT_AVAILABLE, SANDBOX_NOT_AVAILABLE_MSG);
829                 callback.onBindingFailed(exception, sandboxLatencyInfo);
830             }
831             callback.onBindingSuccessful(service, sandboxLatencyInfo);
832             return;
833         }
834 
835         // Prepare sdk data directories before starting the sandbox. If sdk data package directory
836         // is missing, starting the sandbox process would crash as we will fail to mount data_mirror
837         // for sdk-data isolation.
838         mSdkSandboxStorageManager.prepareSdkDataOnLoad(callingInfo);
839         sandboxLatencyInfo.setTimeLoadSandboxStarted(mInjector.elapsedRealtime());
840         mServiceProvider.bindService(
841                 callingInfo,
842                 new SandboxServiceConnection(mServiceProvider, callingInfo, sandboxLatencyInfo));
843     }
844 
845     private void addSandboxBindingCallback(
846             CallingInfo callingInfo, SandboxBindingCallback callback) {
847         synchronized (mLock) {
848             mSandboxBindingCallbacks.computeIfAbsent(callingInfo, k -> new ArrayList<>());
849             mSandboxBindingCallbacks.get(callingInfo).add(callback);
850         }
851     }
852 
853     @Override
854     public void unloadSdk(
855             String callingPackageName, String sdkName, SandboxLatencyInfo sandboxLatencyInfo) {
856         sandboxLatencyInfo.setTimeSystemServerReceivedCallFromApp(mInjector.elapsedRealtime());
857 
858         final int callingUid = Binder.getCallingUid();
859         final CallingInfo callingInfo = CallingInfo.fromBinder(mContext, callingPackageName);
860         enforceCallerOrItsSandboxRunInForeground(callingInfo);
861 
862         final long token = Binder.clearCallingIdentity();
863         try {
864             unloadSdkWithClearIdentity(callingInfo, sdkName, sandboxLatencyInfo);
865         } finally {
866             Binder.restoreCallingIdentity(token);
867         }
868     }
869 
870     private void unloadSdkWithClearIdentity(
871             CallingInfo callingInfo, String sdkName, SandboxLatencyInfo sandboxLatencyInfo) {
872         LoadSdkSession prevLoadSession = null;
873         synchronized (mLock) {
874             // TODO(b/254657226): Add a callback or return value for unloadSdk() to indicate
875             // success of unload.
876 
877             // Get any previous load session for this SDK if exists.
878             if (mLoadSdkSessions.containsKey(callingInfo)) {
879                 prevLoadSession = mLoadSdkSessions.get(callingInfo).get(sdkName);
880             }
881         }
882 
883         // If there was no previous load session or the SDK is not loaded, there is nothing to
884         // unload.
885         if (prevLoadSession == null) {
886             // Unloading SDK that is not loaded is a no-op, return.
887             Log.w(TAG, "SDK " + sdkName + " is not loaded for " + callingInfo);
888             return;
889         }
890 
891         IUnloadSdkCallback unloadSdkCallback =
892                 new IUnloadSdkCallback.Stub() {
893                     @Override
894                     public void onUnloadSdk(SandboxLatencyInfo sandboxLatencyInfo)
895                             throws RemoteException {
896                         sandboxLatencyInfo.setTimeSystemServerCalledApp(
897                                 mInjector.elapsedRealtime());
898                         logSandboxApiLatency(sandboxLatencyInfo);
899                     }
900                 };
901         prevLoadSession.unload(sandboxLatencyInfo, unloadSdkCallback);
902 
903         ArrayList<LoadSdkSession> loadedSdks = getLoadedSdksForApp(callingInfo);
904         if (loadedSdks.isEmpty()) {
905             stopSdkSandboxService(
906                     callingInfo, "Caller " + callingInfo + " has no remaining SDKS loaded.");
907         }
908     }
909 
910     private void enforceCallingPackageBelongsToUid(CallingInfo callingInfo) {
911         int callingUid = callingInfo.getUid();
912         String callingPackage = callingInfo.getPackageName();
913         int packageUid;
914         PackageManager pm = mContext.createContextAsUser(
915                 UserHandle.getUserHandleForUid(callingUid), 0).getPackageManager();
916         try {
917             packageUid = pm.getPackageUid(callingPackage, 0);
918         } catch (PackageManager.NameNotFoundException e) {
919             throw new SecurityException(callingPackage + " not found");
920         }
921         if (packageUid != callingUid) {
922             throw new SecurityException(callingPackage + " does not belong to uid " + callingUid);
923         }
924     }
925 
926     private void enforceCallerOrItsSandboxRunInForeground(CallingInfo callingInfo) {
927         String callingPackage = callingInfo.getPackageName();
928         final long token = Binder.clearCallingIdentity();
929         try {
930             int importance =
931                     Math.min(
932                             mActivityManager.getUidImportance(callingInfo.getUid()),
933                             mActivityManager.getUidImportance(
934                                     Process.toSdkSandboxUid(callingInfo.getUid())));
935             if (importance > IMPORTANCE_FOREGROUND) {
936                 throw new SecurityException(callingPackage + " does not run in the foreground");
937             }
938         } finally {
939             Binder.restoreCallingIdentity(token);
940         }
941     }
942 
943     private void enforceCallerHasNetworkAccess(String callingPackage) {
944         mContext.enforceCallingPermission(android.Manifest.permission.INTERNET,
945                 callingPackage + " does not hold INTERNET permission");
946         mContext.enforceCallingPermission(android.Manifest.permission.ACCESS_NETWORK_STATE,
947                 callingPackage + " does not hold ACCESS_NETWORK_STATE permission");
948     }
949 
950     private void onAppDeath(CallingInfo callingInfo) {
951         synchronized (mLock) {
952             Log.d(TAG, "App " + callingInfo + " has died, cleaning up associated sandbox info");
953             mSandboxLifecycleCallbacks.remove(callingInfo);
954             mSandboxBindingCallbacks.remove(callingInfo);
955             mCallingInfosWithDeathRecipients.remove(callingInfo);
956             if (mCallingInfosWithDeathRecipients.size() == 0) {
957                 mUidImportanceListener.stopListening();
958             }
959             mSyncDataCallbacks.remove(callingInfo);
960             mLoadSdkSessions.remove(callingInfo);
961             mHeldInterfaces.remove(callingInfo);
962             stopSdkSandboxService(callingInfo, "Caller " + callingInfo + " has died");
963             mServiceProvider.onAppDeath(callingInfo);
964         }
965     }
966 
967     @Override
968     public void requestSurfacePackage(
969             String callingPackageName,
970             String sdkName,
971             IBinder hostToken,
972             int displayId,
973             int width,
974             int height,
975             SandboxLatencyInfo sandboxLatencyInfo,
976             Bundle params,
977             IRequestSurfacePackageCallback callback) {
978         try {
979             sandboxLatencyInfo.setTimeSystemServerReceivedCallFromApp(mInjector.elapsedRealtime());
980 
981             LogUtil.d(
982                     TAG,
983                     "requestSurfacePackage call received. callingPackageName: "
984                             + callingPackageName);
985 
986             final int callingUid = Binder.getCallingUid();
987             final CallingInfo callingInfo = CallingInfo.fromBinder(mContext, callingPackageName);
988             enforceCallerOrItsSandboxRunInForeground(callingInfo);
989 
990             final long token = Binder.clearCallingIdentity();
991             try {
992                 requestSurfacePackageWithClearIdentity(
993                         callingInfo,
994                         sdkName,
995                         hostToken,
996                         displayId,
997                         width,
998                         height,
999                         sandboxLatencyInfo,
1000                         params,
1001                         callback);
1002             } finally {
1003                 Binder.restoreCallingIdentity(token);
1004             }
1005         } catch (Throwable e) {
1006             try {
1007                 callback.onSurfacePackageError(
1008                         IRequestSurfacePackageFromSdkCallback.SURFACE_PACKAGE_INTERNAL_ERROR,
1009                         e.getMessage(),
1010                         sandboxLatencyInfo);
1011             } catch (RemoteException ex) {
1012                 Log.e(TAG, "Failed to send onRequestSurfacePackageError", e);
1013             }
1014         }
1015     }
1016 
1017     private void requestSurfacePackageWithClearIdentity(
1018             CallingInfo callingInfo,
1019             String sdkName,
1020             IBinder hostToken,
1021             int displayId,
1022             int width,
1023             int height,
1024             SandboxLatencyInfo sandboxLatencyInfo,
1025             Bundle params,
1026             IRequestSurfacePackageCallback callback) {
1027         LoadSdkSession loadSdkSession = null;
1028         synchronized (mLock) {
1029             if (mLoadSdkSessions.containsKey(callingInfo)) {
1030                 loadSdkSession = mLoadSdkSessions.get(callingInfo).get(sdkName);
1031             }
1032         }
1033         if (loadSdkSession == null) {
1034             LogUtil.d(
1035                     TAG,
1036                     callingInfo + " requested surface package, but could not find SDK " + sdkName);
1037 
1038             final long timeSystemServerProcessedCall = mInjector.elapsedRealtime();
1039             sandboxLatencyInfo.setTimeSystemServerCallFinished(timeSystemServerProcessedCall);
1040             sandboxLatencyInfo.setTimeSystemServerCalledApp(timeSystemServerProcessedCall);
1041             sandboxLatencyInfo.setSandboxStatus(
1042                     SandboxLatencyInfo.SANDBOX_STATUS_FAILED_AT_SYSTEM_SERVER_APP_TO_SANDBOX);
1043 
1044             try {
1045                 callback.onSurfacePackageError(
1046                         REQUEST_SURFACE_PACKAGE_SDK_NOT_LOADED,
1047                         "SDK " + sdkName + " is not loaded",
1048                         sandboxLatencyInfo);
1049             } catch (RemoteException e) {
1050                 Log.w(TAG, "Failed to send onSurfacePackageError", e);
1051             }
1052             return;
1053         }
1054 
1055         loadSdkSession.requestSurfacePackage(
1056                 hostToken, displayId, width, height, sandboxLatencyInfo, params, callback);
1057     }
1058 
1059     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
1060     void onUserUnlocking(int userId) {
1061         Log.i(TAG, "onUserUnlocking " + userId);
1062         // using postDelayed to wait for other volumes to mount
1063         BackgroundThread.getHandler()
1064                 .postDelayed(() -> mSdkSandboxStorageManager.onUserUnlocking(userId), 20000);
1065     }
1066 
1067     @Override
1068     @RequiresPermission(android.Manifest.permission.DUMP)
1069     protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
1070         mContext.enforceCallingPermission(android.Manifest.permission.DUMP,
1071                 "Can't dump " + TAG);
1072 
1073         if (args != null && args.length > 0 && args[0].equals(DUMP_ARG_AD_SERVICES)) {
1074             dumpAdServices(fd, writer, args, /* quiet= */ false);
1075             return;
1076         }
1077 
1078         // TODO(b/211575098): Use IndentingPrintWriter for better formatting
1079         synchronized (mLock) {
1080             writer.println(
1081                     "Killswitch enabled: " + mSdkSandboxSettingsListener.isKillSwitchEnabled());
1082             writer.println("mLoadSdkSessions size: " + mLoadSdkSessions.size());
1083             for (CallingInfo callingInfo : mLoadSdkSessions.keySet()) {
1084                 writer.printf("Caller: %s has following SDKs", callingInfo);
1085                 writer.println();
1086                 ArrayList<LoadSdkSession> loadSessions =
1087                         new ArrayList<>(mLoadSdkSessions.get(callingInfo).values());
1088                 for (int i = 0; i < loadSessions.size(); i++) {
1089                     LoadSdkSession sdk = loadSessions.get(i);
1090                     writer.printf("SDK: %s Status: %s", sdk.mSdkName, sdk.getStatus());
1091                     writer.println();
1092                 }
1093             }
1094             writer.println();
1095 
1096             writer.println("AdServicesManager binder published: " + mAdServicesManagerPublished);
1097         }
1098         if (mInjector.isAdServiceApkPresent()) {
1099             writer.println("AdService package name: " + mInjector.getAdServicesPackageName());
1100         } else {
1101             writer.println("AdService apk not present.");
1102         }
1103         writer.println();
1104 
1105         writer.println("mServiceProvider:");
1106         mServiceProvider.dump(writer);
1107         writer.println();
1108 
1109         dumpAdServices(fd, writer, args, /* quiet= */ true);
1110     }
1111 
1112     private void dumpAdServices(
1113             @Nullable FileDescriptor fd, PrintWriter writer, String[] args, boolean quiet) {
1114 
1115         synchronized (mLock) {
1116             if (mAdServicesManagerPublished) {
1117                 // AdServices registered itself as binder service
1118                 if (quiet) {
1119                     Log.d(TAG, DUMP_AD_SERVICES_MESSAGE_HANDLED_BY_AD_SERVICES_ITSELF);
1120                 } else {
1121                     writer.println(DUMP_AD_SERVICES_MESSAGE_HANDLED_BY_AD_SERVICES_ITSELF);
1122                 }
1123                 return;
1124             }
1125         }
1126 
1127         writer.print("AdServices:");
1128         IBinder adServicesManager = getAdServicesManager();
1129         if (adServicesManager == null) {
1130             // Should not happen on "real life", but it could on unit tests.
1131             Log.e(TAG, "dumpAdServices(): mAdServicesManager not set");
1132             writer.println(" N/A");
1133             return;
1134         }
1135         writer.println();
1136         writer.println();
1137         writer.flush(); // must flush, other raw dump on fd below will be printed before it
1138         try {
1139             adServicesManager.dump(fd, args);
1140         } catch (RemoteException e) {
1141             Log.e(TAG, "Failed to dump AdServices", e);
1142             // Shouldn't happen, but it doesn't hurt to catch
1143             writer.printf("Failed to dump Adservices: %s\n", e);
1144         }
1145         writer.println();
1146     }
1147 
1148     @Override
1149     public void syncDataFromClient(
1150             String callingPackageName,
1151             SandboxLatencyInfo sandboxLatencyInfo,
1152             SharedPreferencesUpdate update,
1153             ISharedPreferencesSyncCallback callback) {
1154         try {
1155             sandboxLatencyInfo.setTimeSystemServerReceivedCallFromApp(mInjector.elapsedRealtime());
1156             logSandboxApiLatency(sandboxLatencyInfo);
1157 
1158             final CallingInfo callingInfo = CallingInfo.fromBinder(mContext, callingPackageName);
1159             enforceCallingPackageBelongsToUid(callingInfo);
1160 
1161             final long token = Binder.clearCallingIdentity();
1162             try {
1163                 syncDataFromClientInternal(callingInfo, update, callback);
1164             } finally {
1165                 Binder.restoreCallingIdentity(token);
1166             }
1167         } catch (Throwable e) {
1168             try {
1169                 callback.onError(
1170                         ISharedPreferencesSyncCallback.PREFERENCES_SYNC_INTERNAL_ERROR,
1171                         e.getMessage());
1172             } catch (RemoteException ex) {
1173                 Log.e(TAG, "Failed to send ISharedPreferencesSyncCallback.onError", e);
1174             }
1175         }
1176     }
1177 
1178     private void syncDataFromClientInternal(
1179             CallingInfo callingInfo,
1180             SharedPreferencesUpdate update,
1181             ISharedPreferencesSyncCallback callback) {
1182         // check first if service already bound
1183         ISdkSandboxService service = mServiceProvider.getSdkSandboxServiceForApp(callingInfo);
1184         if (service != null) {
1185             try {
1186                 service.syncDataFromClient(update);
1187             } catch (RemoteException e) {
1188                 syncDataOnError(callingInfo, callback, e.getMessage());
1189             }
1190         } else {
1191             syncDataOnError(callingInfo, callback, "Sandbox not available");
1192         }
1193     }
1194 
1195     private void syncDataOnError(
1196             CallingInfo callingInfo, ISharedPreferencesSyncCallback callback, String errorMsg) {
1197         // Store reference to the callback so that we can notify SdkSandboxManager when sandbox
1198         // starts
1199         synchronized (mLock) {
1200             mSyncDataCallbacks.put(callingInfo, callback);
1201         }
1202         try {
1203             callback.onError(ISharedPreferencesSyncCallback.SANDBOX_NOT_AVAILABLE, errorMsg);
1204         } catch (RemoteException ignore) {
1205             // App died. Sync will be re-established again by app later.
1206         }
1207     }
1208 
1209     @Override
1210     public void logSandboxApiLatency(SandboxLatencyInfo sandboxLatencyInfo) {
1211         mSdkSandboxStatsdLogger.logSandboxApiLatency(sandboxLatencyInfo);
1212     }
1213 
1214     @Override
1215     public void logSandboxActivityApiLatency(int method, int callResult, int latencyMillis) {
1216         int clientUid = Binder.getCallingUid();
1217         if (Process.isSdkSandboxUid(clientUid)) {
1218             clientUid = Process.getAppUidForSdkSandboxUid(clientUid);
1219         }
1220         logSandboxActivityApiLatency(method, callResult, latencyMillis, clientUid);
1221     }
1222 
1223     private void logSandboxActivityApiLatency(
1224             int method, int callResult, int latencyMillis, int clientUid) {
1225         // TODO(b/321974997): log SDK package name in addition to existing data.
1226         mSdkSandboxStatsdLogger.logSandboxActivityApiLatency(
1227                 method, callResult, latencyMillis, clientUid);
1228     }
1229 
1230     interface SandboxBindingCallback {
1231         void onBindingSuccessful(
1232                 ISdkSandboxService service,
1233                 SandboxLatencyInfo sandboxLatencyInfo);
1234 
1235         void onBindingFailed(
1236                 LoadSdkException exception,
1237                 SandboxLatencyInfo sandboxLatencyInfo);
1238     }
1239 
1240     class SandboxServiceConnection implements ServiceConnection {
1241 
1242         private final SdkSandboxServiceProvider mServiceProvider;
1243         private final CallingInfo mCallingInfo;
1244         private boolean mHasConnectedBefore = false;
1245         private SandboxLatencyInfo mSandboxLatencyInfo;
1246 
1247         SandboxServiceConnection(
1248                 SdkSandboxServiceProvider serviceProvider,
1249                 CallingInfo callingInfo,
1250                 SandboxLatencyInfo sandboxLatencyInfo) {
1251             mServiceProvider = serviceProvider;
1252             mCallingInfo = callingInfo;
1253             mSandboxLatencyInfo = sandboxLatencyInfo;
1254         }
1255 
1256         @Override
1257         public void onServiceConnected(ComponentName name, IBinder service) {
1258             final ISdkSandboxService mService = ISdkSandboxService.Stub.asInterface(service);
1259 
1260             // Perform actions needed after every sandbox restart.
1261             if (!onSandboxConnected(mService)) {
1262                 // We don't need to call sandboxBindingCallback.onBindingFailed() in this case since
1263                 // onSdkSandboxDeath() will take care of iterating through LoadSdkSessions and
1264                 // informing SDKs about load failure.
1265                 return;
1266             }
1267 
1268             // Set connected service for app once all initialization has finished. This needs to be
1269             // set after every sandbox restart as well.
1270             mServiceProvider.onServiceConnected(mCallingInfo, mService);
1271 
1272             // Once bound service has been set, sync manager is notified.
1273             notifySyncManagerSandboxStarted(mCallingInfo);
1274 
1275             BackgroundThread.getExecutor()
1276                     .execute(
1277                             () -> {
1278                                 computeSdkStorage(mCallingInfo, mService);
1279                             });
1280 
1281             mSandboxLatencyInfo.setTimeSandboxLoaded(mInjector.elapsedRealtime());
1282             if (!mHasConnectedBefore) {
1283                 mHasConnectedBefore = true;
1284             }
1285 
1286             ArrayList<SandboxBindingCallback> sandboxBindingCallbacksForApp =
1287                     clearAndGetSandboxBindingCallbacks();
1288             for (int i = 0; i < sandboxBindingCallbacksForApp.size(); i++) {
1289                 SandboxBindingCallback callback = sandboxBindingCallbacksForApp.get(i);
1290                 callback.onBindingSuccessful(mService, mSandboxLatencyInfo);
1291             }
1292         }
1293 
1294         @Override
1295         public void onServiceDisconnected(ComponentName name) {
1296             // Sdk sandbox crashed or killed, system will start it again.
1297             Log.d(TAG, "Sandbox service for " + mCallingInfo + " has been disconnected");
1298             mServiceProvider.onServiceDisconnected(mCallingInfo);
1299         }
1300 
1301         @Override
1302         public void onBindingDied(ComponentName name) {
1303             Log.d(TAG, "Sandbox service for " + mCallingInfo + " : died on binding");
1304             // We call the lifecycle callback only after service is unbound to avoid a race
1305             // condition with a new binding, if the app immediately reloads the SDK.
1306             synchronized (mLock) {
1307                 mServiceProvider.unbindService(mCallingInfo);
1308                 handleSandboxLifecycleCallbacksLocked(mCallingInfo);
1309             }
1310         }
1311 
1312         @Override
1313         public void onNullBinding(ComponentName name) {
1314             Log.d(TAG, "Sandbox service failed to bind for " + mCallingInfo + " : service is null");
1315             LoadSdkException exception =
1316                     new LoadSdkException(
1317                             SdkSandboxManager.LOAD_SDK_INTERNAL_ERROR,
1318                             "Failed to bind the service");
1319             ArrayList<SandboxBindingCallback> sandboxBindingCallbacksForApp =
1320                     clearAndGetSandboxBindingCallbacks();
1321             for (int i = 0; i < sandboxBindingCallbacksForApp.size(); i++) {
1322                 SandboxBindingCallback callback = sandboxBindingCallbacksForApp.get(i);
1323                 callback.onBindingFailed(exception, mSandboxLatencyInfo);
1324             }
1325         }
1326 
1327         /**
1328          * Actions to be performed every time the sandbox connects for a particular app, such as the
1329          * first time the sandbox is brought up and every time it restarts.
1330          *
1331          * @return true if all actions were performed successfully, false otherwise.
1332          */
1333         private boolean onSandboxConnected(ISdkSandboxService service) {
1334             Log.i(
1335                     TAG,
1336                     String.format(
1337                             "Sdk sandbox has been bound for app package %s with uid %d",
1338                             mCallingInfo.getPackageName(), mCallingInfo.getUid()));
1339             try {
1340                 service.asBinder().linkToDeath(() -> onSdkSandboxDeath(mCallingInfo), 0);
1341             } catch (RemoteException e) {
1342                 // Sandbox had already died, cleanup sdk links.
1343                 onSdkSandboxDeath(mCallingInfo);
1344                 return false;
1345             }
1346 
1347             try {
1348                 service.initialize(new SdkToServiceLink());
1349             } catch (Throwable e) {
1350                 handleFailedSandboxInitialization(mCallingInfo);
1351                 return false;
1352             }
1353 
1354             return true;
1355         }
1356 
1357         private ArrayList<SandboxBindingCallback> clearAndGetSandboxBindingCallbacks() {
1358             ArrayList<SandboxBindingCallback> sandboxBindingCallbacksForApp;
1359             synchronized (mLock) {
1360                 sandboxBindingCallbacksForApp = mSandboxBindingCallbacks.get(mCallingInfo);
1361                 mSandboxBindingCallbacks.remove(mCallingInfo);
1362             }
1363             if (sandboxBindingCallbacksForApp == null) {
1364                 sandboxBindingCallbacksForApp = new ArrayList<>();
1365             }
1366             return sandboxBindingCallbacksForApp;
1367         }
1368     }
1369 
1370     void handleFailedSandboxInitialization(CallingInfo callingInfo) {
1371         final String errorMsg = "Failed to initialize sandbox";
1372         Log.e(TAG, errorMsg + " for " + callingInfo);
1373         // Kill the sandbox if it failed to initialize as it might not be properly usable.
1374         stopSdkSandboxService(callingInfo, errorMsg);
1375     }
1376 
1377     private void onSdkSandboxDeath(CallingInfo callingInfo) {
1378         synchronized (mLock) {
1379             killAppOnSandboxDeathIfNeededLocked(callingInfo);
1380             mSandboxBindingCallbacks.remove(callingInfo);
1381             // If SDK sandbox is already unbound then we can invoke callbacks immediately,
1382             // otherwise we defer until onBindingDied is called.
1383             if (mServiceProvider.getSandboxStatusForApp(callingInfo)
1384                             != SdkSandboxServiceProvider.NON_EXISTENT
1385                     && !mServiceProvider.isSandboxBoundForApp(callingInfo)) {
1386                 handleSandboxLifecycleCallbacksLocked(callingInfo);
1387             }
1388 
1389             mServiceProvider.onSandboxDeath(callingInfo);
1390             // All SDK state is lost on death.
1391             if (mLoadSdkSessions.containsKey(callingInfo)) {
1392                 ArrayList<LoadSdkSession> loadSessions =
1393                         new ArrayList<>(mLoadSdkSessions.get(callingInfo).values());
1394                 for (int i = 0; i < loadSessions.size(); i++) {
1395                     LoadSdkSession loadSdkSession = loadSessions.get(i);
1396                     loadSdkSession.onSandboxDeath();
1397                 }
1398                 mLoadSdkSessions.remove(callingInfo);
1399             }
1400         }
1401     }
1402 
1403     @GuardedBy("mLock")
1404     private void killAppOnSandboxDeathIfNeededLocked(CallingInfo callingInfo) {
1405         if (!SdkLevel.isAtLeastU()
1406                 || !mCallingInfosWithDeathRecipients.containsKey(callingInfo)
1407                 || mSandboxLifecycleCallbacks.containsKey(callingInfo)
1408                 || getLoadedSdksForApp(callingInfo).size() == 0) {
1409             /* The app should not be killed in any one of the following cases:
1410                1) The SDK level is not U+ (as app kill API is not supported in that case).
1411                2) The app is already dead.
1412                3) The app has registered at least one callback to deal with sandbox death.
1413                4) The app has no SDKs loaded.
1414             */
1415             return;
1416         }
1417 
1418         // TODO(b/261442377): Only the processes that loaded some SDK should be killed. For now,
1419         // kill the process that loaded the first SDK.
1420         mActivityManagerLocal.killSdkSandboxClientAppProcess(callingInfo.getAppProcessToken());
1421     }
1422 
1423     @GuardedBy("mLock")
1424     private void handleSandboxLifecycleCallbacksLocked(CallingInfo callingInfo) {
1425         RemoteCallbackList<ISdkSandboxProcessDeathCallback> sandboxLifecycleCallbacks;
1426         sandboxLifecycleCallbacks = mSandboxLifecycleCallbacks.get(callingInfo);
1427 
1428         if (sandboxLifecycleCallbacks == null) {
1429             return;
1430         }
1431 
1432         int size = sandboxLifecycleCallbacks.beginBroadcast();
1433         for (int i = 0; i < size; ++i) {
1434             try {
1435                 sandboxLifecycleCallbacks.getBroadcastItem(i).onSdkSandboxDied();
1436             } catch (RemoteException e) {
1437                 Log.w(TAG, "Unable to send sdk sandbox death event to app", e);
1438             }
1439         }
1440         sandboxLifecycleCallbacks.finishBroadcast();
1441     }
1442 
1443     @Override
1444     public boolean isSdkSandboxServiceRunning(String callingPackageName) {
1445         final CallingInfo callingInfo = CallingInfo.fromBinder(mContext, callingPackageName);
1446 
1447         final long token = Binder.clearCallingIdentity();
1448         try {
1449             return isSdkSandboxServiceRunning(callingInfo);
1450         } finally {
1451             Binder.restoreCallingIdentity(token);
1452         }
1453     }
1454 
1455     @Override
1456     public void stopSdkSandbox(String callingPackageName) {
1457         final CallingInfo callingInfo = CallingInfo.fromBinder(mContext, callingPackageName);
1458 
1459         mContext.enforceCallingPermission(
1460                 STOP_SDK_SANDBOX_PERMISSION,
1461                 callingPackageName + " does not have permission to stop their sandbox");
1462 
1463         final long token = Binder.clearCallingIdentity();
1464         try {
1465             stopSdkSandboxService(callingInfo, "App requesting sandbox kill");
1466         } finally {
1467             Binder.restoreCallingIdentity(token);
1468         }
1469     }
1470 
1471     @Override
1472     public IBinder getAdServicesManager() {
1473         synchronized (mLock) {
1474             return mAdServicesManager;
1475         }
1476     }
1477 
1478     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
1479     void registerAdServicesManagerService(IBinder iBinder, boolean published) {
1480         Log.d(TAG, "registerAdServicesManagerService(): published=" + published);
1481         synchronized (mLock) {
1482             mAdServicesManager = iBinder;
1483             mAdServicesManagerPublished = published;
1484         }
1485     }
1486 
1487     boolean isSdkSandboxDisabled() {
1488         if (!SdkLevel.isAtLeastU()) {
1489             return true;
1490         }
1491 
1492         synchronized (mLock) {
1493             if (!mInjector.isAdServiceApkPresent()) {
1494                 return true;
1495             }
1496 
1497             // Ignore killswitch if the device is an emulator
1498             if (mInjector.isEmulator()) {
1499                 return false;
1500             }
1501 
1502             return getSdkSandboxSettingsListener().isKillSwitchEnabled();
1503         }
1504     }
1505 
1506     /**
1507      * Clears the SDK sandbox state. This will result in the state being checked again the next time
1508      * an SDK is loaded.
1509      */
1510     void clearSdkSandboxState() {
1511         synchronized (mLock) {
1512             getSdkSandboxSettingsListener().setKillSwitchState(DEFAULT_VALUE_DISABLE_SDK_SANDBOX);
1513         }
1514     }
1515 
1516     /**
1517      * Enables the sandbox for testing purposes. Note that the sandbox can still be disabled by
1518      * setting the killswitch.
1519      */
1520     void forceEnableSandbox() {
1521         synchronized (mLock) {
1522             getSdkSandboxSettingsListener().setKillSwitchState(false);
1523         }
1524     }
1525 
1526     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
1527     SdkSandboxSettingsListener getSdkSandboxSettingsListener() {
1528         synchronized (mLock) {
1529             return mSdkSandboxSettingsListener;
1530         }
1531     }
1532 
1533     void stopAllSandboxes() {
1534         synchronized (mLock) {
1535             stopAllSandboxesLocked();
1536         }
1537     }
1538 
1539     /** Stops all running sandboxes in the case that the killswitch is triggered. */
1540     @GuardedBy("mLock")
1541     void stopAllSandboxesLocked() {
1542         for (int i = mLoadSdkSessions.size() - 1; i >= 0; --i) {
1543             stopSdkSandboxService(mLoadSdkSessions.keyAt(i), "SDK sandbox killswitch enabled");
1544         }
1545     }
1546 
1547     void stopSdkSandboxService(CallingInfo currentCallingInfo, String reason) {
1548         if (!isSdkSandboxServiceRunning(currentCallingInfo)) {
1549             Log.d(TAG, "Cannot kill sandbox for " + currentCallingInfo + ", already dead");
1550             return;
1551         }
1552 
1553         mServiceProvider.unbindService(currentCallingInfo);
1554 
1555         // For T, we kill the sandbox by uid. For U, we kill a specific sandbox process.
1556         if (SdkLevel.isAtLeastU()) {
1557             mServiceProvider.stopSandboxService(currentCallingInfo);
1558         } else {
1559             // For apps with shared uid, unbind the sandboxes for all the remaining apps since we
1560             // kill the sandbox by uid.
1561             synchronized (mLock) {
1562                 for (int i = 0; i < mCallingInfosWithDeathRecipients.size(); i++) {
1563                     final CallingInfo callingInfo = mCallingInfosWithDeathRecipients.keyAt(i);
1564                     if (callingInfo.getUid() == currentCallingInfo.getUid()) {
1565                         mServiceProvider.unbindService(callingInfo);
1566                     }
1567                 }
1568             }
1569             final int sdkSandboxUid = Process.toSdkSandboxUid(currentCallingInfo.getUid());
1570             Log.i(TAG, "Killing sdk sandbox/s with uid " + sdkSandboxUid);
1571             mActivityManager.killUid(sdkSandboxUid, reason);
1572         }
1573     }
1574 
1575     boolean isSdkSandboxServiceRunning(CallingInfo callingInfo) {
1576         int sandboxStatus = mServiceProvider.getSandboxStatusForApp(callingInfo);
1577         return sandboxStatus == SdkSandboxServiceProvider.CREATED
1578                 || sandboxStatus == SdkSandboxServiceProvider.CREATE_PENDING;
1579     }
1580 
1581     @WorkerThread
1582     private void computeSdkStorage(CallingInfo callingInfo, ISdkSandboxService service) {
1583         final List<StorageDirInfo> sharedStorageDirsInfo =
1584                 mSdkSandboxStorageManager.getInternalStorageDirInfo(callingInfo);
1585         final List<StorageDirInfo> sdkStorageDirsInfo =
1586                 mSdkSandboxStorageManager.getSdkStorageDirInfo(callingInfo);
1587 
1588         try {
1589             service.computeSdkStorage(
1590                     getListOfStoragePaths(sharedStorageDirsInfo),
1591                     getListOfStoragePaths(sdkStorageDirsInfo),
1592                     new IComputeSdkStorageCallback.Stub() {
1593                         @Override
1594                         public void onStorageInfoComputed(int sharedStorageKb, int sdkStorageKb) {
1595                             mSdkSandboxPulledAtoms.logStorage(
1596                                     callingInfo.getUid(), sharedStorageKb, sdkStorageKb);
1597                         }
1598                     });
1599         } catch (RemoteException e) {
1600             Log.e(TAG, "Error while computing sdk storage for CallingInfo: " + callingInfo);
1601         }
1602     }
1603 
1604     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
1605     List<String> getListOfStoragePaths(List<StorageDirInfo> storageDirInfos) {
1606         final List<String> paths = new ArrayList<>();
1607 
1608         for (int i = 0; i < storageDirInfos.size(); i++) {
1609             paths.add(storageDirInfos.get(i).getCeDataDir());
1610             paths.add(storageDirInfos.get(i).getDeDataDir());
1611         }
1612         return paths;
1613     }
1614 
1615     private void notifySyncManagerSandboxStarted(CallingInfo callingInfo) {
1616         ISharedPreferencesSyncCallback syncManagerCallback = null;
1617         synchronized (mLock) {
1618             syncManagerCallback = mSyncDataCallbacks.get(callingInfo);
1619             if (syncManagerCallback != null) {
1620                 try {
1621                     syncManagerCallback.onSandboxStart();
1622                 } catch (RemoteException ignore) {
1623                     // App died.
1624                 }
1625             }
1626             mSyncDataCallbacks.remove(callingInfo);
1627         }
1628     }
1629 
1630     private void loadSdkForService(
1631             LoadSdkSession loadSdkSession,
1632             ISdkSandboxService service,
1633             SandboxLatencyInfo sandboxLatencyInfo) {
1634         CallingInfo callingInfo = loadSdkSession.mCallingInfo;
1635         // Gather sdk storage information
1636         final StorageDirInfo sdkDataInfo =
1637                 mSdkSandboxStorageManager.getSdkStorageDirInfo(
1638                         callingInfo, loadSdkSession.mSdkProviderInfo.getSdkInfo().getName());
1639 
1640         ApplicationInfo customizedInfo =
1641                 createCustomizedApplicationInfo(loadSdkSession.getApplicationInfo(), sdkDataInfo);
1642 
1643         loadSdkSession.load(service, customizedInfo, sandboxLatencyInfo);
1644     }
1645 
1646     /** The customized ApplicationInfo is used to create CustomizedSdkContext for sdks. */
1647     ApplicationInfo createCustomizedApplicationInfo(
1648             ApplicationInfo original, StorageDirInfo dirInfo) {
1649         ApplicationInfo custom = new ApplicationInfo(original);
1650 
1651         // Assign per-sdk storage path as data dir
1652         custom.dataDir = dirInfo.getCeDataDir();
1653         custom.credentialProtectedDataDir = dirInfo.getCeDataDir();
1654         custom.deviceProtectedDataDir = dirInfo.getDeDataDir();
1655 
1656         // Package name still needs to be that of the sandbox because permissions are defined
1657         // for the sandbox app.
1658         custom.packageName = mContext.getPackageManager().getSdkSandboxPackageName();
1659 
1660         return custom;
1661     }
1662 
1663     private void failStartOrBindService(Intent intent) {
1664         throw new SecurityException(
1665                 "SDK sandbox uid may not bind to or start to this service: " + intent.toString());
1666     }
1667 
1668     private void enforceAllowedToStartOrBindService(Intent intent) {
1669         if (!Process.isSdkSandboxUid(Binder.getCallingUid())
1670                 || !mSdkSandboxSettingsListener.areRestrictionsEnforced()) {
1671             return;
1672         }
1673         ComponentName component = intent.getComponent();
1674 
1675         if (component != null) {
1676             String componentPackageName = component.getPackageName();
1677             if ((componentPackageName != null)
1678                     && (componentPackageName.equals(
1679                                     WebViewUpdateService.getCurrentWebViewPackageName())
1680                             || componentPackageName.equals(mInjector.getAdServicesPackageName()))) {
1681                 return;
1682             }
1683         }
1684 
1685         if (requestAllowedPerAllowlist(
1686                 intent.getAction(),
1687                 intent.getPackage(),
1688                 /*componentClassName=*/ (component == null) ? null : component.getClassName(),
1689                 /*componentPackageName=*/ (component == null)
1690                         ? null
1691                         : component.getPackageName())) {
1692             return;
1693         }
1694 
1695         // Default disallow.
1696         failStartOrBindService(intent);
1697     }
1698 
1699     @Override
1700     public int handleShellCommand(ParcelFileDescriptor in, ParcelFileDescriptor out,
1701             ParcelFileDescriptor err, String[] args) {
1702         boolean supportsAdServicesShellCmd = !mAdServicesManagerPublished;
1703         return mInjector
1704                 .createShellCommand(this, mContext, supportsAdServicesShellCmd)
1705                 .exec(
1706                         this,
1707                         in.getFileDescriptor(),
1708                         out.getFileDescriptor(),
1709                         err.getFileDescriptor(),
1710                         args);
1711     }
1712 
1713     private ApplicationInfo getSdkSandboxApplicationInfoForInstrumentation(
1714             ApplicationInfo clientAppInfo, boolean isSdkInSandbox)
1715             throws PackageManager.NameNotFoundException {
1716         int uid = clientAppInfo.uid;
1717         PackageManager pm = mContext.getPackageManager();
1718         ApplicationInfo sdkSandboxInfo =
1719                 pm.getApplicationInfoAsUser(
1720                         pm.getSdkSandboxPackageName(),
1721                         /* flags= */ 0,
1722                         UserHandle.getUserHandleForUid(uid));
1723         ApplicationInfo sdkSandboxInfoForInstrumentation =
1724                 (isSdkInSandbox)
1725                         ? createCustomizedApplicationInfo(
1726                                 clientAppInfo,
1727                                 new StorageDirInfo(
1728                                         sdkSandboxInfo.dataDir,
1729                                         sdkSandboxInfo.deviceProtectedDataDir))
1730                         : sdkSandboxInfo;
1731 
1732         // Required to allow adopt shell permissions in tests.
1733         sdkSandboxInfoForInstrumentation.uid = Process.toSdkSandboxUid(uid);
1734         // We want to use a predictable process name during testing.
1735         sdkSandboxInfoForInstrumentation.processName =
1736                 getLocalManager().getSdkSandboxProcessNameForInstrumentation(clientAppInfo);
1737 
1738         return sdkSandboxInfoForInstrumentation;
1739     }
1740 
1741     /**
1742      * A callback object to establish a link between the sdk in sandbox calling into manager
1743      * service.
1744      *
1745      * <p>When a sandbox is initialized, a callback object of {@link SdkToServiceLink} is passed to
1746      * be used as a part of {@link SdkSandboxController}. The Controller can then can call APIs on
1747      * the link object to get data from the manager service.
1748      */
1749     // TODO(b/268043836): Move SdkToServiceLink out of SdkSandboxManagerService
1750     private class SdkToServiceLink extends ISdkToServiceCallback.Stub {
1751 
1752         /**
1753          * Fetches a list of {@link AppOwnedSdkSandboxInterface} registered for an app
1754          *
1755          * <p>This provides the information on the interfaces that are currently registered in the
1756          * app.
1757          *
1758          * @param clientPackageName of the client package
1759          * @return empty list if callingInfo not found in map otherwise a list of {@link
1760          *     AppOwnedSdkSandboxInterface}
1761          */
1762         @Override
1763         public List<AppOwnedSdkSandboxInterface> getAppOwnedSdkSandboxInterfaces(
1764                 String clientPackageName) throws RemoteException {
1765             int uid = Binder.getCallingUid();
1766             if (Process.isSdkSandboxUid(uid)) {
1767                 uid = Process.getAppUidForSdkSandboxUid(uid);
1768             }
1769             CallingInfo callingInfo = new CallingInfo(uid, clientPackageName);
1770             return getRegisteredAppOwnedSdkSandboxInterfacesForApp(callingInfo);
1771         }
1772 
1773         /**
1774          * Fetches {@link SandboxedSdk} for all SDKs that are loaded in the sandbox.
1775          *
1776          * <p>This provides the information on the library that is currently loaded in the sandbox
1777          * and also channels to communicate with loaded SDK.
1778          *
1779          * @param clientPackageName package name of the app for which the sdk was loaded in the
1780          *     sandbox
1781          * @param sandboxLatencyInfo object containing the information of latency metrics for the
1782          *     api
1783          * @return List of {@link SandboxedSdk} containing all currently loaded sdks
1784          */
1785         @Override
1786         public List<SandboxedSdk> getSandboxedSdks(
1787                 String clientPackageName, SandboxLatencyInfo sandboxLatencyInfo)
1788                 throws RemoteException {
1789             // TODO(b/258195148): Write multiuser tests
1790             // TODO(b/242039497): Add authorisation checks to make sure only the sandbox calls this
1791             //  API.
1792             return SdkSandboxManagerService.this.getSandboxedSdks(
1793                     clientPackageName, sandboxLatencyInfo);
1794         }
1795 
1796         @Override
1797         public void loadSdk(
1798                 String callingPackageName,
1799                 String sdkName,
1800                 SandboxLatencyInfo sandboxLatencyInfo,
1801                 Bundle params,
1802                 ILoadSdkCallback callback)
1803                 throws RemoteException {
1804             // The process token is only used to kill the app process when the
1805             // sandbox dies (for U+, not available on T), so a sandbox process token
1806             // is not needed here. This is taken care of when the first SDK is loaded
1807             // by the app.
1808             SdkSandboxManagerService.this.loadSdk(
1809                     callingPackageName,
1810                     /*callingAppProcessToken=*/ null,
1811                     sdkName,
1812                     sandboxLatencyInfo,
1813                     params,
1814                     callback);
1815         }
1816 
1817         @Override
1818         public void logLatenciesFromSandbox(SandboxLatencyInfo sandboxLatencyInfo) {
1819             logSandboxApiLatency(sandboxLatencyInfo);
1820         }
1821 
1822         @Override
1823         public void logSandboxActivityApiLatencyFromSandbox(
1824                 int method, int callResult, int latencyMillis) {
1825             SdkSandboxManagerService.this.logSandboxActivityApiLatency(
1826                     method, callResult, latencyMillis);
1827         }
1828     }
1829 
1830     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
1831     SdkSandboxManagerLocal getLocalManager() {
1832         return mInjector.getLocalManager();
1833     }
1834 
1835     private void notifyInstrumentationStarted(CallingInfo callingInfo) {
1836         Log.d(
1837                 TAG,
1838                 "notifyInstrumentationStarted: clientApp = "
1839                         + callingInfo.getPackageName()
1840                         + " clientAppUid = "
1841                         + callingInfo.getUid());
1842         synchronized (mLock) {
1843             mServiceProvider.unbindService(callingInfo);
1844             int sdkSandboxUid = Process.toSdkSandboxUid(callingInfo.getUid());
1845             mActivityManager.killUid(sdkSandboxUid, "instrumentation started");
1846             mRunningInstrumentations.add(callingInfo);
1847         }
1848         // TODO(b/223386213): we need to check if there is reconcileSdkData task already enqueued
1849         //  because the instrumented client app was just installed.
1850         mSdkSandboxStorageManager.notifyInstrumentationStarted(callingInfo);
1851     }
1852 
1853     private void notifyInstrumentationFinished(CallingInfo callingInfo) {
1854         Log.d(TAG, "notifyInstrumentationFinished: clientApp = " + callingInfo.getPackageName()
1855                 + " clientAppUid = " + callingInfo.getUid());
1856         synchronized (mLock) {
1857             mRunningInstrumentations.remove(callingInfo);
1858         }
1859     }
1860 
1861     private boolean isInstrumentationRunning(CallingInfo callingInfo) {
1862         synchronized (mLock) {
1863             return mRunningInstrumentations.contains(callingInfo);
1864         }
1865     }
1866 
1867     private boolean isSdkSandboxAllowedToStartActivities(int pid, int uid) {
1868         return mContext.checkPermission(
1869                         "android.permission.START_ACTIVITIES_FROM_SDK_SANDBOX", pid, uid)
1870                 == PackageManager.PERMISSION_GRANTED;
1871     }
1872 
1873     // TODO(b/300059435): remove once the {@link
1874     // SdkSandboxActivityAuthority#isSdkSandboxActivityIntent} API is stable.
1875     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
1876     boolean isSdkSandboxActivity(Intent intent) {
1877         if (intent == null) {
1878             return false;
1879         }
1880         if (intent.getAction() != null
1881                 && intent.getAction().equals(ACTION_START_SANDBOXED_ACTIVITY)) {
1882             return true;
1883         }
1884         final String sandboxPackageName = mContext.getPackageManager().getSdkSandboxPackageName();
1885         if (intent.getPackage() != null && intent.getPackage().equals(sandboxPackageName)) {
1886             return true;
1887         }
1888         if (intent.getComponent() != null
1889                 && intent.getComponent().getPackageName().equals(sandboxPackageName)) {
1890             return true;
1891         }
1892         return false;
1893     }
1894 
1895     /** @hide */
1896     public static class Lifecycle extends SystemService {
1897         @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
1898         SdkSandboxManagerService mService;
1899 
1900         public Lifecycle(Context context) {
1901             super(context);
1902             mService = new SdkSandboxManagerService(getContext());
1903         }
1904 
1905         @Override
1906         public void onStart() {
1907             publishBinderService(SDK_SANDBOX_SERVICE, mService);
1908 
1909             LocalManagerRegistry.addManager(
1910                     SdkSandboxManagerLocal.class, mService.getLocalManager());
1911         }
1912 
1913         @Override
1914         public void onUserUnlocking(TargetUser user) {
1915             final int userId = user.getUserHandle().getIdentifier();
1916             mService.onUserUnlocking(userId);
1917         }
1918     }
1919 
1920     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
1921     private class SdkSandboxInterceptorCallback implements ActivityInterceptorCallback {
1922 
1923         private enum InterceptCase {
1924             SANDBOXED_ACTIVITY,
1925             INSTRUMENTATION_ACTIVITY,
1926             NO_INTERCEPT
1927         }
1928 
1929         private InterceptCase shouldIntercept(ActivityInterceptorInfo info) {
1930             final Intent intent = info.getIntent();
1931             if (intent == null) {
1932                 return InterceptCase.NO_INTERCEPT;
1933             }
1934 
1935             boolean isSdkSandboxActivity =
1936                     (sandboxActivitySdkBasedContext())
1937                             ? SdkSandboxActivityAuthority.isSdkSandboxActivityIntent(
1938                                     mContext, intent)
1939                             : isSdkSandboxActivity(intent);
1940             if (isSdkSandboxActivity) {
1941                 final String sdkSandboxPackageName =
1942                         mContext.getPackageManager().getSdkSandboxPackageName();
1943                 // Only intercept if action and package are both defined and refer to the
1944                 // sandbox activity.
1945                 if (intent.getPackage() == null
1946                         || !intent.getPackage().equals(sdkSandboxPackageName)
1947                         || intent.getAction() == null
1948                         || !intent.getAction().equals(ACTION_START_SANDBOXED_ACTIVITY)) {
1949                     return InterceptCase.NO_INTERCEPT;
1950                 }
1951 
1952                 // If component is set, it should refer to the sandbox package to intercept.
1953                 if (intent.getComponent() != null) {
1954                     if (!intent.getComponent().getPackageName().equals(sdkSandboxPackageName)) {
1955                         return InterceptCase.NO_INTERCEPT;
1956                     }
1957                 }
1958                 return InterceptCase.SANDBOXED_ACTIVITY;
1959             }
1960 
1961             if (info.getActivityInfo() == null
1962                     || !Process.isSdkSandboxUid(info.getCallingUid())
1963                     || !SdkLevel.isAtLeastV()) {
1964                 return InterceptCase.NO_INTERCEPT;
1965             }
1966             final ApplicationInfo applicationInfo = info.getActivityInfo().applicationInfo;
1967             synchronized (mLock) {
1968                 if (applicationInfo.packageName != null
1969                         && mRunningInstrumentations.contains(
1970                                 new CallingInfo(applicationInfo.uid, applicationInfo.packageName))
1971                         && isSdkSandboxAllowedToStartActivities(
1972                                 info.getCallingPid(), info.getCallingUid())) {
1973                     return InterceptCase.INSTRUMENTATION_ACTIVITY;
1974                 }
1975             }
1976 
1977             return InterceptCase.NO_INTERCEPT;
1978         }
1979 
1980         @Override
1981         public ActivityInterceptResult onInterceptActivityLaunch(
1982                 @NonNull ActivityInterceptorInfo info) {
1983             final ActivityInfo activityInfo = info.getActivityInfo();
1984             ActivityInterceptorCallback.ActivityInterceptResult activityInterceptResult = null;
1985             long timeEventStarted = mInjector.elapsedRealtime();
1986             int callingUid = info.getCallingUid();
1987 
1988             // Do not add any lines before checking if interception should apply, this interception
1989             // happens for every single activity and adding logic might add significant performance
1990             // overhead.
1991             switch (shouldIntercept(info)) {
1992                 case SANDBOXED_ACTIVITY:
1993                     // Update process name and uid to match sandbox process for the calling app.
1994                     activityInfo.applicationInfo.uid = Process.toSdkSandboxUid(callingUid);
1995                     CallingInfo callingInfo = new CallingInfo(callingUid, info.getCallingPackage());
1996                     try {
1997                         activityInfo.processName =
1998                                 mInjector
1999                                         .getSdkSandboxServiceProvider()
2000                                         .toSandboxProcessName(callingInfo);
2001                     } catch (PackageManager.NameNotFoundException e) {
2002                         SdkSandboxManagerService.this.logSandboxActivityApiLatency(
2003                                 SdkSandboxStatsLog
2004                                         .SANDBOX_ACTIVITY_EVENT_OCCURRED__METHOD__INTERCEPT_SANDBOX_ACTIVITY,
2005                                 SANDBOX_ACTIVITY_EVENT_OCCURRED__CALL_RESULT__FAILURE_SECURITY_EXCEPTION,
2006                                 (int) (mInjector.elapsedRealtime() - timeEventStarted),
2007                                 callingUid);
2008                         Log.e(
2009                                 TAG,
2010                                 "onInterceptActivityLaunch failed for: " + callingInfo.toString(),
2011                                 e);
2012                         throw new SecurityException(e.toString());
2013                     }
2014                     activityInterceptResult =
2015                             new ActivityInterceptorCallback.ActivityInterceptResult(
2016                                     info.getIntent(), info.getCheckedOptions(), true);
2017                     SdkSandboxManagerService.this.logSandboxActivityApiLatency(
2018                             SdkSandboxStatsLog
2019                                     .SANDBOX_ACTIVITY_EVENT_OCCURRED__METHOD__INTERCEPT_SANDBOX_ACTIVITY,
2020                             SdkSandboxStatsLog
2021                                     .SANDBOX_ACTIVITY_EVENT_OCCURRED__CALL_RESULT__SUCCESS,
2022                             (int) (mInjector.elapsedRealtime() - timeEventStarted),
2023                             callingUid);
2024                     break;
2025                 case INSTRUMENTATION_ACTIVITY:
2026                     // Tests instrumented to run in the Sandbox already use a sandbox Uid.
2027                     activityInfo.applicationInfo.uid = callingUid;
2028                     callingInfo =
2029                             new CallingInfo(callingUid, activityInfo.applicationInfo.packageName);
2030                     activityInterceptResult =
2031                             new ActivityInterceptorCallback.ActivityInterceptResult(
2032                                     info.getIntent(), info.getCheckedOptions(), true);
2033                     try {
2034                         activityInfo.processName =
2035                                 mInjector
2036                                         .getSdkSandboxServiceProvider()
2037                                         .toSandboxProcessNameForInstrumentation(callingInfo);
2038                     } catch (PackageManager.NameNotFoundException e) {
2039                         Log.e(
2040                                 TAG,
2041                                 "onInterceptActivityLaunch failed for: " + callingInfo.toString(),
2042                                 e);
2043                         throw new SecurityException(e.toString());
2044                     }
2045                     break;
2046                 default: // NO_INTERCEPT
2047                     return null;
2048             }
2049 
2050             return activityInterceptResult;
2051         }
2052     }
2053 
2054     private class UidImportanceListener implements ActivityManager.OnUidImportanceListener {
2055 
2056         private final int mImportanceCutpoint;
2057 
2058         public boolean isListening = false;
2059 
2060         UidImportanceListener() {
2061             if (SdkLevel.isAtLeastU()) {
2062                 // On U+, we inform the SDK when the app has transitioned to and from foreground
2063                 // importance.
2064                 mImportanceCutpoint = IMPORTANCE_FOREGROUND;
2065             } else {
2066                 // On T, we unbind the sandbox when the app stops being visible to the user in some
2067                 // way.
2068                 mImportanceCutpoint = IMPORTANCE_VISIBLE;
2069             }
2070         }
2071 
2072         public void startListening() {
2073             synchronized (mLock) {
2074                 if (isListening) {
2075                     return;
2076                 }
2077                 mActivityManager.addOnUidImportanceListener(this, mImportanceCutpoint);
2078                 isListening = true;
2079             }
2080         }
2081 
2082         public void stopListening() {
2083             synchronized (mLock) {
2084                 if (!isListening) {
2085                     return;
2086                 }
2087                 mActivityManager.removeOnUidImportanceListener(this);
2088                 isListening = false;
2089             }
2090         }
2091 
2092         @Override
2093         public void onUidImportance(int uid, int importance) {
2094             synchronized (mLock) {
2095                 for (int i = 0; i < mCallingInfosWithDeathRecipients.size(); i++) {
2096                     final CallingInfo callingInfo = mCallingInfosWithDeathRecipients.keyAt(i);
2097                     if (callingInfo.getUid() == uid) {
2098                         if (SdkLevel.isAtLeastU()) {
2099                             informSdksAboutAppTransition(importance, callingInfo);
2100                         } else {
2101                             unbindSandbox(importance, callingInfo);
2102                         }
2103                     }
2104                 }
2105             }
2106         }
2107 
2108         private void unbindSandbox(int importance, CallingInfo callingInfo) {
2109             if (importance <= mImportanceCutpoint) {
2110                 // The lower the importance value, the more "important" the process is. We
2111                 // are only interested when the process is no longer visible.
2112                 return;
2113             }
2114             LogUtil.d(
2115                     TAG,
2116                     "App with uid "
2117                             + callingInfo.getUid()
2118                             + " is no longer visible, unbinding sandbox");
2119             // Unbind the sandbox when the app is no longer visible to lower its priority.
2120             mServiceProvider.unbindService(callingInfo);
2121         }
2122 
2123         private void informSdksAboutAppTransition(int importance, CallingInfo callingInfo) {
2124             ISdkSandboxService sandbox = mServiceProvider.getSdkSandboxServiceForApp(callingInfo);
2125             if (sandbox == null) {
2126                 return;
2127             }
2128 
2129             try {
2130                 // Inform the sandbox when the client app uid has changed from foreground to
2131                 // background importance or vice versa.
2132                 sandbox.notifySdkSandboxClientImportanceChange(importance <= mImportanceCutpoint);
2133             } catch (RemoteException e) {
2134                 Log.e(
2135                         TAG,
2136                         "Could not inform sandbox about state change of "
2137                                 + callingInfo
2138                                 + " : "
2139                                 + e.getMessage());
2140             }
2141         }
2142     }
2143 
2144     // For testing as SANDBOXED_ACTIVITY_HANDLER_KEY is hidden from
2145     // SdkSandboxManagerServiceUnitTests
2146     @NonNull
2147     public String getSandboxedActivityHandlerKey() {
2148         return EXTRA_SANDBOXED_ACTIVITY_HANDLER;
2149     }
2150 
2151     private ArraySet<String> getContentProviderAllowlist() {
2152         String curWebViewPackageName = WebViewUpdateService.getCurrentWebViewPackageName();
2153         ArraySet<String> contentProviderAuthoritiesAllowlist = new ArraySet<>();
2154         // TODO(b/279557220): Make curWebViewPackageName a static variable once fixed.
2155         for (String webViewAuthority :
2156                 new String[] {
2157                     WEBVIEW_DEVELOPER_MODE_CONTENT_PROVIDER, WEBVIEW_SAFE_MODE_CONTENT_PROVIDER
2158                 }) {
2159             contentProviderAuthoritiesAllowlist.add(curWebViewPackageName + '.' + webViewAuthority);
2160         }
2161 
2162         synchronized (mLock) {
2163             if (mSdkSandboxSettingsListener.applySdkSandboxRestrictionsNext()
2164                     && mSdkSandboxSettingsListener.getNextContentProviderAllowlist() != null) {
2165                 contentProviderAuthoritiesAllowlist.addAll(
2166                         mSdkSandboxSettingsListener.getNextContentProviderAllowlist());
2167                 return contentProviderAuthoritiesAllowlist;
2168             }
2169 
2170             // TODO(b/271547387): Filter out the allowlist based on targetSdkVersion.
2171             ArraySet<String> contentProviderAllowlistForTargetSdkVersion =
2172                     mSdkSandboxSettingsListener
2173                             .getContentProviderAllowlistPerTargetSdkVersion()
2174                             .get(Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
2175             if (contentProviderAllowlistForTargetSdkVersion != null) {
2176                 contentProviderAuthoritiesAllowlist.addAll(
2177                         contentProviderAllowlistForTargetSdkVersion);
2178             } else {
2179                 contentProviderAuthoritiesAllowlist.addAll(
2180                         DEFAULT_CONTENTPROVIDER_ALLOWED_AUTHORITIES);
2181             }
2182         }
2183         return contentProviderAuthoritiesAllowlist;
2184     }
2185 
2186     // Returns null if an allowlist was not set at all.
2187     @Nullable
2188     private ArraySet<String> getBroadcastReceiverAllowlist() {
2189         synchronized (mLock) {
2190             if (mSdkSandboxSettingsListener.applySdkSandboxRestrictionsNext()) {
2191                 return mSdkSandboxSettingsListener.getNextBroadcastReceiverAllowlist();
2192             }
2193 
2194             ArrayMap<Integer, ArraySet<String>> broadcastReceiverAllowlist =
2195                     mSdkSandboxSettingsListener.getBroadcastReceiverAllowlistPerTargetSdkVersion();
2196 
2197             if (broadcastReceiverAllowlist == null) {
2198                 return null;
2199             }
2200             // TODO(b/271547387): Filter out the allowlist based on targetSdkVersion.
2201             return broadcastReceiverAllowlist.get(Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
2202         }
2203     }
2204 
2205     @NonNull
2206     private ArraySet<String> getActivityAllowlist() {
2207         synchronized (mLock) {
2208             if (mSdkSandboxSettingsListener.applySdkSandboxRestrictionsNext()
2209                     && mSdkSandboxSettingsListener.getNextActivityAllowlist() != null) {
2210                 return mSdkSandboxSettingsListener.getNextActivityAllowlist();
2211             }
2212             return getActivityAllowlistForTargetSdk();
2213         }
2214     }
2215 
2216     @NonNull
2217     private ArraySet<String> getActivityAllowlistForTargetSdk() {
2218         synchronized (mLock) {
2219             if (mSdkSandboxSettingsListener.getActivityAllowlistPerTargetSdkVersion() == null) {
2220                 return DEFAULT_ACTIVITY_ALLOWED_ACTIONS;
2221             }
2222             // TODO(b/271547387): Filter out the allowlist based on targetSdkVersion.
2223             ArraySet<String> activityAllowlistPerTargetSdkVersion =
2224                     mSdkSandboxSettingsListener
2225                             .getActivityAllowlistPerTargetSdkVersion()
2226                             .get(Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
2227             if (activityAllowlistPerTargetSdkVersion == null) {
2228                 return DEFAULT_ACTIVITY_ALLOWED_ACTIONS;
2229             }
2230             return activityAllowlistPerTargetSdkVersion;
2231         }
2232     }
2233 
2234     private boolean requestAllowedPerAllowlist(
2235             String action,
2236             String packageName,
2237             String componentClassName,
2238             String componentPackageName) {
2239         // TODO(b/288873117): Use effective targetSdkVersion of the sandbox for the client app.
2240         AllowedServices allowedServices =
2241                 mSdkSandboxSettingsListener.applySdkSandboxRestrictionsNext()
2242                         ? mSdkSandboxSettingsListener.getNextServiceAllowlist()
2243                         : mSdkSandboxSettingsListener.getServiceAllowlistForTargetSdkVersion(
2244                                 /*targetSdkVersion=*/ 34);
2245 
2246         if (Objects.isNull(allowedServices)) {
2247             return false;
2248         }
2249 
2250         for (int i = 0; i < allowedServices.getAllowedServicesCount(); i++) {
2251             AllowedService allowedService = allowedServices.getAllowedServices(i);
2252             if (StringHelper.doesInputMatchWildcardPattern(
2253                             allowedService.getAction(), action, /*matchOnNullInput=*/ true)
2254                     && StringHelper.doesInputMatchWildcardPattern(
2255                             allowedService.getPackageName(),
2256                             packageName,
2257                             /*matchOnNullInput=*/ true)
2258                     && StringHelper.doesInputMatchWildcardPattern(
2259                             allowedService.getComponentClassName(),
2260                             componentClassName,
2261                             /*matchOnNullInput=*/ true)
2262                     && StringHelper.doesInputMatchWildcardPattern(
2263                             allowedService.getComponentPackageName(),
2264                             componentPackageName,
2265                             /*matchOnNullInput=*/ true)) {
2266                 return true;
2267             }
2268         }
2269         return false;
2270     }
2271 
2272     private int getEffectiveTargetSdkVersion(int sdkSandboxUid)
2273             throws PackageManager.NameNotFoundException {
2274         return mSdkSandboxRestrictionManager.getEffectiveTargetSdkVersion(
2275                 Process.getAppUidForSdkSandboxUid(sdkSandboxUid));
2276     }
2277 
2278     class LocalImpl implements SdkSandboxManagerLocal {
2279         // The following test allowlists are used to temporarily allow test components
2280         // (ContentProviders, BroadcastReceivers etc.) to be accessed during testing. This is not
2281         // combined with the existing allowlist and is checked independently.
2282         private ArraySet<String> mTestCpAllowlist = new ArraySet<>();
2283         private ArraySet<String> mTestSendBroadcastAllowlist = new ArraySet<>();
2284 
2285         @Override
2286         public void registerAdServicesManagerService(IBinder iBinder, boolean published) {
2287             SdkSandboxManagerService.this.registerAdServicesManagerService(iBinder, published);
2288         }
2289 
2290         @NonNull
2291         @Override
2292         public String getSdkSandboxProcessNameForInstrumentation(
2293                 @NonNull ApplicationInfo clientAppInfo) {
2294             CallingInfo callingInfo = new CallingInfo(clientAppInfo.uid, clientAppInfo.packageName);
2295             try {
2296                 return mServiceProvider.toSandboxProcessNameForInstrumentation(callingInfo);
2297             } catch (PackageManager.NameNotFoundException e) {
2298                 Log.e(
2299                         TAG,
2300                         "getSdkSandboxProcessNameForInstrumentation failed for: "
2301                                 + callingInfo.toString(),
2302                         e);
2303                 throw new SecurityException(e.toString());
2304             }
2305         }
2306 
2307         @NonNull
2308         @Override
2309         public ApplicationInfo getSdkSandboxApplicationInfoForInstrumentation(
2310                 @NonNull ApplicationInfo clientAppInfo, boolean isSdkInSandbox)
2311                 throws PackageManager.NameNotFoundException {
2312             return SdkSandboxManagerService.this.getSdkSandboxApplicationInfoForInstrumentation(
2313                     clientAppInfo, isSdkInSandbox);
2314         }
2315 
2316         @Override
2317         public void notifyInstrumentationStarted(
2318                 @NonNull String clientAppPackageName, int clientAppUid) {
2319             SdkSandboxManagerService.this.notifyInstrumentationStarted(
2320                     new CallingInfo(clientAppUid, clientAppPackageName));
2321         }
2322 
2323         @Override
2324         public void notifyInstrumentationFinished(
2325                 @NonNull String clientAppPackageName, int clientAppUid) {
2326             SdkSandboxManagerService.this.notifyInstrumentationFinished(
2327                     new CallingInfo(clientAppUid, clientAppPackageName));
2328         }
2329 
2330         @Override
2331         public boolean isInstrumentationRunning(
2332                 @NonNull String clientAppPackageName, int clientAppUid) {
2333             return SdkSandboxManagerService.this.isInstrumentationRunning(
2334                     new CallingInfo(clientAppUid, clientAppPackageName));
2335         }
2336 
2337         @Override
2338         public void enforceAllowedToSendBroadcast(@NonNull Intent intent) {
2339             if (!canSendBroadcast(intent)) {
2340                 throw new SecurityException(
2341                         "Intent "
2342                                 + intent.getAction()
2343                                 + " may not be broadcast from an SDK sandbox uid");
2344             }
2345         }
2346 
2347         @Override
2348         public boolean canSendBroadcast(@NonNull Intent intent) {
2349             return StringHelper.doesInputMatchAnyWildcardPattern(
2350                     mTestSendBroadcastAllowlist, intent.getAction());
2351         }
2352 
2353         @Override
2354         public void enforceAllowedToStartActivity(@NonNull Intent intent) {
2355             if (!Process.isSdkSandboxUid(Binder.getCallingUid())
2356                     || !mSdkSandboxSettingsListener.areRestrictionsEnforced()) {
2357                 return;
2358             }
2359 
2360             if (intent.getAction() == null) {
2361                 return;
2362             }
2363 
2364             if (StringHelper.doesInputMatchAnyWildcardPattern(
2365                     getActivityAllowlist(), intent.getAction())) {
2366                 return;
2367             }
2368             // During CTS-in-sandbox testing, we store the package name of the instrumented test in
2369             // the intent identifier to match it against the running instrumentations.
2370             final String instrumentationPackageName = intent.getIdentifier();
2371             final int callingUid = Binder.getCallingUid();
2372             final int appUid = Process.getAppUidForSdkSandboxUid(callingUid);
2373             synchronized (mLock) {
2374                 if (instrumentationPackageName != null
2375                         && Process.isSdkSandboxUid(callingUid)
2376                         && mRunningInstrumentations.contains(
2377                                 new CallingInfo(appUid, instrumentationPackageName))
2378                         && isSdkSandboxAllowedToStartActivities(
2379                                 Binder.getCallingPid(), callingUid)) {
2380                     // allow launching activities for sdk-in-sandbox instrumented tests.
2381                     return;
2382                 }
2383             }
2384             throw new SecurityException(
2385                     "Intent "
2386                             + intent.getAction()
2387                             + " may not be started from an SDK sandbox uid.");
2388         }
2389 
2390         @Override
2391         public void enforceAllowedToStartOrBindService(@NonNull Intent intent) {
2392             SdkSandboxManagerService.this.enforceAllowedToStartOrBindService(intent);
2393         }
2394 
2395         @Override
2396         public boolean canAccessContentProviderFromSdkSandbox(@NonNull ProviderInfo providerInfo) {
2397             if (!Process.isSdkSandboxUid(Binder.getCallingUid())) {
2398                 return true;
2399             }
2400 
2401             /**
2402              * By clearing the calling identity, system server identity is set which allows us to
2403              * call {@DeviceConfig.getBoolean}
2404              */
2405             long token = Binder.clearCallingIdentity();
2406 
2407             try {
2408                 return !mSdkSandboxSettingsListener.areRestrictionsEnforced()
2409                         || StringHelper.doesInputMatchAnyWildcardPattern(
2410                                 getContentProviderAllowlist(), providerInfo.authority)
2411                         || StringHelper.doesInputMatchAnyWildcardPattern(
2412                                 mTestCpAllowlist, providerInfo.authority);
2413             } finally {
2414                 Binder.restoreCallingIdentity(token);
2415             }
2416         }
2417 
2418         @Override
2419         public void enforceAllowedToHostSandboxedActivity(
2420                 @NonNull Intent intent, int clientAppUid, @NonNull String clientAppPackageName) {
2421             long timeEventStarted = mInjector.elapsedRealtime();
2422             try {
2423                 if (Process.isSdkSandboxUid(clientAppUid)) {
2424                     throw new SecurityException(
2425                             "Sandbox process is not allowed to start sandbox activities.");
2426                 }
2427                 if (intent == null) {
2428                     throw new SecurityException("Intent to start sandbox activity is null.");
2429                 }
2430                 if (intent.getAction() == null
2431                         || !intent.getAction().equals(ACTION_START_SANDBOXED_ACTIVITY)) {
2432                     throw new SecurityException(
2433                             "Sandbox activity intent must have an action ("
2434                                     + ACTION_START_SANDBOXED_ACTIVITY
2435                                     + ").");
2436                 }
2437                 String sandboxPackageName = mContext.getPackageManager().getSdkSandboxPackageName();
2438                 if (intent.getPackage() == null
2439                         || !intent.getPackage().equals(sandboxPackageName)) {
2440                     throw new SecurityException(
2441                             "Sandbox activity intent's package must be set to the sandbox package");
2442                 }
2443                 if (intent.getComponent() != null) {
2444                     final String componentPackageName = intent.getComponent().getPackageName();
2445                     if (!componentPackageName.equals(sandboxPackageName)) {
2446                         throw new SecurityException(
2447                                 "Sandbox activity intent's component must refer to the sandbox"
2448                                         + " package");
2449                     }
2450                 }
2451             } catch (SecurityException e) {
2452                 logEnforceAllowedToHostSandboxedActivityLatency(
2453                         SANDBOX_ACTIVITY_EVENT_OCCURRED__CALL_RESULT__FAILURE_SECURITY_EXCEPTION,
2454                         timeEventStarted);
2455                 throw e;
2456             }
2457 
2458             final CallingInfo callingInfo = new CallingInfo(clientAppUid, clientAppPackageName);
2459             if (mServiceProvider.getSdkSandboxServiceForApp(callingInfo) == null) {
2460                 logEnforceAllowedToHostSandboxedActivityLatency(
2461                         SdkSandboxStatsLog
2462                                 .SANDBOX_ACTIVITY_EVENT_OCCURRED__CALL_RESULT__FAILURE_SECURITY_EXCEPTION_NO_SANDBOX_PROCESS,
2463                         timeEventStarted);
2464                 throw new SecurityException(
2465                         "There is no sandbox process running for the caller uid"
2466                                 + ": "
2467                                 + clientAppUid
2468                                 + ".");
2469             }
2470 
2471             Bundle extras = intent.getExtras();
2472             if (extras == null || extras.getBinder(getSandboxedActivityHandlerKey()) == null) {
2473                 logEnforceAllowedToHostSandboxedActivityLatency(
2474                         SdkSandboxStatsLog
2475                                 .SANDBOX_ACTIVITY_EVENT_OCCURRED__CALL_RESULT__FAILURE_ILLEGAL_ARGUMENT_EXCEPTION,
2476                         timeEventStarted);
2477                 throw new IllegalArgumentException(
2478                         "Intent should contain an extra params with key = "
2479                                 + getSandboxedActivityHandlerKey()
2480                                 + " and value is an IBinder that identifies a registered "
2481                                 + "SandboxedActivityHandler.");
2482             }
2483 
2484             logEnforceAllowedToHostSandboxedActivityLatency(
2485                     SdkSandboxStatsLog.SANDBOX_ACTIVITY_EVENT_OCCURRED__CALL_RESULT__SUCCESS,
2486                     timeEventStarted);
2487         }
2488 
2489         private void logEnforceAllowedToHostSandboxedActivityLatency(
2490                 int callResult, long timeEventStarted) {
2491             SdkSandboxManagerService.this.logSandboxActivityApiLatency(
2492                     SdkSandboxStatsLog
2493                             .SANDBOX_ACTIVITY_EVENT_OCCURRED__METHOD__ENFORCE_ALLOWED_TO_HOST_SANDBOXED_ACTIVITY,
2494                     callResult,
2495                     (int) (mInjector.elapsedRealtime() - timeEventStarted));
2496         }
2497 
2498         @Override
2499         public boolean canRegisterBroadcastReceiver(
2500                 @NonNull IntentFilter intentFilter, int flags, boolean onlyProtectedBroadcasts) {
2501             if (!Process.isSdkSandboxUid(Binder.getCallingUid())) {
2502                 return true;
2503             }
2504 
2505             int actionsCount = intentFilter.countActions();
2506             if (actionsCount == 0) {
2507                 return false;
2508             }
2509 
2510             /**
2511              * By clearing the calling identity, system server identity is set which allows us to
2512              * call {@DeviceConfig.getBoolean}
2513              */
2514             long token = Binder.clearCallingIdentity();
2515 
2516             try {
2517                 if (!mSdkSandboxSettingsListener.areRestrictionsEnforced()) {
2518                     return true;
2519                 }
2520 
2521                 ArraySet<String> broadcastReceiverAllowlist = getBroadcastReceiverAllowlist();
2522                 // If an allowlist was not set at all, only allow protected broadcasts. Note that
2523                 // this is different from an empty allowlist (which blocks all BroadcastReceivers).
2524                 if (broadcastReceiverAllowlist == null) {
2525                     return onlyProtectedBroadcasts;
2526                 }
2527 
2528                 ArraySet<String> actions = new ArraySet<>();
2529                 for (int i = 0; i < actionsCount; ++i) {
2530                     actions.add(intentFilter.getAction(i));
2531                 }
2532 
2533                 return broadcastReceiverAllowlist.containsAll(actions);
2534             } finally {
2535                 Binder.restoreCallingIdentity(token);
2536             }
2537         }
2538 
2539         @Override
2540         public int getEffectiveTargetSdkVersion(int sdkSandboxUid)
2541                 throws PackageManager.NameNotFoundException {
2542             return SdkSandboxManagerService.this.getEffectiveTargetSdkVersion(sdkSandboxUid);
2543         }
2544 
2545         void appendTestContentProviderAllowlist(@NonNull String[] testCpAllowlist) {
2546             mTestCpAllowlist.addAll(Arrays.asList(testCpAllowlist));
2547         }
2548 
2549         void appendTestSendBroadcastAllowlist(@NonNull String[] testSendBroadcastAllowlist) {
2550             mTestSendBroadcastAllowlist.addAll(Arrays.asList(testSendBroadcastAllowlist));
2551         }
2552 
2553         void clearTestAllowlists() {
2554             mTestCpAllowlist = new ArraySet<>();
2555             mTestSendBroadcastAllowlist = new ArraySet<>();
2556         }
2557 
2558         ArraySet<String> getTestContentProviderAllowlist() {
2559             return mTestCpAllowlist;
2560         }
2561 
2562         ArraySet<String> getTestSendBroadcastAllowlist() {
2563             return mTestSendBroadcastAllowlist;
2564         }
2565     }
2566 }
2567