blob: c7cc7ce574da2c10f8312ff7de1c67a15b04514e [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.tests.sdksandbox.endtoend;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
import android.app.sdksandbox.SdkSandboxManager;
import android.app.sdksandbox.testutils.FakeLoadSdkCallback;
import android.app.sdksandbox.testutils.FakeRequestSurfacePackageCallback;
import android.app.sdksandbox.testutils.FakeSendDataCallback;
import android.content.Context;
import android.content.pm.SharedLibraryInfo;
import android.os.Bundle;
import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.util.List;
/*
* TODO(b/215372846): These providers
* (RequestSurfacePackageSuccessfullySdkProvider, RetryLoadSameSdkShouldFailSdkProvider) could be
* deleted after solving this bug, as then tests can onload and load same SDK multiple times.
*/
@RunWith(JUnit4.class)
public class SdkSandboxManagerTest {
private SdkSandboxManager mSdkSandboxManager;
@Before
public void setup() {
final Context context = InstrumentationRegistry.getInstrumentation().getContext();
mSdkSandboxManager = context.getSystemService(SdkSandboxManager.class);
}
@Test
public void loadSdkSuccessfully() {
final String sdkName = "com.android.loadSdkSuccessfullySdkProvider";
final FakeLoadSdkCallback callback = new FakeLoadSdkCallback();
mSdkSandboxManager.loadSdk(sdkName, new Bundle(), Runnable::run, callback);
assertThat(callback.isLoadSdkSuccessful()).isTrue();
mSdkSandboxManager.unloadSdk(sdkName);
}
@Test
public void retryLoadSameSdkShouldFail() {
final String sdkName = "com.android.loadSdkSuccessfullySdkProviderTwo";
FakeLoadSdkCallback callback = new FakeLoadSdkCallback();
mSdkSandboxManager.loadSdk(sdkName, new Bundle(), Runnable::run, callback);
assertThat(callback.isLoadSdkSuccessful()).isTrue();
callback = new FakeLoadSdkCallback();
mSdkSandboxManager.loadSdk(sdkName, new Bundle(), Runnable::run, callback);
assertThat(callback.isLoadSdkSuccessful()).isFalse();
assertThat(callback.getLoadSdkErrorCode())
.isEqualTo(SdkSandboxManager.LOAD_SDK_ALREADY_LOADED);
}
@Test
public void loadNotExistSdkShouldFail() {
final String sdkName = "com.android.not_exist";
final FakeLoadSdkCallback callback = new FakeLoadSdkCallback();
mSdkSandboxManager.loadSdk(sdkName, new Bundle(), Runnable::run, callback);
assertThat(callback.isLoadSdkSuccessful()).isFalse();
assertThat(callback.getLoadSdkErrorCode())
.isEqualTo(SdkSandboxManager.LOAD_SDK_NOT_FOUND);
}
@Test
public void loadSdkWithInternalErrorShouldFail() {
final String sdkName = "com.android.loadSdkWithInternalErrorSdkProvider";
final FakeLoadSdkCallback callback = new FakeLoadSdkCallback();
mSdkSandboxManager.loadSdk(sdkName, new Bundle(), Runnable::run, callback);
assertThat(callback.isLoadSdkSuccessful()).isFalse();
assertThat(callback.getLoadSdkErrorCode())
.isEqualTo(SdkSandboxManager.LOAD_SDK_INTERNAL_ERROR);
}
@Test
public void unloadAndReloadSdk() {
final String sdkName = "com.android.loadSdkSuccessfullySdkProvider";
final FakeLoadSdkCallback callback = new FakeLoadSdkCallback();
mSdkSandboxManager.loadSdk(sdkName, new Bundle(), Runnable::run, callback);
assertThat(callback.isLoadSdkSuccessful()).isTrue();
mSdkSandboxManager.unloadSdk(sdkName);
// Calls to an unloaded SDK should throw an exception.
final FakeSendDataCallback sendDataCallback = new FakeSendDataCallback();
final FakeRequestSurfacePackageCallback requestSurfacePackageCallback =
new FakeRequestSurfacePackageCallback();
assertThrows(
IllegalArgumentException.class,
() ->
mSdkSandboxManager.sendData(
sdkName, new Bundle(), Runnable::run, sendDataCallback));
assertThrows(
IllegalArgumentException.class,
() ->
mSdkSandboxManager.requestSurfacePackage(
sdkName,
0,
500,
500,
new Bundle(),
Runnable::run,
requestSurfacePackageCallback));
// SDK can be reloaded after being unloaded.
final FakeLoadSdkCallback callback2 = new FakeLoadSdkCallback();
mSdkSandboxManager.loadSdk(sdkName, new Bundle(), Runnable::run, callback2);
assertThat(callback2.isLoadSdkSuccessful()).isTrue();
}
@Test
public void unloadingNonexistentSdkThrowsException() {
final String sdkName = "com.android.nonexistent";
assertThrows(IllegalArgumentException.class, () -> mSdkSandboxManager.unloadSdk(sdkName));
}
@Test
public void reloadingSdkDoesNotInvalidateIt() {
final String sdkName = "com.android.requestSurfacePackageSuccessfullySdkProvider";
final FakeLoadSdkCallback callback = new FakeLoadSdkCallback();
mSdkSandboxManager.loadSdk(sdkName, new Bundle(), Runnable::run, callback);
// If the SDK provider has already been loaded from another test, ignore the error.
assertThat(callback.isLoadSdkSuccessful(/*ignoreSdkAlreadyLoadedError=*/ true)).isTrue();
// Attempt to load the SDK again and see that it fails.
final FakeLoadSdkCallback reloadCallback = new FakeLoadSdkCallback();
mSdkSandboxManager.loadSdk(sdkName, new Bundle(), Runnable::run, reloadCallback);
assertThat(reloadCallback.isLoadSdkSuccessful()).isFalse();
// Further calls to the SDK should still be valid.
final FakeRequestSurfacePackageCallback surfacePackageCallback =
new FakeRequestSurfacePackageCallback();
mSdkSandboxManager.requestSurfacePackage(
sdkName, 0, 500, 500, new Bundle(), Runnable::run, surfacePackageCallback);
assertThat(surfacePackageCallback.isRequestSurfacePackageSuccessful()).isTrue();
}
@Test
public void testReloadingSdkAfterKillingSandboxIsSuccessful() throws Exception {
// Killing the sandbox and loading the same SDKs again multiple times should work
for (int i = 0; i < 3; ++i) {
// Kill the sandbox if it already exists from previous tests/loop
killSandboxAndWaitForDeath();
// The same SDKs should be able to be loaded again after sandbox death
loadMultipleSdks();
}
// Clean up before running other tests
killSandboxAndWaitForDeath();
}
@Test
public void getLoadedSdkLibrariesInfoSuccessfully() {
final String sdkName = "com.android.getLoadedSdkLibInfoSuccessfully";
final FakeLoadSdkCallback callback = new FakeLoadSdkCallback();
mSdkSandboxManager.loadSdk(sdkName, new Bundle(), Runnable::run, callback);
List<SharedLibraryInfo> sdkLibrariesInfo = mSdkSandboxManager.getLoadedSdkLibrariesInfo();
assertThat(callback.isLoadSdkSuccessful()).isTrue();
// TODO(b/239025435): assert size 1 after unload is implemented
assertThat(sdkLibrariesInfo.stream().filter(lib -> lib.getName().equals(sdkName)).count())
.isEqualTo(1);
}
@Test
public void getLoadedSdkLibrariesInfoMissesSdkWhenLoadFailed() {
final String sdkName = "com.android.loadSdkWithInternalErrorSdkProvider";
final FakeLoadSdkCallback callback = new FakeLoadSdkCallback();
mSdkSandboxManager.loadSdk(sdkName, new Bundle(), Runnable::run, callback);
assertThat(callback.isLoadSdkSuccessful()).isFalse();
List<SharedLibraryInfo> sdkLibrariesInfo = mSdkSandboxManager.getLoadedSdkLibrariesInfo();
// TODO(b/239025435): assert empty after unload is implemented
assertThat(sdkLibrariesInfo.stream().filter(lib -> lib.getName().equals(sdkName)).count())
.isEqualTo(0);
}
@Test
public void requestSurfacePackageSuccessfully() {
final String sdkName = "com.android.requestSurfacePackageSuccessfullySdkProvider";
final FakeLoadSdkCallback callback = new FakeLoadSdkCallback();
mSdkSandboxManager.loadSdk(sdkName, new Bundle(), Runnable::run, callback);
// If the SDK provider has already been loaded from another test, ignore the SDK already
// loaded error.
assertThat(callback.isLoadSdkSuccessful(/*ignoreSdkAlreadyLoadedError=*/ true)).isTrue();
final FakeRequestSurfacePackageCallback surfacePackageCallback =
new FakeRequestSurfacePackageCallback();
mSdkSandboxManager.requestSurfacePackage(
sdkName, 0, 500, 500, new Bundle(), Runnable::run, surfacePackageCallback);
assertThat(surfacePackageCallback.isRequestSurfacePackageSuccessful()).isTrue();
}
@Test
public void requestSurfacePackageWithInternalErrorShouldFail() {
final String sdkName = "com.android.requestSurfacePackageWithInternalErrorSdkProvider";
final FakeLoadSdkCallback callback = new FakeLoadSdkCallback();
mSdkSandboxManager.loadSdk(sdkName, new Bundle(), Runnable::run, callback);
assertThat(callback.isLoadSdkSuccessful()).isTrue();
final FakeRequestSurfacePackageCallback surfacePackageCallback =
new FakeRequestSurfacePackageCallback();
mSdkSandboxManager.requestSurfacePackage(
sdkName, 0, 500, 500, new Bundle(), Runnable::run, surfacePackageCallback);
assertThat(surfacePackageCallback.isRequestSurfacePackageSuccessful()).isFalse();
assertThat(surfacePackageCallback.getSurfacePackageErrorCode())
.isEqualTo(SdkSandboxManager.REQUEST_SURFACE_PACKAGE_INTERNAL_ERROR);
}
@Test
public void sendDataSuccessfully() {
final String sdkName = "com.android.sendDataSdkProvider";
final FakeLoadSdkCallback callback = new FakeLoadSdkCallback();
mSdkSandboxManager.loadSdk(sdkName, new Bundle(), Runnable::run, callback);
assertThat(callback.isLoadSdkSuccessful(/*ignoreSdkAlreadyLoadedError=*/ true)).isTrue();
Bundle data = new Bundle();
data.putChar("Success", 'S');
final FakeSendDataCallback sendDataCallback = new FakeSendDataCallback();
mSdkSandboxManager.sendData(sdkName, data, Runnable::run, sendDataCallback);
assertThat(sendDataCallback.isSendDataSuccessful()).isTrue();
Bundle returnData = sendDataCallback.getSendDataSuccessBundle();
assertThat(returnData.getChar("Completed")).isEqualTo('C');
}
@Test
public void sendIncorrectDataShouldFail() {
final String sdkName = "com.android.sendDataSdkProvider";
final FakeLoadSdkCallback callback = new FakeLoadSdkCallback();
mSdkSandboxManager.loadSdk(sdkName, new Bundle(), Runnable::run, callback);
assertThat(callback.isLoadSdkSuccessful(/*ignoreSdkAlreadyLoadedError=*/ true)).isTrue();
final FakeSendDataCallback sendDataCallback = new FakeSendDataCallback();
mSdkSandboxManager.sendData(sdkName, new Bundle(), Runnable::run, sendDataCallback);
assertThat(sendDataCallback.isSendDataSuccessful()).isFalse();
assertThat(sendDataCallback.getSendDataErrorCode())
.isEqualTo(SdkSandboxManager.SEND_DATA_INTERNAL_ERROR);
assertThat(sendDataCallback.getSendDataErrorMsg()).contains("Unable to process data");
}
@Test
public void testResourcesAndAssets() {
final String sdkName = "com.android.codeproviderresources";
FakeLoadSdkCallback callback = new FakeLoadSdkCallback();
mSdkSandboxManager.loadSdk(sdkName, new Bundle(), Runnable::run, callback);
assertThat(callback.isLoadSdkSuccessful()).isTrue();
}
private void loadMultipleSdks() {
FakeLoadSdkCallback callback = new FakeLoadSdkCallback();
final String sdk1 = "com.android.loadSdkSuccessfullySdkProvider";
mSdkSandboxManager.loadSdk(sdk1, new Bundle(), Runnable::run, callback);
assertThat(callback.isLoadSdkSuccessful()).isTrue();
FakeLoadSdkCallback callback2 = new FakeLoadSdkCallback();
final String sdk2 = "com.android.loadSdkSuccessfullySdkProviderTwo";
mSdkSandboxManager.loadSdk(sdk2, new Bundle(), Runnable::run, callback2);
assertThat(callback2.isLoadSdkSuccessful()).isTrue();
}
private void killSandboxAndWaitForDeath() throws Exception {
// TODO(b/241542162): Avoid using reflection as a workaround once test apis can be run
// without issue.
mSdkSandboxManager.getClass().getMethod("stopSdkSandbox").invoke(mSdkSandboxManager);
Thread.sleep(1000);
}
}