diff options
Diffstat (limited to 'tests/BinaryTransparencyHostTest')
7 files changed, 330 insertions, 0 deletions
diff --git a/tests/BinaryTransparencyHostTest/Android.bp b/tests/BinaryTransparencyHostTest/Android.bp new file mode 100644 index 000000000000..142e3ddf9fe7 --- /dev/null +++ b/tests/BinaryTransparencyHostTest/Android.bp @@ -0,0 +1,42 @@ +// Copyright (C) 2023 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 { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +java_test_host { + name: "BinaryTransparencyHostTest", + srcs: ["src/**/*.java"], + libs: [ + "tradefed", + "compatibility-tradefed", + "compatibility-host-util", + ], + static_libs: [ + "truth-prebuilt", + ], + data: [ + ":BinaryTransparencyTestApp", + ":EasterEgg", + ], + test_suites: [ + "general-tests", + ], +} diff --git a/tests/BinaryTransparencyHostTest/AndroidTest.xml b/tests/BinaryTransparencyHostTest/AndroidTest.xml new file mode 100644 index 000000000000..e0d11c0c1097 --- /dev/null +++ b/tests/BinaryTransparencyHostTest/AndroidTest.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2023 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. +--> +<configuration description="Binary Transparency integration test"> + <option name="test-suite-tag" value="apct" /> + + <!-- Service is not exposed to apps. Disable SELinux for testing purpose. --> + <target_preparer class="com.android.tradefed.targetprep.DisableSELinuxTargetPreparer" /> + + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true" /> + <option name="test-file-name" value="BinaryTransparencyTestApp.apk" /> + </target_preparer> + + <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" > + <option name="jar" value="BinaryTransparencyHostTest.jar" /> + <option name="runtime-hint" value="1m" /> + </test> +</configuration> diff --git a/tests/BinaryTransparencyHostTest/OWNERS b/tests/BinaryTransparencyHostTest/OWNERS new file mode 100644 index 000000000000..ca84550c76a4 --- /dev/null +++ b/tests/BinaryTransparencyHostTest/OWNERS @@ -0,0 +1 @@ +include /core/java/android/transparency/OWNERS diff --git a/tests/BinaryTransparencyHostTest/src/android/transparency/test/BinaryTransparencyHostTest.java b/tests/BinaryTransparencyHostTest/src/android/transparency/test/BinaryTransparencyHostTest.java new file mode 100644 index 000000000000..84bed92f5117 --- /dev/null +++ b/tests/BinaryTransparencyHostTest/src/android/transparency/test/BinaryTransparencyHostTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2023 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 android.transparency.test; + +import static org.junit.Assert.assertTrue; + +import com.android.tradefed.device.DeviceNotAvailableException; +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; +import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; +import com.android.tradefed.testtype.junit4.DeviceTestRunOptions; +import com.android.tradefed.util.CommandResult; +import com.android.tradefed.util.CommandStatus; + +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; + +// TODO: Add @Presubmit +@RunWith(DeviceJUnit4ClassRunner.class) +public final class BinaryTransparencyHostTest extends BaseHostJUnit4Test { + private static final String PACKAGE_NAME = "android.transparency.test.app"; + + @After + public void tearDown() throws Exception { + uninstallPackage("com.android.egg"); + } + + @Test + public void testCollectAllApexInfo() throws Exception { + var options = new DeviceTestRunOptions(PACKAGE_NAME); + options.setTestClassName(PACKAGE_NAME + ".BinaryTransparencyTest"); + options.setTestMethodName("testCollectAllApexInfo"); + + // Collect APEX package names from /apex, then pass them as expectation to be verified. + CommandResult result = getDevice().executeShellV2Command( + "ls -d /apex/*/ |grep -v @ |grep -v /apex/sharedlibs |cut -d/ -f3"); + assertTrue(result.getStatus() == CommandStatus.SUCCESS); + String[] packageNames = result.getStdout().split("\n"); + for (var i = 0; i < packageNames.length; i++) { + options.addInstrumentationArg("apex-" + String.valueOf(i), packageNames[i]); + } + options.addInstrumentationArg("apex-number", Integer.toString(packageNames.length)); + runDeviceTests(options); + } + + @Test + public void testCollectAllUpdatedPreloadInfo() throws Exception { + installPackage("EasterEgg.apk"); + runDeviceTest("testCollectAllUpdatedPreloadInfo"); + } + + @Test + public void testMeasureMbas() throws Exception { + // TODO(265244016): figure out a way to install an MBA + } + + private void runDeviceTest(String method) throws DeviceNotAvailableException { + var options = new DeviceTestRunOptions(PACKAGE_NAME); + options.setTestClassName(PACKAGE_NAME + ".BinaryTransparencyTest"); + options.setTestMethodName(method); + runDeviceTests(options); + } +} diff --git a/tests/BinaryTransparencyHostTest/test-app/Android.bp b/tests/BinaryTransparencyHostTest/test-app/Android.bp new file mode 100644 index 000000000000..b5193ddf7c2c --- /dev/null +++ b/tests/BinaryTransparencyHostTest/test-app/Android.bp @@ -0,0 +1,40 @@ +// Copyright (C) 2023 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 { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +android_test_helper_app { + name: "BinaryTransparencyTestApp", + manifest: "AndroidManifest.xml", + srcs: ["src/**/*.java"], + static_libs: [ + "androidx.test.core", + "compatibility-device-util-axt", + "junit", + ], + test_suites: [ + "general-tests", + ], + platform_apis: true, + dex_preopt: { + enabled: false, + }, +} diff --git a/tests/BinaryTransparencyHostTest/test-app/AndroidManifest.xml b/tests/BinaryTransparencyHostTest/test-app/AndroidManifest.xml new file mode 100644 index 000000000000..42e616e24eb9 --- /dev/null +++ b/tests/BinaryTransparencyHostTest/test-app/AndroidManifest.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * Copyright (C) 2023 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. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.transparency.test.app"> + <application> + <uses-library android:name="android.test.runner" /> + </application> + + <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner" + android:label="APCT tests for binary transparency" + android:targetPackage="android.transparency.test.app" /> +</manifest> diff --git a/tests/BinaryTransparencyHostTest/test-app/src/android/transparency/test/app/BinaryTransparencyTest.java b/tests/BinaryTransparencyHostTest/test-app/src/android/transparency/test/app/BinaryTransparencyTest.java new file mode 100644 index 000000000000..aedb3666a574 --- /dev/null +++ b/tests/BinaryTransparencyHostTest/test-app/src/android/transparency/test/app/BinaryTransparencyTest.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2023 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 android.transparency.test.app; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + +import android.content.Context; +import android.os.Bundle; +import android.transparency.BinaryTransparencyManager; +import android.util.Log; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import com.android.internal.os.IBinaryTransparencyService.AppInfo; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.HashSet; +import java.util.HexFormat; +import java.util.stream.Collectors; + +@RunWith(AndroidJUnit4.class) +public class BinaryTransparencyTest { + private static final String TAG = "BinaryTransparencyTest"; + + private BinaryTransparencyManager mBt; + + @Before + public void setUp() { + Context context = InstrumentationRegistry.getInstrumentation().getContext(); + mBt = context.getSystemService(BinaryTransparencyManager.class); + } + + @Test + public void testCollectAllApexInfo() { + // Prepare the expectation received from host's shell command + Bundle args = InstrumentationRegistry.getArguments(); + assertThat(args).isNotNull(); + int number = Integer.valueOf(args.getString("apex-number")); + assertThat(number).isGreaterThan(0); + var expectedApexNames = new HashSet<String>(); + for (var i = 0; i < number; i++) { + String moduleName = args.getString("apex-" + Integer.toString(i)); + expectedApexNames.add(moduleName); + } + + // Action + var apexInfoList = mBt.collectAllApexInfo(/* includeTestOnly */ true); + + // Verify actual apex names + var actualApexesNames = apexInfoList.stream().map((apex) -> apex.moduleName) + .collect(Collectors.toList()); + assertThat(actualApexesNames).containsExactlyElementsIn(expectedApexNames); + + // Perform more valitidy checks + var digestsSeen = new HashSet<String>(); + var hexFormatter = HexFormat.of(); + for (var apex : apexInfoList) { + Log.d(TAG, "Verifying " + apex.packageName + " / " + apex.moduleName); + + assertThat(apex.longVersion).isGreaterThan(0); + assertThat(apex.digestAlgorithm).isGreaterThan(0); + assertThat(apex.signerDigests).asList().containsNoneOf(null, ""); + + assertThat(apex.digest).isNotNull(); + String digestHex = hexFormatter.formatHex(apex.digest); + boolean isNew = digestsSeen.add(digestHex); + assertWithMessage( + "Digest should be unique, but received a dup: " + digestHex) + .that(isNew).isTrue(); + } + } + + @Test + public void testCollectAllUpdatedPreloadInfo() { + var preloadInfoList = mBt.collectAllUpdatedPreloadInfo(new Bundle()); + assertThat(preloadInfoList).isNotEmpty(); // because we just installed from the host side + AppInfo updatedPreload = null; + for (var preload : preloadInfoList) { + Log.d(TAG, "Received " + preload.packageName); + if (preload.packageName.equals("com.android.egg")) { + assertWithMessage("Received the same package").that(updatedPreload).isNull(); + updatedPreload = preload; + } + } + + // Verify + assertThat(updatedPreload.longVersion).isGreaterThan(0); + assertThat(updatedPreload.digestAlgorithm).isGreaterThan(0); + assertThat(updatedPreload.digest).isNotEmpty(); + assertThat(updatedPreload.mbaStatus).isEqualTo(/* MBA_STATUS_UPDATED_PRELOAD */ 2); + assertThat(updatedPreload.signerDigests).asList().containsNoneOf(null, ""); + } +} |