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