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.tests.sdksandbox.endtoend;
18 
19 import static android.app.sdksandbox.SdkSandboxManager.EXTRA_DISPLAY_ID;
20 import static android.app.sdksandbox.SdkSandboxManager.EXTRA_HEIGHT_IN_PIXELS;
21 import static android.app.sdksandbox.SdkSandboxManager.EXTRA_HOST_TOKEN;
22 import static android.app.sdksandbox.SdkSandboxManager.EXTRA_WIDTH_IN_PIXELS;
23 import static android.app.sdksandbox.SdkSandboxManager.LOAD_SDK_INTERNAL_ERROR;
24 
25 import static androidx.lifecycle.Lifecycle.State;
26 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
27 
28 import static com.android.sdksandbox.flags.Flags.FLAG_SANDBOX_ACTIVITY_SDK_BASED_CONTEXT;
29 
30 import static com.google.common.truth.Truth.assertThat;
31 import static com.google.common.truth.Truth.assertWithMessage;
32 
33 import static org.junit.Assert.assertEquals;
34 import static org.junit.Assert.assertFalse;
35 import static org.junit.Assert.assertNotNull;
36 import static org.junit.Assert.assertThrows;
37 import static org.junit.Assert.assertTrue;
38 import static org.junit.Assert.fail;
39 import static org.junit.Assume.assumeTrue;
40 
41 import android.Manifest;
42 import android.app.Activity;
43 import android.app.ActivityManager;
44 import android.app.sdksandbox.AppOwnedSdkSandboxInterface;
45 import android.app.sdksandbox.LoadSdkException;
46 import android.app.sdksandbox.SandboxedSdk;
47 import android.app.sdksandbox.SdkSandboxManager;
48 import android.app.sdksandbox.testutils.ConfigListener;
49 import android.app.sdksandbox.testutils.DeviceConfigUtils;
50 import android.app.sdksandbox.testutils.FakeLoadSdkCallback;
51 import android.app.sdksandbox.testutils.FakeRequestSurfacePackageCallback;
52 import android.app.sdksandbox.testutils.FakeSdkSandboxProcessDeathCallback;
53 import android.app.sdksandbox.testutils.SdkSandboxDeviceSupportedRule;
54 import android.content.Context;
55 import android.content.Intent;
56 import android.content.pm.PackageInfo;
57 import android.content.pm.PackageManager;
58 import android.content.pm.PermissionInfo;
59 import android.content.res.Configuration;
60 import android.os.Binder;
61 import android.os.Bundle;
62 import android.os.IBinder;
63 import android.os.RemoteException;
64 import android.platform.test.annotations.RequiresFlagsDisabled;
65 import android.platform.test.annotations.RequiresFlagsEnabled;
66 import android.platform.test.flag.junit.CheckFlagsRule;
67 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
68 import android.provider.DeviceConfig;
69 
70 import androidx.lifecycle.Lifecycle;
71 import androidx.test.core.app.ActivityScenario;
72 import androidx.test.ext.junit.rules.ActivityScenarioRule;
73 import androidx.test.platform.app.InstrumentationRegistry;
74 import androidx.test.uiautomator.By;
75 import androidx.test.uiautomator.UiDevice;
76 import androidx.test.uiautomator.Until;
77 
78 import com.android.compatibility.common.util.SystemUtil;
79 import com.android.ctssdkprovider.IActivityActionExecutor;
80 import com.android.ctssdkprovider.IActivityStarter;
81 import com.android.ctssdkprovider.ICtsSdkProviderApi;
82 import com.android.modules.utils.build.SdkLevel;
83 
84 import com.google.common.truth.Expect;
85 
86 import org.junit.After;
87 import org.junit.Before;
88 import org.junit.Rule;
89 import org.junit.Test;
90 import org.junit.runner.RunWith;
91 import org.junit.runners.JUnit4;
92 
93 import java.util.Arrays;
94 import java.util.List;
95 import java.util.Random;
96 
97 /** End-to-end tests of {@link SdkSandboxManager} APIs. */
98 @RunWith(JUnit4.class)
99 public final class SdkSandboxManagerTest extends SandboxKillerBeforeTest {
100 
101     private static final String TAG = SdkSandboxManagerTest.class.getSimpleName();
102     private static final String NON_EXISTENT_SDK = "com.android.not_exist";
103 
104     private static final String APP_OWNED_SDK_SANDBOX_INTERFACE_NAME =
105             "com.android.ctsappownedsdksandboxinterface";
106     private static final String SDK_NAME_1 = "com.android.ctssdkprovider";
107     private static final String SDK_NAME_2 = "com.android.emptysdkprovider";
108 
109     private static final String TEST_OPTION = "test-option";
110     private static final String OPTION_THROW_INTERNAL_ERROR = "internal-error";
111     private static final String OPTION_THROW_REQUEST_SURFACE_PACKAGE_ERROR = "rsp-error";
112 
113     private static final String NAMESPACE_WINDOW_MANAGER = "window_manager";
114     private static final String ASM_RESTRICTIONS_ENABLED =
115             "ActivitySecurity__asm_restrictions_enabled";
116     private static final String UNREGISTER_BEFORE_STARTING_KEY = "UNREGISTER_BEFORE_STARTING_KEY";
117     private static final String ACTIVITY_STARTER_KEY = "ACTIVITY_STARTER_KEY";
118     private static final String TEXT_KEY = "TEXT_KEY";
119     private static final int WAIT_FOR_TEXT_IN_MS = 1000;
120     private static final String ORIENTATION_PORTRAIT_MESSAGE =
121             "orientation: " + Configuration.ORIENTATION_PORTRAIT;
122     private static final String ORIENTATION_LANDSCAPE_MESSAGE =
123             "orientation: " + Configuration.ORIENTATION_LANDSCAPE;
124     private static final UiDevice sUiDevice = UiDevice.getInstance(getInstrumentation());
125 
126     @Rule(order = 0)
127     public final SdkSandboxDeviceSupportedRule supportedRule = new SdkSandboxDeviceSupportedRule();
128 
129     @Rule(order = 1)
130     public final ActivityScenarioRule<TestActivity> activityScenarioRule =
131             new ActivityScenarioRule<>(TestActivity.class);
132 
133     @Rule(order = 2)
134     public final Expect expect = Expect.create();
135 
136     @Rule
137     public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
138 
139     private ActivityScenario<TestActivity> mScenario;
140 
141     private SdkSandboxManager mSdkSandboxManager;
142     private String mInitialValueAsmRestrictionsEnabled;
143 
144     private final Random mRandom = new Random();
145     private ConfigListener mConfigListener;
146     private DeviceConfigUtils mDeviceConfigUtils;
147 
148     @Before
setup()149     public void setup() throws Exception {
150         Context context = InstrumentationRegistry.getInstrumentation().getContext();
151 
152         InstrumentationRegistry.getInstrumentation()
153                 .getUiAutomation()
154                 .adoptShellPermissionIdentity(
155                         Manifest.permission.READ_DEVICE_CONFIG,
156                         Manifest.permission.WRITE_DEVICE_CONFIG);
157 
158         mSdkSandboxManager = context.getSystemService(SdkSandboxManager.class);
159         mScenario = activityScenarioRule.getScenario();
160 
161         mConfigListener = new ConfigListener();
162         DeviceConfig.addOnPropertiesChangedListener(
163                 NAMESPACE_WINDOW_MANAGER, context.getMainExecutor(), mConfigListener);
164         mDeviceConfigUtils = new DeviceConfigUtils(mConfigListener, NAMESPACE_WINDOW_MANAGER);
165 
166         mInitialValueAsmRestrictionsEnabled =
167                 DeviceConfig.getProperty(NAMESPACE_WINDOW_MANAGER, ASM_RESTRICTIONS_ENABLED);
168         mDeviceConfigUtils.deleteProperty(ASM_RESTRICTIONS_ENABLED);
169         sUiDevice.setOrientationNatural();
170     }
171 
172     @After
tearDown()173     public void tearDown() throws Exception {
174         if (mDeviceConfigUtils != null) {
175             mDeviceConfigUtils.resetToInitialValue(
176                     ASM_RESTRICTIONS_ENABLED, mInitialValueAsmRestrictionsEnabled);
177         }
178 
179         InstrumentationRegistry.getInstrumentation()
180                 .getUiAutomation()
181                 .dropShellPermissionIdentity();
182 
183         DeviceConfig.removeOnPropertiesChangedListener(mConfigListener);
184     }
185 
186     @Test
testGetSdkSandboxState()187     public void testGetSdkSandboxState() {
188         int state = SdkSandboxManager.getSdkSandboxState();
189         assertThat(state).isEqualTo(SdkSandboxManager.SDK_SANDBOX_STATE_ENABLED_PROCESS_ISOLATION);
190     }
191 
192     @Test
testLoadSdkSuccessfully()193     public void testLoadSdkSuccessfully() {
194         final FakeLoadSdkCallback callback = new FakeLoadSdkCallback();
195         mSdkSandboxManager.loadSdk(SDK_NAME_1, new Bundle(), Runnable::run, callback);
196         callback.assertLoadSdkIsSuccessful();
197         assertNotNull(callback.getSandboxedSdk());
198         assertNotNull(callback.getSandboxedSdk().getInterface());
199     }
200 
201     @Test
testRegisterAndGetAppOwnedSdkSandboxInterface()202     public void testRegisterAndGetAppOwnedSdkSandboxInterface() throws Exception {
203         try {
204             IBinder iBinder = new Binder();
205             mSdkSandboxManager.registerAppOwnedSdkSandboxInterface(
206                     new AppOwnedSdkSandboxInterface(
207                             APP_OWNED_SDK_SANDBOX_INTERFACE_NAME,
208                             /*version=*/ 0,
209                             /*interfaceIBinder=*/ iBinder));
210             final List<AppOwnedSdkSandboxInterface> appOwnedSdkSandboxInterfaceList =
211                     mSdkSandboxManager.getAppOwnedSdkSandboxInterfaces();
212             assertThat(appOwnedSdkSandboxInterfaceList).hasSize(1);
213             assertThat(appOwnedSdkSandboxInterfaceList.get(0).getName())
214                     .isEqualTo(APP_OWNED_SDK_SANDBOX_INTERFACE_NAME);
215             assertThat(appOwnedSdkSandboxInterfaceList.get(0).getVersion()).isEqualTo(0);
216             assertThat(appOwnedSdkSandboxInterfaceList.get(0).getInterface()).isEqualTo(iBinder);
217         } finally {
218             mSdkSandboxManager.unregisterAppOwnedSdkSandboxInterface(
219                     APP_OWNED_SDK_SANDBOX_INTERFACE_NAME);
220         }
221     }
222 
223     @Test
testUnregisterAppOwnedSdkSandboxInterface()224     public void testUnregisterAppOwnedSdkSandboxInterface() throws Exception {
225         mSdkSandboxManager.registerAppOwnedSdkSandboxInterface(
226                 new AppOwnedSdkSandboxInterface(
227                         APP_OWNED_SDK_SANDBOX_INTERFACE_NAME,
228                         /*version=*/ 0,
229                         /*interfaceIBinder=*/ new Binder()));
230         mSdkSandboxManager.unregisterAppOwnedSdkSandboxInterface(
231                 APP_OWNED_SDK_SANDBOX_INTERFACE_NAME);
232         assertThat(mSdkSandboxManager.getAppOwnedSdkSandboxInterfaces()).hasSize(0);
233     }
234 
235     @Test
testRegisterAppOwnedSdkSandboxInterfaceAlreadyRegistered()236     public void testRegisterAppOwnedSdkSandboxInterfaceAlreadyRegistered() throws Exception {
237         try {
238             mSdkSandboxManager.registerAppOwnedSdkSandboxInterface(
239                     new AppOwnedSdkSandboxInterface(
240                             APP_OWNED_SDK_SANDBOX_INTERFACE_NAME,
241                             /*version=*/ 0,
242                             /*interfaceIBinder=*/ new Binder()));
243             assertThrows(
244                     RuntimeException.class,
245                     () ->
246                             mSdkSandboxManager.registerAppOwnedSdkSandboxInterface(
247                                     new AppOwnedSdkSandboxInterface(
248                                             APP_OWNED_SDK_SANDBOX_INTERFACE_NAME,
249                                             /*version=*/ 0,
250                                             /*interfaceIBinder=*/ new Binder())));
251         } finally {
252             mSdkSandboxManager.unregisterAppOwnedSdkSandboxInterface(
253                     APP_OWNED_SDK_SANDBOX_INTERFACE_NAME);
254         }
255     }
256 
257     @Test
testGetSandboxedSdkSuccessfully()258     public void testGetSandboxedSdkSuccessfully() {
259         loadSdk();
260 
261         List<SandboxedSdk> sandboxedSdks = mSdkSandboxManager.getSandboxedSdks();
262 
263         assertThat(sandboxedSdks.size()).isEqualTo(1);
264         assertThat(sandboxedSdks.get(0).getSharedLibraryInfo().getName()).isEqualTo(SDK_NAME_1);
265 
266         mSdkSandboxManager.unloadSdk(SDK_NAME_1);
267         List<SandboxedSdk> sandboxedSdksAfterUnload = mSdkSandboxManager.getSandboxedSdks();
268         assertThat(sandboxedSdksAfterUnload.size()).isEqualTo(0);
269     }
270 
271     @Test
testLoadSdkAndCheckClassloader()272     public void testLoadSdkAndCheckClassloader() throws Exception {
273         ICtsSdkProviderApi sdk = loadSdk();
274         sdk.checkClassloaders();
275     }
276 
277     @Test
testGetOpPackageName()278     public void testGetOpPackageName() throws Exception {
279         ICtsSdkProviderApi sdk = loadSdk();
280         final PackageManager pm =
281                 InstrumentationRegistry.getInstrumentation().getContext().getPackageManager();
282         assertThat(sdk.getOpPackageName()).isEqualTo(pm.getSdkSandboxPackageName());
283     }
284 
285     @Test
testRetryLoadSameSdkShouldFail()286     public void testRetryLoadSameSdkShouldFail() {
287         FakeLoadSdkCallback callback = new FakeLoadSdkCallback();
288 
289         mSdkSandboxManager.loadSdk(SDK_NAME_1, new Bundle(), Runnable::run, callback);
290         callback.assertLoadSdkIsSuccessful();
291 
292         callback = new FakeLoadSdkCallback();
293         mSdkSandboxManager.loadSdk(SDK_NAME_1, new Bundle(), Runnable::run, callback);
294         callback.assertLoadSdkIsUnsuccessful();
295         assertThat(callback.getLoadSdkErrorCode())
296                 .isEqualTo(SdkSandboxManager.LOAD_SDK_ALREADY_LOADED);
297     }
298 
299     @Test
testLoadNonExistentSdk()300     public void testLoadNonExistentSdk() {
301         final FakeLoadSdkCallback callback = new FakeLoadSdkCallback();
302 
303         mSdkSandboxManager.loadSdk(NON_EXISTENT_SDK, new Bundle(), Runnable::run, callback);
304         callback.assertLoadSdkIsUnsuccessful();
305         assertThat(callback.getLoadSdkErrorCode())
306                 .isEqualTo(SdkSandboxManager.LOAD_SDK_NOT_FOUND);
307         LoadSdkException loadSdkException = callback.getLoadSdkException();
308         assertThat(loadSdkException.getExtraInformation()).isNotNull();
309         assertThat(loadSdkException.getExtraInformation().isEmpty()).isTrue();
310     }
311 
312     @Test
testLoadSdkWithInternalErrorShouldFail()313     public void testLoadSdkWithInternalErrorShouldFail() throws Exception {
314         final FakeLoadSdkCallback callback = new FakeLoadSdkCallback();
315         Bundle params = new Bundle();
316         params.putString(TEST_OPTION, OPTION_THROW_INTERNAL_ERROR);
317         mSdkSandboxManager.loadSdk(SDK_NAME_1, params, Runnable::run, callback);
318         callback.assertLoadSdkIsUnsuccessful();
319         assertThat(callback.getLoadSdkErrorCode())
320                 .isEqualTo(SdkSandboxManager.LOAD_SDK_SDK_DEFINED_ERROR);
321     }
322 
323     @Test
testLoadSdkPropertySdkProviderClassNameNotSet()324     public void testLoadSdkPropertySdkProviderClassNameNotSet() {
325         FakeLoadSdkCallback callback = new FakeLoadSdkCallback();
326         mSdkSandboxManager.loadSdk(
327                 "com.android.property_sdkprovider_classname_not_present",
328                 new Bundle(),
329                 Runnable::run,
330                 callback);
331         callback.assertLoadSdkIsUnsuccessful();
332         assertThat(callback.getLoadSdkErrorCode()).isEqualTo(SdkSandboxManager.LOAD_SDK_NOT_FOUND);
333         assertThat(callback.getLoadSdkErrorMsg())
334                 .contains("android.sdksandbox.PROPERTY_SDK_PROVIDER_CLASS_NAME property");
335     }
336 
337     @Test
testUnloadAndReloadSdk()338     public void testUnloadAndReloadSdk() throws Exception {
339         final FakeLoadSdkCallback callback = new FakeLoadSdkCallback();
340         mSdkSandboxManager.loadSdk(SDK_NAME_1, new Bundle(), Runnable::run, callback);
341         callback.assertLoadSdkIsSuccessful();
342 
343         mSdkSandboxManager.unloadSdk(SDK_NAME_1);
344         // Wait till SDK is unloaded.
345         Thread.sleep(2000);
346 
347         // Calls to an unloaded SDK should fail.
348         final FakeRequestSurfacePackageCallback requestSurfacePackageCallback =
349                 new FakeRequestSurfacePackageCallback();
350         mSdkSandboxManager.requestSurfacePackage(
351                 SDK_NAME_1,
352                 getRequestSurfacePackageParams(),
353                 Runnable::run,
354                 requestSurfacePackageCallback);
355 
356         assertThat(requestSurfacePackageCallback.isRequestSurfacePackageSuccessful()).isFalse();
357         assertThat(requestSurfacePackageCallback.getSurfacePackageErrorCode())
358                 .isEqualTo(SdkSandboxManager.REQUEST_SURFACE_PACKAGE_SDK_NOT_LOADED);
359 
360         // SDK can be reloaded after being unloaded.
361         final FakeLoadSdkCallback callback2 = new FakeLoadSdkCallback();
362         mSdkSandboxManager.loadSdk(SDK_NAME_1, new Bundle(), Runnable::run, callback2);
363         callback2.assertLoadSdkIsSuccessful();
364     }
365 
366     @Test
testUnloadNonexistentSdk()367     public void testUnloadNonexistentSdk() {
368         final FakeLoadSdkCallback callback = new FakeLoadSdkCallback();
369         mSdkSandboxManager.loadSdk(SDK_NAME_1, new Bundle(), Runnable::run, callback);
370         callback.assertLoadSdkIsSuccessful();
371 
372         final String nonexistentSdk = "com.android.nonexistent";
373         // Unloading does nothing - call should go through without error.
374         mSdkSandboxManager.unloadSdk(nonexistentSdk);
375     }
376 
377     @Test
testReloadingSdkDoesNotInvalidateIt()378     public void testReloadingSdkDoesNotInvalidateIt() {
379 
380         final FakeLoadSdkCallback callback = new FakeLoadSdkCallback();
381         mSdkSandboxManager.loadSdk(SDK_NAME_1, new Bundle(), Runnable::run, callback);
382         callback.assertLoadSdkIsSuccessful();
383         SandboxedSdk sandboxedSdk = callback.getSandboxedSdk();
384         assertNotNull(sandboxedSdk.getInterface());
385 
386         // Attempt to load the SDK again and see that it fails.
387         final FakeLoadSdkCallback reloadCallback = new FakeLoadSdkCallback();
388         mSdkSandboxManager.loadSdk(SDK_NAME_1, new Bundle(), Runnable::run, reloadCallback);
389         reloadCallback.assertLoadSdkIsUnsuccessful();
390 
391         // SDK's interface should still be obtainable.
392         assertNotNull(sandboxedSdk.getInterface());
393 
394         // Further calls to the SDK should still be valid.
395         final FakeRequestSurfacePackageCallback surfacePackageCallback =
396                 new FakeRequestSurfacePackageCallback();
397         mSdkSandboxManager.requestSurfacePackage(
398                 SDK_NAME_1,
399                 getRequestSurfacePackageParams(),
400                 Runnable::run,
401                 surfacePackageCallback);
402         assertThat(surfacePackageCallback.isRequestSurfacePackageSuccessful()).isTrue();
403     }
404 
405     @Test
testReloadingSdkAfterKillingSandboxIsSuccessful()406     public void testReloadingSdkAfterKillingSandboxIsSuccessful() throws Exception {
407         // Kill the sandbox if it already exists from previous tests
408         killSandboxIfExists();
409 
410         FakeSdkSandboxProcessDeathCallback callback = new FakeSdkSandboxProcessDeathCallback();
411         mSdkSandboxManager.addSdkSandboxProcessDeathCallback(Runnable::run, callback);
412         assertThat(callback.waitForSandboxDeath()).isFalse();
413 
414         // Killing the sandbox and loading the same SDKs again multiple times should work
415         for (int i = 1; i <= 3; ++i) {
416             // The same SDKs should be able to be loaded again after sandbox death
417             loadMultipleSdks();
418             callback.resetLatch();
419             killSandbox();
420             assertThat(callback.waitForSandboxDeath()).isTrue();
421         }
422     }
423 
424     @Test
testAddSdkSandboxProcessDeathCallback_BeforeStartingSandbox()425     public void testAddSdkSandboxProcessDeathCallback_BeforeStartingSandbox() throws Exception {
426         // Kill the sandbox if it already exists from previous tests
427         killSandboxIfExists();
428 
429         // Add a sandbox lifecycle callback before starting the sandbox
430         FakeSdkSandboxProcessDeathCallback lifecycleCallback =
431                 new FakeSdkSandboxProcessDeathCallback();
432         mSdkSandboxManager.addSdkSandboxProcessDeathCallback(Runnable::run, lifecycleCallback);
433 
434         // Bring up the sandbox
435         loadSdk();
436 
437         killSandbox();
438         assertThat(lifecycleCallback.waitForSandboxDeath()).isTrue();
439     }
440 
441     @Test
testAddSdkSandboxProcessDeathCallback_AfterStartingSandbox()442     public void testAddSdkSandboxProcessDeathCallback_AfterStartingSandbox() throws Exception {
443         // Bring up the sandbox
444         loadSdk();
445 
446         // Add a sandbox lifecycle callback before starting the sandbox
447         FakeSdkSandboxProcessDeathCallback lifecycleCallback =
448                 new FakeSdkSandboxProcessDeathCallback();
449         mSdkSandboxManager.addSdkSandboxProcessDeathCallback(Runnable::run, lifecycleCallback);
450 
451         killSandbox();
452         assertThat(lifecycleCallback.waitForSandboxDeath()).isTrue();
453     }
454 
455     @Test
testRegisterMultipleSdkSandboxProcessDeathCallbacks()456     public void testRegisterMultipleSdkSandboxProcessDeathCallbacks() throws Exception {
457         // Kill the sandbox if it already exists from previous tests
458         killSandboxIfExists();
459 
460         // Add a sandbox lifecycle callback before starting the sandbox
461         FakeSdkSandboxProcessDeathCallback lifecycleCallback1 =
462                 new FakeSdkSandboxProcessDeathCallback();
463         mSdkSandboxManager.addSdkSandboxProcessDeathCallback(Runnable::run, lifecycleCallback1);
464 
465         // Bring up the sandbox
466         loadSdk();
467 
468         // Add another sandbox lifecycle callback after starting it
469         FakeSdkSandboxProcessDeathCallback lifecycleCallback2 =
470                 new FakeSdkSandboxProcessDeathCallback();
471         mSdkSandboxManager.addSdkSandboxProcessDeathCallback(Runnable::run, lifecycleCallback2);
472 
473         killSandbox();
474         assertThat(lifecycleCallback1.waitForSandboxDeath()).isTrue();
475         assertThat(lifecycleCallback2.waitForSandboxDeath()).isTrue();
476     }
477 
478     @Test
testRemoveSdkSandboxProcessDeathCallback()479     public void testRemoveSdkSandboxProcessDeathCallback() throws Exception {
480         // Bring up the sandbox
481         loadSdk();
482 
483         // Add and remove a sandbox lifecycle callback
484         FakeSdkSandboxProcessDeathCallback lifecycleCallback1 =
485                 new FakeSdkSandboxProcessDeathCallback();
486         mSdkSandboxManager.addSdkSandboxProcessDeathCallback(Runnable::run, lifecycleCallback1);
487         mSdkSandboxManager.removeSdkSandboxProcessDeathCallback(lifecycleCallback1);
488 
489         // Add a lifecycle callback but don't remove it
490         FakeSdkSandboxProcessDeathCallback lifecycleCallback2 =
491                 new FakeSdkSandboxProcessDeathCallback();
492         mSdkSandboxManager.addSdkSandboxProcessDeathCallback(Runnable::run, lifecycleCallback2);
493 
494         killSandbox();
495         assertThat(lifecycleCallback1.waitForSandboxDeath()).isFalse();
496         assertThat(lifecycleCallback2.waitForSandboxDeath()).isTrue();
497     }
498 
499     @Test
testRequestSurfacePackageSuccessfully()500     public void testRequestSurfacePackageSuccessfully() {
501         loadSdk();
502 
503         final FakeRequestSurfacePackageCallback surfacePackageCallback =
504                 new FakeRequestSurfacePackageCallback();
505         mSdkSandboxManager.requestSurfacePackage(
506                 SDK_NAME_1,
507                 getRequestSurfacePackageParams(),
508                 Runnable::run,
509                 surfacePackageCallback);
510         assertThat(surfacePackageCallback.isRequestSurfacePackageSuccessful()).isTrue();
511     }
512 
513     @Test
testRequestSurfacePackageWithInternalErrorShouldFail()514     public void testRequestSurfacePackageWithInternalErrorShouldFail() {
515         loadSdk();
516 
517         final FakeRequestSurfacePackageCallback surfacePackageCallback =
518                 new FakeRequestSurfacePackageCallback();
519         Bundle params = getRequestSurfacePackageParams();
520         params.putString(TEST_OPTION, OPTION_THROW_REQUEST_SURFACE_PACKAGE_ERROR);
521         mSdkSandboxManager.requestSurfacePackage(
522                 SDK_NAME_1, params, Runnable::run, surfacePackageCallback);
523         assertThat(surfacePackageCallback.isRequestSurfacePackageSuccessful()).isFalse();
524         assertThat(surfacePackageCallback.getSurfacePackageErrorCode())
525                 .isEqualTo(SdkSandboxManager.REQUEST_SURFACE_PACKAGE_INTERNAL_ERROR);
526         assertThat(surfacePackageCallback.getExtraErrorInformation()).isNotNull();
527         assertThat(surfacePackageCallback.getExtraErrorInformation().isEmpty()).isTrue();
528     }
529 
530     @Test
testRequestSurfacePackage_SandboxDiesAfterLoadingSdk()531     public void testRequestSurfacePackage_SandboxDiesAfterLoadingSdk() throws Exception {
532         loadSdk();
533 
534         assertThat(killSandboxIfExists()).isTrue();
535 
536         final FakeRequestSurfacePackageCallback surfacePackageCallback =
537                 new FakeRequestSurfacePackageCallback();
538         mSdkSandboxManager.requestSurfacePackage(
539                 SDK_NAME_1,
540                 getRequestSurfacePackageParams(),
541                 Runnable::run,
542                 surfacePackageCallback);
543         assertThat(surfacePackageCallback.isRequestSurfacePackageSuccessful()).isFalse();
544         assertThat(surfacePackageCallback.getSurfacePackageErrorCode())
545                 .isEqualTo(SdkSandboxManager.REQUEST_SURFACE_PACKAGE_SDK_NOT_LOADED);
546     }
547 
548     @Test
testResourcesAndAssets()549     public void testResourcesAndAssets() throws Exception {
550         ICtsSdkProviderApi sdk = loadSdk();
551         sdk.checkResourcesAndAssets();
552     }
553 
554     @Test
testLoadSdkInBackgroundFails()555     public void testLoadSdkInBackgroundFails() throws Exception {
556         mScenario.moveToState(Lifecycle.State.DESTROYED);
557 
558         // Wait for the activity to be destroyed
559         Thread.sleep(1000);
560 
561         final FakeLoadSdkCallback callback = new FakeLoadSdkCallback();
562         mSdkSandboxManager.loadSdk(SDK_NAME_1, new Bundle(), Runnable::run, callback);
563 
564         LoadSdkException thrown = callback.getLoadSdkException();
565 
566         assertEquals(LOAD_SDK_INTERNAL_ERROR, thrown.getLoadSdkErrorCode());
567         assertThat(thrown).hasMessageThat().contains("does not run in the foreground");
568     }
569 
570     @Test
testSandboxApisAreUsableAfterUnbindingSandbox()571     public void testSandboxApisAreUsableAfterUnbindingSandbox() throws Exception {
572         FakeLoadSdkCallback callback1 = new FakeLoadSdkCallback();
573         mSdkSandboxManager.loadSdk(SDK_NAME_1, new Bundle(), Runnable::run, callback1);
574         callback1.assertLoadSdkIsSuccessful();
575 
576         // Move the app to the background and bring it back to the foreground again.
577         mScenario.recreate();
578 
579         // Loading another sdk should work without issue
580         FakeLoadSdkCallback callback2 = new FakeLoadSdkCallback();
581         mSdkSandboxManager.loadSdk(SDK_NAME_2, new Bundle(), Runnable::run, callback2);
582         callback2.assertLoadSdkIsSuccessful();
583 
584         // Requesting surface package from the first loaded sdk should work.
585         final FakeRequestSurfacePackageCallback surfacePackageCallback =
586                 new FakeRequestSurfacePackageCallback();
587         mSdkSandboxManager.requestSurfacePackage(
588                 SDK_NAME_1,
589                 getRequestSurfacePackageParams(),
590                 Runnable::run,
591                 surfacePackageCallback);
592         assertThat(surfacePackageCallback.isRequestSurfacePackageSuccessful()).isTrue();
593     }
594 
595     /** Checks that {@code SdkSandbox.apk} only requests normal permissions in its manifest. */
596     // TODO: This should probably be a separate test module
597     @Test
testSdkSandboxPermissions()598     public void testSdkSandboxPermissions() throws Exception {
599         final PackageManager pm =
600                 InstrumentationRegistry.getInstrumentation().getContext().getPackageManager();
601         final PackageInfo sdkSandboxPackage =
602                 pm.getPackageInfo(
603                         pm.getSdkSandboxPackageName(),
604                         PackageManager.PackageInfoFlags.of(PackageManager.GET_PERMISSIONS));
605         for (int i = 0; i < sdkSandboxPackage.requestedPermissions.length; i++) {
606             final String permissionName = sdkSandboxPackage.requestedPermissions[i];
607             final PermissionInfo permissionInfo = pm.getPermissionInfo(permissionName, 0);
608             expect.withMessage("SdkSandbox.apk requests non-normal permission %s", permissionName)
609                     .that(permissionInfo.getProtection())
610                     .isEqualTo(PermissionInfo.PROTECTION_NORMAL);
611         }
612     }
613 
614     @Test
testSdkAndAppProcessImportanceIsAligned_AppIsBackgrounded()615     public void testSdkAndAppProcessImportanceIsAligned_AppIsBackgrounded() throws Exception {
616         // Sandbox and app priority is aligned only in U+.
617         assumeTrue(SdkLevel.isAtLeastU());
618 
619         ICtsSdkProviderApi sdk = loadSdk();
620         assertThat(sdk.getProcessImportance()).isEqualTo(getAppProcessImportance());
621 
622         // Move the app to the background.
623         mScenario.moveToState(Lifecycle.State.DESTROYED);
624         Thread.sleep(1000);
625 
626         assertThat(sdk.getProcessImportance()).isEqualTo(getAppProcessImportance());
627     }
628 
629     @Test
testSdkAndAppProcessImportanceIsAligned_AppIsBackgroundedAndForegrounded()630     public void testSdkAndAppProcessImportanceIsAligned_AppIsBackgroundedAndForegrounded()
631             throws Exception {
632         // Sandbox and app priority is aligned only in U+.
633         assumeTrue(SdkLevel.isAtLeastU());
634 
635         ICtsSdkProviderApi sdk = loadSdk();
636         assertThat(sdk.getProcessImportance()).isEqualTo(getAppProcessImportance());
637 
638         // Move the app to the background and bring it back to the foreground again.
639         mScenario.recreate();
640 
641         // The sandbox should have foreground importance again.
642         assertThat(sdk.getProcessImportance()).isEqualTo(getAppProcessImportance());
643     }
644 
645     @Test
testSDKCanNotStartSandboxActivityDirectlyByAction()646     public void testSDKCanNotStartSandboxActivityDirectlyByAction() {
647         assumeTrue(SdkLevel.isAtLeastU());
648 
649         final ICtsSdkProviderApi sdk = loadSdk();
650 
651         assertThat(mScenario.getState()).isEqualTo(State.RESUMED);
652         SecurityException exception =
653                 assertThrows(
654                         SecurityException.class,
655                         () -> sdk.startSandboxActivityDirectlyByAction(getSdkSandboxPackageName()));
656         assertThat(exception.getMessage())
657                 .isEqualTo("Sandbox process is not allowed to start sandbox activities.");
658         assertThat(mScenario.getState()).isEqualTo(State.RESUMED);
659     }
660 
661     @Test
testSDKCanNotStartSandboxActivityDirectlyByComponent()662     public void testSDKCanNotStartSandboxActivityDirectlyByComponent() {
663         assumeTrue(SdkLevel.isAtLeastU());
664 
665         final ICtsSdkProviderApi sdk = loadSdk();
666 
667         assertThat(mScenario.getState()).isEqualTo(State.RESUMED);
668         SecurityException exception =
669                 assertThrows(
670                         SecurityException.class,
671                         () ->
672                                 sdk.startSandboxActivityDirectlyByComponent(
673                                         getSdkSandboxPackageName()));
674         assertThat(exception.getMessage())
675                 .isEqualTo("Sandbox process is not allowed to start sandbox activities.");
676         assertThat(mScenario.getState()).isEqualTo(State.RESUMED);
677     }
678 
679     @Test
testSandboxProcessShouldBeRunningToHostTheSandboxActivity()680     public void testSandboxProcessShouldBeRunningToHostTheSandboxActivity() {
681         assumeTrue(SdkLevel.isAtLeastU());
682 
683         assertThat(mScenario.getState()).isEqualTo(State.RESUMED);
684         mScenario.onActivity(
685                 clientActivity -> {
686                     SecurityException exception =
687                             assertThrows(
688                                     SecurityException.class,
689                                     () ->
690                                             mSdkSandboxManager.startSdkSandboxActivity(
691                                                     clientActivity, new Binder()));
692                     assertThat(exception.getMessage())
693                             .contains("There is no sandbox process running");
694                 });
695         assertThat(mScenario.getState()).isEqualTo(State.RESUMED);
696     }
697 
698     @Test
testStartSdkSandboxActivity()699     public void testStartSdkSandboxActivity() {
700         assumeTrue(SdkLevel.isAtLeastU());
701 
702         ICtsSdkProviderApi sdk = loadSdk();
703 
704         assertThat(mScenario.getState()).isEqualTo(State.RESUMED);
705         ActivityStarter activityStarter = new ActivityStarter();
706         assertThat(activityStarter.isActivityResumed()).isFalse();
707 
708         startSandboxActivity(sdk, activityStarter);
709 
710         assertThat(mScenario.getState()).isIn(Arrays.asList(State.CREATED, State.STARTED));
711         assertThat(activityStarter.isActivityResumed()).isTrue();
712     }
713 
714     @Test
testStartSdkSandboxActivityOnTopOfASandboxActivity()715     public void testStartSdkSandboxActivityOnTopOfASandboxActivity() {
716         assumeTrue(SdkLevel.isAtLeastU());
717 
718         ICtsSdkProviderApi sdk = loadSdk();
719 
720         ActivityStarter sandboxActivity1Starter = new ActivityStarter();
721         ActivityStarter sandboxActivity2Starter = new ActivityStarter();
722         assertThat(sandboxActivity1Starter.isActivityResumed()).isFalse();
723         assertThat(sandboxActivity2Starter.isActivityResumed()).isFalse();
724         assertThat(mScenario.getState()).isEqualTo(State.RESUMED);
725 
726         startSandboxActivity(sdk, sandboxActivity1Starter);
727 
728         assertThat(mScenario.getState()).isIn(Arrays.asList(State.CREATED, State.STARTED));
729         assertThat(sandboxActivity1Starter.isActivityResumed()).isTrue();
730         assertThat(sandboxActivity2Starter.isActivityResumed()).isFalse();
731 
732         startSandboxActivity(sdk, sandboxActivity2Starter);
733 
734         assertThat(mScenario.getState()).isIn(Arrays.asList(State.CREATED, State.STARTED));
735         assertThat(sandboxActivity1Starter.isActivityResumed()).isFalse();
736         assertThat(sandboxActivity2Starter.isActivityResumed()).isTrue();
737     }
738 
739     @Test
testStartLocalActivityOnTopOfASandboxActivity()740     public void testStartLocalActivityOnTopOfASandboxActivity() {
741         assumeTrue(SdkLevel.isAtLeastU());
742 
743         ICtsSdkProviderApi sdk = loadSdk();
744 
745         ActivityStarter sandboxActivityStarter = new ActivityStarter();
746         ActivityStarter otherClientActivityStarter = new ActivityStarter();
747         assertThat(sandboxActivityStarter.isActivityResumed()).isFalse();
748         assertThat(otherClientActivityStarter.isActivityResumed()).isFalse();
749         assertThat(mScenario.getState()).isEqualTo(State.RESUMED);
750 
751         startSandboxActivity(sdk, sandboxActivityStarter);
752 
753         assertThat(mScenario.getState()).isIn(Arrays.asList(State.CREATED, State.STARTED));
754         assertThat(otherClientActivityStarter.isActivityResumed()).isFalse();
755         assertThat(sandboxActivityStarter.isActivityResumed()).isTrue();
756 
757         mScenario.onActivity(
758                 clientActivity -> {
759                     otherClientActivityStarter.setFromActivity(clientActivity);
760                 });
761         otherClientActivityStarter.startLocalActivity();
762 
763         assertThat(mScenario.getState()).isIn(Arrays.asList(State.CREATED, State.STARTED));
764         assertThat(sandboxActivityStarter.isActivityResumed()).isFalse();
765         assertThat(otherClientActivityStarter.isActivityResumed()).isTrue();
766     }
767 
768     @Test
testClientAppCanClearTopWhileOtherActivitiesOnTopIncludingSandboxActivities()769     public void testClientAppCanClearTopWhileOtherActivitiesOnTopIncludingSandboxActivities() {
770         assumeTrue(SdkLevel.isAtLeastU());
771 
772         ICtsSdkProviderApi sdk = loadSdk();
773 
774         // Start 2 sandbox activities.
775         ActivityStarter sandboxActivity1Starter = new ActivityStarter();
776         ActivityStarter sandboxActivity2Starter = new ActivityStarter();
777         startSandboxActivity(sdk, sandboxActivity1Starter);
778         startSandboxActivity(sdk, sandboxActivity2Starter);
779 
780         assertThat(mScenario.getState()).isIn(Arrays.asList(State.CREATED, State.STARTED));
781         assertThat(sandboxActivity1Starter.isActivityResumed()).isFalse();
782         assertThat(sandboxActivity2Starter.isActivityResumed()).isTrue();
783 
784         // Clear top (include the sandbox activities on top).
785         ActivityStarter clearTopActivityStarter = new ActivityStarter();
786         mScenario.onActivity(
787                 clientActivity -> {
788                     clearTopActivityStarter.setFromActivity(clientActivity);
789                 });
790         clearTopActivityStarter.startLocalActivity(Intent.FLAG_ACTIVITY_CLEAR_TOP);
791         assertThat(sandboxActivity1Starter.isActivityResumed()).isFalse();
792         assertThat(sandboxActivity2Starter.isActivityResumed()).isFalse();
793         assertThat(clearTopActivityStarter.isActivityResumed()).isTrue();
794     }
795 
796     /**
797      * Test that the sandbox activity context is created using the SDK ApplicationInfo.
798      *
799      * @throws RemoteException
800      */
801     @Test
802     @RequiresFlagsEnabled(FLAG_SANDBOX_ACTIVITY_SDK_BASED_CONTEXT)
testSandboxActivityUseSdkBasedContextIfRequiredFlagAreEnabled()803     public void testSandboxActivityUseSdkBasedContextIfRequiredFlagAreEnabled()
804             throws RemoteException {
805         assumeTrue(SdkLevel.isAtLeastV());
806 
807         ICtsSdkProviderApi sdk = loadSdk();
808 
809         ActivityStarter sandboxActivityStarter = new ActivityStarter();
810         IActivityActionExecutor actionExecutor = startSandboxActivity(sdk, sandboxActivityStarter);
811         assertThat(mScenario.getState()).isIn(Arrays.asList(State.CREATED, State.STARTED));
812         assertThat(sandboxActivityStarter.isActivityResumed()).isTrue();
813 
814         String dataDir = actionExecutor.getDataDir();
815         assertThat(dataDir).contains(SDK_NAME_1);
816         assertThat(dataDir).doesNotContain(getSdkSandboxPackageName());
817     }
818 
819     /**
820      * Test that the sandbox activity context is created using the sandbox App ApplicationInfo.
821      *
822      * @throws RemoteException
823      */
824     @Test
825     @RequiresFlagsDisabled(FLAG_SANDBOX_ACTIVITY_SDK_BASED_CONTEXT)
testSandboxActivityUseAppBasedContextIfSdkBasedFlagIDisabled()826     public void testSandboxActivityUseAppBasedContextIfSdkBasedFlagIDisabled()
827             throws RemoteException {
828         assumeTrue(SdkLevel.isAtLeastV());
829 
830         ICtsSdkProviderApi sdk = loadSdk();
831 
832         ActivityStarter sandboxActivityStarter = new ActivityStarter();
833         IActivityActionExecutor actionExecutor = startSandboxActivity(sdk, sandboxActivityStarter);
834         assertThat(mScenario.getState()).isIn(Arrays.asList(State.CREATED, State.STARTED));
835         assertThat(sandboxActivityStarter.isActivityResumed()).isTrue();
836 
837         String dataDir = actionExecutor.getDataDir();
838         assertThat(dataDir).doesNotContain(SDK_NAME_1);
839         assertThat(dataDir).contains(getSdkSandboxPackageName());
840     }
841 
842     /**
843      * Ensure that SDK can lock back navigation
844      *
845      * @throws RemoteException
846      */
847     @Test
testBackNavigationControl()848     public void testBackNavigationControl() throws RemoteException {
849         assumeTrue(SdkLevel.isAtLeastU());
850 
851         ICtsSdkProviderApi sdk = loadSdk();
852 
853         ActivityStarter sandboxActivityStarter = new ActivityStarter();
854         IActivityActionExecutor actionExecutor = startSandboxActivity(sdk, sandboxActivityStarter);
855 
856         assertThat(mScenario.getState()).isIn(Arrays.asList(State.CREATED, State.STARTED));
857         assertThat(sandboxActivityStarter.isActivityResumed()).isTrue();
858 
859         actionExecutor.disableBackButton();
860         sUiDevice.pressBack();
861         assertFalse(
862                 sUiDevice.wait(Until.hasObject(By.text("DEFAULT_SHOW_TEXT")), WAIT_FOR_TEXT_IN_MS));
863         assertThat(mScenario.getState()).isIn(Arrays.asList(State.CREATED, State.STARTED));
864         assertThat(sandboxActivityStarter.isActivityResumed()).isTrue();
865 
866         actionExecutor.enableBackButton();
867         sUiDevice.pressBack();
868         assertTrue(
869                 sUiDevice.wait(Until.hasObject(By.text("DEFAULT_SHOW_TEXT")), WAIT_FOR_TEXT_IN_MS));
870         assertThat(mScenario.getState()).isEqualTo(State.RESUMED);
871         assertThat(sandboxActivityStarter.isActivityResumed()).isFalse();
872     }
873 
874     /**
875      * Tests that orientation work for sandbox activity
876      *
877      * @throws RemoteException
878      */
879     @Test
testSandboxActivityShouldRotateIfNotLocked()880     public void testSandboxActivityShouldRotateIfNotLocked() throws RemoteException {
881         assumeTrue(SdkLevel.isAtLeastU());
882 
883         ICtsSdkProviderApi sdk = loadSdk();
884 
885         ActivityStarter sandboxActivityStarter = new ActivityStarter();
886         startSandboxActivity(sdk, sandboxActivityStarter);
887         assertThat(mScenario.getState()).isIn(Arrays.asList(State.CREATED, State.STARTED));
888         assertThat(sandboxActivityStarter.isActivityResumed()).isTrue();
889 
890         // Rotate the device to portrait
891         sUiDevice.setOrientationPortrait();
892         // Assert Portrait Rotation.
893         assertTrue(
894                 sUiDevice.wait(
895                         Until.hasObject(By.textContains(ORIENTATION_PORTRAIT_MESSAGE)),
896                         WAIT_FOR_TEXT_IN_MS));
897 
898         sUiDevice.setOrientationLandscape();
899         assertTrue(
900                 sUiDevice.wait(
901                         Until.hasObject(By.textContains(ORIENTATION_LANDSCAPE_MESSAGE)),
902                         WAIT_FOR_TEXT_IN_MS));
903         assertThat(mScenario.getState()).isIn(Arrays.asList(State.CREATED, State.STARTED));
904         assertThat(sandboxActivityStarter.isActivityResumed()).isTrue();
905     }
906 
907     /**
908      * Tests that SDK can lock sandbox activity orientation
909      *
910      * @throws Exception
911      */
912     @Test
testSandboxActivityOrientationLocking()913     public void testSandboxActivityOrientationLocking() throws RemoteException {
914         assumeTrue(SdkLevel.isAtLeastU());
915 
916         ICtsSdkProviderApi sdk = loadSdk();
917 
918         ActivityStarter sandboxActivityStarter = new ActivityStarter();
919         IActivityActionExecutor actionExecutor = startSandboxActivity(sdk, sandboxActivityStarter);
920         assertThat(mScenario.getState()).isIn(Arrays.asList(State.CREATED, State.STARTED));
921         assertThat(sandboxActivityStarter.isActivityResumed()).isTrue();
922 
923         // Rotate the device to portrait
924         sUiDevice.setOrientationPortrait();
925         // Assert Portrait Rotation.
926         assertTrue(
927                 sUiDevice.wait(
928                         Until.hasObject(By.textContains(ORIENTATION_PORTRAIT_MESSAGE)),
929                         WAIT_FOR_TEXT_IN_MS));
930 
931         // Locking orientation to landscape
932         actionExecutor.setOrientationToLandscape();
933         assertTrue(
934                 sUiDevice.wait(
935                         Until.hasObject(By.textContains(ORIENTATION_LANDSCAPE_MESSAGE)),
936                         WAIT_FOR_TEXT_IN_MS));
937         // Rotation the device should not affect the locked display orientation.
938         sUiDevice.setOrientationPortrait();
939         assertFalse(
940                 sUiDevice.wait(
941                         Until.hasObject(By.textContains(ORIENTATION_PORTRAIT_MESSAGE)),
942                         WAIT_FOR_TEXT_IN_MS));
943         assertThat(mScenario.getState()).isIn(Arrays.asList(State.CREATED, State.STARTED));
944         assertThat(sandboxActivityStarter.isActivityResumed()).isTrue();
945 
946         // Locking orientation to portrait
947         actionExecutor.setOrientationToPortrait();
948         assertTrue(
949                 sUiDevice.wait(
950                         Until.hasObject(By.textContains(ORIENTATION_PORTRAIT_MESSAGE)),
951                         WAIT_FOR_TEXT_IN_MS));
952 
953         // Rotation the device should not affect the locked display orientation.
954         sUiDevice.setOrientationLandscape();
955         assertFalse(
956                 sUiDevice.wait(
957                         Until.hasObject(By.textContains(ORIENTATION_LANDSCAPE_MESSAGE)),
958                         WAIT_FOR_TEXT_IN_MS));
959         assertThat(mScenario.getState()).isIn(Arrays.asList(State.CREATED, State.STARTED));
960         assertThat(sandboxActivityStarter.isActivityResumed()).isTrue();
961     }
962 
963     @Test
testStartSdkSandboxedActivityFailIfTheHandlerUnregistered()964     public void testStartSdkSandboxedActivityFailIfTheHandlerUnregistered() {
965         assumeTrue(SdkLevel.isAtLeastU());
966 
967         // Load SDK in sandbox
968         ICtsSdkProviderApi sdk = loadSdk();
969 
970         ActivityStarter activityStarter = new ActivityStarter();
971         assertThat(mScenario.getState()).isEqualTo(State.RESUMED);
972 
973         Bundle extras = new Bundle();
974         extras.putBoolean(UNREGISTER_BEFORE_STARTING_KEY, true);
975         startSandboxActivity(sdk, activityStarter, extras);
976 
977         assertThat(mScenario.getState()).isEqualTo(State.RESUMED);
978         assertThat(activityStarter.isActivityResumed()).isFalse();
979     }
980 
981     @Test
testSandboxActivityStartIntentViewWithNoSecurityExceptions()982     public void testSandboxActivityStartIntentViewWithNoSecurityExceptions() throws Exception {
983         assumeTrue(SdkLevel.isAtLeastU());
984 
985         ICtsSdkProviderApi sdk = loadSdk();
986 
987         ActivityStarter sandboxActivityStarter = new ActivityStarter();
988         IActivityActionExecutor actionExecutor = startSandboxActivity(sdk, sandboxActivityStarter);
989         assertThat(mScenario.getState()).isIn(Arrays.asList(State.CREATED, State.STARTED));
990         assertThat(sandboxActivityStarter.isActivityResumed()).isTrue();
991 
992         actionExecutor.openLandingPage();
993     }
994 
995     /**
996      * Ensure that SDK can finish the sandbox activity.
997      *
998      * @throws RemoteException
999      */
1000     @Test
testSdkCanFinishSandboxActivity()1001     public void testSdkCanFinishSandboxActivity() throws RemoteException {
1002         assumeTrue(SdkLevel.isAtLeastU());
1003 
1004         ICtsSdkProviderApi sdk = loadSdk();
1005 
1006         ActivityStarter sandboxActivityStarter = new ActivityStarter();
1007         IActivityActionExecutor actionExecutor = startSandboxActivity(sdk, sandboxActivityStarter);
1008         assertThat(mScenario.getState()).isIn(Arrays.asList(State.CREATED, State.STARTED));
1009         assertThat(sandboxActivityStarter.isActivityResumed()).isTrue();
1010 
1011         actionExecutor.finish();
1012         assertTrue(
1013                 sUiDevice.wait(Until.hasObject(By.text("DEFAULT_SHOW_TEXT")), WAIT_FOR_TEXT_IN_MS));
1014         assertThat(mScenario.getState()).isEqualTo(State.RESUMED);
1015         assertThat(sandboxActivityStarter.isActivityResumed()).isFalse();
1016     }
1017 
1018     // Verifies that the test allowlists in {@link SdkSandboxManagerService#LocalImpl} are initially
1019     // empty.
1020     @Test
testInitialSandboxTestAllowlistsAreEmpty()1021     public void testInitialSandboxTestAllowlistsAreEmpty() {
1022         assumeTrue(SdkLevel.isAtLeastV());
1023         assertThat(
1024                         SystemUtil.runShellCommand(
1025                                 "cmd sdk_sandbox get-test-allowlist content-provider"))
1026                 .isEqualTo("\n");
1027         assertThat(SystemUtil.runShellCommand("cmd sdk_sandbox get-test-allowlist send-broadcast"))
1028                 .isEqualTo("\n");
1029     }
1030 
1031     // Helper method to load SDK_NAME_1
loadSdk()1032     private ICtsSdkProviderApi loadSdk() {
1033         final FakeLoadSdkCallback callback = new FakeLoadSdkCallback();
1034         mSdkSandboxManager.loadSdk(SDK_NAME_1, new Bundle(), Runnable::run, callback);
1035         callback.assertLoadSdkIsSuccessful();
1036 
1037         final SandboxedSdk sandboxedSdk = callback.getSandboxedSdk();
1038         assertNotNull(sandboxedSdk);
1039         return ICtsSdkProviderApi.Stub.asInterface(callback.getSandboxedSdk().getInterface());
1040     }
1041 
getAppProcessImportance()1042     private int getAppProcessImportance() {
1043         ActivityManager.RunningAppProcessInfo processInfo =
1044                 new ActivityManager.RunningAppProcessInfo();
1045         ActivityManager.getMyMemoryState(processInfo);
1046         return processInfo.importance;
1047     }
1048 
startSandboxActivity( ICtsSdkProviderApi sdk, ActivityStarter activityStarter)1049     private IActivityActionExecutor startSandboxActivity(
1050             ICtsSdkProviderApi sdk, ActivityStarter activityStarter) {
1051         return startSandboxActivity(sdk, activityStarter, new Bundle());
1052     }
1053 
startSandboxActivity( ICtsSdkProviderApi sdk, ActivityStarter activityStarter, Bundle extras)1054     private IActivityActionExecutor startSandboxActivity(
1055             ICtsSdkProviderApi sdk, ActivityStarter activityStarter, Bundle extras) {
1056         final String randomText = mRandom.nextInt(Integer.MAX_VALUE) + "";
1057         extras.putString(TEXT_KEY, randomText);
1058         ActivityExecutorContainer activityExecutorContainer = new ActivityExecutorContainer();
1059         mScenario.onActivity(
1060                 clientActivity -> {
1061                     activityStarter.setFromActivity(clientActivity);
1062                     IActivityActionExecutor actionExecutor = null;
1063                     try {
1064                         actionExecutor =
1065                                 (IActivityActionExecutor)
1066                                         sdk.startActivity(activityStarter, extras);
1067                     } catch (Exception e) {
1068                         fail("Got exception while starting activity: " + e.getMessage());
1069                     }
1070                     activityExecutorContainer.setExecutor(actionExecutor);
1071                 });
1072         IActivityActionExecutor actionExecutor = activityExecutorContainer.getExecutor();
1073         assertThat(actionExecutor).isNotNull();
1074         if (extras.containsKey(UNREGISTER_BEFORE_STARTING_KEY)) {
1075             assertFalse(
1076                     sUiDevice.wait(
1077                             Until.hasObject(By.textContains(randomText)), WAIT_FOR_TEXT_IN_MS));
1078         } else {
1079             assertWithMessage("Activity has random text")
1080                     .that(
1081                             sUiDevice.wait(
1082                                     Until.hasObject(By.textContains(randomText)),
1083                                     WAIT_FOR_TEXT_IN_MS))
1084                     .isTrue();
1085         }
1086         return actionExecutor;
1087     }
1088 
1089     // Separate class to store IActivityActionExecutor which is returned in a lambda expression.
1090     private static class ActivityExecutorContainer {
1091         private IActivityActionExecutor mExecutor;
1092 
setExecutor(IActivityActionExecutor executor)1093         public void setExecutor(IActivityActionExecutor executor) {
1094             mExecutor = executor;
1095         }
1096 
getExecutor()1097         public IActivityActionExecutor getExecutor() {
1098             return mExecutor;
1099         }
1100     }
1101 
1102     private class ActivityStarter extends IActivityStarter.Stub {
1103         private Activity mFromActivity;
1104         private boolean mActivityResumed = false;
1105 
ActivityStarter()1106         ActivityStarter() {}
1107 
1108         // To be called by SDKs to start sandbox activities.
1109         @Override
startSdkSandboxActivity(IBinder token)1110         public void startSdkSandboxActivity(IBinder token) throws RemoteException {
1111             assertThat(mFromActivity).isNotNull();
1112 
1113             mSdkSandboxManager.startSdkSandboxActivity(mFromActivity, token);
1114         }
1115 
1116         // It is called to notify that onResume() is called against the new started Activity.
1117         @Override
onActivityResumed()1118         public void onActivityResumed() {
1119             mActivityResumed = true;
1120         }
1121 
1122         // It is called to notify the new started Activity is no longer in the Resumed state.
1123         @Override
onLeftActivityResumed()1124         public void onLeftActivityResumed() {
1125             mActivityResumed = false;
1126         }
1127 
1128         // To start local test activities (can not be called between processes).
startLocalActivity()1129         public void startLocalActivity() {
1130             assertThat(mFromActivity).isNotNull();
1131             startLocalActivity(0);
1132         }
1133 
1134         // To start local test activities (can not be called between processes).
startLocalActivity(int flags)1135         public void startLocalActivity(int flags) {
1136             assertThat(mFromActivity).isNotNull();
1137 
1138             final Intent intent = new Intent(mFromActivity, TestActivity.class);
1139             final Bundle params = new Bundle();
1140             final String randomText = mRandom.nextInt(Integer.MAX_VALUE) + "";
1141             params.putString(TEXT_KEY, randomText);
1142             params.putBinder(ACTIVITY_STARTER_KEY, this);
1143             intent.putExtras(params);
1144             intent.addFlags(flags);
1145             mFromActivity.startActivity(intent);
1146             assertTrue(sUiDevice.wait(Until.hasObject(By.text(randomText)), WAIT_FOR_TEXT_IN_MS));
1147         }
1148 
setFromActivity(Activity activity)1149         public void setFromActivity(Activity activity) {
1150             mFromActivity = activity;
1151         }
1152 
isActivityResumed()1153         public boolean isActivityResumed() {
1154             return mActivityResumed;
1155         }
1156     }
1157 
getRequestSurfacePackageParams()1158     private Bundle getRequestSurfacePackageParams() {
1159         Bundle params = new Bundle();
1160         params.putInt(EXTRA_WIDTH_IN_PIXELS, 500);
1161         params.putInt(EXTRA_HEIGHT_IN_PIXELS, 500);
1162         params.putInt(EXTRA_DISPLAY_ID, 0);
1163         params.putBinder(EXTRA_HOST_TOKEN, new Binder());
1164 
1165         return params;
1166     }
1167 
getSdkSandboxPackageName()1168     private String getSdkSandboxPackageName() {
1169         return InstrumentationRegistry.getInstrumentation()
1170                 .getContext()
1171                 .getPackageManager()
1172                 .getSdkSandboxPackageName();
1173     }
1174 
loadMultipleSdks()1175     private void loadMultipleSdks() {
1176         FakeLoadSdkCallback callback = new FakeLoadSdkCallback();
1177         mSdkSandboxManager.loadSdk(SDK_NAME_1, new Bundle(), Runnable::run, callback);
1178         callback.assertLoadSdkIsSuccessful();
1179 
1180         FakeLoadSdkCallback callback2 = new FakeLoadSdkCallback();
1181         mSdkSandboxManager.loadSdk(SDK_NAME_2, new Bundle(), Runnable::run, callback2);
1182         callback2.assertLoadSdkIsSuccessful();
1183     }
1184 }
1185